From 193434bcb17f4f7099b2989ce54eb5b4ae986107 Mon Sep 17 00:00:00 2001 From: Felix Prasanna Date: Sat, 30 Mar 2024 15:41:27 -0400 Subject: [PATCH 1/2] set correct lint level for superior formatting --- src/bootstrap/src/bin/rustc.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs index 4b182a7a693dd..7050dd6ace0f6 100644 --- a/src/bootstrap/src/bin/rustc.rs +++ b/src/bootstrap/src/bin/rustc.rs @@ -252,6 +252,9 @@ fn main() { bin_helpers::maybe_dump(format!("stage{stage}-rustc"), &cmd); + // Unformatting! + cmd.arg("--cap-lints=allow"); + let start = Instant::now(); let (child, status) = { let errmsg = format!("\nFailed to run:\n{cmd:?}\n-------------"); From 92bd29f462b4a4cb651b0570baf97f4d847a13d0 Mon Sep 17 00:00:00 2001 From: Felix Prasanna Date: Mon, 1 Apr 2024 11:12:47 -0400 Subject: [PATCH 2/2] apply superior formatting --- compiler/rustc/build.rs | 37 +- compiler/rustc_abi/src/layout.rs | 1649 +---- compiler/rustc_arena/src/lib.rs | 838 +-- compiler/rustc_arena/src/tests.rs | 295 +- compiler/rustc_ast/src/ast_traits.rs | 526 +- compiler/rustc_ast/src/attr/mod.rs | 812 +-- compiler/rustc_ast/src/expand/allocator.rs | 94 +- compiler/rustc_ast/src/expand/mod.rs | 26 +- compiler/rustc_ast/src/format.rs | 313 +- compiler/rustc_ast/src/lib.rs | 84 +- compiler/rustc_ast/src/mut_visit.rs | 2218 ++---- compiler/rustc_ast/src/node_id.rs | 49 +- compiler/rustc_ast/src/ptr.rs | 247 +- compiler/rustc_ast/src/token.rs | 1254 +--- compiler/rustc_ast/src/tokenstream.rs | 967 +-- compiler/rustc_ast/src/util/case.rs | 7 +- compiler/rustc_ast/src/util/classify.rs | 111 +- compiler/rustc_ast/src/util/comments.rs | 157 +- compiler/rustc_ast/src/util/comments/tests.rs | 87 +- compiler/rustc_ast/src/util/literal.rs | 432 +- compiler/rustc_ast/src/util/parser.rs | 488 +- compiler/rustc_ast/src/util/unicode.rs | 41 +- compiler/rustc_ast/src/visit.rs | 1441 ++-- compiler/rustc_ast_ir/src/lib.rs | 86 +- compiler/rustc_ast_ir/src/visit.rs | 103 +- .../rustc_ast_passes/src/ast_validation.rs | 2252 ++---- compiler/rustc_ast_passes/src/errors.rs | 1050 +-- compiler/rustc_ast_passes/src/feature_gate.rs | 916 +-- compiler/rustc_ast_passes/src/lib.rs | 26 +- compiler/rustc_ast_passes/src/node_count.rs | 163 +- compiler/rustc_ast_passes/src/show_span.rs | 82 +- compiler/rustc_ast_pretty/src/helpers.rs | 57 +- compiler/rustc_ast_pretty/src/lib.rs | 10 +- compiler/rustc_ast_pretty/src/pp.rs | 520 +- .../rustc_ast_pretty/src/pp/convenience.rs | 116 +- compiler/rustc_ast_pretty/src/pp/ring.rs | 91 +- compiler/rustc_ast_pretty/src/pprust/mod.rs | 116 +- compiler/rustc_ast_pretty/src/pprust/state.rs | 2579 ++----- .../rustc_ast_pretty/src/pprust/state/expr.rs | 1332 +--- .../rustc_ast_pretty/src/pprust/state/item.rs | 958 +-- compiler/rustc_ast_pretty/src/pprust/tests.rs | 83 +- compiler/rustc_attr/src/builtin.rs | 1583 +---- compiler/rustc_attr/src/lib.rs | 34 +- .../rustc_attr/src/session_diagnostics.rs | 507 +- compiler/rustc_baked_icu_data/src/data/any.rs | 3 +- .../macros/fallback_likelysubtags_v1.data.rs | 84 +- .../data/macros/fallback_parents_v1.data.rs | 49 +- .../macros/fallback_supplement_co_v1.data.rs | 56 +- .../src/data/macros/list_and_v1.data.rs | 499 +- compiler/rustc_baked_icu_data/src/data/mod.rs | 56 +- compiler/rustc_baked_icu_data/src/lib.rs | 62 +- compiler/rustc_borrowck/src/borrow_set.rs | 446 +- .../rustc_borrowck/src/borrowck_errors.rs | 613 +- .../rustc_borrowck/src/constraints/graph.rs | 304 +- .../rustc_borrowck/src/constraints/mod.rs | 155 +- compiler/rustc_borrowck/src/consumers.rs | 137 +- compiler/rustc_borrowck/src/dataflow.rs | 800 +-- compiler/rustc_borrowck/src/def_use.rs | 106 +- .../src/diagnostics/bound_region_errors.rs | 624 +- .../src/diagnostics/conflict_errors.rs | 5241 ++++---------- .../src/diagnostics/explain_borrow.rs | 943 +-- .../src/diagnostics/find_all_local_uses.rs | 34 +- .../src/diagnostics/find_use.rs | 164 +- .../rustc_borrowck/src/diagnostics/mod.rs | 1685 +---- .../src/diagnostics/move_errors.rs | 811 +-- .../src/diagnostics/outlives_suggestion.rs | 321 +- .../src/diagnostics/var_name.rs | 173 +- compiler/rustc_borrowck/src/facts.rs | 251 +- compiler/rustc_borrowck/src/lib.rs | 3183 ++------- compiler/rustc_borrowck/src/location.rs | 130 +- .../rustc_borrowck/src/member_constraints.rs | 283 +- compiler/rustc_borrowck/src/nll.rs | 440 +- compiler/rustc_borrowck/src/path_utils.rs | 209 +- compiler/rustc_borrowck/src/place_ext.rs | 85 +- .../rustc_borrowck/src/places_conflict.rs | 636 +- .../src/polonius/loan_invalidations.rs | 540 +- .../rustc_borrowck/src/polonius/loan_kills.rs | 194 +- compiler/rustc_borrowck/src/polonius/mod.rs | 243 +- compiler/rustc_borrowck/src/prefixes.rs | 122 +- .../src/region_infer/dump_mir.rs | 114 +- .../src/region_infer/graphviz.rs | 186 +- .../rustc_borrowck/src/region_infer/mod.rs | 2863 ++------ .../src/region_infer/opaque_types.rs | 670 +- .../src/region_infer/reverse_sccs.rs | 85 +- .../rustc_borrowck/src/region_infer/values.rs | 699 +- compiler/rustc_borrowck/src/renumber.rs | 160 +- .../rustc_borrowck/src/session_diagnostics.rs | 606 +- .../src/type_check/canonical.rs | 275 +- .../src/type_check/constraint_conversion.rs | 443 +- .../src/type_check/free_region_relations.rs | 542 +- .../src/type_check/input_output.rs | 293 +- .../src/type_check/liveness/local_use_map.rs | 214 +- .../src/type_check/liveness/mod.rs | 276 +- .../src/type_check/liveness/polonius.rs | 200 +- .../src/type_check/liveness/trace.rs | 771 +-- compiler/rustc_borrowck/src/type_check/mod.rs | 3689 +++------- .../src/type_check/relate_tys.rs | 764 +- .../rustc_borrowck/src/universal_regions.rs | 1167 +--- compiler/rustc_borrowck/src/used_muts.rs | 143 +- .../rustc_borrowck/src/util/collect_writes.rs | 47 +- compiler/rustc_borrowck/src/util/mod.rs | 4 +- .../src/alloc_error_handler.rs | 131 +- compiler/rustc_builtin_macros/src/asm.rs | 1059 +-- compiler/rustc_builtin_macros/src/assert.rs | 203 +- .../src/assert/context.rs | 581 +- compiler/rustc_builtin_macros/src/cfg.rs | 68 +- .../src/cfg_accessible.rs | 91 +- compiler/rustc_builtin_macros/src/cfg_eval.rs | 387 +- .../rustc_builtin_macros/src/cmdline_attrs.rs | 51 +- .../rustc_builtin_macros/src/compile_error.rs | 38 +- compiler/rustc_builtin_macros/src/concat.rs | 116 +- .../rustc_builtin_macros/src/concat_bytes.rs | 246 +- .../rustc_builtin_macros/src/concat_idents.rs | 94 +- compiler/rustc_builtin_macros/src/derive.rs | 194 +- .../src/deriving/bounds.rs | 66 +- .../src/deriving/clone.rs | 278 +- .../src/deriving/cmp/eq.rs | 117 +- .../src/deriving/cmp/ord.rs | 104 +- .../src/deriving/cmp/partial_eq.rs | 146 +- .../src/deriving/cmp/partial_ord.rs | 194 +- .../src/deriving/debug.rs | 313 +- .../src/deriving/decodable.rs | 295 +- .../src/deriving/default.rs | 332 +- .../src/deriving/encodable.rs | 366 +- .../src/deriving/generic/mod.rs | 2057 +----- .../src/deriving/generic/ty.rs | 253 +- .../rustc_builtin_macros/src/deriving/hash.rs | 107 +- .../rustc_builtin_macros/src/edition_panic.rs | 104 +- compiler/rustc_builtin_macros/src/env.rs | 206 +- compiler/rustc_builtin_macros/src/errors.rs | 1083 +-- compiler/rustc_builtin_macros/src/format.rs | 1290 +--- .../src/format_foreign.rs | 974 +-- .../src/format_foreign/printf/tests.rs | 202 +- .../src/format_foreign/shell/tests.rs | 76 +- .../src/global_allocator.rs | 237 +- compiler/rustc_builtin_macros/src/lib.rs | 185 +- .../rustc_builtin_macros/src/log_syntax.rs | 19 +- .../src/proc_macro_harness.rs | 491 +- .../rustc_builtin_macros/src/source_util.rs | 446 +- .../src/standard_library_imports.rs | 134 +- compiler/rustc_builtin_macros/src/test.rs | 767 +-- .../rustc_builtin_macros/src/test_harness.rs | 515 +- .../rustc_builtin_macros/src/trace_macros.rs | 40 +- compiler/rustc_builtin_macros/src/util.rs | 67 +- .../build_system/abi_cafe.rs | 77 +- .../build_system/build_backend.rs | 75 +- .../build_system/config.rs | 71 +- .../build_system/main.rs | 346 +- .../build_system/path.rs | 91 +- .../build_system/prepare.rs | 394 +- .../build_system/rustc_info.rs | 128 +- .../build_system/shared_utils.rs | 33 +- .../build_system/tests.rs | 681 +- .../build_system/utils.rs | 383 +- .../example/alloc_example.rs | 53 +- .../example/alloc_system.rs | 164 +- ...itrary_self_types_pointers_and_wrappers.rs | 84 +- .../example/dst-field-align.rs | 78 +- .../example/example.rs | 241 +- .../example/float-minmax-pass.rs | 62 +- .../example/issue-59326.rs | 32 +- .../example/issue-72793.rs | 30 +- .../example/mod_bench.rs | 44 +- .../rustc_codegen_cranelift/example/neon.rs | 307 +- .../example/polymorphize_coroutine.rs | 19 +- .../example/std_example.rs | 625 +- .../example/subslice-patterns-const-eval.rs | 125 +- .../example/track-caller-attribute.rs | 50 +- .../scripts/cargo-clif.rs | 126 +- .../scripts/filter_profile.rs | 175 +- .../src/abi/comments.rs | 125 +- .../rustc_codegen_cranelift/src/abi/mod.rs | 913 +-- .../src/abi/pass_mode.rs | 403 +- .../src/abi/returning.rs | 177 +- .../rustc_codegen_cranelift/src/allocator.rs | 138 +- .../rustc_codegen_cranelift/src/analyze.rs | 50 +- .../rustc_codegen_cranelift/src/archive.rs | 34 +- compiler/rustc_codegen_cranelift/src/base.rs | 1344 +--- compiler/rustc_codegen_cranelift/src/cast.rs | 210 +- .../src/codegen_i128.rs | 192 +- .../rustc_codegen_cranelift/src/common.rs | 682 +- .../src/compiler_builtins.rs | 97 +- .../src/concurrency_limiter.rs | 274 +- .../rustc_codegen_cranelift/src/config.rs | 126 +- .../rustc_codegen_cranelift/src/constant.rs | 755 +- .../src/debuginfo/emit.rs | 263 +- .../src/debuginfo/line_info.rs | 235 +- .../src/debuginfo/mod.rs | 458 +- .../src/debuginfo/object.rs | 109 +- .../src/debuginfo/types.rs | 277 +- .../src/debuginfo/unwind.rs | 171 +- .../src/discriminant.rs | 265 +- .../rustc_codegen_cranelift/src/driver/aot.rs | 903 +-- .../rustc_codegen_cranelift/src/driver/jit.rs | 555 +- .../rustc_codegen_cranelift/src/driver/mod.rs | 92 +- .../rustc_codegen_cranelift/src/global_asm.rs | 288 +- .../rustc_codegen_cranelift/src/inline_asm.rs | 1035 +-- .../src/intrinsics/llvm.rs | 105 +- .../src/intrinsics/llvm_aarch64.rs | 424 +- .../src/intrinsics/llvm_x86.rs | 2022 ++---- .../src/intrinsics/mod.rs | 1707 ++--- .../src/intrinsics/simd.rs | 1549 ++--- compiler/rustc_codegen_cranelift/src/lib.rs | 477 +- .../rustc_codegen_cranelift/src/linkage.rs | 50 +- .../rustc_codegen_cranelift/src/main_shim.rs | 236 +- compiler/rustc_codegen_cranelift/src/num.rs | 587 +- .../src/optimize/mod.rs | 4 +- .../src/optimize/peephole.rs | 58 +- .../rustc_codegen_cranelift/src/pointer.rs | 172 +- .../src/pretty_clif.rs | 344 +- .../rustc_codegen_cranelift/src/toolchain.rs | 37 +- compiler/rustc_codegen_cranelift/src/trap.rs | 49 +- .../rustc_codegen_cranelift/src/unsize.rs | 403 +- .../src/value_and_place.rs | 1338 +--- .../rustc_codegen_cranelift/src/vtable.rs | 135 +- compiler/rustc_codegen_gcc/build.rs | 9 +- .../build_sysroot/src/lib.rs | 2 +- .../build_system/src/build.rs | 299 +- .../build_system/src/cargo.rs | 144 +- .../build_system/src/clone_gcc.rs | 98 +- .../build_system/src/config.rs | 700 +- .../build_system/src/info.rs | 25 +- .../build_system/src/main.rs | 97 +- .../build_system/src/prepare.rs | 345 +- .../build_system/src/rustc_info.rs | 17 +- .../build_system/src/test.rs | 1533 +---- .../build_system/src/utils.rs | 574 +- .../example/alloc_example.rs | 58 +- .../rustc_codegen_gcc/example/alloc_system.rs | 283 +- ...itrary_self_types_pointers_and_wrappers.rs | 88 +- .../example/dst-field-align.rs | 79 +- compiler/rustc_codegen_gcc/example/example.rs | 243 +- .../rustc_codegen_gcc/example/mod_bench.rs | 43 +- .../rustc_codegen_gcc/example/std_example.rs | 401 +- .../example/subslice-patterns-const-eval.rs | 120 +- .../example/track-caller-attribute.rs | 50 +- compiler/rustc_codegen_gcc/src/abi.rs | 295 +- compiler/rustc_codegen_gcc/src/allocator.rs | 193 +- compiler/rustc_codegen_gcc/src/archive.rs | 36 +- compiler/rustc_codegen_gcc/src/asm.rs | 1237 +--- compiler/rustc_codegen_gcc/src/attributes.rs | 174 +- compiler/rustc_codegen_gcc/src/back/lto.rs | 452 +- compiler/rustc_codegen_gcc/src/back/mod.rs | 3 +- compiler/rustc_codegen_gcc/src/back/write.rs | 251 +- compiler/rustc_codegen_gcc/src/base.rs | 288 +- compiler/rustc_codegen_gcc/src/builder.rs | 3198 +++------ compiler/rustc_codegen_gcc/src/callee.rs | 199 +- compiler/rustc_codegen_gcc/src/common.rs | 591 +- compiler/rustc_codegen_gcc/src/consts.rs | 508 +- compiler/rustc_codegen_gcc/src/context.rs | 810 +-- .../rustc_codegen_gcc/src/coverageinfo.rs | 16 +- compiler/rustc_codegen_gcc/src/debuginfo.rs | 380 +- compiler/rustc_codegen_gcc/src/declare.rs | 339 +- compiler/rustc_codegen_gcc/src/errors.rs | 137 +- compiler/rustc_codegen_gcc/src/gcc_util.rs | 295 +- compiler/rustc_codegen_gcc/src/int.rs | 1355 +--- .../rustc_codegen_gcc/src/intrinsic/llvm.rs | 1588 ++--- .../rustc_codegen_gcc/src/intrinsic/mod.rs | 1670 ++--- .../rustc_codegen_gcc/src/intrinsic/simd.rs | 1667 ++--- compiler/rustc_codegen_gcc/src/mono_item.rs | 116 +- compiler/rustc_codegen_gcc/src/type_.rs | 396 +- compiler/rustc_codegen_gcc/src/type_of.rs | 491 +- .../tests/lang_tests_common.rs | 184 +- .../tests/lang_tests_debug.rs | 7 +- .../tests/lang_tests_release.rs | 7 +- .../rustc_codegen_gcc/tests/run/abort1.rs | 60 +- .../rustc_codegen_gcc/tests/run/abort2.rs | 62 +- compiler/rustc_codegen_gcc/tests/run/array.rs | 268 +- compiler/rustc_codegen_gcc/tests/run/asm.rs | 212 +- .../rustc_codegen_gcc/tests/run/assign.rs | 177 +- .../rustc_codegen_gcc/tests/run/closure.rs | 279 +- .../rustc_codegen_gcc/tests/run/condition.rs | 375 +- .../rustc_codegen_gcc/tests/run/empty_main.rs | 45 +- compiler/rustc_codegen_gcc/tests/run/exit.rs | 56 +- .../rustc_codegen_gcc/tests/run/exit_code.rs | 45 +- .../rustc_codegen_gcc/tests/run/fun_ptr.rs | 260 +- compiler/rustc_codegen_gcc/tests/run/gep.rs | 12 +- compiler/rustc_codegen_gcc/tests/run/int.rs | 448 +- .../tests/run/int_overflow.rs | 27 +- .../rustc_codegen_gcc/tests/run/mut_ref.rs | 191 +- .../rustc_codegen_gcc/tests/run/operations.rs | 255 +- .../rustc_codegen_gcc/tests/run/ptr_cast.rs | 259 +- .../tests/run/return-tuple.rs | 87 +- compiler/rustc_codegen_gcc/tests/run/slice.rs | 155 +- .../rustc_codegen_gcc/tests/run/static.rs | 130 +- .../rustc_codegen_gcc/tests/run/structs.rs | 80 +- compiler/rustc_codegen_gcc/tests/run/tuple.rs | 59 +- .../rustc_codegen_gcc/tests/run/volatile.rs | 31 +- compiler/rustc_codegen_llvm/src/abi.rs | 813 +-- compiler/rustc_codegen_llvm/src/asm.rs | 1573 ++--- compiler/rustc_codegen_llvm/src/attributes.rs | 680 +- .../src/back/owned_target_machine.rs | 128 +- .../rustc_codegen_llvm/src/back/profiling.rs | 86 +- compiler/rustc_codegen_llvm/src/callee.rs | 224 +- compiler/rustc_codegen_llvm/src/common.rs | 549 +- .../src/coverageinfo/ffi.rs | 335 +- .../src/coverageinfo/map_data.rs | 338 +- .../src/coverageinfo/mapgen.rs | 613 +- .../src/coverageinfo/mod.rs | 373 +- .../src/debuginfo/create_scope_map.rs | 174 +- .../src/debuginfo/metadata/enums/cpp_like.rs | 1168 +--- .../src/debuginfo/metadata/enums/mod.rs | 581 +- .../src/debuginfo/metadata/enums/native.rs | 548 +- .../src/debuginfo/metadata/type_map.rs | 360 +- .../src/debuginfo/namespace.rs | 62 +- .../rustc_codegen_llvm/src/debuginfo/utils.rs | 124 +- compiler/rustc_codegen_llvm/src/declare.rs | 288 +- compiler/rustc_codegen_llvm/src/errors.rs | 351 +- compiler/rustc_codegen_llvm/src/intrinsic.rs | 3097 ++------- .../rustc_codegen_llvm/src/llvm/archive_ro.rs | 115 +- .../rustc_codegen_llvm/src/llvm/diagnostic.rs | 273 +- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 3125 ++------- compiler/rustc_codegen_llvm/src/llvm/mod.rs | 414 +- compiler/rustc_codegen_llvm/src/llvm_util.rs | 849 +-- compiler/rustc_codegen_llvm/src/mono_item.rs | 208 +- compiler/rustc_codegen_llvm/src/type_.rs | 473 +- compiler/rustc_codegen_llvm/src/type_of.rs | 451 +- compiler/rustc_codegen_llvm/src/va_arg.rs | 418 +- compiler/rustc_codegen_llvm/src/value.rs | 39 +- .../src/assert_module_sources.rs | 380 +- .../rustc_codegen_ssa/src/back/archive.rs | 406 +- .../rustc_codegen_ssa/src/back/command.rs | 204 +- compiler/rustc_codegen_ssa/src/back/link.rs | 3957 +++-------- compiler/rustc_codegen_ssa/src/back/linker.rs | 2558 ++----- compiler/rustc_codegen_ssa/src/back/lto.rs | 129 +- .../rustc_codegen_ssa/src/back/metadata.rs | 859 +-- compiler/rustc_codegen_ssa/src/back/mod.rs | 11 +- compiler/rustc_codegen_ssa/src/back/rpath.rs | 148 +- .../rustc_codegen_ssa/src/back/rpath/tests.rs | 92 +- .../src/back/symbol_export.rs | 860 +-- compiler/rustc_codegen_ssa/src/back/write.rs | 2638 ++----- compiler/rustc_codegen_ssa/src/base.rs | 1364 +--- .../rustc_codegen_ssa/src/codegen_attrs.rs | 885 +-- compiler/rustc_codegen_ssa/src/common.rs | 267 +- .../rustc_codegen_ssa/src/debuginfo/mod.rs | 40 +- .../src/debuginfo/type_names.rs | 1039 +-- compiler/rustc_codegen_ssa/src/errors.rs | 1367 +--- compiler/rustc_codegen_ssa/src/lib.rs | 354 +- compiler/rustc_codegen_ssa/src/meth.rs | 149 +- compiler/rustc_codegen_ssa/src/mir/analyze.rs | 487 +- compiler/rustc_codegen_ssa/src/mir/block.rs | 2343 ++----- .../rustc_codegen_ssa/src/mir/constant.rs | 129 +- .../rustc_codegen_ssa/src/mir/coverageinfo.rs | 26 +- .../rustc_codegen_ssa/src/mir/debuginfo.rs | 713 +- .../rustc_codegen_ssa/src/mir/intrinsic.rs | 697 +- compiler/rustc_codegen_ssa/src/mir/locals.rs | 105 +- compiler/rustc_codegen_ssa/src/mir/mod.rs | 558 +- compiler/rustc_codegen_ssa/src/mir/operand.rs | 735 +- compiler/rustc_codegen_ssa/src/mir/place.rs | 661 +- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 1366 +--- .../rustc_codegen_ssa/src/mir/statement.rs | 140 +- compiler/rustc_codegen_ssa/src/mono_item.rs | 205 +- compiler/rustc_codegen_ssa/src/size_of_val.rs | 221 +- .../rustc_codegen_ssa/src/target_features.rs | 218 +- compiler/rustc_codegen_ssa/src/traits/abi.rs | 7 +- compiler/rustc_codegen_ssa/src/traits/asm.rs | 88 +- .../rustc_codegen_ssa/src/traits/backend.rs | 210 +- .../rustc_codegen_ssa/src/traits/builder.rs | 552 +- .../rustc_codegen_ssa/src/traits/consts.rs | 59 +- .../src/traits/coverageinfo.rs | 15 +- .../rustc_codegen_ssa/src/traits/debuginfo.rs | 106 +- .../rustc_codegen_ssa/src/traits/declare.rs | 27 +- .../rustc_codegen_ssa/src/traits/intrinsic.rs | 52 +- compiler/rustc_codegen_ssa/src/traits/misc.rs | 33 +- compiler/rustc_codegen_ssa/src/traits/mod.rs | 129 +- .../rustc_codegen_ssa/src/traits/statics.rs | 31 +- .../rustc_codegen_ssa/src/traits/type_.rs | 253 +- .../rustc_codegen_ssa/src/traits/write.rs | 95 +- .../src/const_eval/dummy_machine.rs | 249 +- .../rustc_const_eval/src/const_eval/error.rs | 234 +- .../src/const_eval/eval_queries.rs | 579 +- .../src/const_eval/fn_queries.rs | 129 +- .../src/const_eval/machine.rs | 974 +-- .../rustc_const_eval/src/const_eval/mod.rs | 130 +- .../src/const_eval/valtrees.rs | 583 +- compiler/rustc_const_eval/src/errors.rs | 1228 +--- .../rustc_const_eval/src/interpret/cast.rs | 629 +- .../src/interpret/discriminant.rs | 386 +- .../src/interpret/eval_context.rs | 1591 +---- .../rustc_const_eval/src/interpret/intern.rs | 415 +- .../src/interpret/intrinsics.rs | 924 +-- .../rustc_const_eval/src/interpret/machine.rs | 766 +-- .../rustc_const_eval/src/interpret/memory.rs | 1750 +---- .../rustc_const_eval/src/interpret/mod.rs | 59 +- .../rustc_const_eval/src/interpret/operand.rs | 1026 +-- .../src/interpret/operator.rs | 664 +- .../rustc_const_eval/src/interpret/place.rs | 1365 +--- .../src/interpret/projection.rs | 465 +- .../rustc_const_eval/src/interpret/step.rs | 469 +- .../src/interpret/terminator.rs | 1211 +--- .../rustc_const_eval/src/interpret/traits.rs | 81 +- .../rustc_const_eval/src/interpret/util.rs | 144 +- .../src/interpret/validity.rs | 1281 +--- .../rustc_const_eval/src/interpret/visitor.rs | 257 +- compiler/rustc_const_eval/src/lib.rs | 92 +- .../src/transform/check_consts/check.rs | 1269 +--- .../src/transform/check_consts/mod.rs | 178 +- .../src/transform/check_consts/ops.rs | 840 +-- .../check_consts/post_drop_elaboration.rs | 158 +- .../src/transform/check_consts/qualifs.rs | 485 +- .../src/transform/check_consts/resolver.rs | 458 +- .../rustc_const_eval/src/transform/mod.rs | 3 +- .../src/transform/validate.rs | 1786 ++--- .../rustc_const_eval/src/util/alignment.rs | 88 +- .../src/util/caller_location.rs | 102 +- .../src/util/check_validity_requirement.rs | 201 +- .../src/util/compare_types.rs | 71 +- compiler/rustc_const_eval/src/util/mod.rs | 49 +- .../rustc_const_eval/src/util/type_name.rs | 233 +- compiler/rustc_data_structures/src/aligned.rs | 37 +- .../rustc_data_structures/src/atomic_ref.rs | 33 +- compiler/rustc_data_structures/src/base_n.rs | 54 +- .../rustc_data_structures/src/base_n/tests.rs | 29 +- .../src/binary_search_util/mod.rs | 32 +- .../src/binary_search_util/tests.rs | 31 +- .../rustc_data_structures/src/captures.rs | 9 +- .../rustc_data_structures/src/fingerprint.rs | 286 +- .../src/fingerprint/tests.rs | 22 +- .../src/flat_map_in_place.rs | 84 +- compiler/rustc_data_structures/src/flock.rs | 29 +- .../rustc_data_structures/src/flock/linux.rs | 44 +- .../rustc_data_structures/src/flock/unix.rs | 87 +- .../src/flock/unsupported.rs | 20 +- .../src/flock/windows.rs | 110 +- compiler/rustc_data_structures/src/frozen.rs | 67 +- compiler/rustc_data_structures/src/fx.rs | 41 +- .../src/graph/dominators/mod.rs | 555 +- .../src/graph/dominators/tests.rs | 98 +- .../src/graph/implementation/mod.rs | 428 +- .../src/graph/implementation/tests.rs | 164 +- .../src/graph/iterate/mod.rs | 423 +- .../src/graph/iterate/tests.rs | 50 +- .../rustc_data_structures/src/graph/mod.rs | 102 +- .../src/graph/reference.rs | 51 +- .../src/graph/scc/mod.rs | 688 +- .../src/graph/scc/tests.rs | 251 +- .../rustc_data_structures/src/graph/tests.rs | 93 +- .../src/graph/vec_graph/mod.rs | 126 +- .../src/graph/vec_graph/tests.rs | 51 +- compiler/rustc_data_structures/src/hashes.rs | 171 +- compiler/rustc_data_structures/src/intern.rs | 139 +- .../rustc_data_structures/src/intern/tests.rs | 73 +- .../rustc_data_structures/src/jobserver.rs | 100 +- compiler/rustc_data_structures/src/lib.rs | 200 +- compiler/rustc_data_structures/src/macros.rs | 45 +- compiler/rustc_data_structures/src/marker.rs | 341 +- compiler/rustc_data_structures/src/memmap.rs | 139 +- .../src/obligation_forest/graphviz.rs | 114 +- .../src/obligation_forest/mod.rs | 853 +-- .../src/obligation_forest/tests.rs | 627 +- .../rustc_data_structures/src/owned_slice.rs | 163 +- .../src/owned_slice/tests.rs | 104 +- compiler/rustc_data_structures/src/packed.rs | 86 +- .../rustc_data_structures/src/profiling.rs | 1156 +--- .../src/profiling/tests.rs | 26 +- compiler/rustc_data_structures/src/sharded.rs | 301 +- compiler/rustc_data_structures/src/sip128.rs | 587 +- .../rustc_data_structures/src/sip128/tests.rs | 443 +- .../rustc_data_structures/src/small_c_str.rs | 109 +- .../src/snapshot_map/mod.rs | 176 +- .../src/snapshot_map/tests.rs | 56 +- .../rustc_data_structures/src/sorted_map.rs | 393 +- .../src/sorted_map/index_map.rs | 199 +- .../src/sorted_map/tests.rs | 279 +- compiler/rustc_data_structures/src/sso/map.rs | 655 +- compiler/rustc_data_structures/src/sso/mod.rs | 6 +- compiler/rustc_data_structures/src/sso/set.rs | 276 +- .../src/stable_hasher.rs | 894 +-- .../src/stable_hasher/tests.rs | 200 +- compiler/rustc_data_structures/src/stack.rs | 21 +- compiler/rustc_data_structures/src/steal.rs | 73 +- compiler/rustc_data_structures/src/svh.rs | 56 +- compiler/rustc_data_structures/src/sync.rs | 537 +- .../rustc_data_structures/src/sync/freeze.rs | 242 +- .../rustc_data_structures/src/sync/lock.rs | 331 +- .../src/sync/parallel.rs | 289 +- .../rustc_data_structures/src/sync/vec.rs | 113 +- .../src/sync/worker_local.rs | 214 +- .../rustc_data_structures/src/tagged_ptr.rs | 316 +- .../src/tagged_ptr/impl_tag.rs | 152 +- .../src/tagged_ptr/impl_tag/tests.rs | 42 +- .../rustc_data_structures/src/temp_dir.rs | 41 +- .../rustc_data_structures/src/tiny_list.rs | 94 +- .../src/tiny_list/tests.rs | 188 +- .../src/transitive_relation.rs | 464 +- .../src/transitive_relation/tests.rs | 462 +- compiler/rustc_data_structures/src/unhash.rs | 36 +- compiler/rustc_data_structures/src/unord.rs | 893 +-- .../src/vec_linked_list.rs | 84 +- .../rustc_data_structures/src/work_queue.rs | 52 +- compiler/rustc_driver/src/lib.rs | 10 +- compiler/rustc_driver_impl/src/args.rs | 190 +- compiler/rustc_driver_impl/src/lib.rs | 2009 ++---- compiler/rustc_driver_impl/src/pretty.rs | 465 +- compiler/rustc_driver_impl/src/print.rs | 25 +- .../src/session_diagnostics.rs | 126 +- .../rustc_driver_impl/src/signal_handler.rs | 196 +- compiler/rustc_error_codes/src/lib.rs | 753 +- compiler/rustc_error_messages/src/lib.rs | 801 +-- .../src/annotate_snippet_emitter_writer.rs | 279 +- compiler/rustc_errors/src/codes.rs | 48 +- compiler/rustc_errors/src/diagnostic.rs | 1699 +---- compiler/rustc_errors/src/diagnostic_impls.rs | 452 +- compiler/rustc_errors/src/emitter.rs | 3420 ++------- compiler/rustc_errors/src/error.rs | 180 +- compiler/rustc_errors/src/json.rs | 708 +- compiler/rustc_errors/src/json/tests.rs | 234 +- compiler/rustc_errors/src/lib.rs | 2430 ++----- compiler/rustc_errors/src/lock.rs | 99 +- compiler/rustc_errors/src/markdown/mod.rs | 90 +- compiler/rustc_errors/src/markdown/parse.rs | 752 +- .../rustc_errors/src/markdown/tests/parse.rs | 395 +- .../rustc_errors/src/markdown/tests/term.rs | 105 +- compiler/rustc_errors/src/registry.rs | 29 +- compiler/rustc_errors/src/snippet.rs | 254 +- compiler/rustc_errors/src/styled_buffer.rs | 183 +- compiler/rustc_errors/src/tests.rs | 255 +- compiler/rustc_expand/src/base.rs | 2033 ++---- compiler/rustc_expand/src/build.rs | 887 +-- compiler/rustc_expand/src/config.rs | 574 +- compiler/rustc_expand/src/errors.rs | 573 +- compiler/rustc_expand/src/expand.rs | 2661 ++----- compiler/rustc_expand/src/lib.rs | 84 +- compiler/rustc_expand/src/mbe.rs | 134 +- compiler/rustc_expand/src/mbe/diagnostics.rs | 440 +- compiler/rustc_expand/src/mbe/macro_check.rs | 778 +-- compiler/rustc_expand/src/mbe/macro_parser.rs | 907 +-- compiler/rustc_expand/src/mbe/macro_rules.rs | 1744 +---- compiler/rustc_expand/src/mbe/quoted.rs | 453 +- compiler/rustc_expand/src/mbe/transcribe.rs | 841 +-- compiler/rustc_expand/src/mut_visit/tests.rs | 93 +- compiler/rustc_expand/src/parse/tests.rs | 497 +- compiler/rustc_expand/src/placeholders.rs | 490 +- compiler/rustc_expand/src/proc_macro.rs | 252 +- .../rustc_expand/src/proc_macro_server.rs | 1070 +-- compiler/rustc_expand/src/tests.rs | 968 +-- .../rustc_expand/src/tokenstream/tests.rs | 143 +- compiler/rustc_feature/src/accepted.rs | 506 +- compiler/rustc_feature/src/builtin_attrs.rs | 1501 ++-- compiler/rustc_feature/src/lib.rs | 164 +- compiler/rustc_feature/src/removed.rs | 325 +- compiler/rustc_feature/src/tests.rs | 31 +- compiler/rustc_feature/src/unstable.rs | 816 +-- compiler/rustc_fluent_macro/src/fluent.rs | 448 +- compiler/rustc_fluent_macro/src/lib.rs | 74 +- compiler/rustc_fs_util/src/lib.rs | 119 +- compiler/rustc_graphviz/src/lib.rs | 741 +- compiler/rustc_graphviz/src/tests.rs | 454 +- compiler/rustc_hir/src/arena.rs | 20 +- compiler/rustc_hir/src/def_path_hash_map.rs | 47 +- compiler/rustc_hir/src/definitions.rs | 565 +- compiler/rustc_hir/src/diagnostic_items.rs | 25 +- compiler/rustc_hir/src/hir_id.rs | 219 +- compiler/rustc_hir/src/intravisit.rs | 1715 ++--- compiler/rustc_hir/src/lang_items.rs | 674 +- compiler/rustc_hir/src/lib.rs | 59 +- compiler/rustc_hir/src/pat_util.rs | 178 +- compiler/rustc_hir/src/stable_hash_impls.rs | 150 +- compiler/rustc_hir/src/target.rs | 294 +- compiler/rustc_hir/src/tests.rs | 54 +- compiler/rustc_hir/src/weak_lang_items.rs | 37 +- compiler/rustc_hir_analysis/src/autoderef.rs | 331 +- compiler/rustc_hir_analysis/src/bounds.rs | 109 +- .../rustc_hir_analysis/src/check/check.rs | 2064 ++---- .../src/check/compare_impl_item.rs | 2920 ++------ .../src/check/compare_impl_item/refine.rs | 443 +- .../rustc_hir_analysis/src/check/dropck.rs | 277 +- .../rustc_hir_analysis/src/check/entry.rs | 361 +- compiler/rustc_hir_analysis/src/check/errs.rs | 103 +- .../rustc_hir_analysis/src/check/intrinsic.rs | 909 +-- .../src/check/intrinsicck.rs | 621 +- .../rustc_hir_analysis/src/check/region.rs | 1067 +-- .../rustc_hir_analysis/src/check/wfcheck.rs | 2588 ++----- .../rustc_hir_analysis/src/check_unused.rs | 61 +- .../src/coherence/builtin.rs | 824 +-- .../src/coherence/inherent_impls.rs | 249 +- .../src/coherence/inherent_impls_overlap.rs | 444 +- .../rustc_hir_analysis/src/coherence/mod.rs | 292 +- .../src/coherence/orphan.rs | 480 +- .../src/coherence/unsafety.rs | 130 +- compiler/rustc_hir_analysis/src/collect.rs | 2283 ++---- .../src/collect/generics_of.rs | 690 +- .../src/collect/item_bounds.rs | 299 +- .../src/collect/predicates_of.rs | 1011 +-- .../src/collect/resolve_bound_vars.rs | 2641 ++----- .../rustc_hir_analysis/src/collect/type_of.rs | 848 +-- .../src/collect/type_of/opaque.rs | 605 +- .../src/constrained_generic_params.rs | 278 +- compiler/rustc_hir_analysis/src/errors.rs | 2098 ++---- .../src/hir_ty_lowering/bounds.rs | 868 +-- .../src/hir_ty_lowering/generics.rs | 833 +-- .../src/hir_ty_lowering/lint.rs | 396 +- .../src/hir_ty_lowering/object_safety.rs | 522 +- .../rustc_hir_analysis/src/hir_wf_check.rs | 247 +- .../rustc_hir_analysis/src/impl_wf_check.rs | 252 +- .../src/impl_wf_check/min_specialization.rs | 661 +- .../src/outlives/explicit.rs | 81 +- .../src/outlives/implicit_infer.rs | 404 +- .../rustc_hir_analysis/src/outlives/mod.rs | 125 +- .../rustc_hir_analysis/src/outlives/test.rs | 40 +- .../rustc_hir_analysis/src/outlives/utils.rs | 209 +- .../src/structured_errors.rs | 46 +- .../missing_cast_for_variadic_arg.rs | 72 +- .../structured_errors/sized_unsized_cast.rs | 57 +- .../wrong_number_of_generic_args.rs | 1461 +--- .../src/variance/constraints.rs | 580 +- .../rustc_hir_analysis/src/variance/mod.rs | 237 +- .../rustc_hir_analysis/src/variance/solve.rs | 167 +- .../rustc_hir_analysis/src/variance/terms.rs | 181 +- .../rustc_hir_analysis/src/variance/test.rs | 48 +- .../rustc_hir_analysis/src/variance/xform.rs | 27 +- compiler/rustc_hir_pretty/src/lib.rs | 3016 ++------ compiler/rustc_hir_typeck/src/_match.rs | 773 +-- compiler/rustc_hir_typeck/src/autoderef.rs | 90 +- compiler/rustc_hir_typeck/src/callee.rs | 1303 +--- compiler/rustc_hir_typeck/src/cast.rs | 1275 +--- compiler/rustc_hir_typeck/src/check.rs | 321 +- compiler/rustc_hir_typeck/src/closure.rs | 1297 +--- compiler/rustc_hir_typeck/src/coercion.rs | 2604 ++----- compiler/rustc_hir_typeck/src/demand.rs | 1511 +--- compiler/rustc_hir_typeck/src/diverges.rs | 88 +- compiler/rustc_hir_typeck/src/errors.rs | 818 +-- compiler/rustc_hir_typeck/src/expectation.rs | 142 +- compiler/rustc_hir_typeck/src/expr.rs | 4424 +++--------- .../rustc_hir_typeck/src/expr_use_visitor.rs | 1148 +--- compiler/rustc_hir_typeck/src/fallback.rs | 572 +- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 2094 ++---- .../src/fn_ctxt/adjust_fulfillment_errors.rs | 1189 +--- .../src/fn_ctxt/arg_matrix.rs | 514 +- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 2908 ++------ compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 563 +- .../rustc_hir_typeck/src/gather_locals.rs | 245 +- compiler/rustc_hir_typeck/src/intrinsicck.rs | 179 +- compiler/rustc_hir_typeck/src/lib.rs | 580 +- .../src/mem_categorization.rs | 960 +-- .../rustc_hir_typeck/src/method/confirm.rs | 849 +-- compiler/rustc_hir_typeck/src/method/mod.rs | 697 +- .../src/method/prelude2021.rs | 503 +- .../rustc_hir_typeck/src/method/suggest.rs | 4689 +++---------- compiler/rustc_hir_typeck/src/op.rs | 1417 +--- compiler/rustc_hir_typeck/src/pat.rs | 3014 ++------ compiler/rustc_hir_typeck/src/place_op.rs | 542 +- .../rustc_hir_typeck/src/rvalue_scopes.rs | 99 +- .../rustc_hir_typeck/src/typeck_root_ctxt.rs | 228 +- compiler/rustc_hir_typeck/src/upvar.rs | 2934 ++------ compiler/rustc_hir_typeck/src/writeback.rs | 1117 +-- .../rustc_incremental/src/assert_dep_graph.rs | 560 +- compiler/rustc_incremental/src/errors.rs | 384 +- compiler/rustc_incremental/src/lib.rs | 38 +- .../rustc_incremental/src/persist/data.rs | 16 +- .../src/persist/dirty_clean.rs | 598 +- .../src/persist/file_format.rs | 224 +- compiler/rustc_incremental/src/persist/fs.rs | 1174 +--- .../rustc_incremental/src/persist/fs/tests.rs | 102 +- .../rustc_incremental/src/persist/load.rs | 286 +- compiler/rustc_incremental/src/persist/mod.rs | 27 +- .../rustc_incremental/src/persist/save.rs | 230 +- .../src/persist/work_product.rs | 74 +- compiler/rustc_index_macros/src/lib.rs | 46 +- compiler/rustc_index_macros/src/newtype.rs | 361 +- compiler/rustc_infer/src/errors/mod.rs | 1912 ++---- .../src/errors/note_and_explain.rs | 230 +- compiler/rustc_infer/src/infer/at.rs | 639 +- .../src/infer/canonical/canonicalizer.rs | 986 +-- .../src/infer/canonical/instantiate.rs | 99 +- .../rustc_infer/src/infer/canonical/mod.rs | 215 +- .../src/infer/canonical/query_response.rs | 866 +-- .../src/infer/error_reporting/mod.rs | 3804 +++------- .../nice_region_error/different_lifetimes.rs | 190 +- .../nice_region_error/find_anon_type.rs | 286 +- .../mismatched_static_lifetime.rs | 162 +- .../error_reporting/nice_region_error/mod.rs | 114 +- .../nice_region_error/placeholder_error.rs | 636 +- .../nice_region_error/placeholder_relation.rs | 113 +- .../nice_region_error/static_impl_trait.rs | 806 +-- .../trait_impl_difference.rs | 210 +- .../error_reporting/nice_region_error/util.rs | 207 +- .../src/infer/error_reporting/note.rs | 506 +- .../infer/error_reporting/note_and_explain.rs | 1196 +--- .../infer/error_reporting/sub_relations.rs | 100 +- .../rustc_infer/src/infer/free_regions.rs | 124 +- compiler/rustc_infer/src/infer/freshen.rs | 302 +- .../src/infer/lexical_region_resolve/mod.rs | 1240 +--- .../rustc_infer/src/infer/opaque_types/mod.rs | 746 +- .../src/infer/opaque_types/table.rs | 93 +- .../src/infer/outlives/components.rs | 313 +- .../rustc_infer/src/infer/outlives/env.rs | 189 +- .../src/infer/outlives/for_liveness.rs | 141 +- .../rustc_infer/src/infer/outlives/mod.rs | 156 +- .../src/infer/outlives/obligations.rs | 654 +- .../src/infer/outlives/test_type_match.rs | 268 +- .../rustc_infer/src/infer/outlives/verify.rs | 391 +- compiler/rustc_infer/src/infer/projection.rs | 51 +- .../infer/region_constraints/leak_check.rs | 529 +- .../src/infer/region_constraints/mod.rs | 991 +-- .../rustc_infer/src/infer/relate/combine.rs | 492 +- .../src/infer/relate/generalize.rs | 861 +-- compiler/rustc_infer/src/infer/relate/glb.rs | 203 +- .../src/infer/relate/higher_ranked.rs | 133 +- .../rustc_infer/src/infer/relate/lattice.rs | 152 +- compiler/rustc_infer/src/infer/relate/lub.rs | 203 +- compiler/rustc_infer/src/infer/relate/mod.rs | 25 +- .../src/infer/relate/type_relating.rs | 438 +- compiler/rustc_infer/src/infer/resolve.rs | 319 +- .../rustc_infer/src/infer/snapshot/fudge.rs | 318 +- .../rustc_infer/src/infer/snapshot/mod.rs | 137 +- .../src/infer/snapshot/undo_log.rs | 269 +- .../rustc_infer/src/infer/type_variable.rs | 393 +- compiler/rustc_infer/src/lib.rs | 59 +- compiler/rustc_infer/src/traits/engine.rs | 97 +- .../src/traits/error_reporting/mod.rs | 272 +- compiler/rustc_infer/src/traits/mod.rs | 279 +- compiler/rustc_infer/src/traits/project.rs | 309 +- .../src/traits/structural_impls.rs | 124 +- compiler/rustc_infer/src/traits/util.rs | 575 +- compiler/rustc_interface/src/callbacks.rs | 136 +- compiler/rustc_interface/src/errors.rs | 136 +- compiler/rustc_interface/src/lib.rs | 34 +- compiler/rustc_interface/src/passes.rs | 1253 +--- .../rustc_interface/src/proc_macro_decls.rs | 29 +- compiler/rustc_interface/src/queries.rs | 433 +- compiler/rustc_interface/src/tests.rs | 1205 +--- compiler/rustc_interface/src/util.rs | 666 +- compiler/rustc_lexer/src/cursor.rs | 123 +- compiler/rustc_lexer/src/lib.rs | 1037 +-- compiler/rustc_lexer/src/tests.rs | 273 +- compiler/rustc_lexer/src/unescape.rs | 532 +- compiler/rustc_lexer/src/unescape/tests.rs | 403 +- compiler/rustc_lint/src/array_into_iter.rs | 178 +- compiler/rustc_lint/src/async_fn_in_trait.rs | 143 +- compiler/rustc_lint/src/builtin.rs | 3573 ++-------- compiler/rustc_lint/src/context.rs | 1274 +--- .../src/context/diagnostics/check_cfg.rs | 377 +- .../src/deref_into_dyn_supertrait.rs | 133 +- .../rustc_lint/src/drop_forget_useless.rs | 259 +- compiler/rustc_lint/src/early.rs | 565 +- .../src/enum_intrinsics_non_enums.rs | 105 +- compiler/rustc_lint/src/errors.rs | 145 +- compiler/rustc_lint/src/expect.rs | 60 +- .../src/for_loops_over_fallibles.rs | 214 +- compiler/rustc_lint/src/foreign_modules.rs | 503 +- .../src/hidden_unicode_codepoints.rs | 145 +- compiler/rustc_lint/src/internal.rs | 722 +- compiler/rustc_lint/src/invalid_from_utf8.rs | 160 +- compiler/rustc_lint/src/late.rs | 591 +- compiler/rustc_lint/src/let_underscore.rs | 198 +- compiler/rustc_lint/src/levels.rs | 1466 +--- compiler/rustc_lint/src/lib.rs | 838 +-- compiler/rustc_lint/src/lints.rs | 2488 ++----- compiler/rustc_lint/src/map_unit_fn.rs | 156 +- compiler/rustc_lint/src/methods.rs | 87 +- .../src/multiple_supertrait_upcastable.rs | 73 +- compiler/rustc_lint/src/non_ascii_idents.rs | 478 +- compiler/rustc_lint/src/non_fmt_panic.rs | 425 +- compiler/rustc_lint/src/non_local_def.rs | 282 +- compiler/rustc_lint/src/nonstandard_style.rs | 691 +- .../rustc_lint/src/nonstandard_style/tests.rs | 28 +- compiler/rustc_lint/src/noop_method_call.rs | 190 +- .../src/opaque_hidden_inferred_bound.rs | 249 +- compiler/rustc_lint/src/pass_by_value.rs | 117 +- compiler/rustc_lint/src/passes.rs | 322 +- .../rustc_lint/src/redundant_semicolon.rs | 69 +- compiler/rustc_lint/src/reference_casting.rs | 342 +- compiler/rustc_lint/src/tests.rs | 35 +- compiler/rustc_lint/src/traits.rs | 143 +- compiler/rustc_lint/src/types.rs | 2526 ++----- compiler/rustc_lint/src/unit_bindings.rs | 84 +- compiler/rustc_lint_defs/src/builtin.rs | 5069 ++------------ compiler/rustc_lint_defs/src/lib.rs | 1063 +-- compiler/rustc_llvm/build.rs | 510 +- compiler/rustc_llvm/src/lib.rs | 271 +- compiler/rustc_log/src/lib.rs | 251 +- compiler/rustc_macros/build.rs | 25 +- compiler/rustc_macros/src/current_version.rs | 52 +- .../src/diagnostics/diagnostic.rs | 311 +- .../src/diagnostics/diagnostic_builder.rs | 635 +- .../rustc_macros/src/diagnostics/error.rs | 125 +- compiler/rustc_macros/src/diagnostics/mod.rs | 167 +- .../rustc_macros/src/diagnostics/utils.rs | 1087 +-- compiler/rustc_macros/src/extension.rs | 193 +- compiler/rustc_macros/src/hash_stable.rs | 189 +- compiler/rustc_macros/src/lib.rs | 196 +- compiler/rustc_macros/src/lift.rs | 68 +- compiler/rustc_macros/src/query.rs | 517 +- compiler/rustc_macros/src/serialize.rs | 375 +- compiler/rustc_macros/src/symbols.rs | 400 +- compiler/rustc_macros/src/symbols/tests.rs | 126 +- compiler/rustc_macros/src/type_foldable.rs | 74 +- compiler/rustc_macros/src/type_visitable.rs | 78 +- .../rustc_metadata/src/dependency_format.rs | 524 +- compiler/rustc_metadata/src/errors.rs | 934 +-- .../rustc_metadata/src/foreign_modules.rs | 38 +- compiler/rustc_metadata/src/fs.rs | 179 +- compiler/rustc_metadata/src/lib.rs | 64 +- compiler/rustc_metadata/src/locator.rs | 1411 +--- compiler/rustc_metadata/src/native_libs.rs | 733 +- compiler/rustc_metadata/src/rmeta/decoder.rs | 2497 ++----- .../src/rmeta/decoder/cstore_impl.rs | 898 +-- .../src/rmeta/def_path_hash_map.rs | 87 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 3169 ++------- compiler/rustc_metadata/src/rmeta/mod.rs | 767 +-- compiler/rustc_metadata/src/rmeta/table.rs | 661 +- compiler/rustc_middle/src/arena.rs | 186 +- .../rustc_middle/src/dep_graph/dep_node.rs | 560 +- compiler/rustc_middle/src/dep_graph/mod.rs | 104 +- compiler/rustc_middle/src/error.rs | 191 +- compiler/rustc_middle/src/hir/map/mod.rs | 1727 ++--- compiler/rustc_middle/src/hir/mod.rs | 289 +- .../rustc_middle/src/hir/nested_filter.rs | 36 +- compiler/rustc_middle/src/hir/place.rs | 143 +- compiler/rustc_middle/src/hooks/mod.rs | 104 +- compiler/rustc_middle/src/infer/canonical.rs | 438 +- compiler/rustc_middle/src/infer/mod.rs | 39 +- compiler/rustc_middle/src/infer/unify_key.rs | 329 +- compiler/rustc_middle/src/lib.rs | 134 +- compiler/rustc_middle/src/lint.rs | 566 +- compiler/rustc_middle/src/macros.rs | 134 +- compiler/rustc_middle/src/metadata.rs | 55 +- .../src/middle/codegen_fn_attrs.rs | 170 +- .../src/middle/debugger_visualizer.rs | 49 +- .../src/middle/dependency_format.rs | 32 +- .../src/middle/exported_symbols.rs | 100 +- .../rustc_middle/src/middle/lang_items.rs | 106 +- compiler/rustc_middle/src/middle/limits.rs | 104 +- compiler/rustc_middle/src/middle/mod.rs | 51 +- compiler/rustc_middle/src/middle/privacy.rs | 369 +- compiler/rustc_middle/src/middle/region.rs | 452 +- .../src/middle/resolve_bound_vars.rs | 71 +- compiler/rustc_middle/src/middle/stability.rs | 756 +- compiler/rustc_middle/src/mir/basic_blocks.rs | 257 +- compiler/rustc_middle/src/mir/consts.rs | 663 +- compiler/rustc_middle/src/mir/coverage.rs | 297 +- .../rustc_middle/src/mir/generic_graph.rs | 91 +- .../rustc_middle/src/mir/generic_graphviz.rs | 223 +- compiler/rustc_middle/src/mir/graphviz.rs | 161 +- .../src/mir/interpret/allocation.rs | 799 +-- .../src/mir/interpret/allocation/init_mask.rs | 847 +-- .../interpret/allocation/init_mask/tests.rs | 250 +- .../interpret/allocation/provenance_map.rs | 410 +- .../rustc_middle/src/mir/interpret/error.rs | 664 +- .../rustc_middle/src/mir/interpret/mod.rs | 863 +-- .../rustc_middle/src/mir/interpret/pointer.rs | 484 +- .../rustc_middle/src/mir/interpret/queries.rs | 248 +- .../rustc_middle/src/mir/interpret/value.rs | 563 +- compiler/rustc_middle/src/mir/mod.rs | 2287 ++---- compiler/rustc_middle/src/mir/mono.rs | 687 +- compiler/rustc_middle/src/mir/patch.rs | 335 +- compiler/rustc_middle/src/mir/query.rs | 519 +- compiler/rustc_middle/src/mir/statement.rs | 560 +- compiler/rustc_middle/src/mir/syntax.rs | 1598 +---- compiler/rustc_middle/src/mir/tcx.rs | 419 +- compiler/rustc_middle/src/mir/terminator.rs | 869 +-- compiler/rustc_middle/src/mir/traversal.rs | 321 +- .../rustc_middle/src/mir/type_foldable.rs | 80 +- compiler/rustc_middle/src/mir/visit.rs | 1733 +---- compiler/rustc_middle/src/query/erase.rs | 513 +- compiler/rustc_middle/src/query/keys.rs | 699 +- compiler/rustc_middle/src/query/mod.rs | 2951 ++------ .../rustc_middle/src/query/on_disk_cache.rs | 1299 +--- compiler/rustc_middle/src/query/plumbing.rs | 843 +-- compiler/rustc_middle/src/tests.rs | 14 +- compiler/rustc_middle/src/thir.rs | 1441 +--- compiler/rustc_middle/src/thir/visit.rs | 340 +- compiler/rustc_middle/src/traits/mod.rs | 1258 +--- compiler/rustc_middle/src/traits/query.rs | 257 +- compiler/rustc_middle/src/traits/select.rs | 366 +- compiler/rustc_middle/src/traits/solve.rs | 422 +- .../rustc_middle/src/traits/solve/cache.rs | 160 +- .../rustc_middle/src/traits/solve/inspect.rs | 184 +- .../src/traits/solve/inspect/format.rs | 213 +- .../src/traits/specialization_graph.rs | 319 +- .../src/traits/structural_impls.rs | 40 +- compiler/rustc_middle/src/traits/util.rs | 81 +- compiler/rustc_middle/src/ty/_match.rs | 143 +- .../rustc_middle/src/ty/abstract_const.rs | 89 +- compiler/rustc_middle/src/ty/adjustment.rs | 248 +- compiler/rustc_middle/src/ty/adt.rs | 732 +- compiler/rustc_middle/src/ty/assoc.rs | 262 +- compiler/rustc_middle/src/ty/cast.rs | 132 +- compiler/rustc_middle/src/ty/closure.rs | 510 +- compiler/rustc_middle/src/ty/codec.rs | 793 +-- compiler/rustc_middle/src/ty/consts.rs | 617 +- compiler/rustc_middle/src/ty/consts/int.rs | 705 +- compiler/rustc_middle/src/ty/consts/kind.rs | 100 +- .../rustc_middle/src/ty/consts/valtree.rs | 129 +- compiler/rustc_middle/src/ty/context.rs | 3260 ++------- compiler/rustc_middle/src/ty/context/tls.rs | 191 +- compiler/rustc_middle/src/ty/diagnostics.rs | 819 +-- compiler/rustc_middle/src/ty/erase_regions.rs | 82 +- compiler/rustc_middle/src/ty/error.rs | 520 +- compiler/rustc_middle/src/ty/fast_reject.rs | 487 +- compiler/rustc_middle/src/ty/flags.rs | 528 +- compiler/rustc_middle/src/ty/fold.rs | 655 +- compiler/rustc_middle/src/ty/generic_args.rs | 1336 +--- compiler/rustc_middle/src/ty/generics.rs | 575 +- compiler/rustc_middle/src/ty/impls_ty.rs | 139 +- compiler/rustc_middle/src/ty/instance.rs | 1175 +--- compiler/rustc_middle/src/ty/intrinsic.rs | 22 +- compiler/rustc_middle/src/ty/layout.rs | 1611 +---- compiler/rustc_middle/src/ty/list.rs | 275 +- .../src/ty/normalize_erasing_regions.rs | 316 +- compiler/rustc_middle/src/ty/opaque_types.rs | 272 +- compiler/rustc_middle/src/ty/parameterized.rs | 183 +- compiler/rustc_middle/src/ty/predicate.rs | 1368 +--- compiler/rustc_middle/src/ty/print/mod.rs | 424 +- compiler/rustc_middle/src/ty/region.rs | 543 +- compiler/rustc_middle/src/ty/relate.rs | 1061 +-- compiler/rustc_middle/src/ty/rvalue_scopes.rs | 72 +- .../rustc_middle/src/ty/structural_impls.rs | 1101 +-- compiler/rustc_middle/src/ty/trait_def.rs | 341 +- .../rustc_middle/src/ty/typeck_results.rs | 927 +-- compiler/rustc_middle/src/ty/util.rs | 2107 ++---- compiler/rustc_middle/src/ty/visit.rs | 441 +- compiler/rustc_middle/src/ty/vtable.rs | 159 +- compiler/rustc_middle/src/ty/walk.rs | 286 +- compiler/rustc_middle/src/util/bug.rs | 71 +- compiler/rustc_middle/src/util/call_kind.rs | 190 +- compiler/rustc_middle/src/util/common.rs | 98 +- .../rustc_middle/src/util/common/tests.rs | 20 +- .../rustc_middle/src/util/find_self_call.rs | 56 +- compiler/rustc_middle/src/util/mod.rs | 39 +- compiler/rustc_middle/src/values.rs | 507 +- compiler/rustc_mir_build/src/build/block.rs | 467 +- compiler/rustc_mir_build/src/build/cfg.rs | 170 +- .../rustc_mir_build/src/build/coverageinfo.rs | 186 +- .../rustc_mir_build/src/build/custom/mod.rs | 225 +- .../rustc_mir_build/src/build/custom/parse.rs | 422 +- .../src/build/custom/parse/instruction.rs | 493 +- .../src/build/expr/as_constant.rs | 237 +- .../src/build/expr/as_operand.rs | 229 +- .../src/build/expr/as_place.rs | 921 +-- .../src/build/expr/as_rvalue.rs | 1060 +-- .../rustc_mir_build/src/build/expr/as_temp.rs | 158 +- .../src/build/expr/category.rs | 114 +- .../rustc_mir_build/src/build/expr/into.rs | 765 +-- .../rustc_mir_build/src/build/expr/mod.rs | 72 +- .../rustc_mir_build/src/build/expr/stmt.rs | 188 +- .../rustc_mir_build/src/build/matches/mod.rs | 2956 ++------ .../src/build/matches/simplify.rs | 81 +- .../rustc_mir_build/src/build/matches/test.rs | 897 +-- .../rustc_mir_build/src/build/matches/util.rs | 464 +- compiler/rustc_mir_build/src/build/misc.rs | 87 +- compiler/rustc_mir_build/src/build/mod.rs | 1404 +--- compiler/rustc_mir_build/src/build/scope.rs | 1879 +---- .../rustc_mir_build/src/check_unsafety.rs | 1255 +--- compiler/rustc_mir_build/src/errors.rs | 1267 +--- compiler/rustc_mir_build/src/lib.rs | 53 +- compiler/rustc_mir_build/src/lints.rs | 319 +- compiler/rustc_mir_build/src/thir/constant.rs | 104 +- compiler/rustc_mir_build/src/thir/cx/block.rs | 160 +- compiler/rustc_mir_build/src/thir/cx/expr.rs | 1565 +---- compiler/rustc_mir_build/src/thir/cx/mod.rs | 269 +- compiler/rustc_mir_build/src/thir/mod.rs | 13 +- .../src/thir/pattern/check_match.rs | 1579 +---- .../src/thir/pattern/const_to_pat.rs | 601 +- .../rustc_mir_build/src/thir/pattern/mod.rs | 882 +-- compiler/rustc_mir_build/src/thir/print.rs | 1275 +--- compiler/rustc_mir_build/src/thir/util.rs | 42 +- compiler/rustc_mir_dataflow/src/debuginfo.rs | 27 +- .../src/drop_flag_effects.rs | 225 +- .../rustc_mir_dataflow/src/elaborate_drops.rs | 1232 +--- compiler/rustc_mir_dataflow/src/errors.rs | 92 +- .../src/framework/cursor.rs | 298 +- .../src/framework/direction.rs | 764 +- .../src/framework/engine.rs | 514 +- .../rustc_mir_dataflow/src/framework/fmt.rs | 304 +- .../src/framework/graphviz.rs | 856 +-- .../src/framework/lattice.rs | 423 +- .../rustc_mir_dataflow/src/framework/mod.rs | 681 +- .../rustc_mir_dataflow/src/framework/tests.rs | 399 +- .../src/framework/visitor.rs | 225 +- .../src/impls/borrowed_locals.rs | 217 +- .../src/impls/initialized.rs | 956 +-- .../rustc_mir_dataflow/src/impls/liveness.rs | 400 +- compiler/rustc_mir_dataflow/src/impls/mod.rs | 27 +- .../src/impls/storage_liveness.rs | 468 +- compiler/rustc_mir_dataflow/src/lib.rs | 60 +- .../src/move_paths/abs_domain.rs | 81 +- .../src/move_paths/builder.rs | 795 +-- .../rustc_mir_dataflow/src/move_paths/mod.rs | 476 +- compiler/rustc_mir_dataflow/src/points.rs | 197 +- compiler/rustc_mir_dataflow/src/rustc_peek.rs | 374 +- compiler/rustc_mir_dataflow/src/storage.rs | 26 +- compiler/rustc_mir_dataflow/src/un_derefer.rs | 124 +- .../rustc_mir_dataflow/src/value_analysis.rs | 1581 +---- .../src/abort_unwinding_calls.rs | 150 +- .../src/add_call_guards.rs | 100 +- .../src/add_moves_for_packed_drops.rs | 134 +- compiler/rustc_mir_transform/src/add_retag.rs | 217 +- .../src/add_subtyping_projections.rs | 90 +- .../src/check_alignment.rs | 321 +- .../src/check_const_item_mutation.rs | 195 +- .../src/check_packed_ref.rs | 80 +- .../rustc_mir_transform/src/check_unsafety.rs | 801 +-- .../src/cleanup_post_borrowck.rs | 71 +- .../src/const_debuginfo.rs | 134 +- compiler/rustc_mir_transform/src/copy_prop.rs | 232 +- compiler/rustc_mir_transform/src/coroutine.rs | 2657 ++----- .../src/coroutine/by_move_body.rs | 161 +- .../rustc_mir_transform/src/cost_checker.rs | 128 +- .../src/coverage/counters.rs | 656 +- .../rustc_mir_transform/src/coverage/graph.rs | 719 +- .../rustc_mir_transform/src/coverage/mod.rs | 535 +- .../rustc_mir_transform/src/coverage/query.rs | 110 +- .../rustc_mir_transform/src/coverage/spans.rs | 486 +- .../src/coverage/spans/from_mir.rs | 509 +- .../rustc_mir_transform/src/coverage/tests.rs | 824 +-- .../src/cross_crate_inline.rs | 182 +- .../rustc_mir_transform/src/ctfe_limit.rs | 74 +- .../src/dataflow_const_prop.rs | 1134 +-- .../src/deduce_param_attrs.rs | 263 +- .../src/deduplicate_blocks.rs | 243 +- .../src/deref_separator.rs | 111 +- compiler/rustc_mir_transform/src/dest_prop.rs | 990 +-- compiler/rustc_mir_transform/src/dump_mir.rs | 43 +- .../src/early_otherwise_branch.rs | 490 +- .../src/elaborate_box_derefs.rs | 197 +- .../src/elaborate_drops.rs | 659 +- compiler/rustc_mir_transform/src/errors.rs | 396 +- .../src/ffi_unwind_calls.rs | 214 +- .../src/function_item_references.rs | 252 +- compiler/rustc_mir_transform/src/inline.rs | 1390 +--- .../rustc_mir_transform/src/inline/cycle.rs | 228 +- .../rustc_mir_transform/src/instsimplify.rs | 448 +- .../rustc_mir_transform/src/jump_threading.rs | 1051 +-- .../src/known_panics_lint.rs | 1275 +--- .../rustc_mir_transform/src/large_enums.rs | 383 +- compiler/rustc_mir_transform/src/lib.rs | 900 +-- compiler/rustc_mir_transform/src/lint.rs | 198 +- .../src/lower_slice_len.rs | 97 +- .../rustc_mir_transform/src/match_branches.rs | 222 +- .../src/mentioned_items.rs | 153 +- .../src/multiple_return_terminators.rs | 56 +- compiler/rustc_mir_transform/src/nrvo.rs | 290 +- .../rustc_mir_transform/src/pass_manager.rs | 271 +- compiler/rustc_mir_transform/src/prettify.rs | 185 +- .../rustc_mir_transform/src/promote_consts.rs | 1225 +--- compiler/rustc_mir_transform/src/ref_prop.rs | 504 +- .../src/remove_noop_landing_pads.rs | 183 +- .../src/remove_place_mention.rs | 30 +- .../src/remove_storage_markers.rs | 32 +- .../src/remove_uninit_drops.rs | 198 +- .../src/remove_unneeded_drops.rs | 56 +- .../rustc_mir_transform/src/remove_zsts.rs | 181 +- .../src/required_consts.rs | 38 +- .../rustc_mir_transform/src/reveal_all.rs | 88 +- compiler/rustc_mir_transform/src/shim.rs | 1431 +--- compiler/rustc_mir_transform/src/simplify.rs | 731 +- .../src/simplify_branches.rs | 82 +- .../src/simplify_comparison_integral.rs | 300 +- compiler/rustc_mir_transform/src/sroa.rs | 574 +- compiler/rustc_mir_transform/src/ssa.rs | 488 +- .../src/uninhabited_enum_branching.rs | 222 +- .../src/unreachable_prop.rs | 197 +- compiler/rustc_monomorphize/src/collector.rs | 2223 ++---- compiler/rustc_monomorphize/src/errors.rs | 138 +- compiler/rustc_monomorphize/src/lib.rs | 96 +- .../rustc_monomorphize/src/partitioning.rs | 1620 +---- .../rustc_monomorphize/src/polymorphize.rs | 426 +- compiler/rustc_monomorphize/src/util.rs | 93 +- .../src/canonicalizer.rs | 591 +- compiler/rustc_next_trait_solver/src/lib.rs | 2 +- compiler/rustc_parse/src/lexer/diagnostics.rs | 153 +- compiler/rustc_parse/src/lexer/mod.rs | 1092 +-- compiler/rustc_parse/src/lexer/tokentrees.rs | 395 +- .../rustc_parse/src/lexer/unicode_chars.rs | 568 +- compiler/rustc_parse/src/lib.rs | 314 +- compiler/rustc_parse/src/parser/attr.rs | 568 +- .../rustc_parse/src/parser/attr_wrapper.rs | 582 +- .../rustc_parse/src/parser/diagnostics.rs | 3874 +++-------- compiler/rustc_parse/src/parser/generics.rs | 654 +- compiler/rustc_parse/src/parser/item.rs | 3681 +++------- compiler/rustc_parse/src/parser/mod.rs | 1980 +----- .../rustc_parse/src/parser/nonterminal.rs | 269 +- compiler/rustc_parse/src/parser/pat.rs | 1817 ++--- compiler/rustc_parse/src/parser/path.rs | 1178 +--- compiler/rustc_parse/src/parser/stmt.rs | 1090 +-- compiler/rustc_parse/src/parser/ty.rs | 1504 +--- compiler/rustc_parse/src/validate_attr.rs | 308 +- compiler/rustc_parse_format/src/lib.rs | 1326 +--- compiler/rustc_parse_format/src/tests.rs | 567 +- compiler/rustc_passes/src/abi_test.rs | 256 +- compiler/rustc_passes/src/check_attr.rs | 3329 ++------- compiler/rustc_passes/src/check_const.rs | 298 +- compiler/rustc_passes/src/dead.rs | 1543 +---- .../rustc_passes/src/debugger_visualizer.rs | 136 +- compiler/rustc_passes/src/diagnostic_items.rs | 126 +- compiler/rustc_passes/src/entry.rs | 266 +- compiler/rustc_passes/src/errors.rs | 2282 ++---- compiler/rustc_passes/src/hir_id_validator.rs | 217 +- compiler/rustc_passes/src/hir_stats.rs | 914 +-- compiler/rustc_passes/src/lang_items.rs | 453 +- compiler/rustc_passes/src/layout_test.rs | 211 +- compiler/rustc_passes/src/lib.rs | 79 +- compiler/rustc_passes/src/lib_features.rs | 199 +- compiler/rustc_passes/src/liveness.rs | 2169 ++---- .../rustc_passes/src/liveness/rwu_table.rs | 184 +- compiler/rustc_passes/src/loops.rs | 336 +- compiler/rustc_passes/src/naked_functions.rs | 380 +- compiler/rustc_passes/src/reachable.rs | 600 +- compiler/rustc_passes/src/stability.rs | 1396 +--- compiler/rustc_passes/src/upvars.rs | 121 +- compiler/rustc_passes/src/weak_lang_items.rs | 115 +- .../rustc_pattern_analysis/src/constructor.rs | 1335 +--- compiler/rustc_pattern_analysis/src/errors.rs | 190 +- compiler/rustc_pattern_analysis/src/lib.rs | 206 +- compiler/rustc_pattern_analysis/src/lints.rs | 145 +- compiler/rustc_pattern_analysis/src/pat.rs | 355 +- .../rustc_pattern_analysis/src/pat_column.rs | 112 +- compiler/rustc_pattern_analysis/src/rustc.rs | 1304 +--- .../rustc_pattern_analysis/src/usefulness.rs | 2031 +----- .../tests/common/mod.rs | 405 +- .../tests/complexity.rs | 131 +- .../tests/exhaustiveness.rs | 96 +- .../tests/intersection.rs | 84 +- compiler/rustc_privacy/src/errors.rs | 135 +- compiler/rustc_query_impl/src/lib.rs | 295 +- compiler/rustc_query_impl/src/plumbing.rs | 1098 +-- .../rustc_query_impl/src/profiling_support.rs | 323 +- compiler/rustc_query_system/src/cache.rs | 74 +- .../rustc_query_system/src/dep_graph/debug.rs | 78 +- .../src/dep_graph/dep_node.rs | 379 +- .../rustc_query_system/src/dep_graph/edges.rs | 86 +- .../rustc_query_system/src/dep_graph/graph.rs | 1699 +---- .../rustc_query_system/src/dep_graph/mod.rs | 190 +- .../rustc_query_system/src/dep_graph/query.rs | 87 +- .../src/dep_graph/serialized.rs | 768 +-- compiler/rustc_query_system/src/error.rs | 124 +- compiler/rustc_query_system/src/ich/hcx.rs | 172 +- .../src/ich/impls_syntax.rs | 164 +- compiler/rustc_query_system/src/ich/mod.rs | 23 +- compiler/rustc_query_system/src/lib.rs | 36 +- .../rustc_query_system/src/query/caches.rs | 260 +- .../rustc_query_system/src/query/config.rs | 100 +- compiler/rustc_query_system/src/query/job.rs | 792 +-- compiler/rustc_query_system/src/query/mod.rs | 171 +- .../rustc_query_system/src/query/plumbing.rs | 1060 +-- compiler/rustc_query_system/src/values.rs | 28 +- .../rustc_resolve/src/build_reduced_graph.rs | 2005 ++---- compiler/rustc_resolve/src/check_unused.rs | 722 +- compiler/rustc_resolve/src/def_collector.rs | 528 +- compiler/rustc_resolve/src/diagnostics.rs | 3887 +++-------- .../rustc_resolve/src/diagnostics/tests.rs | 55 +- .../src/effective_visibilities.rs | 376 +- compiler/rustc_resolve/src/errors.rs | 1075 +-- compiler/rustc_resolve/src/ident.rs | 2049 ++---- compiler/rustc_resolve/src/imports.rs | 1940 ++---- compiler/rustc_resolve/src/late.rs | 6116 ++++------------- .../rustc_resolve/src/late/diagnostics.rs | 4394 +++--------- compiler/rustc_resolve/src/lib.rs | 2903 ++------ compiler/rustc_resolve/src/macros.rs | 1285 +--- compiler/rustc_resolve/src/rustdoc.rs | 673 +- compiler/rustc_serialize/src/leb128.rs | 190 +- compiler/rustc_serialize/src/lib.rs | 37 +- compiler/rustc_serialize/src/opaque.rs | 537 +- compiler/rustc_serialize/src/serialize.rs | 871 +-- compiler/rustc_serialize/tests/leb128.rs | 122 +- compiler/rustc_serialize/tests/opaque.rs | 360 +- compiler/rustc_session/src/code_stats.rs | 335 +- compiler/rustc_session/src/config.rs | 4438 +++--------- compiler/rustc_session/src/config/sigpipe.rs | 28 +- compiler/rustc_session/src/cstore.rs | 300 +- compiler/rustc_session/src/errors.rs | 624 +- compiler/rustc_session/src/filesearch.rs | 361 +- compiler/rustc_session/src/lib.rs | 56 +- compiler/rustc_session/src/options.rs | 2965 +++----- compiler/rustc_session/src/parse.rs | 449 +- compiler/rustc_session/src/search_paths.rs | 131 +- compiler/rustc_session/src/session.rs | 1905 ++--- compiler/rustc_session/src/utils.rs | 222 +- compiler/rustc_session/src/version.rs | 25 +- compiler/rustc_smir/src/lib.rs | 25 +- .../rustc_smir/src/rustc_internal/internal.rs | 784 +-- compiler/rustc_smir/src/rustc_internal/mod.rs | 536 +- .../rustc_smir/src/rustc_internal/pretty.rs | 28 +- compiler/rustc_smir/src/rustc_smir/alloc.rs | 188 +- compiler/rustc_smir/src/rustc_smir/builder.rs | 101 +- compiler/rustc_smir/src/rustc_smir/context.rs | 977 +-- .../rustc_smir/src/rustc_smir/convert/abi.rs | 398 +- .../src/rustc_smir/convert/error.rs | 28 +- .../rustc_smir/src/rustc_smir/convert/mir.rs | 1038 +-- .../rustc_smir/src/rustc_smir/convert/mod.rs | 111 +- .../rustc_smir/src/rustc_smir/convert/ty.rs | 1177 +--- compiler/rustc_smir/src/rustc_smir/mod.rs | 227 +- .../rustc_span/src/analyze_source_file.rs | 321 +- .../src/analyze_source_file/tests.rs | 163 +- .../rustc_span/src/caching_source_map_view.rs | 370 +- compiler/rustc_span/src/def_id.rs | 652 +- compiler/rustc_span/src/edit_distance.rs | 338 +- .../rustc_span/src/edit_distance/tests.rs | 115 +- compiler/rustc_span/src/edition.rs | 123 +- compiler/rustc_span/src/fatal_error.rs | 30 +- compiler/rustc_span/src/hygiene.rs | 1957 ++---- compiler/rustc_span/src/lib.rs | 3170 ++------- compiler/rustc_span/src/profiling.rs | 37 +- compiler/rustc_span/src/source_map.rs | 1617 +---- compiler/rustc_span/src/source_map/tests.rs | 727 +- compiler/rustc_span/src/span_encoding.rs | 330 +- compiler/rustc_span/src/symbol.rs | 2965 ++------ compiler/rustc_span/src/symbol/tests.rs | 32 +- compiler/rustc_span/src/tests.rs | 64 +- compiler/rustc_symbol_mangling/src/errors.rs | 51 +- compiler/rustc_symbol_mangling/src/hashed.rs | 55 +- compiler/rustc_symbol_mangling/src/legacy.rs | 569 +- compiler/rustc_symbol_mangling/src/lib.rs | 331 +- compiler/rustc_symbol_mangling/src/test.rs | 113 +- compiler/rustc_symbol_mangling/src/typeid.rs | 94 +- .../src/typeid/typeid_itanium_cxx_abi.rs | 1662 +---- compiler/rustc_target/src/abi/call/aarch64.rs | 154 +- compiler/rustc_target/src/abi/call/amdgpu.rs | 44 +- compiler/rustc_target/src/abi/call/arm.rs | 130 +- compiler/rustc_target/src/abi/call/avr.rs | 65 +- compiler/rustc_target/src/abi/call/bpf.rs | 38 +- compiler/rustc_target/src/abi/call/csky.rs | 72 +- compiler/rustc_target/src/abi/call/hexagon.rs | 37 +- .../rustc_target/src/abi/call/loongarch.rs | 446 +- compiler/rustc_target/src/abi/call/m68k.rs | 42 +- compiler/rustc_target/src/abi/call/mips.rs | 67 +- compiler/rustc_target/src/abi/call/mips64.rs | 206 +- compiler/rustc_target/src/abi/call/msp430.rs | 46 +- compiler/rustc_target/src/abi/call/nvptx64.rs | 93 +- compiler/rustc_target/src/abi/call/powerpc.rs | 37 +- .../rustc_target/src/abi/call/powerpc64.rs | 179 +- compiler/rustc_target/src/abi/call/riscv.rs | 452 +- compiler/rustc_target/src/abi/call/s390x.rs | 75 +- compiler/rustc_target/src/abi/call/sparc.rs | 67 +- compiler/rustc_target/src/abi/call/sparc64.rs | 284 +- compiler/rustc_target/src/abi/call/wasm.rs | 126 +- compiler/rustc_target/src/abi/call/x86.rs | 224 +- compiler/rustc_target/src/abi/call/x86_64.rs | 308 +- .../rustc_target/src/abi/call/x86_win64.rs | 49 +- compiler/rustc_target/src/abi/mod.rs | 360 +- compiler/rustc_target/src/asm/aarch64.rs | 268 +- compiler/rustc_target/src/asm/arm.rs | 429 +- compiler/rustc_target/src/asm/avr.rs | 243 +- compiler/rustc_target/src/asm/bpf.rs | 140 +- compiler/rustc_target/src/asm/csky.rs | 165 +- compiler/rustc_target/src/asm/hexagon.rs | 119 +- compiler/rustc_target/src/asm/loongarch.rs | 169 +- compiler/rustc_target/src/asm/m68k.rs | 105 +- compiler/rustc_target/src/asm/mips.rs | 171 +- compiler/rustc_target/src/asm/msp430.rs | 103 +- compiler/rustc_target/src/asm/nvptx.rs | 61 +- compiler/rustc_target/src/asm/riscv.rs | 236 +- compiler/rustc_target/src/asm/s390x.rs | 137 +- compiler/rustc_target/src/asm/spirv.rs | 57 +- compiler/rustc_target/src/asm/wasm.rs | 57 +- compiler/rustc_target/src/asm/x86.rs | 634 +- compiler/rustc_target/src/json.rs | 166 +- compiler/rustc_target/src/lib.rs | 103 +- compiler/rustc_target/src/spec/abi/mod.rs | 431 +- compiler/rustc_target/src/spec/abi/tests.rs | 33 +- compiler/rustc_target/src/spec/base/aix.rs | 44 +- .../rustc_target/src/spec/base/android.rs | 22 +- .../rustc_target/src/spec/base/apple/mod.rs | 468 +- .../rustc_target/src/spec/base/apple/tests.rs | 49 +- .../rustc_target/src/spec/base/avr_gnu.rs | 544 +- compiler/rustc_target/src/spec/base/bpf.rs | 36 +- .../rustc_target/src/spec/base/dragonfly.rs | 19 +- .../rustc_target/src/spec/base/freebsd.rs | 22 +- .../rustc_target/src/spec/base/fuchsia.rs | 55 +- compiler/rustc_target/src/spec/base/haiku.rs | 14 +- compiler/rustc_target/src/spec/base/hermit.rs | 21 +- compiler/rustc_target/src/spec/base/hurd.rs | 19 +- .../rustc_target/src/spec/base/hurd_gnu.rs | 7 +- .../rustc_target/src/spec/base/illumos.rs | 66 +- compiler/rustc_target/src/spec/base/l4re.rs | 19 +- compiler/rustc_target/src/spec/base/linux.rs | 28 +- .../rustc_target/src/spec/base/linux_gnu.rs | 7 +- .../rustc_target/src/spec/base/linux_musl.rs | 22 +- .../rustc_target/src/spec/base/linux_ohos.rs | 15 +- .../src/spec/base/linux_uclibc.rs | 7 +- compiler/rustc_target/src/spec/base/mod.rs | 48 +- compiler/rustc_target/src/spec/base/msvc.rs | 34 +- compiler/rustc_target/src/spec/base/netbsd.rs | 22 +- .../rustc_target/src/spec/base/nto_qnx.rs | 24 +- .../rustc_target/src/spec/base/openbsd.rs | 23 +- compiler/rustc_target/src/spec/base/redox.rs | 22 +- .../rustc_target/src/spec/base/solaris.rs | 21 +- compiler/rustc_target/src/spec/base/solid.rs | 16 +- compiler/rustc_target/src/spec/base/teeos.rs | 39 +- compiler/rustc_target/src/spec/base/thumb.rs | 65 +- .../rustc_target/src/spec/base/uefi_msvc.rs | 60 +- .../src/spec/base/unikraft_linux_musl.rs | 20 +- .../rustc_target/src/spec/base/vxworks.rs | 27 +- compiler/rustc_target/src/spec/base/wasm.rs | 148 +- .../rustc_target/src/spec/base/windows_gnu.rs | 138 +- .../src/spec/base/windows_gnullvm.rs | 61 +- .../src/spec/base/windows_msvc.rs | 45 +- .../src/spec/base/windows_uwp_gnu.rs | 45 +- .../src/spec/base/windows_uwp_msvc.rs | 15 +- compiler/rustc_target/src/spec/crt_objects.rs | 156 +- .../src/spec/targets/aarch64_apple_darwin.rs | 43 +- .../src/spec/targets/aarch64_apple_ios.rs | 40 +- .../spec/targets/aarch64_apple_ios_macabi.rs | 37 +- .../src/spec/targets/aarch64_apple_ios_sim.rs | 40 +- .../src/spec/targets/aarch64_apple_tvos.rs | 32 +- .../spec/targets/aarch64_apple_tvos_sim.rs | 32 +- .../src/spec/targets/aarch64_apple_watchos.rs | 33 +- .../spec/targets/aarch64_apple_watchos_sim.rs | 36 +- .../targets/aarch64_be_unknown_linux_gnu.rs | 33 +- .../aarch64_be_unknown_linux_gnu_ilp32.rs | 38 +- .../spec/targets/aarch64_be_unknown_netbsd.rs | 32 +- .../src/spec/targets/aarch64_fuchsia.rs | 2 +- .../spec/targets/aarch64_kmc_solid_asp3.rs | 35 +- .../src/spec/targets/aarch64_linux_android.rs | 43 +- .../aarch64_nintendo_switch_freestanding.rs | 48 +- .../targets/aarch64_pc_windows_gnullvm.rs | 29 +- .../spec/targets/aarch64_pc_windows_msvc.rs | 28 +- .../spec/targets/aarch64_unknown_freebsd.rs | 35 +- .../spec/targets/aarch64_unknown_fuchsia.rs | 33 +- .../spec/targets/aarch64_unknown_hermit.rs | 30 +- .../spec/targets/aarch64_unknown_illumos.rs | 34 +- .../spec/targets/aarch64_unknown_linux_gnu.rs | 43 +- .../aarch64_unknown_linux_gnu_ilp32.rs | 33 +- .../targets/aarch64_unknown_linux_musl.rs | 38 +- .../targets/aarch64_unknown_linux_ohos.rs | 44 +- .../spec/targets/aarch64_unknown_netbsd.rs | 31 +- .../src/spec/targets/aarch64_unknown_none.rs | 58 +- .../targets/aarch64_unknown_none_softfloat.rs | 50 +- .../targets/aarch64_unknown_nto_qnx710.rs | 43 +- .../spec/targets/aarch64_unknown_openbsd.rs | 29 +- .../src/spec/targets/aarch64_unknown_redox.rs | 29 +- .../src/spec/targets/aarch64_unknown_teeos.rs | 29 +- .../src/spec/targets/aarch64_unknown_uefi.rs | 34 +- .../spec/targets/aarch64_uwp_windows_msvc.rs | 27 +- .../src/spec/targets/aarch64_wrs_vxworks.rs | 29 +- .../spec/targets/arm64_32_apple_watchos.rs | 33 +- .../src/spec/targets/arm64e_apple_darwin.rs | 43 +- .../src/spec/targets/arm64e_apple_ios.rs | 40 +- .../spec/targets/arm64ec_pc_windows_msvc.rs | 35 +- .../src/spec/targets/arm_linux_androideabi.rs | 32 +- .../spec/targets/arm_unknown_linux_gnueabi.rs | 33 +- .../targets/arm_unknown_linux_gnueabihf.rs | 33 +- .../targets/arm_unknown_linux_musleabi.rs | 36 +- .../targets/arm_unknown_linux_musleabihf.rs | 36 +- .../targets/armeb_unknown_linux_gnueabi.rs | 35 +- .../src/spec/targets/armebv7r_none_eabi.rs | 42 +- .../src/spec/targets/armebv7r_none_eabihf.rs | 43 +- .../src/spec/targets/armv4t_none_eabi.rs | 67 +- .../targets/armv4t_unknown_linux_gnueabi.rs | 35 +- .../src/spec/targets/armv5te_none_eabi.rs | 57 +- .../targets/armv5te_unknown_linux_gnueabi.rs | 33 +- .../targets/armv5te_unknown_linux_musleabi.rs | 37 +- .../armv5te_unknown_linux_uclibceabi.rs | 33 +- .../src/spec/targets/armv6_unknown_freebsd.rs | 34 +- .../targets/armv6_unknown_netbsd_eabihf.rs | 30 +- .../src/spec/targets/armv6k_nintendo_3ds.rs | 54 +- .../spec/targets/armv7_linux_androideabi.rs | 43 +- .../targets/armv7_sony_vita_newlibeabihf.rs | 62 +- .../src/spec/targets/armv7_unknown_freebsd.rs | 32 +- .../targets/armv7_unknown_linux_gnueabi.rs | 36 +- .../targets/armv7_unknown_linux_gnueabihf.rs | 35 +- .../targets/armv7_unknown_linux_musleabi.rs | 40 +- .../targets/armv7_unknown_linux_musleabihf.rs | 39 +- .../spec/targets/armv7_unknown_linux_ohos.rs | 38 +- .../targets/armv7_unknown_linux_uclibceabi.rs | 37 +- .../armv7_unknown_linux_uclibceabihf.rs | 38 +- .../targets/armv7_unknown_netbsd_eabihf.rs | 31 +- .../spec/targets/armv7_wrs_vxworks_eabihf.rs | 31 +- .../targets/armv7a_kmc_solid_asp3_eabi.rs | 33 +- .../targets/armv7a_kmc_solid_asp3_eabihf.rs | 33 +- .../src/spec/targets/armv7a_none_eabi.rs | 57 +- .../src/spec/targets/armv7a_none_eabihf.rs | 49 +- .../src/spec/targets/armv7k_apple_watchos.rs | 33 +- .../src/spec/targets/armv7r_none_eabi.rs | 40 +- .../src/spec/targets/armv7r_none_eabihf.rs | 42 +- .../src/spec/targets/armv7s_apple_ios.rs | 30 +- .../src/spec/targets/armv8r_none_eabihf.rs | 51 +- .../spec/targets/avr_unknown_gnu_atmega328.rs | 7 +- .../src/spec/targets/bpfeb_unknown_none.rs | 23 +- .../src/spec/targets/bpfel_unknown_none.rs | 23 +- .../targets/csky_unknown_linux_gnuabiv2.rs | 31 +- .../targets/csky_unknown_linux_gnuabiv2hf.rs | 33 +- .../targets/hexagon_unknown_linux_musl.rs | 46 +- .../spec/targets/hexagon_unknown_none_elf.rs | 44 +- .../src/spec/targets/i386_apple_ios.rs | 34 +- .../src/spec/targets/i586_pc_nto_qnx700.rs | 37 +- .../src/spec/targets/i586_pc_windows_msvc.rs | 11 +- .../spec/targets/i586_unknown_linux_gnu.rs | 11 +- .../spec/targets/i586_unknown_linux_musl.rs | 11 +- .../src/spec/targets/i586_unknown_netbsd.rs | 32 +- .../src/spec/targets/i686_apple_darwin.rs | 41 +- .../src/spec/targets/i686_linux_android.rs | 39 +- .../src/spec/targets/i686_pc_windows_gnu.rs | 43 +- .../spec/targets/i686_pc_windows_gnullvm.rs | 41 +- .../src/spec/targets/i686_pc_windows_msvc.rs | 48 +- .../src/spec/targets/i686_unknown_freebsd.rs | 33 +- .../src/spec/targets/i686_unknown_haiku.rs | 32 +- .../src/spec/targets/i686_unknown_hurd_gnu.rs | 33 +- .../spec/targets/i686_unknown_linux_gnu.rs | 35 +- .../spec/targets/i686_unknown_linux_musl.rs | 48 +- .../src/spec/targets/i686_unknown_netbsd.rs | 34 +- .../src/spec/targets/i686_unknown_openbsd.rs | 33 +- .../src/spec/targets/i686_unknown_uefi.rs | 102 +- .../src/spec/targets/i686_uwp_windows_gnu.rs | 41 +- .../src/spec/targets/i686_uwp_windows_msvc.rs | 29 +- .../spec/targets/i686_win7_windows_msvc.rs | 47 +- .../src/spec/targets/i686_wrs_vxworks.rs | 33 +- .../targets/loongarch64_unknown_linux_gnu.rs | 31 +- .../targets/loongarch64_unknown_linux_musl.rs | 31 +- .../spec/targets/loongarch64_unknown_none.rs | 39 +- .../loongarch64_unknown_none_softfloat.rs | 40 +- .../spec/targets/m68k_unknown_linux_gnu.rs | 30 +- .../spec/targets/mips64_openwrt_linux_musl.rs | 41 +- .../targets/mips64_unknown_linux_gnuabi64.rs | 36 +- .../targets/mips64_unknown_linux_muslabi64.rs | 36 +- .../mips64el_unknown_linux_gnuabi64.rs | 33 +- .../mips64el_unknown_linux_muslabi64.rs | 30 +- .../spec/targets/mips_unknown_linux_gnu.rs | 34 +- .../spec/targets/mips_unknown_linux_musl.rs | 31 +- .../spec/targets/mips_unknown_linux_uclibc.rs | 34 +- .../src/spec/targets/mipsel_sony_psp.rs | 54 +- .../src/spec/targets/mipsel_sony_psx.rs | 54 +- .../spec/targets/mipsel_unknown_linux_gnu.rs | 32 +- .../spec/targets/mipsel_unknown_linux_musl.rs | 30 +- .../targets/mipsel_unknown_linux_uclibc.rs | 32 +- .../src/spec/targets/mipsel_unknown_netbsd.rs | 35 +- .../src/spec/targets/mipsel_unknown_none.rs | 42 +- .../targets/mipsisa32r6_unknown_linux_gnu.rs | 34 +- .../mipsisa32r6el_unknown_linux_gnu.rs | 32 +- .../mipsisa64r6_unknown_linux_gnuabi64.rs | 36 +- .../mipsisa64r6el_unknown_linux_gnuabi64.rs | 33 +- .../src/spec/targets/msp430_none_elf.rs | 76 +- .../src/spec/targets/nvptx64_nvidia_cuda.rs | 75 +- .../src/spec/targets/powerpc64_ibm_aix.rs | 32 +- .../spec/targets/powerpc64_unknown_freebsd.rs | 33 +- .../targets/powerpc64_unknown_linux_gnu.rs | 34 +- .../targets/powerpc64_unknown_linux_musl.rs | 34 +- .../spec/targets/powerpc64_unknown_openbsd.rs | 33 +- .../src/spec/targets/powerpc64_wrs_vxworks.rs | 33 +- .../targets/powerpc64le_unknown_freebsd.rs | 31 +- .../targets/powerpc64le_unknown_linux_gnu.rs | 32 +- .../targets/powerpc64le_unknown_linux_musl.rs | 32 +- .../spec/targets/powerpc_unknown_freebsd.rs | 42 +- .../spec/targets/powerpc_unknown_linux_gnu.rs | 32 +- .../targets/powerpc_unknown_linux_gnuspe.rs | 37 +- .../targets/powerpc_unknown_linux_musl.rs | 32 +- .../spec/targets/powerpc_unknown_netbsd.rs | 32 +- .../spec/targets/powerpc_unknown_openbsd.rs | 30 +- .../src/spec/targets/powerpc_wrs_vxworks.rs | 32 +- .../spec/targets/powerpc_wrs_vxworks_spe.rs | 38 +- .../targets/riscv32gc_unknown_linux_gnu.rs | 36 +- .../targets/riscv32gc_unknown_linux_musl.rs | 36 +- .../spec/targets/riscv32i_unknown_none_elf.rs | 40 +- .../spec/targets/riscv32im_risc0_zkvm_elf.rs | 52 +- .../targets/riscv32im_unknown_none_elf.rs | 40 +- .../targets/riscv32ima_unknown_none_elf.rs | 38 +- .../spec/targets/riscv32imac_esp_espidf.rs | 47 +- .../targets/riscv32imac_unknown_none_elf.rs | 38 +- .../targets/riscv32imac_unknown_xous_elf.rs | 37 +- .../spec/targets/riscv32imafc_esp_espidf.rs | 46 +- .../targets/riscv32imafc_unknown_none_elf.rs | 40 +- .../src/spec/targets/riscv32imc_esp_espidf.rs | 50 +- .../targets/riscv32imc_unknown_none_elf.rs | 40 +- .../src/spec/targets/riscv64_linux_android.rs | 38 +- .../spec/targets/riscv64gc_unknown_freebsd.rs | 31 +- .../spec/targets/riscv64gc_unknown_fuchsia.rs | 33 +- .../spec/targets/riscv64gc_unknown_hermit.rs | 35 +- .../targets/riscv64gc_unknown_linux_gnu.rs | 36 +- .../targets/riscv64gc_unknown_linux_musl.rs | 36 +- .../spec/targets/riscv64gc_unknown_netbsd.rs | 33 +- .../targets/riscv64gc_unknown_none_elf.rs | 46 +- .../spec/targets/riscv64gc_unknown_openbsd.rs | 31 +- .../targets/riscv64imac_unknown_none_elf.rs | 43 +- .../spec/targets/s390x_unknown_linux_gnu.rs | 42 +- .../spec/targets/s390x_unknown_linux_musl.rs | 44 +- .../spec/targets/sparc64_unknown_linux_gnu.rs | 30 +- .../spec/targets/sparc64_unknown_netbsd.rs | 31 +- .../spec/targets/sparc64_unknown_openbsd.rs | 32 +- .../spec/targets/sparc_unknown_linux_gnu.rs | 32 +- .../spec/targets/sparc_unknown_none_elf.rs | 44 +- .../src/spec/targets/sparcv9_sun_solaris.rs | 38 +- .../src/spec/targets/thumbv4t_none_eabi.rs | 76 +- .../src/spec/targets/thumbv5te_none_eabi.rs | 57 +- .../src/spec/targets/thumbv6m_none_eabi.rs | 37 +- .../spec/targets/thumbv7a_pc_windows_msvc.rs | 43 +- .../spec/targets/thumbv7a_uwp_windows_msvc.rs | 31 +- .../src/spec/targets/thumbv7em_none_eabi.rs | 39 +- .../src/spec/targets/thumbv7em_none_eabihf.rs | 48 +- .../src/spec/targets/thumbv7m_none_eabi.rs | 30 +- .../targets/thumbv7neon_linux_androideabi.rs | 41 +- .../thumbv7neon_unknown_linux_gnueabihf.rs | 37 +- .../thumbv7neon_unknown_linux_musleabihf.rs | 43 +- .../spec/targets/thumbv8m_base_none_eabi.rs | 34 +- .../spec/targets/thumbv8m_main_none_eabi.rs | 32 +- .../spec/targets/thumbv8m_main_none_eabihf.rs | 38 +- .../spec/targets/wasm32_unknown_emscripten.rs | 50 +- .../spec/targets/wasm32_unknown_unknown.rs | 71 +- .../src/spec/targets/wasm32_wasi.rs | 12 +- .../src/spec/targets/wasm32_wasip1.rs | 77 +- .../src/spec/targets/wasm32_wasip1_threads.rs | 92 +- .../src/spec/targets/wasm32_wasip2.rs | 84 +- .../spec/targets/wasm64_unknown_unknown.rs | 64 +- .../src/spec/targets/x86_64_apple_darwin.rs | 43 +- .../src/spec/targets/x86_64_apple_ios.rs | 34 +- .../spec/targets/x86_64_apple_ios_macabi.rs | 33 +- .../src/spec/targets/x86_64_apple_tvos.rs | 30 +- .../spec/targets/x86_64_apple_watchos_sim.rs | 28 +- .../targets/x86_64_fortanix_unknown_sgx.rs | 112 +- .../src/spec/targets/x86_64_fuchsia.rs | 2 +- .../src/spec/targets/x86_64_linux_android.rs | 42 +- .../src/spec/targets/x86_64_pc_nto_qnx710.rs | 37 +- .../src/spec/targets/x86_64_pc_solaris.rs | 37 +- .../src/spec/targets/x86_64_pc_windows_gnu.rs | 42 +- .../spec/targets/x86_64_pc_windows_gnullvm.rs | 35 +- .../spec/targets/x86_64_pc_windows_msvc.rs | 34 +- .../targets/x86_64_unikraft_linux_musl.rs | 34 +- .../spec/targets/x86_64_unknown_dragonfly.rs | 34 +- .../spec/targets/x86_64_unknown_freebsd.rs | 39 +- .../spec/targets/x86_64_unknown_fuchsia.rs | 36 +- .../src/spec/targets/x86_64_unknown_haiku.rs | 36 +- .../src/spec/targets/x86_64_unknown_hermit.rs | 33 +- .../spec/targets/x86_64_unknown_illumos.rs | 36 +- .../targets/x86_64_unknown_l4re_uclibc.rs | 32 +- .../spec/targets/x86_64_unknown_linux_gnu.rs | 49 +- .../targets/x86_64_unknown_linux_gnux32.rs | 39 +- .../spec/targets/x86_64_unknown_linux_musl.rs | 45 +- .../spec/targets/x86_64_unknown_linux_ohos.rs | 44 +- .../src/spec/targets/x86_64_unknown_netbsd.rs | 45 +- .../src/spec/targets/x86_64_unknown_none.rs | 60 +- .../spec/targets/x86_64_unknown_openbsd.rs | 35 +- .../src/spec/targets/x86_64_unknown_redox.rs | 34 +- .../src/spec/targets/x86_64_unknown_uefi.rs | 56 +- .../spec/targets/x86_64_uwp_windows_gnu.rs | 40 +- .../spec/targets/x86_64_uwp_windows_msvc.rs | 32 +- .../spec/targets/x86_64_win7_windows_msvc.rs | 32 +- .../src/spec/targets/x86_64_wrs_vxworks.rs | 36 +- .../src/spec/targets/x86_64h_apple_darwin.rs | 64 +- .../rustc_target/src/spec/tests/tests_impl.rs | 216 +- compiler/rustc_target/src/target_features.rs | 574 +- compiler/rustc_target/src/tests.rs | 54 +- compiler/rustc_trait_selection/src/errors.rs | 230 +- compiler/rustc_trait_selection/src/infer.rs | 185 +- compiler/rustc_trait_selection/src/regions.rs | 44 +- .../src/solve/alias_relate.rs | 225 +- .../src/solve/assembly/mod.rs | 1096 +-- .../src/solve/assembly/structural_traits.rs | 918 +-- .../src/solve/eval_ctxt/canonical.rs | 532 +- .../src/solve/eval_ctxt/commit_if_ok.rs | 62 +- .../src/solve/eval_ctxt/mod.rs | 1322 +--- .../src/solve/eval_ctxt/probe.rs | 142 +- .../src/solve/eval_ctxt/select.rs | 490 +- .../src/solve/fulfill.rs | 345 +- .../src/solve/inspect/analyse.rs | 297 +- .../src/solve/inspect/build.rs | 728 +- .../src/solve/inspect/mod.rs | 9 +- .../rustc_trait_selection/src/solve/mod.rs | 412 +- .../src/solve/normalize.rs | 358 +- .../src/solve/normalizes_to/anon_const.rs | 36 +- .../src/solve/normalizes_to/inherent.rs | 64 +- .../src/solve/normalizes_to/mod.rs | 1101 +-- .../src/solve/normalizes_to/opaque_types.rs | 125 +- .../src/solve/normalizes_to/weak_types.rs | 43 +- .../src/solve/project_goals.rs | 52 +- .../src/solve/search_graph.rs | 615 +- .../src/solve/trait_goals.rs | 1439 +--- .../src/traits/auto_trait.rs | 1037 +-- .../src/traits/coherence.rs | 1447 +--- .../src/traits/const_evaluatable.rs | 291 +- .../src/traits/engine.rs | 342 +- .../src/traits/error_reporting/ambiguity.rs | 151 +- .../traits/error_reporting/infer_ctxt_ext.rs | 317 +- .../src/traits/error_reporting/mod.rs | 228 +- .../error_reporting/on_unimplemented.rs | 1289 +--- .../src/traits/fulfill.rs | 1081 +-- .../rustc_trait_selection/src/traits/misc.rs | 289 +- .../rustc_trait_selection/src/traits/mod.rs | 668 +- .../src/traits/normalize.rs | 529 +- .../src/traits/object_safety.rs | 1167 +--- .../src/traits/outlives_bounds.rs | 184 +- .../src/traits/project.rs | 2739 ++------ .../src/traits/query/dropck_outlives.rs | 396 +- .../src/traits/query/evaluate_obligation.rs | 155 +- .../src/traits/query/method_autoderef.rs | 5 +- .../src/traits/query/mod.rs | 16 +- .../src/traits/query/normalize.rs | 452 +- .../traits/query/type_op/ascribe_user_type.rs | 203 +- .../src/traits/query/type_op/custom.rs | 163 +- .../src/traits/query/type_op/eq.rs | 45 +- .../query/type_op/implied_outlives_bounds.rs | 415 +- .../src/traits/query/type_op/mod.rs | 265 +- .../src/traits/query/type_op/normalize.rs | 109 +- .../src/traits/query/type_op/outlives.rs | 69 +- .../traits/query/type_op/prove_predicate.rs | 88 +- .../src/traits/query/type_op/subtype.rs | 42 +- .../src/traits/select/candidate_assembly.rs | 1719 +---- .../src/traits/select/confirmation.rs | 1973 ++---- .../src/traits/select/mod.rs | 3903 +++-------- .../src/traits/specialize/mod.rs | 696 +- .../traits/specialize/specialization_graph.rs | 514 +- .../src/traits/structural_match.rs | 204 +- .../src/traits/structural_normalize.rs | 69 +- .../rustc_trait_selection/src/traits/util.rs | 934 +-- .../src/traits/vtable.rs | 511 +- .../rustc_trait_selection/src/traits/wf.rs | 1206 +--- compiler/rustc_traits/src/codegen.rs | 111 +- compiler/rustc_traits/src/dropck_outlives.rs | 106 +- .../rustc_traits/src/evaluate_obligation.rs | 44 +- .../src/implied_outlives_bounds.rs | 63 +- .../src/normalize_erasing_regions.rs | 96 +- .../src/normalize_projection_ty.rs | 165 +- compiler/rustc_traits/src/type_op.rs | 183 +- compiler/rustc_transmute/src/layout/dfa.rs | 233 +- compiler/rustc_transmute/src/layout/mod.rs | 146 +- compiler/rustc_transmute/src/layout/nfa.rs | 218 +- compiler/rustc_transmute/src/layout/tree.rs | 628 +- .../rustc_transmute/src/layout/tree/tests.rs | 134 +- compiler/rustc_transmute/src/lib.rs | 231 +- .../src/maybe_transmutable/mod.rs | 497 +- .../src/maybe_transmutable/query_context.rs | 68 +- .../src/maybe_transmutable/tests.rs | 224 +- compiler/rustc_ty_utils/src/abi.rs | 1101 +-- compiler/rustc_ty_utils/src/assoc.rs | 487 +- compiler/rustc_ty_utils/src/common_traits.rs | 53 +- compiler/rustc_ty_utils/src/consts.rs | 576 +- compiler/rustc_ty_utils/src/errors.rs | 172 +- compiler/rustc_ty_utils/src/implied_bounds.rs | 232 +- compiler/rustc_ty_utils/src/instance.rs | 443 +- compiler/rustc_ty_utils/src/layout.rs | 1515 +--- .../rustc_ty_utils/src/layout_sanity_check.rs | 388 +- compiler/rustc_ty_utils/src/lib.rs | 73 +- compiler/rustc_ty_utils/src/needs_drop.rs | 488 +- compiler/rustc_ty_utils/src/opaque_types.rs | 460 +- .../rustc_ty_utils/src/representability.rs | 155 +- compiler/rustc_ty_utils/src/sig_types.rs | 170 +- .../rustc_ty_utils/src/structural_match.rs | 48 +- compiler/rustc_ty_utils/src/ty.rs | 461 +- compiler/rustc_type_ir/src/binder.rs | 9 +- compiler/rustc_type_ir/src/canonical.rs | 467 +- compiler/rustc_type_ir/src/codec.rs | 75 +- compiler/rustc_type_ir/src/const_kind.rs | 207 +- compiler/rustc_type_ir/src/debug.rs | 171 +- compiler/rustc_type_ir/src/flags.rs | 151 +- compiler/rustc_type_ir/src/fold.rs | 391 +- compiler/rustc_type_ir/src/infcx.rs | 50 +- compiler/rustc_type_ir/src/interner.rs | 273 +- compiler/rustc_type_ir/src/lib.rs | 472 +- compiler/rustc_type_ir/src/macros.rs | 66 +- compiler/rustc_type_ir/src/new.rs | 21 +- compiler/rustc_type_ir/src/predicate_kind.rs | 374 +- compiler/rustc_type_ir/src/region_kind.rs | 322 +- compiler/rustc_type_ir/src/ty_info.rs | 147 +- compiler/rustc_type_ir/src/ty_kind.rs | 995 +-- compiler/rustc_type_ir/src/visit.rs | 667 +- compiler/stable_mir/src/abi.rs | 525 +- compiler/stable_mir/src/compiler_interface.rs | 306 +- compiler/stable_mir/src/crate_def.rs | 79 +- compiler/stable_mir/src/error.rs | 104 +- compiler/stable_mir/src/lib.rs | 247 +- compiler/stable_mir/src/mir.rs | 10 +- compiler/stable_mir/src/mir/alloc.rs | 102 +- compiler/stable_mir/src/mir/body.rs | 1293 +--- compiler/stable_mir/src/mir/mono.rs | 352 +- compiler/stable_mir/src/mir/pretty.rs | 522 +- compiler/stable_mir/src/mir/visit.rs | 629 +- compiler/stable_mir/src/target.rs | 70 +- compiler/stable_mir/src/ty.rs | 1699 +---- compiler/stable_mir/src/visitor.rs | 268 +- 1659 files changed, 155249 insertions(+), 577340 deletions(-) diff --git a/compiler/rustc/build.rs b/compiler/rustc/build.rs index 8b7d28d2b8aa6..f6a6eccc88b31 100644 --- a/compiler/rustc/build.rs +++ b/compiler/rustc/build.rs @@ -1,27 +1,10 @@ -use std::env; - -fn main() { - let target_os = env::var("CARGO_CFG_TARGET_OS"); - let target_env = env::var("CARGO_CFG_TARGET_ENV"); - if Ok("windows") == target_os.as_deref() && Ok("msvc") == target_env.as_deref() { - set_windows_exe_options(); - } else { - // Avoid rerunning the build script every time. - println!("cargo:rerun-if-changed=build.rs"); - } -} - -// Add a manifest file to rustc.exe. -fn set_windows_exe_options() { - static WINDOWS_MANIFEST_FILE: &str = "Windows Manifest.xml"; - - let mut manifest = env::current_dir().unwrap(); - manifest.push(WINDOWS_MANIFEST_FILE); - - println!("cargo:rerun-if-changed={WINDOWS_MANIFEST_FILE}"); - // Embed the Windows application manifest file. - println!("cargo:rustc-link-arg-bin=rustc-main=/MANIFEST:EMBED"); - println!("cargo:rustc-link-arg-bin=rustc-main=/MANIFESTINPUT:{}", manifest.to_str().unwrap()); - // Turn linker warnings into errors. - println!("cargo:rustc-link-arg-bin=rustc-main=/WX"); -} +use std::env;fn main(){();let target_os=env::var("CARGO_CFG_TARGET_OS");();3;let +target_env=env::var("CARGO_CFG_TARGET_ENV");((),());if Ok("windows")==target_os. +as_deref()&&Ok("msvc")==target_env.as_deref(){;set_windows_exe_options();;}else{ +println!("cargo:rerun-if-changed=build.rs");();}}fn set_windows_exe_options(){3; +static WINDOWS_MANIFEST_FILE:&str="Windows Manifest.xml";;let mut manifest=env:: +current_dir().unwrap();();();manifest.push(WINDOWS_MANIFEST_FILE);();3;println!( +"cargo:rerun-if-changed={WINDOWS_MANIFEST_FILE}");let _=||();if true{};println!( +"cargo:rustc-link-arg-bin=rustc-main=/MANIFEST:EMBED");((),());((),());println!( +"cargo:rustc-link-arg-bin=rustc-main=/MANIFESTINPUT:{}",manifest.to_str().//{;}; +unwrap());{();};{();};println!("cargo:rustc-link-arg-bin=rustc-main=/WX");({});} diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 3584eea0f1498..36e1e127565d2 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -1,1315 +1,336 @@ -use std::borrow::{Borrow, Cow}; -use std::cmp; -use std::fmt::{self, Write}; -use std::iter; -use std::ops::Bound; -use std::ops::Deref; - -use rustc_index::Idx; -use tracing::debug; - -use crate::{ - Abi, AbiAndPrefAlign, Align, FieldsShape, IndexSlice, IndexVec, Integer, LayoutS, Niche, - NonZeroUsize, Primitive, ReprOptions, Scalar, Size, StructKind, TagEncoding, TargetDataLayout, - Variants, WrappingRange, -}; - -// 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). -fn absent<'a, FieldIdx, VariantIdx, F>(fields: &IndexSlice) -> bool -where - FieldIdx: Idx, - VariantIdx: Idx, - F: Deref> + fmt::Debug, -{ - let uninhabited = fields.iter().any(|f| f.abi.is_uninhabited()); - // We cannot ignore alignment; that might lead us to entirely discard a variant and - // produce an enum that is less aligned than it should be! - let is_1zst = fields.iter().all(|f| f.is_1zst()); - uninhabited && is_1zst -} - -pub trait LayoutCalculator { - type TargetDataLayoutRef: Borrow; - - fn delayed_bug(&self, txt: impl Into>); - fn current_data_layout(&self) -> Self::TargetDataLayoutRef; - - fn scalar_pair( - &self, - a: Scalar, - b: Scalar, - ) -> LayoutS { - let dl = self.current_data_layout(); - let dl = dl.borrow(); - 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: [Size::ZERO, b_offset].into(), - memory_index: [0, 1].into(), - }, - abi: Abi::ScalarPair(a, b), - largest_niche, - align, - size, - max_repr_align: None, - unadjusted_abi_align: align.abi, - } - } - - fn univariant< - 'a, - FieldIdx: Idx, - VariantIdx: Idx, - F: Deref> + fmt::Debug, - >( - &self, - dl: &TargetDataLayout, - fields: &IndexSlice, - repr: &ReprOptions, - kind: StructKind, - ) -> Option> { - let layout = univariant(self, dl, fields, repr, kind, NicheBias::Start); - // Enums prefer niches close to the beginning or the end of the variants so that other - // (smaller) data-carrying variants can be packed into the space after/before the niche. - // If the default field ordering does not give us a niche at the front then we do a second - // run and bias niches to the right and then check which one is closer to one of the - // struct's edges. - if let Some(layout) = &layout { - // Don't try to calculate an end-biased layout for unsizable structs, - // otherwise we could end up with different layouts for - // Foo and Foo which would break unsizing. - if !matches!(kind, StructKind::MaybeUnsized) { - if let Some(niche) = layout.largest_niche { - let head_space = niche.offset.bytes(); - let niche_len = niche.value.size(dl).bytes(); - let tail_space = layout.size.bytes() - head_space - niche_len; - - // This may end up doing redundant work if the niche is already in the last - // field (e.g. a trailing bool) and there is tail padding. But it's non-trivial - // to get the unpadded size so we try anyway. - if fields.len() > 1 && head_space != 0 && tail_space > 0 { - let alt_layout = univariant(self, dl, fields, repr, kind, NicheBias::End) - .expect("alt layout should always work"); - let alt_niche = alt_layout - .largest_niche - .expect("alt layout should have a niche like the regular one"); - let alt_head_space = alt_niche.offset.bytes(); - let alt_niche_len = alt_niche.value.size(dl).bytes(); - let alt_tail_space = - alt_layout.size.bytes() - alt_head_space - alt_niche_len; - - debug_assert_eq!(layout.size.bytes(), alt_layout.size.bytes()); - - let prefer_alt_layout = - alt_head_space > head_space && alt_head_space > tail_space; - - debug!( - "sz: {}, default_niche_at: {}+{}, default_tail_space: {}, alt_niche_at/head_space: {}+{}, alt_tail: {}, num_fields: {}, better: {}\n\ +use std::borrow::{Borrow,Cow};use std::cmp ;use std::fmt::{self,Write};use std:: +iter;use std::ops::Bound;use std:: ops::Deref;use rustc_index::Idx;use tracing:: +debug;use crate::{Abi,AbiAndPrefAlign,Align,FieldsShape,IndexSlice,IndexVec,//3; +Integer,LayoutS,Niche,NonZeroUsize, Primitive,ReprOptions,Scalar,Size,StructKind +,TagEncoding,TargetDataLayout,Variants,WrappingRange,};fn absent<'a,FieldIdx,//; +VariantIdx,F>(fields:&IndexSlice)->bool where FieldIdx:Idx,//*&*&(); +VariantIdx:Idx,F:Deref>+fmt::Debug,{;let +uninhabited=fields.iter().any(|f|f.abi.is_uninhabited());3;3;let is_1zst=fields. +iter().all(|f|f.is_1zst());;uninhabited&&is_1zst}pub trait LayoutCalculator{type +TargetDataLayoutRef:Borrow;fn delayed_bug(&self,txt:impl//{;}; +Into>);fn current_data_layout(&self)->Self:://((),());let _=(); +TargetDataLayoutRef;fn scalar_pair(&self,a:Scalar, +b:Scalar,)->LayoutS{;let dl=self.current_data_layout();;let +dl=dl.borrow();;;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);;;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:[Size::ZERO,b_offset] +.into(),memory_index:(([0,1]).into ()),},abi:Abi::ScalarPair(a,b),largest_niche, +align,size,max_repr_align:None,unadjusted_abi_align:align.abi,}}fn univariant> ++fmt::Debug,>(&self,dl:&TargetDataLayout,fields:&IndexSlice,repr:&// +ReprOptions,kind:StructKind,)->Option>{;let layout= +univariant(self,dl,fields,repr,kind,NicheBias::Start);({});if let Some(layout)=& +layout{if(!(matches!(kind,StructKind::MaybeUnsized))){if let Some(niche)=layout. +largest_niche{3;let head_space=niche.offset.bytes();;;let niche_len=niche.value. +size(dl).bytes();3;;let tail_space=layout.size.bytes()-head_space-niche_len;;if +fields.len()>1&&head_space!=0&&tail_space>0{3;let alt_layout=univariant(self,dl, +fields,repr,kind,NicheBias::End).expect("alt layout should always work");3;3;let +alt_niche=alt_layout.largest_niche.expect(//let _=();let _=();let _=();let _=(); +"alt layout should have a niche like the regular one");();();let alt_head_space= +alt_niche.offset.bytes();;let alt_niche_len=alt_niche.value.size(dl).bytes();let +alt_tail_space=alt_layout.size.bytes()-alt_head_space-alt_niche_len;{();};{();}; +debug_assert_eq!(layout.size.bytes(),alt_layout.size.bytes());((),());*&*&();let +prefer_alt_layout=alt_head_space>head_space&&alt_head_space>tail_space;;;debug!( +"sz: {}, default_niche_at: {}+{}, default_tail_space: {}, alt_niche_at/head_space: {}+{}, alt_tail: {}, num_fields: {}, better: {}\n\ layout: {}\n\ - alt_layout: {}\n", - layout.size.bytes(), - head_space, - niche_len, - tail_space, - alt_head_space, - alt_niche_len, - alt_tail_space, - layout.fields.count(), - prefer_alt_layout, - format_field_niches(layout, fields, dl), - format_field_niches(&alt_layout, fields, dl), - ); - - if prefer_alt_layout { - return Some(alt_layout); - } - } - } - } - } - layout - } - - fn layout_of_never_type( - &self, - ) -> LayoutS { - let dl = self.current_data_layout(); - let dl = dl.borrow(); - LayoutS { - variants: Variants::Single { index: VariantIdx::new(0) }, - fields: FieldsShape::Primitive, - abi: Abi::Uninhabited, - largest_niche: None, - align: dl.i8_align, - size: Size::ZERO, - max_repr_align: None, - unadjusted_abi_align: dl.i8_align.abi, - } - } - - fn layout_of_struct_or_enum< - 'a, - FieldIdx: Idx, - VariantIdx: Idx, - F: Deref> + fmt::Debug, - >( - &self, - repr: &ReprOptions, - variants: &IndexSlice>, - is_enum: bool, - is_unsafe_cell: bool, - scalar_valid_range: (Bound, Bound), - discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool), - discriminants: impl Iterator, - dont_niche_optimize_enum: bool, - always_sized: bool, - ) -> Option> { - let dl = self.current_data_layout(); - let dl = dl.borrow(); - - 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 is_enum => { - return Some(self.layout_of_never_type()); - } - // If it's a struct, still compute a layout so that we can still compute the - // field offsets. - None => VariantIdx::new(0), - }; - - // take the struct path if it is an actual struct - if !is_enum || - // or for optimizing univariant enums - (present_second.is_none() && !repr.inhibit_enum_layout_opt()) - { - layout_of_struct( - self, - repr, - variants, - is_enum, - is_unsafe_cell, - scalar_valid_range, - always_sized, - dl, - present_first, - ) - } else { - // At this point, we have handled all unions and - // structs. (We have also handled univariant enums - // that allow representation optimization.) - assert!(is_enum); - layout_of_enum( - self, - repr, - variants, - discr_range_of_repr, - discriminants, - dont_niche_optimize_enum, - dl, - ) - } - } - - fn layout_of_union< - 'a, - FieldIdx: Idx, - VariantIdx: Idx, - F: Deref> + fmt::Debug, - >( - &self, - repr: &ReprOptions, - variants: &IndexSlice>, - ) -> Option> { - let dl = self.current_data_layout(); - let dl = dl.borrow(); - let mut align = if repr.pack.is_some() { dl.i8_align } else { dl.aggregate_align }; - let mut max_repr_align = repr.align; - - // If all the non-ZST fields have the same ABI and union ABI optimizations aren't - // disabled, we can use that common ABI for the union as a whole. - struct AbiMismatch; - let mut common_non_zst_abi_and_align = if repr.inhibit_union_abi_opt() { - // Can't optimize - Err(AbiMismatch) - } else { - Ok(None) - }; - - let mut size = Size::ZERO; - let only_variant = &variants[VariantIdx::new(0)]; - for field in only_variant { - if field.is_unsized() { - self.delayed_bug("unsized field in union".to_string()); - } - - align = align.max(field.align); - max_repr_align = max_repr_align.max(field.max_repr_align); - size = cmp::max(size, field.size); - - if field.is_zst() { - // Nothing more to do for ZST fields - continue; - } - - if let Ok(common) = common_non_zst_abi_and_align { - // Discard valid range information and allow undef - let field_abi = field.abi.to_union(); - - if let Some((common_abi, common_align)) = common { - if common_abi != field_abi { - // Different fields have different ABI: disable opt - common_non_zst_abi_and_align = Err(AbiMismatch); - } else { - // Fields with the same non-Aggregate ABI should also - // have the same alignment - if !matches!(common_abi, Abi::Aggregate { .. }) { - assert_eq!( - common_align, field.align.abi, - "non-Aggregate field with matching ABI but differing alignment" - ); - } - } - } else { - // First non-ZST field: record its ABI and alignment - common_non_zst_abi_and_align = Ok(Some((field_abi, field.align.abi))); - } - } - } - - if let Some(pack) = repr.pack { - align = align.min(AbiAndPrefAlign::new(pack)); - } - // The unadjusted ABI alignment does not include repr(align), but does include repr(pack). - // See documentation on `LayoutS::unadjusted_abi_align`. - let unadjusted_abi_align = align.abi; - if let Some(repr_align) = repr.align { - align = align.max(AbiAndPrefAlign::new(repr_align)); - } - // `align` must not be modified after this, or `unadjusted_abi_align` could be inaccurate. - let align = align; - - // If all non-ZST fields have the same ABI, we may forward that ABI - // for the union as a whole, unless otherwise inhibited. - let abi = match common_non_zst_abi_and_align { - Err(AbiMismatch) | Ok(None) => Abi::Aggregate { sized: true }, - Ok(Some((abi, _))) => { - if abi.inherent_align(dl).map(|a| a.abi) != Some(align.abi) { - // Mismatched alignment (e.g. union is #[repr(packed)]): disable opt - Abi::Aggregate { sized: true } - } else { - abi - } - } - }; - - Some(LayoutS { - variants: Variants::Single { index: VariantIdx::new(0) }, - fields: FieldsShape::Union(NonZeroUsize::new(only_variant.len())?), - abi, - largest_niche: None, - align, - size: size.align_to(align.abi), - max_repr_align, - unadjusted_abi_align, - }) - } -} - -/// single-variant enums are just structs, if you think about it -fn layout_of_struct<'a, LC, FieldIdx: Idx, VariantIdx: Idx, F>( - layout_calc: &LC, - repr: &ReprOptions, - variants: &IndexSlice>, - is_enum: bool, - is_unsafe_cell: bool, - scalar_valid_range: (Bound, Bound), - always_sized: bool, - dl: &TargetDataLayout, - present_first: VariantIdx, -) -> Option> -where - LC: LayoutCalculator + ?Sized, - F: Deref> + fmt::Debug, -{ - // Struct, or univariant enum equivalent to a struct. - // (Typechecking will reject discriminant-sizing attrs.) - - let v = present_first; - let kind = if is_enum || variants[v].is_empty() || always_sized { - StructKind::AlwaysSized - } else { - StructKind::MaybeUnsized - }; - - let mut st = layout_calc.univariant(dl, &variants[v], repr, kind)?; - st.variants = Variants::Single { index: v }; - - if 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 Some(st); - } - - let (start, end) = scalar_valid_range; - match st.abi { - Abi::Scalar(ref mut scalar) | Abi::ScalarPair(ref mut scalar, _) => { - // Enlarging validity ranges would result in missed - // optimizations, *not* wrongly assuming the inner - // value is valid. e.g. unions already enlarge validity ranges, - // because the values may be uninitialized. - // - // Because of that we only check that the start and end - // of the range is representable with this scalar type. - - let max_value = scalar.size(dl).unsigned_int_max(); - if let Bound::Included(start) = start { - // FIXME(eddyb) this might be incorrect - it doesn't - // account for wrap-around (end < start) ranges. - assert!(start <= max_value, "{start} > {max_value}"); - scalar.valid_range_mut().start = start; - } - if let Bound::Included(end) = end { - // FIXME(eddyb) this might be incorrect - it doesn't - // account for wrap-around (end < start) ranges. - assert!(end <= max_value, "{end} > {max_value}"); - scalar.valid_range_mut().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: {st:#?}", - ), - } - - Some(st) -} - -fn layout_of_enum<'a, LC, FieldIdx: Idx, VariantIdx: Idx, F>( - layout_calc: &LC, - repr: &ReprOptions, - variants: &IndexSlice>, - discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool), - discriminants: impl Iterator, - dont_niche_optimize_enum: bool, - dl: &TargetDataLayout, -) -> Option> -where - LC: LayoutCalculator + ?Sized, - F: Deref> + fmt::Debug, -{ - // 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 { - layout: LayoutS, - variants: IndexVec>, - } - - let calculate_niche_filling_layout = || -> Option> { - if dont_niche_optimize_enum { - return None; - } - - if variants.len() < 2 { - return None; - } - - let mut align = dl.aggregate_align; - let mut max_repr_align = repr.align; - let mut unadjusted_abi_align = align.abi; - - let mut variant_layouts = variants - .iter_enumerated() - .map(|(j, v)| { - let mut st = layout_calc.univariant(dl, v, repr, StructKind::AlwaysSized)?; - st.variants = Variants::Single { index: j }; - - align = align.max(st.align); - max_repr_align = max_repr_align.max(st.max_repr_align); - unadjusted_abi_align = unadjusted_abi_align.max(st.unadjusted_abi_align); - - Some(st) - }) - .collect::>>()?; - - let largest_variant_index = variant_layouts - .iter_enumerated() - .max_by_key(|(_i, layout)| layout.size.bytes()) - .map(|(i, _layout)| i)?; - - let all_indices = variants.indices(); - let needs_disc = - |index: VariantIdx| index != largest_variant_index && !absent(&variants[index]); - let niche_variants = all_indices.clone().find(|v| needs_disc(*v)).unwrap() - ..=all_indices.rev().find(|v| needs_disc(*v)).unwrap(); - - let count = - (niche_variants.end().index() as u128 - niche_variants.start().index() as u128) + 1; - - // Find the field with the largest niche - let (field_index, niche, (niche_start, niche_scalar)) = 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(dl, count)?)))?; - 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 offset in offsets.iter_mut() { - *offset += this_offset; - } - } - FieldsShape::Primitive | FieldsShape::Array { .. } | FieldsShape::Union(..) => { - 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 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: [niche_offset].into(), - memory_index: [0].into(), - }, - abi, - largest_niche, - size, - align, - max_repr_align, - unadjusted_abi_align, - }; - - 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 = repr.discr_type(); - let bits = Integer::from_attr(dl, discr_type).size().bits(); - for (i, mut val) in discriminants { - if variants[i].iter().any(|f| f.abi.is_uninhabited()) { - continue; - } - if discr_type.is_signed() { - // sign extend the raw representation to be an i128 - val = (val << (128 - bits)) >> (128 - bits); - } - if val < min { - min = val; - } - if val > max { - max = val; - } - } - // 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) = discr_range_of_repr(min, max); //Integer::repr_discr(tcx, ty, &repr, min, max); - - let mut align = dl.aggregate_align; - let mut max_repr_align = repr.align; - let mut unadjusted_abi_align = align.abi; - - 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 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 = layout_calc.univariant( - dl, - field_layouts, - 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_idx in st.fields.index_by_increasing_offset() { - let field = &field_layouts[FieldIdx::new(field_idx)]; - if !field.is_1zst() { - start_align = start_align.min(field.align.abi); - break; - } - } - size = cmp::max(size, st.size); - align = align.max(st.align); - max_repr_align = max_repr_align.max(st.max_repr_align); - unadjusted_abi_align = unadjusted_abi_align.max(st.unadjusted_abi_align); - Some(st) - }) - .collect::>>()?; - - // Align the maximum variant size to the largest alignment. - size = size.align_to(align.abi); - - // FIXME(oli-obk): deduplicate and harden these checks - if size.bytes() >= dl.obj_size_bound() { - return None; - } - - let typeck_ity = Integer::from_attr(dl, 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) - panic!( - "layout decided on a larger discriminant type ({min_ity:?}) than typeck ({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 repr.c() || 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; - } - } - FieldsShape::Primitive | FieldsShape::Array { .. } | FieldsShape::Union(..) => { - panic!("encountered a non-arbitrary layout during enum layout") - } - } - } - } - - let tag_mask = ity.size().unsigned_int_max(); - let tag = Scalar::Initialized { - value: Primitive::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. - // That's possible only if we can find a common primitive type for all variants. - 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 { - panic!("encountered a non-arbitrary layout during enum layout"); - }; - // We skip *all* ZST here and later check if we are good in terms of alignment. - // This lets us handle some cases involving aligned ZST. - 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((old_prim, common_offset)) = common_prim { - // All variants must be at the same offset - if offset != common_offset { - common_prim = None; - break; - } - // This is pretty conservative. We could go fancier - // by realising that (u8, u8) could just cohabit with - // u16 or even u32. - let new_prim = match (old_prim, prim) { - // Allow all identical primitives. - (x, y) if x == y => x, - // Allow integers of the same size with differing signedness. - // We arbitrarily choose the signedness of the first variant. - (p @ Primitive::Int(x, _), Primitive::Int(y, _)) if x == y => p, - // Allow integers mixed with pointers of the same layout. - // We must represent this using a pointer, to avoid - // roundtripping pointers through ptrtoint/inttoptr. - (p @ Primitive::Pointer(_), i @ Primitive::Int(..)) - | (i @ Primitive::Int(..), p @ Primitive::Pointer(_)) - if p.size(dl) == i.size(dl) && p.align(dl) == i.align(dl) => - { - p - } - _ => { - common_prim = None; - break; - } - }; - // We may be updating the primitive here, for example from int->ptr. - common_prim = Some((new_prim, common_offset)); - } else { - common_prim = Some((prim, offset)); - } - } - if let Some((prim, offset)) = common_prim { - let prim_scalar = if common_prim_initialized_in_all_variants { - let size = prim.size(dl); - assert!(size.bits() <= 128); - Scalar::Initialized { value: prim, valid_range: WrappingRange::full(size) } - } else { - // Common prim might be uninit. - Scalar::Union { value: prim } - }; - let pair = layout_calc.scalar_pair::(tag, prim_scalar); - let pair_offsets = match pair.fields { - FieldsShape::Arbitrary { ref offsets, ref memory_index } => { - assert_eq!(memory_index.raw, [0, 1]); - offsets - } - _ => panic!("encountered a non-arbitrary layout during enum layout"), - }; - if pair_offsets[FieldIdx::new(0)] == Size::ZERO - && pair_offsets[FieldIdx::new(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: [Size::ZERO].into(), memory_index: [0].into() }, - largest_niche, - abi, - align, - size, - max_repr_align, - unadjusted_abi_align, - }; - - 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 cmp::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 } - } - Variants::Single { .. } => { - panic!("encountered a single-variant enum during multi-variant layout") - } - }; - Some(best_layout.layout) -} - -/// Determines towards which end of a struct layout optimizations will try to place the best niches. -enum NicheBias { - Start, - End, -} - -fn univariant< - 'a, - FieldIdx: Idx, - VariantIdx: Idx, - F: Deref> + fmt::Debug, ->( - this: &(impl LayoutCalculator + ?Sized), - dl: &TargetDataLayout, - fields: &IndexSlice, - repr: &ReprOptions, - kind: StructKind, - niche_bias: NicheBias, -) -> Option> { - let pack = repr.pack; - let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align }; - let mut max_repr_align = repr.align; - let mut inverse_memory_index: IndexVec = fields.indices().collect(); - let optimize = !repr.inhibit_struct_field_reordering_opt(); - if optimize && fields.len() > 1 { - let end = if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() }; - let optimizing = &mut inverse_memory_index.raw[..end]; - let fields_excluding_tail = &fields.raw[..end]; - - // If `-Z randomize-layout` was enabled for the type definition we can shuffle - // the field ordering to try and catch some code making assumptions about layouts - // we don't guarantee. - if repr.can_randomize_type_layout() && cfg!(feature = "randomize") { - #[cfg(feature = "randomize")] - { - use rand::{seq::SliceRandom, SeedableRng}; - // `ReprOptions.field_shuffle_seed` is a deterministic seed we can use to randomize field - // ordering. - let mut rng = - rand_xoshiro::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 { - // To allow unsizing `&Foo` -> `&Foo`, the layout of the struct must - // not depend on the layout of the tail. - let max_field_align = - fields_excluding_tail.iter().map(|f| f.align.abi.bytes()).max().unwrap_or(1); - let largest_niche_size = fields_excluding_tail - .iter() - .filter_map(|f| f.largest_niche) - .map(|n| n.available(dl)) - .max() - .unwrap_or(0); - - // Calculates a sort key to group fields by their alignment or possibly some - // size-derived pseudo-alignment. - let alignment_group_key = |layout: &F| { - if let Some(pack) = pack { - // Return the packed alignment in bytes. - layout.align.abi.min(pack).bytes() - } else { - // Returns `log2(effective-align)`. This is ok since `pack` applies to all - // fields equally. The calculation assumes that size is an integer multiple of - // align, except for ZSTs. - let align = layout.align.abi.bytes(); - let size = layout.size.bytes(); - let niche_size = layout.largest_niche.map(|n| n.available(dl)).unwrap_or(0); - // Group [u8; 4] with align-4 or [u8; 6] with align-2 fields. - let size_as_align = align.max(size).trailing_zeros(); - let size_as_align = if largest_niche_size > 0 { - match niche_bias { - // Given `A(u8, [u8; 16])` and `B(bool, [u8; 16])` we want to bump the - // array to the front in the first case (for aligned loads) but keep - // the bool in front in the second case for its niches. - NicheBias::Start => max_field_align.trailing_zeros().min(size_as_align), - // When moving niches towards the end of the struct then for - // A((u8, u8, u8, bool), (u8, bool, u8)) we want to keep the first tuple - // in the align-1 group because its bool can be moved closer to the end. - NicheBias::End if niche_size == largest_niche_size => { - align.trailing_zeros() - } - NicheBias::End => size_as_align, - } - } else { - size_as_align - }; - size_as_align as u64 - } - }; - - match kind { - StructKind::AlwaysSized | StructKind::MaybeUnsized => { - // Currently `LayoutS` only exposes a single niche so sorting is usually - // sufficient to get one niche into the preferred position. If it ever - // supported multiple niches then a more advanced pick-and-pack approach could - // provide better results. But even for the single-niche cache it's not - // optimal. E.g. for A(u32, (bool, u8), u16) it would be possible to move the - // bool to the front but it would require packing the tuple together with the - // u16 to build a 4-byte group so that the u32 can be placed after it without - // padding. This kind of packing can't be achieved by sorting. - optimizing.sort_by_key(|&x| { - let f = &fields[x]; - let field_size = f.size.bytes(); - let niche_size = f.largest_niche.map_or(0, |n| n.available(dl)); - let niche_size_key = match niche_bias { - // large niche first - NicheBias::Start => !niche_size, - // large niche last - NicheBias::End => niche_size, - }; - let inner_niche_offset_key = match niche_bias { - NicheBias::Start => f.largest_niche.map_or(0, |n| n.offset.bytes()), - NicheBias::End => f.largest_niche.map_or(0, |n| { - !(field_size - n.value.size(dl).bytes() - n.offset.bytes()) - }), - }; - - ( - // Then place largest alignments first. - cmp::Reverse(alignment_group_key(f)), - // Then prioritize niche placement within alignment group according to - // `niche_bias_start`. - niche_size_key, - // Then among fields with equally-sized niches prefer the ones - // closer to the start/end of the field. - inner_niche_offset_key, - ) - }); - } - - StructKind::Prefixed(..) => { - // Sort in ascending alignment so that the layout stays optimal - // regardless of the prefix. - // And put the largest niche in an alignment group at the end - // so it can be used as discriminant in jagged enums - optimizing.sort_by_key(|&x| { - let f = &fields[x]; - let niche_size = f.largest_niche.map_or(0, |n| n.available(dl)); - (alignment_group_key(f), niche_size) - }); - } - } - - // FIXME(Kixiron): We can always shuffle fields within a given alignment class - // regardless of the status of `-Z randomize-layout` - } - } - // inverse_memory_index holds field indices by increasing memory offset. - // That is, if field 5 has offset 0, the first element of inverse_memory_index is 5. - // We now write field offsets to the corresponding offset slot; - // field 5 with offset 0 puts 0 in offsets[5]. - // At the bottom of this function, we invert `inverse_memory_index` to - // produce `memory_index` (see `invert_mapping`). - let mut sized = true; - let mut offsets = IndexVec::from_elem(Size::ZERO, fields); - let mut offset = Size::ZERO; - let mut largest_niche = None; - let mut largest_niche_available = 0; - if let StructKind::Prefixed(prefix_size, prefix_align) = kind { - let prefix_align = - if let Some(pack) = pack { prefix_align.min(pack) } else { prefix_align }; - align = align.max(AbiAndPrefAlign::new(prefix_align)); - offset = prefix_size.align_to(prefix_align); - } - for &i in &inverse_memory_index { - let field = &fields[i]; - if !sized { - this.delayed_bug(format!( - "univariant: field #{} comes after unsized field", - offsets.len(), - )); - } - - 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); - max_repr_align = max_repr_align.max(field.max_repr_align); - - debug!("univariant offset: {:?} field: {:#?}", offset, field); - offsets[i] = offset; - - if let Some(mut niche) = field.largest_niche { - let available = niche.available(dl); - // Pick up larger niches. - let prefer_new_niche = match niche_bias { - NicheBias::Start => available > largest_niche_available, - // if there are several niches of the same size then pick the last one - NicheBias::End => available >= largest_niche_available, - }; - if prefer_new_niche { - largest_niche_available = available; - niche.offset += offset; - largest_niche = Some(niche); - } - } - - offset = offset.checked_add(field.size, dl)?; - } - - // The unadjusted ABI alignment does not include repr(align), but does include repr(pack). - // See documentation on `LayoutS::unadjusted_abi_align`. - let unadjusted_abi_align = align.abi; - if let Some(repr_align) = repr.align { - align = align.max(AbiAndPrefAlign::new(repr_align)); - } - // `align` must not be modified after this point, or `unadjusted_abi_align` could be inaccurate. - let align = align; - - debug!("univariant min_size: {:?}", offset); - let min_size = offset; - // As stated above, inverse_memory_index holds field indices by increasing offset. - // This makes it an already-sorted view of the offsets vec. - // To invert it, consider: - // If field 5 has offset 0, offsets[0] is 5, and memory_index[5] should be 0. - // Field 5 would be the first element, so memory_index is i: - // Note: if we didn't optimize, it's already right. - let memory_index = if optimize { - inverse_memory_index.invert_bijective_mapping() - } else { - debug_assert!(inverse_memory_index.iter().copied().eq(fields.indices())); - inverse_memory_index.into_iter().map(|it| it.index() as u32).collect() - }; - let size = min_size.align_to(align.abi); - // FIXME(oli-obk): deduplicate and harden these checks - if size.bytes() >= dl.obj_size_bound() { - return None; - } - let mut layout_of_single_non_zst_field = None; - let mut abi = Abi::Aggregate { sized }; - // Try to make this a Scalar/ScalarPair. - if sized && size.bytes() > 0 { - // We skip *all* ZST here and later check if we are good in terms of alignment. - // This lets us handle some cases involving aligned ZST. - let mut non_zst_fields = fields.iter_enumerated().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) => { - layout_of_single_non_zst_field = Some(field); - - // Field fills the struct and it has a scalar or scalar pair ABI. - if offsets[i].bytes() == 0 && align.abi == field.align.abi && size == field.size { - match field.abi { - // For plain scalars, or vectors of them, we can't unpack - // newtypes for `#[repr(C)]`, as that affects C ABIs. - Abi::Scalar(_) | Abi::Vector { .. } if optimize => { - abi = field.abi; - } - // But scalar pairs are Rust-specific and get - // treated as aggregates by C ABIs anyway. - Abi::ScalarPair(..) => { - abi = field.abi; - } - _ => {} - } - } - } - - // Two non-ZST fields, and they're both scalars. - (Some((i, a)), Some((j, b)), None) => { - match (a.abi, b.abi) { - (Abi::Scalar(a), Abi::Scalar(b)) => { - // Order by the memory placement, not source order. - let ((i, a), (j, b)) = if offsets[i] < offsets[j] { - ((i, a), (j, b)) - } else { - ((j, b), (i, a)) - }; - let pair = this.scalar_pair::(a, b); - let pair_offsets = match pair.fields { - FieldsShape::Arbitrary { ref offsets, ref memory_index } => { - assert_eq!(memory_index.raw, [0, 1]); - offsets - } - FieldsShape::Primitive - | FieldsShape::Array { .. } - | FieldsShape::Union(..) => { - panic!("encountered a non-arbitrary layout during enum layout") - } - }; - if offsets[i] == pair_offsets[FieldIdx::new(0)] - && offsets[j] == pair_offsets[FieldIdx::new(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; - } - - let unadjusted_abi_align = if repr.transparent() { - match layout_of_single_non_zst_field { - Some(l) => l.unadjusted_abi_align, - None => { - // `repr(transparent)` with all ZST fields. - align.abi - } - } - } else { - unadjusted_abi_align - }; - - Some(LayoutS { - variants: Variants::Single { index: VariantIdx::new(0) }, - fields: FieldsShape::Arbitrary { offsets, memory_index }, - abi, - largest_niche, - align, - size, - max_repr_align, - unadjusted_abi_align, - }) -} - -fn format_field_niches< - 'a, - FieldIdx: Idx, - VariantIdx: Idx, - F: Deref> + fmt::Debug, ->( - layout: &LayoutS, - fields: &IndexSlice, - dl: &TargetDataLayout, -) -> String { - let mut s = String::new(); - for i in layout.fields.index_by_increasing_offset() { - let offset = layout.fields.offset(i); - let f = &fields[FieldIdx::new(i)]; - write!(s, "[o{}a{}s{}", offset.bytes(), f.align.abi.bytes(), f.size.bytes()).unwrap(); - if let Some(n) = f.largest_niche { - write!( - s, - " n{}b{}s{}", - n.offset.bytes(), - n.available(dl).ilog2(), - n.value.size(dl).bytes() - ) - .unwrap(); - } - write!(s, "] ").unwrap(); - } - s -} + alt_layout: {}\n" +,layout.size.bytes(),head_space,niche_len,tail_space,alt_head_space,//if true{}; +alt_niche_len,alt_tail_space,layout.fields.count(),prefer_alt_layout,//let _=(); +format_field_niches(layout,fields,dl) ,format_field_niches(&alt_layout,fields,dl +),);{();};if prefer_alt_layout{{();};return Some(alt_layout);({});}}}}}layout}fn +layout_of_never_type(&self,)->LayoutS{3;let dl=self.current_data_layout();3;3;let dl=dl.borrow();;LayoutS{ +variants:((Variants::Single{index:(VariantIdx::new((0)))})),fields:FieldsShape:: +Primitive,abi:Abi::Uninhabited,largest_niche:None ,align:dl.i8_align,size:Size:: +ZERO,max_repr_align:None,unadjusted_abi_align:dl.i8_align.abi,}}fn//loop{break}; +layout_of_struct_or_enum<'a,FieldIdx:Idx,VariantIdx:Idx,F:Deref>+fmt::Debug,>(&self,repr:&ReprOptions,variants:&//; +IndexSlice>,is_enum:bool,is_unsafe_cell:bool,//; +scalar_valid_range:(Bound,Bound),discr_range_of_repr:impl Fn(i128,// +i128)->(Integer,bool),discriminants:impl Iterator,//{;}; +dont_niche_optimize_enum:bool,always_sized:bool,)->Option>{3;let dl=self.current_data_layout();3;3;let dl=dl.borrow();3;3;let( +present_first,present_second)={*&*&();((),());let mut present_variants=variants. +iter_enumerated().filter_map(|(i,v)|if absent(v){None}else{Some(i)});if true{};( +present_variants.next(),present_variants.next())};{;};();let present_first=match +present_first{Some(present_first)=>present_first,None if is_enum=>{;return Some( +self.layout_of_never_type());({});}None=>VariantIdx::new(0),};({});if!is_enum||( +present_second.is_none()&&(!(repr.inhibit_enum_layout_opt()))){layout_of_struct( +self,repr,variants,is_enum,is_unsafe_cell,scalar_valid_range,always_sized,dl,//; +present_first,)}else{{;};assert!(is_enum);{;};layout_of_enum(self,repr,variants, +discr_range_of_repr,discriminants,dont_niche_optimize_enum,dl,)}}fn//let _=||(); +layout_of_union<'a,FieldIdx:Idx,VariantIdx:Idx,F:Deref>+fmt::Debug,>( &self,repr:&ReprOptions,variants:&IndexSlice +>,)->Option>{();let +dl=self.current_data_layout();;;let dl=dl.borrow();;;let mut align=if repr.pack. +is_some(){dl.i8_align}else{dl.aggregate_align};();3;let mut max_repr_align=repr. +align;();();struct AbiMismatch;3;3;let mut common_non_zst_abi_and_align=if repr. +inhibit_union_abi_opt(){Err(AbiMismatch)}else{Ok(None)};;let mut size=Size::ZERO +;;;let only_variant=&variants[VariantIdx::new(0)];;for field in only_variant{if +field.is_unsized(){3;self.delayed_bug("unsized field in union".to_string());3;}; +align=align.max(field.align);{();};({});max_repr_align=max_repr_align.max(field. +max_repr_align);;;size=cmp::max(size,field.size);;if field.is_zst(){continue;}if +let Ok(common)=common_non_zst_abi_and_align{;let field_abi=field.abi.to_union(); +if let Some((common_abi,common_align))=common{if common_abi!=field_abi{let _=(); +common_non_zst_abi_and_align=Err(AbiMismatch);3;}else{if!matches!(common_abi,Abi +::Aggregate{..}){let _=||();loop{break};assert_eq!(common_align,field.align.abi, +"non-Aggregate field with matching ABI but differing alignment");{;};}}}else{(); +common_non_zst_abi_and_align=Ok(Some((field_abi,field.align.abi)));{;};}}}if let +Some(pack)=repr.pack{{;};align=align.min(AbiAndPrefAlign::new(pack));{;};}();let +unadjusted_abi_align=align.abi;;if let Some(repr_align)=repr.align{;align=align. +max(AbiAndPrefAlign::new(repr_align));();}();let align=align;();();let abi=match +common_non_zst_abi_and_align{Err(AbiMismatch)|Ok(None)=>Abi::Aggregate{sized://; +true},Ok(Some((abi,_)))=>{if (abi.inherent_align(dl).map(|a|a.abi))!=Some(align. +abi){Abi::Aggregate{sized:true}}else{abi}}};{;};Some(LayoutS{variants:Variants:: +Single{index:(VariantIdx::new(0))} ,fields:FieldsShape::Union(NonZeroUsize::new( +only_variant.len())?),abi, largest_niche:None,align,size:size.align_to(align.abi +),max_repr_align,unadjusted_abi_align,})}}fn layout_of_struct<'a,LC,FieldIdx://; +Idx,VariantIdx:Idx,F>(layout_calc:&LC,repr:&ReprOptions,variants:&IndexSlice>,is_enum:bool,is_unsafe_cell:bool,//loop{break}; +scalar_valid_range:(Bound,Bound),always_sized:bool,dl:&//let _=||(); +TargetDataLayout,present_first:VariantIdx,) ->Option>where LC:LayoutCalculator+?Sized,F:Deref>+fmt::Debug,{;let v=present_first;;let kind=if is_enum||variants[v]. +is_empty()||always_sized{ StructKind::AlwaysSized}else{StructKind::MaybeUnsized} +;3;;let mut st=layout_calc.univariant(dl,&variants[v],repr,kind)?;;;st.variants= +Variants::Single{index:v};();if is_unsafe_cell{3;let hide_niches=|scalar:&mut _| +match scalar{Scalar::Initialized{value, valid_range}=>{((((((*valid_range))))))= +WrappingRange::full(value.size(dl))}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 Some(st);}let +(start,end)=scalar_valid_range;();match st.abi{Abi::Scalar(ref mut scalar)|Abi:: +ScalarPair(ref mut scalar,_)=>{;let max_value=scalar.size(dl).unsigned_int_max() +;let _=();if let Bound::Included(start)=start{let _=();assert!(start<=max_value, +"{start} > {max_value}");;;scalar.valid_range_mut().start=start;;}if let Bound:: +Included(end)=end{();assert!(end<=max_value,"{end} > {max_value}");();();scalar. +valid_range_mut().end=end;;}let niche=Niche::from_scalar(dl,Size::ZERO,*scalar); +if let Some(niche)=niche{match st.largest_niche{Some(largest_niche)=>{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,//if let _=(){};*&*&();((),());*&*&();((),());*&*&();((),()); +"nonscalar layout for layout_scalar_valid_range type: {st:#?}",),}( Some(st))}fn +layout_of_enum<'a,LC,FieldIdx:Idx,VariantIdx:Idx,F>(layout_calc:&LC,repr:&//{;}; +ReprOptions,variants:&IndexSlice>,//loop{break}; +discr_range_of_repr:impl Fn(i128,i128)->(Integer,bool),discriminants:impl//({}); +Iterator,dont_niche_optimize_enum:bool,dl:&//let _=||(); +TargetDataLayout,)->Option>where LC://loop{break;}; +LayoutCalculator+?Sized,F:Deref>+fmt::// +Debug,{();struct TmpLayout{layout:LayoutS,variants:IndexVec>,}();3;let +calculate_niche_filling_layout=||->Option>{if//3; +dont_niche_optimize_enum{;return None;;}if variants.len()<2{return None;}let mut +align=dl.aggregate_align;{;};{;};let mut max_repr_align=repr.align;();();let mut +unadjusted_abi_align=align.abi;;let mut variant_layouts=variants.iter_enumerated +().map(|(j,v)|{let _=();let mut st=layout_calc.univariant(dl,v,repr,StructKind:: +AlwaysSized)?;;;st.variants=Variants::Single{index:j};align=align.max(st.align); +max_repr_align=max_repr_align.max(st.max_repr_align);();();unadjusted_abi_align= +unadjusted_abi_align.max(st.unadjusted_abi_align);3;Some(st)}).collect::>>()?;({});({});let largest_variant_index=variant_layouts. +iter_enumerated().max_by_key(|(_i,layout)|layout. size.bytes()).map(|(i,_layout) +|i)?;;;let all_indices=variants.indices();let needs_disc=|index:VariantIdx|index +!=largest_variant_index&&!absent(&variants[index]);({});({});let niche_variants= +all_indices.clone().find(|v|needs_disc(*v) ).unwrap()..=all_indices.rev().find(| +v|needs_disc(*v)).unwrap();();();let count=(niche_variants.end().index()as u128- +niche_variants.start().index()as u128)+1;3;3;let(field_index,niche,(niche_start, +niche_scalar))=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(dl,count)?)))?;({});{;};let +niche_offset=niche.offset+ variant_layouts[largest_variant_index].fields.offset( +field_index);3;3;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==//((),());let _=(); +largest_variant_index{;return true;;};layout.largest_niche=None;if layout.size<= +niche_offset{;return true;;};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;;}match layout.fields{FieldsShape::Arbitrary{ref mut offsets,..}=>{ +for offset in offsets.iter_mut(){;*offset+=this_offset;}}FieldsShape::Primitive| +FieldsShape::Array{..}|FieldsShape::Union(..)=>{panic!(//let _=||();loop{break}; +"Layout of fields should be Arbitrary for variants")}}if!layout.abi.//if true{}; +is_uninhabited(){{;};layout.abi=Abi::Aggregate{sized:true};{;};}();layout.size+= +this_offset;;true});;if!all_variants_fit{;return 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);3;3;let same_size=size==variant_layouts[largest_variant_index].size;3;;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{Abi::Scalar(_)=>(Abi::Scalar(niche_scalar)),Abi::ScalarPair(first,second)=>{ +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:([niche_offset].into()), +memory_index:(((([(0)])).into())),},abi,largest_niche,size,align,max_repr_align, +unadjusted_abi_align,};3;Some(TmpLayout{layout,variants:variant_layouts})};;;let +niche_filling_layout=calculate_niche_filling_layout();3;3;let(mut min,mut max)=( +i128::MAX,i128::MIN);3;3;let discr_type=repr.discr_type();3;3;let bits=Integer:: +from_attr(dl,discr_type).size().bits();*&*&();for(i,mut val)in discriminants{if +variants[i].iter().any(|f|f.abi.is_uninhabited()){();continue;();}if discr_type. +is_signed(){;val=(val<<(128-bits))>>(128-bits);;}if valmax{ +max=val;;}}if(min,max)==(i128::MAX,i128::MIN){;min=0;;;max=0;;}assert!(min<=max, +"discriminant range is {min}...{max}");;let(min_ity,signed)=discr_range_of_repr( +min,max);;let mut align=dl.aggregate_align;let mut max_repr_align=repr.align;let +mut unadjusted_abi_align=align.abi;;;let mut size=Size::ZERO;let mut start_align +=Align::from_bytes(256).unwrap();;assert_eq!(Integer::for_align(dl,start_align), +None);3;3;let mut prefix_align=min_ity.align(dl).abi;3;if repr.c(){for fields in +variants{for field in fields{;prefix_align=prefix_align.max(field.align.abi);}}} +let mut layout_variants=variants.iter_enumerated().map(|(i,field_layouts)|{3;let +mut st=layout_calc.univariant(dl,field_layouts,repr,StructKind::Prefixed(//({}); +min_ity.size(),prefix_align),)?;();3;st.variants=Variants::Single{index:i};3;for +field_idx in st.fields.index_by_increasing_offset(){();let field=&field_layouts[ +FieldIdx::new(field_idx)];;if!field.is_1zst(){start_align=start_align.min(field. +align.abi);;;break;;}};size=cmp::max(size,st.size);;;align=align.max(st.align);; +max_repr_align=max_repr_align.max(st.max_repr_align);();();unadjusted_abi_align= +unadjusted_abi_align.max(st.unadjusted_abi_align);3;Some(st)}).collect::>>()?;;;size=size.align_to(align.abi);if size.bytes()>=dl. +obj_size_bound(){();return None;();}3;let typeck_ity=Integer::from_attr(dl,repr. +discr_type());let _=();if true{};if typeck_ity{for i in offsets{if*i<=old_ity_size{{;};assert_eq!(*i,old_ity_size);();();*i= +new_ity_size;();}}if variant.size<=old_ity_size{3;variant.size=new_ity_size;3;}} +FieldsShape::Primitive|FieldsShape::Array{..}|FieldsShape::Union(..)=>{panic!(// +"encountered a non-arbitrary layout during enum layout")}}}}();let tag_mask=ity. +size().unsigned_int_max();;let tag=Scalar::Initialized{value:Primitive::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()){3;abi=Abi::Uninhabited;3;}else if tag.size(dl)== +size{{;};abi=Abi::Scalar(tag);();}else{();let mut common_prim=None;();();let mut +common_prim_initialized_in_all_variants=true;3;for(field_layouts,layout_variant) +in iter::zip(variants,&layout_variants){;let FieldsShape::Arbitrary{ref offsets, +..}=layout_variant.fields else{if true{};let _=||();if true{};let _=||();panic!( +"encountered a non-arbitrary layout during enum layout");;};;let mut fields=iter +::zip(field_layouts,offsets).filter(|p|!p.0.is_zst());;;let(field,offset)=match( +fields.next(),fields.next()){(None,None)=>{let _=();let _=();let _=();if true{}; +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((old_prim, +common_offset))=common_prim{if offset!=common_offset{;common_prim=None;;;break;} +let new_prim=match(((old_prim,prim))){(x,y)if (x==y)=>x,(p@Primitive::Int(x,_), +Primitive::Int(y,_))if x==y=>p,( p@Primitive::Pointer(_),i@Primitive::Int(..))|( +i@Primitive::Int(..),p@Primitive::Pointer(_))if p.size(dl)==i.size(dl)&&p.align +(dl)==i.align(dl)=>{p}_=>{;common_prim=None;break;}};common_prim=Some((new_prim, +common_offset));3;}else{3;common_prim=Some((prim,offset));3;}}if let Some((prim, +offset))=common_prim{;let prim_scalar=if common_prim_initialized_in_all_variants +{;let size=prim.size(dl);;;assert!(size.bits()<=128);;Scalar::Initialized{value: +prim,valid_range:WrappingRange::full(size)}}else{Scalar::Union{value:prim}};;let +pair=layout_calc.scalar_pair::(tag,prim_scalar);{;};{;};let +pair_offsets=match pair.fields{FieldsShape::Arbitrary{ref offsets,ref//let _=(); +memory_index}=>{{();};assert_eq!(memory_index.raw,[0,1]);({});offsets}_=>panic!( +"encountered a non-arbitrary layout during enum layout"),};({});if pair_offsets[ +FieldIdx::new(0)]==Size::ZERO&&pair_offsets[ FieldIdx::new(1)]==*offset&&align== +pair.align&&size==pair.size{;abi=pair.abi;}}}if matches!(abi,Abi::Scalar(..)|Abi +::ScalarPair(..)){for variant in&mut layout_variants{if variant.fields.count()> +0&&matches!(variant.abi,Abi::Aggregate{..}){;variant.abi=abi;;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:[ +Size::ZERO].into(),memory_index:(([(0 )]).into())},largest_niche,abi,align,size, +max_repr_align,unadjusted_abi_align,};{;};();let tagged_layout=TmpLayout{layout: +tagged_layout,variants:layout_variants};;let mut best_layout=match(tagged_layout +,niche_filling_layout){(tl,Some(nl))=>{3;use cmp::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,};3;3; +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}}Variants::Single{..}=>{panic!(//*&*&(); +"encountered a single-variant enum during multi-variant layout")}};((),());Some( +best_layout.layout)}enum NicheBias{Start,End,}fn univariant<'a,FieldIdx:Idx,//3; +VariantIdx:Idx,F:Deref>+fmt::Debug,>(//; +this:&(impl LayoutCalculator+?Sized),dl:&TargetDataLayout,fields:&IndexSlice,repr:&ReprOptions,kind:StructKind,niche_bias:NicheBias,)->Option>{;let pack=repr.pack;let mut align=if pack.is_some( +){dl.i8_align}else{dl.aggregate_align};;;let mut max_repr_align=repr.align;;;let +mut inverse_memory_index:IndexVec=fields.indices().collect();;;let +optimize=!repr.inhibit_struct_field_reordering_opt();;if optimize&&fields.len()> +1{;let end=if let StructKind::MaybeUnsized=kind{fields.len()-1}else{fields.len() +};;let optimizing=&mut inverse_memory_index.raw[..end];let fields_excluding_tail +=&fields.raw[..end];if true{};if repr.can_randomize_type_layout()&&cfg!(feature= +"randomize"){#[cfg(feature="randomize")]{let _=||();use rand::{seq::SliceRandom, +SeedableRng};;;let mut rng=rand_xoshiro::Xoshiro128StarStar::seed_from_u64(repr. +field_shuffle_seed);;;optimizing.shuffle(&mut rng);;}}else{;let max_field_align= +fields_excluding_tail.iter().map(|f|f.align.abi.bytes()).max().unwrap_or(1);;let +largest_niche_size=(fields_excluding_tail.iter().filter_map(|f|f.largest_niche)) +.map(|n|n.available(dl)).max().unwrap_or(0);;let alignment_group_key=|layout:&F| +{if let Some(pack)=pack{layout.align.abi.min(pack).bytes()}else{{();};let align= +layout.align.abi.bytes();;;let size=layout.size.bytes();;;let niche_size=layout. +largest_niche.map(|n|n.available(dl)).unwrap_or(0);;let size_as_align=align.max( +size).trailing_zeros();({});({});let size_as_align=if largest_niche_size>0{match +niche_bias{NicheBias::Start=>max_field_align .trailing_zeros().min(size_as_align +),NicheBias::End if (niche_size==largest_niche_size)=>{(align.trailing_zeros())} +NicheBias::End=>size_as_align,}}else{size_as_align};();size_as_align as u64}};3; +match kind{StructKind::AlwaysSized|StructKind::MaybeUnsized=>{*&*&();optimizing. +sort_by_key(|&x|{;let f=&fields[x];let field_size=f.size.bytes();let niche_size= +f.largest_niche.map_or(0,|n|n.available(dl));{();};({});let niche_size_key=match +niche_bias{NicheBias::Start=>!niche_size,NicheBias::End=>niche_size,};{;};();let +inner_niche_offset_key=match niche_bias{NicheBias::Start=>f.largest_niche.//{;}; +map_or((0),|n|n.offset.bytes()),NicheBias ::End=>f.largest_niche.map_or(0,|n|{!( +field_size-n.value.size(dl).bytes()-n.offset.bytes())}),};((),());(cmp::Reverse( +alignment_group_key(f)),niche_size_key,inner_niche_offset_key,)});;}StructKind:: +Prefixed(..)=>{;optimizing.sort_by_key(|&x|{;let f=&fields[x];;let niche_size=f. +largest_niche.map_or(0,|n|n.available(dl));;(alignment_group_key(f),niche_size)} +);;}}}}let mut sized=true;let mut offsets=IndexVec::from_elem(Size::ZERO,fields) +;{;};();let mut offset=Size::ZERO;();();let mut largest_niche=None;();();let mut +largest_niche_available=0;;if let StructKind::Prefixed(prefix_size,prefix_align) +=kind{{();};let prefix_align=if let Some(pack)=pack{prefix_align.min(pack)}else{ +prefix_align};3;3;align=align.max(AbiAndPrefAlign::new(prefix_align));3;;offset= +prefix_size.align_to(prefix_align);3;}for&i in&inverse_memory_index{;let field=& +fields[i];let _=();let _=();if!sized{let _=();let _=();this.delayed_bug(format!( +"univariant: field #{} comes after unsized field",offsets.len(),));();}if field. +is_unsized(){;sized=false;;};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);max_repr_align=max_repr_align.max +(field.max_repr_align);3;3;debug!("univariant offset: {:?} field: {:#?}",offset, +field);();3;offsets[i]=offset;3;if let Some(mut niche)=field.largest_niche{3;let +available=niche.available(dl);;let prefer_new_niche=match niche_bias{NicheBias:: +Start=>((((((available>largest_niche_available)))))),NicheBias::End=>available>= +largest_niche_available,};;if prefer_new_niche{largest_niche_available=available +;;;niche.offset+=offset;;;largest_niche=Some(niche);}}offset=offset.checked_add( +field.size,dl)?;3;};let unadjusted_abi_align=align.abi;;if let Some(repr_align)= +repr.align{;align=align.max(AbiAndPrefAlign::new(repr_align));;}let align=align; +debug!("univariant min_size: {:?}",offset);;let min_size=offset;let memory_index +=if optimize{inverse_memory_index.invert_bijective_mapping()}else{;debug_assert! +(inverse_memory_index.iter().copied().eq(fields.indices()));if true{};if true{}; +inverse_memory_index.into_iter().map(|it|it.index()as u32).collect()};;let size= +min_size.align_to(align.abi);;if size.bytes()>=dl.obj_size_bound(){return None;} +let mut layout_of_single_non_zst_field=None;;;let mut abi=Abi::Aggregate{sized}; +if sized&&size.bytes()>0{;let mut non_zst_fields=fields.iter_enumerated().filter +(|&(_,f)|!f.is_zst());((),());match(non_zst_fields.next(),non_zst_fields.next(), +non_zst_fields.next()){(Some((i,field)),None,None)=>{loop{break;};if let _=(){}; +layout_of_single_non_zst_field=Some(field);3;if offsets[i].bytes()==0&&align.abi +==field.align.abi&&size==field.size {match field.abi{Abi::Scalar(_)|Abi::Vector{ +..}if optimize=>{;abi=field.abi;;}Abi::ScalarPair(..)=>{abi=field.abi;}_=>{}}}}( +Some((i,a)),Some((j,b)),None)=>{match (a.abi,b.abi){(Abi::Scalar(a),Abi::Scalar( +b))=>{;let((i,a),(j,b))=if offsets[i](a,b);let pair_offsets=match +pair.fields{FieldsShape::Arbitrary{ref offsets,ref memory_index}=>{3;assert_eq!( +memory_index.raw,[0,1]);3;offsets}FieldsShape::Primitive|FieldsShape::Array{..}| +FieldsShape::Union(..)=>{panic!(//let _=||();loop{break};let _=||();loop{break}; +"encountered a non-arbitrary layout during enum layout")}};{();};if offsets[i]== +pair_offsets[(FieldIdx::new((0)))]&&offsets[j]==pair_offsets[FieldIdx::new(1)]&& +align==pair.align&&size==pair.size{;abi=pair.abi;}}_=>{}}}_=>{}}}if fields.iter( +).any(|f|f.abi.is_uninhabited()){;abi=Abi::Uninhabited;}let unadjusted_abi_align +=if ((((repr.transparent())))){ match layout_of_single_non_zst_field{Some(l)=>l. +unadjusted_abi_align,None=>{align.abi}}}else{unadjusted_abi_align};;Some(LayoutS +{variants:(Variants::Single{index:(VariantIdx::new ((0)))}),fields:FieldsShape:: +Arbitrary{offsets,memory_index},abi,largest_niche,align,size,max_repr_align,//3; +unadjusted_abi_align,})}fn format_field_niches< 'a,FieldIdx:Idx,VariantIdx:Idx,F +:Deref>+fmt::Debug,>(layout:&LayoutS,fields:&IndexSlice,dl:&TargetDataLayout,)->//3; +String{loop{break;};let mut s=String::new();loop{break;};for i in layout.fields. +index_by_increasing_offset(){;let offset=layout.fields.offset(i);;let f=&fields[ +FieldIdx::new(i)];3;;write!(s,"[o{}a{}s{}",offset.bytes(),f.align.abi.bytes(),f. +size.bytes()).unwrap();;if let Some(n)=f.largest_niche{;write!(s," n{}b{}s{}",n. +offset.bytes(),n.available(dl).ilog2(),n.value.size(dl).bytes()).unwrap();();}3; +write!(s,"] ").unwrap();loop{break;};loop{break;};loop{break;};if let _=(){};}s} diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index bdbc59821de2f..9c1718e8615ca 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -1,707 +1,131 @@ -//! The arena, a fast but limited type of allocator. -//! -//! Arenas are a type of allocator that destroy the objects within, all at -//! once, once the arena itself is destroyed. They do not support deallocation -//! of individual objects while the arena itself is still alive. The benefit -//! of an arena is very fast allocation; just a pointer bump. -//! -//! This crate implements several kinds of arena. - -#![doc( - html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", - test(no_crate_inject, attr(deny(warnings))) -)] -#![doc(rust_logo)] -#![feature(rustdoc_internals)] -#![feature(core_intrinsics)] -#![feature(dropck_eyepatch)] -#![feature(new_uninit)] -#![feature(maybe_uninit_slice)] -#![feature(decl_macro)] -#![feature(rustc_attrs)] -#![cfg_attr(test, feature(test))] -#![feature(strict_provenance)] -#![deny(unsafe_op_in_unsafe_fn)] -#![allow(internal_features)] -#![allow(clippy::mut_from_ref)] // Arena allocators are one of the places where this pattern is fine. - -use smallvec::SmallVec; - -use std::alloc::Layout; -use std::cell::{Cell, RefCell}; -use std::marker::PhantomData; -use std::mem::{self, MaybeUninit}; -use std::ptr::{self, NonNull}; -use std::slice; -use std::{cmp, intrinsics}; - -/// This calls the passed function while ensuring it won't be inlined into the caller. -#[inline(never)] -#[cold] -fn outline R, R>(f: F) -> R { - f() -} - -struct ArenaChunk { - /// The raw storage for the arena chunk. - storage: NonNull<[MaybeUninit]>, - /// The number of valid entries in the chunk. - entries: usize, -} - -unsafe impl<#[may_dangle] T> Drop for ArenaChunk { - fn drop(&mut self) { - unsafe { drop(Box::from_raw(self.storage.as_mut())) } - } -} - -impl ArenaChunk { - #[inline] - unsafe fn new(capacity: usize) -> ArenaChunk { - ArenaChunk { - storage: NonNull::from(Box::leak(Box::new_uninit_slice(capacity))), - entries: 0, - } - } - - /// Destroys this arena chunk. - /// - /// # Safety - /// - /// The caller must ensure that `len` elements of this chunk have been initialized. - #[inline] - unsafe fn destroy(&mut self, len: usize) { - // The branch on needs_drop() is an -O1 performance optimization. - // Without the branch, dropping TypedArena takes linear time. - if mem::needs_drop::() { - // SAFETY: The caller must ensure that `len` elements of this chunk have - // been initialized. - unsafe { - let slice = self.storage.as_mut(); - ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(&mut slice[..len])); - } - } - } - - // Returns a pointer to the first allocated object. - #[inline] - fn start(&mut self) -> *mut T { - self.storage.as_ptr() as *mut T - } - - // Returns a pointer to the end of the allocated space. - #[inline] - fn end(&mut self) -> *mut T { - unsafe { - if mem::size_of::() == 0 { - // A pointer as large as possible for zero-sized elements. - ptr::without_provenance_mut(!0) - } else { - self.start().add(self.storage.len()) - } - } - } -} - -// The arenas start with PAGE-sized chunks, and then each new chunk is twice as -// big as its predecessor, up until we reach HUGE_PAGE-sized chunks, whereupon -// we stop growing. This scales well, from arenas that are barely used up to -// arenas that are used for 100s of MiBs. Note also that the chosen sizes match -// the usual sizes of pages and huge pages on Linux. -const PAGE: usize = 4096; -const HUGE_PAGE: usize = 2 * 1024 * 1024; - -/// An arena that can hold objects of only one type. -pub struct TypedArena { - /// A pointer to the next object to be allocated. - ptr: Cell<*mut T>, - - /// A pointer to the end of the allocated area. When this pointer is - /// reached, a new chunk is allocated. - end: Cell<*mut T>, - - /// A vector of arena chunks. - chunks: RefCell>>, - - /// Marker indicating that dropping the arena causes its owned - /// instances of `T` to be dropped. - _own: PhantomData, -} - -impl Default for TypedArena { - /// Creates a new `TypedArena`. - fn default() -> TypedArena { - TypedArena { - // We set both `ptr` and `end` to 0 so that the first call to - // alloc() will trigger a grow(). - ptr: Cell::new(ptr::null_mut()), - end: Cell::new(ptr::null_mut()), - chunks: Default::default(), - _own: PhantomData, - } - } -} - -impl TypedArena { - /// Allocates an object in the `TypedArena`, returning a reference to it. - #[inline] - pub fn alloc(&self, object: T) -> &mut T { - if self.ptr == self.end { - self.grow(1) - } - - unsafe { - if mem::size_of::() == 0 { - self.ptr.set(self.ptr.get().wrapping_byte_add(1)); - let ptr = ptr::NonNull::::dangling().as_ptr(); - // Don't drop the object. This `write` is equivalent to `forget`. - ptr::write(ptr, object); - &mut *ptr - } else { - let ptr = self.ptr.get(); - // Advance the pointer. - self.ptr.set(self.ptr.get().add(1)); - // Write into uninitialized memory. - ptr::write(ptr, object); - &mut *ptr - } - } - } - - #[inline] - fn can_allocate(&self, additional: usize) -> bool { - // FIXME: this should *likely* use `offset_from`, but more - // investigation is needed (including running tests in miri). - let available_bytes = self.end.get().addr() - self.ptr.get().addr(); - let additional_bytes = additional.checked_mul(mem::size_of::()).unwrap(); - available_bytes >= additional_bytes - } - - #[inline] - fn alloc_raw_slice(&self, len: usize) -> *mut T { - assert!(mem::size_of::() != 0); - assert!(len != 0); - - // Ensure the current chunk can fit `len` objects. - if !self.can_allocate(len) { - self.grow(len); - debug_assert!(self.can_allocate(len)); - } - - let start_ptr = self.ptr.get(); - // SAFETY: `can_allocate`/`grow` ensures that there is enough space for - // `len` elements. - unsafe { self.ptr.set(start_ptr.add(len)) }; - start_ptr - } - - /// Allocates the elements of this iterator into a contiguous slice in the `TypedArena`. - /// - /// Note: for reasons of reentrancy and panic safety we collect into a `SmallVec<[_; 8]>` before - /// storing the elements in the arena. - #[inline] - pub fn alloc_from_iter>(&self, iter: I) -> &mut [T] { - // Despite the similarlty with `DroplessArena`, we cannot reuse their fast case. The reason - // is subtle: these arenas are reentrant. In other words, `iter` may very well be holding a - // reference to `self` and adding elements to the arena during iteration. - // - // For this reason, if we pre-allocated any space for the elements of this iterator, we'd - // have to track that some uninitialized elements are followed by some initialized elements, - // else we might accidentally drop uninitialized memory if something panics or if the - // iterator doesn't fill all the length we expected. - // - // So we collect all the elements beforehand, which takes care of reentrancy and panic - // safety. This function is much less hot than `DroplessArena::alloc_from_iter`, so it - // doesn't need to be hyper-optimized. - assert!(mem::size_of::() != 0); - - let mut vec: SmallVec<[_; 8]> = iter.into_iter().collect(); - if vec.is_empty() { - return &mut []; - } - // Move the content to the arena by copying and then forgetting it. - let len = vec.len(); - let start_ptr = self.alloc_raw_slice(len); - unsafe { - vec.as_ptr().copy_to_nonoverlapping(start_ptr, len); - vec.set_len(0); - slice::from_raw_parts_mut(start_ptr, len) - } - } - - /// Grows the arena. - #[inline(never)] - #[cold] - fn grow(&self, additional: usize) { - unsafe { - // We need the element size to convert chunk sizes (ranging from - // PAGE to HUGE_PAGE bytes) to element counts. - let elem_size = cmp::max(1, mem::size_of::()); - let mut chunks = self.chunks.borrow_mut(); - let mut new_cap; - if let Some(last_chunk) = chunks.last_mut() { - // If a type is `!needs_drop`, we don't need to keep track of how many elements - // the chunk stores - the field will be ignored anyway. - if mem::needs_drop::() { - // FIXME: this should *likely* use `offset_from`, but more - // investigation is needed (including running tests in miri). - let used_bytes = self.ptr.get().addr() - last_chunk.start().addr(); - last_chunk.entries = used_bytes / mem::size_of::(); - } - - // If the previous chunk's len is less than HUGE_PAGE - // bytes, then this chunk will be least double the previous - // chunk's size. - new_cap = last_chunk.storage.len().min(HUGE_PAGE / elem_size / 2); - new_cap *= 2; - } else { - new_cap = PAGE / elem_size; - } - // Also ensure that this chunk can fit `additional`. - new_cap = cmp::max(additional, new_cap); - - let mut chunk = ArenaChunk::::new(new_cap); - self.ptr.set(chunk.start()); - self.end.set(chunk.end()); - chunks.push(chunk); - } - } - - // Drops the contents of the last chunk. The last chunk is partially empty, unlike all other - // chunks. - fn clear_last_chunk(&self, last_chunk: &mut ArenaChunk) { - // Determine how much was filled. - let start = last_chunk.start().addr(); - // We obtain the value of the pointer to the first uninitialized element. - let end = self.ptr.get().addr(); - // We then calculate the number of elements to be dropped in the last chunk, - // which is the filled area's length. - let diff = if mem::size_of::() == 0 { - // `T` is ZST. It can't have a drop flag, so the value here doesn't matter. We get - // the number of zero-sized values in the last and only chunk, just out of caution. - // Recall that `end` was incremented for each allocated value. - end - start - } else { - // FIXME: this should *likely* use `offset_from`, but more - // investigation is needed (including running tests in miri). - (end - start) / mem::size_of::() - }; - // Pass that to the `destroy` method. - unsafe { - last_chunk.destroy(diff); - } - // Reset the chunk. - self.ptr.set(last_chunk.start()); - } -} - -unsafe impl<#[may_dangle] T> Drop for TypedArena { - fn drop(&mut self) { - unsafe { - // Determine how much was filled. - let mut chunks_borrow = self.chunks.borrow_mut(); - if let Some(mut last_chunk) = chunks_borrow.pop() { - // Drop the contents of the last chunk. - self.clear_last_chunk(&mut last_chunk); - // The last chunk will be dropped. Destroy all other chunks. - for chunk in chunks_borrow.iter_mut() { - chunk.destroy(chunk.entries); - } - } - // Box handles deallocation of `last_chunk` and `self.chunks`. - } - } -} - -unsafe impl Send for TypedArena {} - -#[inline(always)] -fn align_down(val: usize, align: usize) -> usize { - debug_assert!(align.is_power_of_two()); - val & !(align - 1) -} - -#[inline(always)] -fn align_up(val: usize, align: usize) -> usize { - debug_assert!(align.is_power_of_two()); - (val + align - 1) & !(align - 1) -} - -// Pointer alignment is common in compiler types, so keep `DroplessArena` aligned to them -// to optimize away alignment code. -const DROPLESS_ALIGNMENT: usize = mem::align_of::(); - -/// An arena that can hold objects of multiple different types that impl `Copy` -/// and/or satisfy `!mem::needs_drop`. -pub struct DroplessArena { - /// A pointer to the start of the free space. - start: Cell<*mut u8>, - - /// A pointer to the end of free space. - /// - /// The allocation proceeds downwards from the end of the chunk towards the - /// start. (This is slightly simpler and faster than allocating upwards, - /// see .) - /// When this pointer crosses the start pointer, a new chunk is allocated. - /// - /// This is kept aligned to DROPLESS_ALIGNMENT. - end: Cell<*mut u8>, - - /// A vector of arena chunks. - chunks: RefCell>, -} - -unsafe impl Send for DroplessArena {} - -impl Default for DroplessArena { - #[inline] - fn default() -> DroplessArena { - DroplessArena { - // We set both `start` and `end` to 0 so that the first call to - // alloc() will trigger a grow(). - start: Cell::new(ptr::null_mut()), - end: Cell::new(ptr::null_mut()), - chunks: Default::default(), - } - } -} - -impl DroplessArena { - #[inline(never)] - #[cold] - fn grow(&self, layout: Layout) { - // Add some padding so we can align `self.end` while - // still fitting in a `layout` allocation. - let additional = layout.size() + cmp::max(DROPLESS_ALIGNMENT, layout.align()) - 1; - - unsafe { - let mut chunks = self.chunks.borrow_mut(); - let mut new_cap; - if let Some(last_chunk) = chunks.last_mut() { - // There is no need to update `last_chunk.entries` because that - // field isn't used by `DroplessArena`. - - // If the previous chunk's len is less than HUGE_PAGE - // bytes, then this chunk will be least double the previous - // chunk's size. - new_cap = last_chunk.storage.len().min(HUGE_PAGE / 2); - new_cap *= 2; - } else { - new_cap = PAGE; - } - // Also ensure that this chunk can fit `additional`. - new_cap = cmp::max(additional, new_cap); - - let mut chunk = ArenaChunk::new(align_up(new_cap, PAGE)); - self.start.set(chunk.start()); - - // Align the end to DROPLESS_ALIGNMENT. - let end = align_down(chunk.end().addr(), DROPLESS_ALIGNMENT); - - // Make sure we don't go past `start`. This should not happen since the allocation - // should be at least DROPLESS_ALIGNMENT - 1 bytes. - debug_assert!(chunk.start().addr() <= end); - - self.end.set(chunk.end().with_addr(end)); - - chunks.push(chunk); - } - } - - #[inline] - pub fn alloc_raw(&self, layout: Layout) -> *mut u8 { - assert!(layout.size() != 0); - - // This loop executes once or twice: if allocation fails the first - // time, the `grow` ensures it will succeed the second time. - loop { - let start = self.start.get().addr(); - let old_end = self.end.get(); - let end = old_end.addr(); - - // Align allocated bytes so that `self.end` stays aligned to - // DROPLESS_ALIGNMENT. - let bytes = align_up(layout.size(), DROPLESS_ALIGNMENT); - - // Tell LLVM that `end` is aligned to DROPLESS_ALIGNMENT. - unsafe { intrinsics::assume(end == align_down(end, DROPLESS_ALIGNMENT)) }; - - if let Some(sub) = end.checked_sub(bytes) { - let new_end = align_down(sub, layout.align()); - if start <= new_end { - let new_end = old_end.with_addr(new_end); - // `new_end` is aligned to DROPLESS_ALIGNMENT as `align_down` - // preserves alignment as both `end` and `bytes` are already - // aligned to DROPLESS_ALIGNMENT. - self.end.set(new_end); - return new_end; - } - } - - // No free space left. Allocate a new chunk to satisfy the request. - // On failure the grow will panic or abort. - self.grow(layout); - } - } - - #[inline] - pub fn alloc(&self, object: T) -> &mut T { - assert!(!mem::needs_drop::()); - assert!(mem::size_of::() != 0); - - let mem = self.alloc_raw(Layout::new::()) as *mut T; - - unsafe { - // Write into uninitialized memory. - ptr::write(mem, object); - &mut *mem - } - } - - /// Allocates a slice of objects that are copied into the `DroplessArena`, returning a mutable - /// reference to it. Will panic if passed a zero-sized type. - /// - /// Panics: - /// - /// - Zero-sized types - /// - Zero-length slices - #[inline] - pub fn alloc_slice(&self, slice: &[T]) -> &mut [T] - where - T: Copy, - { - assert!(!mem::needs_drop::()); - assert!(mem::size_of::() != 0); - assert!(!slice.is_empty()); - - let mem = self.alloc_raw(Layout::for_value::<[T]>(slice)) as *mut T; - - unsafe { - mem.copy_from_nonoverlapping(slice.as_ptr(), slice.len()); - slice::from_raw_parts_mut(mem, slice.len()) - } - } - - /// Used by `Lift` to check whether this slice is allocated - /// in this arena. - #[inline] - pub fn contains_slice(&self, slice: &[T]) -> bool { - for chunk in self.chunks.borrow_mut().iter_mut() { - let ptr = slice.as_ptr().cast::().cast_mut(); - if chunk.start() <= ptr && chunk.end() >= ptr { - return true; - } - } - false - } - - /// Allocates a string slice that is copied into the `DroplessArena`, returning a - /// reference to it. Will panic if passed an empty string. - /// - /// Panics: - /// - /// - Zero-length string - #[inline] - pub fn alloc_str(&self, string: &str) -> &str { - let slice = self.alloc_slice(string.as_bytes()); - - // SAFETY: the result has a copy of the same valid UTF-8 bytes. - unsafe { std::str::from_utf8_unchecked(slice) } - } - - /// # Safety - /// - /// The caller must ensure that `mem` is valid for writes up to `size_of::() * len`, and that - /// that memory stays allocated and not shared for the lifetime of `self`. This must hold even - /// if `iter.next()` allocates onto `self`. - #[inline] - unsafe fn write_from_iter>( - &self, - mut iter: I, - len: usize, - mem: *mut T, - ) -> &mut [T] { - let mut i = 0; - // Use a manual loop since LLVM manages to optimize it better for - // slice iterators - loop { - // SAFETY: The caller must ensure that `mem` is valid for writes up to - // `size_of::() * len`. - unsafe { - match iter.next() { - Some(value) if i < len => mem.add(i).write(value), - Some(_) | None => { - // We only return as many items as the iterator gave us, even - // though it was supposed to give us `len` - return slice::from_raw_parts_mut(mem, i); - } - } - } - i += 1; - } - } - - #[inline] - pub fn alloc_from_iter>(&self, iter: I) -> &mut [T] { - // Warning: this function is reentrant: `iter` could hold a reference to `&self` and - // allocate additional elements while we're iterating. - let iter = iter.into_iter(); - assert!(mem::size_of::() != 0); - assert!(!mem::needs_drop::()); - - let size_hint = iter.size_hint(); - - match size_hint { - (min, Some(max)) if min == max => { - // We know the exact number of elements the iterator expects to produce here. - let len = min; - - if len == 0 { - return &mut []; - } - - let mem = self.alloc_raw(Layout::array::(len).unwrap()) as *mut T; - // SAFETY: `write_from_iter` doesn't touch `self`. It only touches the slice we just - // reserved. If the iterator panics or doesn't output `len` elements, this will - // leave some unallocated slots in the arena, which is fine because we do not call - // `drop`. - unsafe { self.write_from_iter(iter, len, mem) } - } - (_, _) => { - outline(move || -> &mut [T] { - // Takes care of reentrancy. - let mut vec: SmallVec<[_; 8]> = iter.collect(); - if vec.is_empty() { - return &mut []; - } - // Move the content to the arena by copying it and then forgetting - // the content of the SmallVec - unsafe { - let len = vec.len(); - let start_ptr = - self.alloc_raw(Layout::for_value::<[T]>(vec.as_slice())) as *mut T; - vec.as_ptr().copy_to_nonoverlapping(start_ptr, len); - vec.set_len(0); - slice::from_raw_parts_mut(start_ptr, len) - } - }) - } - } - } -} - -/// Declare an `Arena` containing one dropless arena and many typed arenas (the -/// types of the typed arenas are specified by the arguments). -/// -/// There are three cases of interest. -/// - Types that are `Copy`: these need not be specified in the arguments. They -/// will use the `DroplessArena`. -/// - Types that are `!Copy` and `!Drop`: these must be specified in the -/// arguments. An empty `TypedArena` will be created for each one, but the -/// `DroplessArena` will always be used and the `TypedArena` will stay empty. -/// This is odd but harmless, because an empty arena allocates no memory. -/// - Types that are `!Copy` and `Drop`: these must be specified in the -/// arguments. The `TypedArena` will be used for them. -/// -#[rustc_macro_transparency = "semitransparent"] -pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { - #[derive(Default)] - pub struct Arena<'tcx> { - pub dropless: $crate::DroplessArena, - $($name: $crate::TypedArena<$ty>,)* - } - - pub trait ArenaAllocatable<'tcx, C = rustc_arena::IsNotCopy>: Sized { - #[allow(clippy::mut_from_ref)] - fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self; - #[allow(clippy::mut_from_ref)] - fn allocate_from_iter<'a>( - arena: &'a Arena<'tcx>, - iter: impl ::std::iter::IntoIterator, - ) -> &'a mut [Self]; - } - - // Any type that impls `Copy` can be arena-allocated in the `DroplessArena`. - impl<'tcx, T: Copy> ArenaAllocatable<'tcx, rustc_arena::IsCopy> for T { - #[inline] - #[allow(clippy::mut_from_ref)] - fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self { - arena.dropless.alloc(self) - } - #[inline] - #[allow(clippy::mut_from_ref)] - fn allocate_from_iter<'a>( - arena: &'a Arena<'tcx>, - iter: impl ::std::iter::IntoIterator, - ) -> &'a mut [Self] { - arena.dropless.alloc_from_iter(iter) - } - } - $( - impl<'tcx> ArenaAllocatable<'tcx, rustc_arena::IsNotCopy> for $ty { - #[inline] - fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self { - if !::std::mem::needs_drop::() { - arena.dropless.alloc(self) - } else { - arena.$name.alloc(self) - } - } - - #[inline] - #[allow(clippy::mut_from_ref)] - fn allocate_from_iter<'a>( - arena: &'a Arena<'tcx>, - iter: impl ::std::iter::IntoIterator, - ) -> &'a mut [Self] { - if !::std::mem::needs_drop::() { - arena.dropless.alloc_from_iter(iter) - } else { - arena.$name.alloc_from_iter(iter) - } - } - } - )* - - impl<'tcx> Arena<'tcx> { - #[inline] - #[allow(clippy::mut_from_ref)] - pub fn alloc, C>(&self, value: T) -> &mut T { - value.allocate_on(self) - } - - // Any type that impls `Copy` can have slices be arena-allocated in the `DroplessArena`. - #[inline] - #[allow(clippy::mut_from_ref)] - pub fn alloc_slice(&self, value: &[T]) -> &mut [T] { - if value.is_empty() { - return &mut []; - } - self.dropless.alloc_slice(value) - } - - #[inline] - pub fn alloc_str(&self, string: &str) -> &str { - if string.is_empty() { - return ""; - } - self.dropless.alloc_str(string) - } - - #[allow(clippy::mut_from_ref)] - pub fn alloc_from_iter, C>( - &self, - iter: impl ::std::iter::IntoIterator, - ) -> &mut [T] { - T::allocate_from_iter(self, iter) - } - } -} - -// Marker types that let us give different behaviour for arenas allocating -// `Copy` types vs `!Copy` types. -pub struct IsCopy; -pub struct IsNotCopy; - -#[cfg(test)] -mod tests; +#![doc(html_root_url="https://doc.rust-lang.org/nightly/nightly-rustc/",test(//; +no_crate_inject,attr(deny(warnings))))]#![doc(rust_logo)]#![feature(//if true{}; +rustdoc_internals)]#![feature(core_intrinsics)]#![feature(dropck_eyepatch)]#![// +feature(new_uninit)]#![feature(maybe_uninit_slice)]#![feature(decl_macro)]#![//; +feature(rustc_attrs)]#![cfg_attr(test,feature(test))]#![feature(//if let _=(){}; +strict_provenance)]#![deny(unsafe_op_in_unsafe_fn )]#![allow(internal_features)] +#![allow(clippy::mut_from_ref)]use smallvec::SmallVec;use std::alloc::Layout;//; +use std::cell::{Cell,RefCell};use std::marker::PhantomData;use std::mem::{self, +MaybeUninit};use std::ptr::{self,NonNull};use std::slice;use std::{cmp,//*&*&(); +intrinsics};#[inline(never)]#[cold]fn outlineR,R>(f:F)->R{((f()))} +struct ArenaChunk{storage:NonNull< [MaybeUninit]>,entries:usize,}unsafe +impl<#[may_dangle]T>Drop for ArenaChunk{fn drop(&mut self){unsafe{drop(Box//; +::from_raw(((self.storage.as_mut()))))}}}implArenaChunk{#[inline]unsafe fn +new(capacity:usize)->ArenaChunk{ArenaChunk{storage:NonNull::from(Box::leak(// +Box::new_uninit_slice(capacity))),entries:(0 ),}}#[inline]unsafe fn destroy(&mut +self,len:usize){if mem::needs_drop::(){unsafe{;let slice=self.storage.as_mut( +);;ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(&mut slice[..len]));}}} +#[inline]fn start(&mut self)->*mut T{(self.storage.as_ptr()as*mut T)}#[inline]fn +end(&mut self)->*mut T{unsafe{if (((((( mem::size_of::())))==(((0)))))){ptr:: +without_provenance_mut((!0))}else{self.start() .add(self.storage.len())}}}}const +PAGE:usize=4096;const HUGE_PAGE:usize=2* 1024*1024;pub struct TypedArena{ptr: +Cell<*mut T>,end:Cell<*mut T>,chunks:RefCell>>,_own://((),()); +PhantomData,}implDefault for TypedArena{fn default()->TypedArena{//; +TypedArena{ptr:Cell::new(ptr::null_mut()) ,end:Cell::new(ptr::null_mut()),chunks +:((Default::default())),_own:PhantomData,}}}implTypedArena{#[inline]pub fn +alloc(&self,object:T)->&mut T{if (self.ptr==self.end){self.grow(1)}unsafe{if mem +::size_of::()==0{;self.ptr.set(self.ptr.get().wrapping_byte_add(1));;let ptr= +ptr::NonNull::::dangling().as_ptr();;ptr::write(ptr,object);&mut*ptr}else{let +ptr=self.ptr.get();;;self.ptr.set(self.ptr.get().add(1));ptr::write(ptr,object); +&mut*ptr}}}#[inline]fn can_allocate(&self,additional:usize)->bool{let _=||();let +available_bytes=self.end.get().addr()-self.ptr.get().addr();let _=();((),());let +additional_bytes=additional.checked_mul(mem::size_of::()).unwrap();if true{}; +available_bytes>=additional_bytes}#[inline]fn alloc_raw_slice(&self,len:usize)// +->*mut T{;assert!(mem::size_of::()!=0);;assert!(len!=0);if!self.can_allocate( +len){;self.grow(len);;debug_assert!(self.can_allocate(len));}let start_ptr=self. +ptr.get();3;;unsafe{self.ptr.set(start_ptr.add(len))};;start_ptr}#[inline]pub fn +alloc_from_iter>(&self,iter:I)->&mut[T]{{;};assert!(mem:: +size_of::()!=0);;;let mut vec:SmallVec<[_;8]>=iter.into_iter().collect();;if +vec.is_empty(){();return&mut[];();}();let len=vec.len();();3;let start_ptr=self. +alloc_raw_slice(len);;unsafe{vec.as_ptr().copy_to_nonoverlapping(start_ptr,len); +vec.set_len(0);;slice::from_raw_parts_mut(start_ptr,len)}}#[inline(never)]#[cold +]fn grow(&self,additional:usize){unsafe{;let elem_size=cmp::max(1,mem::size_of:: +());;;let mut chunks=self.chunks.borrow_mut();;;let mut new_cap;;if let Some( +last_chunk)=chunks.last_mut(){if mem::needs_drop::(){;let used_bytes=self.ptr +.get().addr()-last_chunk.start().addr();();3;last_chunk.entries=used_bytes/mem:: +size_of::();;};new_cap=last_chunk.storage.len().min(HUGE_PAGE/elem_size/2);;; +new_cap*=2;;}else{;new_cap=PAGE/elem_size;}new_cap=cmp::max(additional,new_cap); +let mut chunk=ArenaChunk::::new(new_cap);;;self.ptr.set(chunk.start());;self. +end.set(chunk.end());;chunks.push(chunk);}}fn clear_last_chunk(&self,last_chunk: +&mut ArenaChunk){;let start=last_chunk.start().addr();let end=self.ptr.get(). +addr();();();let diff=if mem::size_of::()==0{end-start}else{(end-start)/mem:: +size_of::()};;unsafe{last_chunk.destroy(diff);}self.ptr.set(last_chunk.start( +));{();};}}unsafe impl<#[may_dangle]T>Drop for TypedArena{fn drop(&mut self){ +unsafe{{();};let mut chunks_borrow=self.chunks.borrow_mut();({});if let Some(mut +last_chunk)=chunks_borrow.pop(){();self.clear_last_chunk(&mut last_chunk);();for +chunk in chunks_borrow.iter_mut(){;chunk.destroy(chunk.entries);}}}}}unsafe impl +Send for TypedArena{}# [inline(always)]fn align_down(val:usize,align: +usize)->usize{3;debug_assert!(align.is_power_of_two());;val&!(align-1)}#[inline( +always)]fn align_up(val:usize,align:usize)->usize{if true{};debug_assert!(align. +is_power_of_two());3;(val+align-1)&!(align-1)}const DROPLESS_ALIGNMENT:usize=mem +::align_of::();pub struct DroplessArena{start:Cell<*mut u8>,end:Cell<*//; +mut u8>,chunks:RefCell>,}unsafe impl Send for DroplessArena{}//; +impl Default for DroplessArena{#[inline]fn default()->DroplessArena{//if true{}; +DroplessArena{start:(Cell::new(ptr::null_mut())),end:Cell::new(ptr::null_mut()), +chunks:Default::default(),}}}impl DroplessArena{#[inline(never)]#[cold]fn grow( +&self,layout:Layout){3;let additional=layout.size()+cmp::max(DROPLESS_ALIGNMENT, +layout.align())-1;3;unsafe{3;let mut chunks=self.chunks.borrow_mut();3;3;let mut +new_cap;3;if let Some(last_chunk)=chunks.last_mut(){;new_cap=last_chunk.storage. +len().min(HUGE_PAGE/2);3;3;new_cap*=2;3;}else{;new_cap=PAGE;;};new_cap=cmp::max( +additional,new_cap);;let mut chunk=ArenaChunk::new(align_up(new_cap,PAGE));self. +start.set(chunk.start());let _=();((),());let end=align_down(chunk.end().addr(), +DROPLESS_ALIGNMENT);;debug_assert!(chunk.start().addr()<=end);self.end.set(chunk +.end().with_addr(end));3;;chunks.push(chunk);;}}#[inline]pub fn alloc_raw(&self, +layout:Layout)->*mut u8{;assert!(layout.size()!=0);loop{let start=self.start.get +().addr();;let old_end=self.end.get();let end=old_end.addr();let bytes=align_up( +layout.size(),DROPLESS_ALIGNMENT);;unsafe{intrinsics::assume(end==align_down(end +,DROPLESS_ALIGNMENT))};();if let Some(sub)=end.checked_sub(bytes){3;let new_end= +align_down(sub,layout.align());;if start<=new_end{let new_end=old_end.with_addr( +new_end);;;self.end.set(new_end);;return new_end;}}self.grow(layout);}}#[inline] +pub fn alloc(&self,object:T)->&mut T{;assert!(!mem::needs_drop::());assert +!(mem::size_of::()!=0);;;let mem=self.alloc_raw(Layout::new::())as*mut T;; +unsafe{3;ptr::write(mem,object);;&mut*mem}}#[inline]pub fn alloc_slice(&self, +slice:&[T])->&mut[T]where T:Copy,{;assert!(!mem::needs_drop::());;assert!(mem +::size_of::()!=0);;assert!(!slice.is_empty());let mem=self.alloc_raw(Layout:: +for_value::<[T]>(slice))as*mut T;();unsafe{3;mem.copy_from_nonoverlapping(slice. +as_ptr(),slice.len());3;slice::from_raw_parts_mut(mem,slice.len())}}#[inline]pub +fn contains_slice(&self,slice:&[T])->bool{for chunk in self.chunks.//((),()); +borrow_mut().iter_mut(){;let ptr=slice.as_ptr().cast::().cast_mut();if chunk +.start()<=ptr&&chunk.end()>=ptr{;return true;}}false}#[inline]pub fn alloc_str(& +self,string:&str)->&str{3;let slice=self.alloc_slice(string.as_bytes());;unsafe{ +std::str::from_utf8_unchecked(slice)}}#[inline]unsafe fn write_from_iter>(&self,mut iter:I,len:usize,mem:*mut T,)->&mut[T]{;let mut i=0; +loop{unsafe{match iter.next(){Some(value)if imem.add(i).write(value),Some +(_)|None=>{;return slice::from_raw_parts_mut(mem,i);;}}};i+=1;;}}#[inline]pub fn +alloc_from_iter>(&self,iter:I)->&mut[T]{;let iter=iter. +into_iter();;;assert!(mem::size_of::()!=0);;assert!(!mem::needs_drop::()); +let size_hint=iter.size_hint();;match size_hint{(min,Some(max))if min==max=>{let +len=min;;if len==0{;return&mut[];}let mem=self.alloc_raw(Layout::array::(len) +.unwrap())as*mut T;3;unsafe{self.write_from_iter(iter,len,mem)}}(_,_)=>{outline( +move||->&mut[T]{;let mut vec:SmallVec<[_;8]>=iter.collect();;if vec.is_empty(){; +return&mut[];;}unsafe{;let len=vec.len();;;let start_ptr=self.alloc_raw(Layout:: +for_value::<[T]>(vec.as_slice()))as*mut T;;;vec.as_ptr().copy_to_nonoverlapping( +start_ptr,len);;vec.set_len(0);slice::from_raw_parts_mut(start_ptr,len)}})}}}}#[ +rustc_macro_transparency="semitransparent"]pub macro declare_arena([$($a:tt$//3; +name:ident:$ty:ty,)*]){#[derive(Default)]pub struct Arena<'tcx>{pub dropless:$// +crate::DroplessArena,$($name:$crate::TypedArena<$ty>,)*}pub trait//loop{break;}; +ArenaAllocatable<'tcx,C=rustc_arena::IsNotCopy>:Sized{#[allow(clippy:://((),()); +mut_from_ref)]fn allocate_on<'a>(self,arena:&'a Arena<'tcx>)->&'a mut Self;#[//; +allow(clippy::mut_from_ref)]fn allocate_from_iter<'a>(arena:&'a Arena<'tcx>,//3; +iter:impl::std::iter::IntoIterator,)->&'a mut[Self];}impl<'tcx,T://3; +Copy>ArenaAllocatable<'tcx,rustc_arena::IsCopy>for T{#[inline]#[allow(clippy::// +mut_from_ref)]fn allocate_on<'a>(self,arena:&'a Arena<'tcx>)->&'a mut Self{//(); +arena.dropless.alloc(self)}#[inline]#[allow(clippy::mut_from_ref)]fn//if true{}; +allocate_from_iter<'a>(arena:&'a Arena< 'tcx>,iter:impl::std::iter::IntoIterator +,)->&'a mut[Self]{ arena.dropless.alloc_from_iter(iter)}}$(impl<'tcx> +ArenaAllocatable<'tcx,rustc_arena::IsNotCopy>for$ty {#[inline]fn allocate_on<'a> +(self,arena:&'a Arena<'tcx>)->&'a mut Self{if!::std::mem::needs_drop::(){ +arena.dropless.alloc(self)}else{arena.$name.alloc(self)}}#[inline]#[allow(//{;}; +clippy::mut_from_ref)]fn allocate_from_iter<'a>( arena:&'a Arena<'tcx>,iter:impl +::std::iter::IntoIterator,)->& 'a mut[Self]{if!::std::mem::needs_drop +::(){arena.dropless.alloc_from_iter(iter)}else{arena.$name.//loop{break;}; +alloc_from_iter(iter)}}})*impl<'tcx>Arena<'tcx>{#[inline]#[allow(clippy:://({}); +mut_from_ref)]pub fn alloc,C>(&self,value:T)->&mut T +{value.allocate_on(self)}#[inline]#[allow(clippy::mut_from_ref)]pub fn//((),()); +alloc_slice(&self,value:&[T])->&mut[T]{if value.//{();}; +is_empty(){return&mut[];}self.dropless.alloc_slice(value)}#[inline]pub fn//({}); +alloc_str(&self,string:&str)->&str{if string.is_empty(){return "";}self.//{();}; +dropless.alloc_str(string)}#[allow (clippy::mut_from_ref)]pub fn alloc_from_iter +,C>(&self ,iter:impl::std::iter::IntoIterator +,)->&mut[T]{T::allocate_from_iter(self,iter)}}}pub struct IsCopy;pub struct//(); +IsNotCopy;#[cfg(test)]mod tests;//let _=||();loop{break};let _=||();loop{break}; diff --git a/compiler/rustc_arena/src/tests.rs b/compiler/rustc_arena/src/tests.rs index 49a070badc6de..e82a89733b2d6 100644 --- a/compiler/rustc_arena/src/tests.rs +++ b/compiler/rustc_arena/src/tests.rs @@ -1,244 +1,51 @@ -extern crate test; -use super::TypedArena; -use std::cell::Cell; -use test::Bencher; - -#[allow(dead_code)] -#[derive(Debug, Eq, PartialEq)] -struct Point { - x: i32, - y: i32, - z: i32, -} - -impl TypedArena { - /// Clears the arena. Deallocates all but the longest chunk which may be reused. - fn clear(&mut self) { - unsafe { - // Clear the last chunk, which is partially filled. - let mut chunks_borrow = self.chunks.borrow_mut(); - if let Some(mut last_chunk) = chunks_borrow.last_mut() { - self.clear_last_chunk(&mut last_chunk); - let len = chunks_borrow.len(); - // If `T` is ZST, code below has no effect. - for mut chunk in chunks_borrow.drain(..len - 1) { - chunk.destroy(chunk.entries); - } - } - } - } -} - -#[test] -pub fn test_unused() { - let arena: TypedArena = TypedArena::default(); - assert!(arena.chunks.borrow().is_empty()); -} - -#[test] -fn test_arena_alloc_nested() { - struct Inner { - value: u8, - } - struct Outer<'a> { - inner: &'a Inner, - } - enum EI<'e> { - I(Inner), - O(Outer<'e>), - } - - struct Wrap<'a>(TypedArena>); - - impl<'a> Wrap<'a> { - fn alloc_inner Inner>(&self, f: F) -> &Inner { - match self.0.alloc(EI::I(f())) { - EI::I(i) => i, - _ => panic!("mismatch"), - } - } - fn alloc_outer Outer<'a>>(&self, f: F) -> &Outer<'_> { - match self.0.alloc(EI::O(f())) { - EI::O(o) => o, - _ => panic!("mismatch"), - } - } - } - - let arena = Wrap(TypedArena::default()); - - let result = arena.alloc_outer(|| Outer { inner: arena.alloc_inner(|| Inner { value: 10 }) }); - - assert_eq!(result.inner.value, 10); -} - -#[test] -pub fn test_copy() { - let arena = TypedArena::default(); - #[cfg(not(miri))] - const N: usize = 100000; - #[cfg(miri)] - const N: usize = 1000; - for _ in 0..N { - arena.alloc(Point { x: 1, y: 2, z: 3 }); - } -} - -#[bench] -pub fn bench_copy(b: &mut Bencher) { - let arena = TypedArena::default(); - b.iter(|| arena.alloc(Point { x: 1, y: 2, z: 3 })) -} - -#[bench] -pub fn bench_copy_nonarena(b: &mut Bencher) { - b.iter(|| { - let _: Box<_> = Box::new(Point { x: 1, y: 2, z: 3 }); - }) -} - -#[allow(dead_code)] -struct Noncopy { - string: String, - array: Vec, -} - -#[test] -pub fn test_noncopy() { - let arena = TypedArena::default(); - #[cfg(not(miri))] - const N: usize = 100000; - #[cfg(miri)] - const N: usize = 1000; - for _ in 0..N { - arena.alloc(Noncopy { string: "hello world".to_string(), array: vec![1, 2, 3, 4, 5] }); - } -} - -#[test] -pub fn test_typed_arena_zero_sized() { - let arena = TypedArena::default(); - #[cfg(not(miri))] - const N: usize = 100000; - #[cfg(miri)] - const N: usize = 1000; - for _ in 0..N { - arena.alloc(()); - } -} - -#[test] -pub fn test_typed_arena_clear() { - let mut arena = TypedArena::default(); - for _ in 0..10 { - arena.clear(); - #[cfg(not(miri))] - const N: usize = 10000; - #[cfg(miri)] - const N: usize = 100; - for _ in 0..N { - arena.alloc(Point { x: 1, y: 2, z: 3 }); - } - } -} - -#[bench] -pub fn bench_typed_arena_clear(b: &mut Bencher) { - let mut arena = TypedArena::default(); - b.iter(|| { - arena.alloc(Point { x: 1, y: 2, z: 3 }); - arena.clear(); - }) -} - -#[bench] -pub fn bench_typed_arena_clear_100(b: &mut Bencher) { - let mut arena = TypedArena::default(); - b.iter(|| { - for _ in 0..100 { - arena.alloc(Point { x: 1, y: 2, z: 3 }); - } - arena.clear(); - }) -} - -// Drop tests - -struct DropCounter<'a> { - count: &'a Cell, -} - -impl Drop for DropCounter<'_> { - fn drop(&mut self) { - self.count.set(self.count.get() + 1); - } -} - -#[test] -fn test_typed_arena_drop_count() { - let counter = Cell::new(0); - { - let arena: TypedArena> = TypedArena::default(); - for _ in 0..100 { - // Allocate something with drop glue to make sure it doesn't leak. - arena.alloc(DropCounter { count: &counter }); - } - }; - assert_eq!(counter.get(), 100); -} - -#[test] -fn test_typed_arena_drop_on_clear() { - let counter = Cell::new(0); - let mut arena: TypedArena> = TypedArena::default(); - for i in 0..10 { - for _ in 0..100 { - // Allocate something with drop glue to make sure it doesn't leak. - arena.alloc(DropCounter { count: &counter }); - } - arena.clear(); - assert_eq!(counter.get(), i * 100 + 100); - } -} - -thread_local! { - static DROP_COUNTER: Cell = Cell::new(0) -} - -struct SmallDroppable; - -impl Drop for SmallDroppable { - fn drop(&mut self) { - DROP_COUNTER.with(|c| c.set(c.get() + 1)); - } -} - -#[test] -fn test_typed_arena_drop_small_count() { - DROP_COUNTER.with(|c| c.set(0)); - { - let arena: TypedArena = TypedArena::default(); - for _ in 0..100 { - // Allocate something with drop glue to make sure it doesn't leak. - arena.alloc(SmallDroppable); - } - // dropping - }; - assert_eq!(DROP_COUNTER.with(|c| c.get()), 100); -} - -#[bench] -pub fn bench_noncopy(b: &mut Bencher) { - let arena = TypedArena::default(); - b.iter(|| { - arena.alloc(Noncopy { string: "hello world".to_string(), array: vec![1, 2, 3, 4, 5] }) - }) -} - -#[bench] -pub fn bench_noncopy_nonarena(b: &mut Bencher) { - b.iter(|| { - let _: Box<_> = - Box::new(Noncopy { string: "hello world".to_string(), array: vec![1, 2, 3, 4, 5] }); - }) -} +extern crate test;use super::TypedArena;use std::cell::Cell;use test::Bencher;# +[allow(dead_code)]#[derive(Debug,Eq,PartialEq)] struct Point{x:i32,y:i32,z:i32,} +implTypedArena{fn clear(&mut self){unsafe{({});let mut chunks_borrow=self. +chunks.borrow_mut();;if let Some(mut last_chunk)=chunks_borrow.last_mut(){;self. +clear_last_chunk(&mut last_chunk);;let len=chunks_borrow.len();for mut chunk in +chunks_borrow.drain(..len-1){3;chunk.destroy(chunk.entries);3;}}}}}#[test]pub fn +test_unused(){;let arena:TypedArena=TypedArena::default();;assert!(arena. +chunks.borrow().is_empty());;}#[test]fn test_arena_alloc_nested(){;struct Inner{ +value:u8,};struct Outer<'a>{inner:&'a Inner,}enum EI<'e>{I(Inner),O(Outer<'e>),} +struct Wrap<'a>(TypedArena>);3;3;impl<'a>Wrap<'a>{fn alloc_inner +Inner>(&self,f:F)->&Inner{match self.0.alloc(EI:: I(f())){EI::I(i)=>i,_=>panic!( +"mismatch"),}}fn alloc_outerOuter<'a>>(&self,f:F)->&Outer<'_>{match //; +self.0.alloc(EI::O(f())){EI::O(o)=>o,_=>panic!("mismatch"),}}}3;;let arena=Wrap( +TypedArena::default());{;};{;};let result=arena.alloc_outer(||Outer{inner:arena. +alloc_inner(||Inner{value:10})});;;assert_eq!(result.inner.value,10);}#[test]pub +fn test_copy(){;let arena=TypedArena::default();;#[cfg(not(miri))]const N:usize= +100000;;#[cfg(miri)]const N:usize=1000;for _ in 0..N{arena.alloc(Point{x:1,y:2,z +:3});;}}#[bench]pub fn bench_copy(b:&mut Bencher){let arena=TypedArena::default( +);;b.iter(||arena.alloc(Point{x:1,y:2,z:3}))}#[bench]pub fn bench_copy_nonarena( +b:&mut Bencher){b.iter(||{;let _:Box<_>=Box::new(Point{x:1,y:2,z:3});})}#[allow( +dead_code)]struct Noncopy{string:String,array:Vec,}#[test]pub fn//let _=(); +test_noncopy(){;let arena=TypedArena::default();;#[cfg(not(miri))]const N:usize= +100000;;#[cfg(miri)]const N:usize=1000;for _ in 0..N{arena.alloc(Noncopy{string: +"hello world".to_string(),array:vec![1,2,3,4,5]});*&*&();((),());}}#[test]pub fn +test_typed_arena_zero_sized(){;let arena=TypedArena::default();#[cfg(not(miri))] +const N:usize=100000;;#[cfg(miri)]const N:usize=1000;for _ in 0..N{arena.alloc(( +));;}}#[test]pub fn test_typed_arena_clear(){let mut arena=TypedArena::default() +;;for _ in 0..10{arena.clear();#[cfg(not(miri))]const N:usize=10000;#[cfg(miri)] +const N:usize=100;;for _ in 0..N{;arena.alloc(Point{x:1,y:2,z:3});}}}#[bench]pub +fn bench_typed_arena_clear(b:&mut Bencher){;let mut arena=TypedArena::default(); +b.iter(||{3;arena.alloc(Point{x:1,y:2,z:3});3;3;arena.clear();;})}#[bench]pub fn +bench_typed_arena_clear_100(b:&mut Bencher){;let mut arena=TypedArena::default() +;;b.iter(||{for _ in 0..100{;arena.alloc(Point{x:1,y:2,z:3});;}arena.clear();})} +struct DropCounter<'a>{count:&'a Cell,}impl Drop for DropCounter<'_>{fn//3; +drop(&mut self){let _=();self.count.set(self.count.get()+1);let _=();}}#[test]fn +test_typed_arena_drop_count(){;let counter=Cell::new(0);;;{let arena:TypedArena< +DropCounter<'_>>=TypedArena::default();;for _ in 0..100{arena.alloc(DropCounter{ +count:&counter});({});}};({});({});assert_eq!(counter.get(),100);({});}#[test]fn +test_typed_arena_drop_on_clear(){();let counter=Cell::new(0);();3;let mut arena: +TypedArena>=TypedArena::default();();for i in 0..10{for _ in 0.. +100{;arena.alloc(DropCounter{count:&counter});}arena.clear();assert_eq!(counter. +get(),i*100+100);{;};}}thread_local!{static DROP_COUNTER:Cell=Cell::new(0)} +struct SmallDroppable;impl Drop for SmallDroppable{fn drop(&mut self){if true{}; +DROP_COUNTER.with(|c|c.set(c.get()+1));*&*&();((),());*&*&();((),());}}#[test]fn +test_typed_arena_drop_small_count(){;DROP_COUNTER.with(|c|c.set(0));;{let arena: +TypedArena=TypedArena::default();3;for _ in 0..100{;arena.alloc( +SmallDroppable);;}};;;assert_eq!(DROP_COUNTER.with(|c|c.get()),100);}#[bench]pub +fn bench_noncopy(b:&mut Bencher){();let arena=TypedArena::default();3;b.iter(||{ +arena.alloc(Noncopy{string:"hello world".to_string(),array: vec![1,2,3,4,5]})})} +#[bench]pub fn bench_noncopy_nonarena(b:&mut Bencher){b.iter(||{();let _:Box<_>= +Box::new(Noncopy{string:"hello world".to_string(),array:vec![1,2,3,4,5]});();})} diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs index a0486227f2afb..5cfa6edf85889 100644 --- a/compiler/rustc_ast/src/ast_traits.rs +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -1,416 +1,110 @@ -//! A set of traits implemented for various AST nodes, -//! typically those used in AST fragments during macro expansion. -//! The traits are not implemented exhaustively, only when actually necessary. - -use crate::ptr::P; -use crate::token::Nonterminal; -use crate::tokenstream::LazyAttrTokenStream; -use crate::{Arm, Crate, ExprField, FieldDef, GenericParam, Param, PatField, Variant}; -use crate::{AssocItem, Expr, ForeignItem, Item, NodeId}; -use crate::{AttrItem, AttrKind, Block, Pat, Path, Ty, Visibility}; -use crate::{AttrVec, Attribute, Stmt, StmtKind}; - -use rustc_span::Span; - -use std::fmt; -use std::marker::PhantomData; - -/// A utility trait to reduce boilerplate. -/// Standard `Deref(Mut)` cannot be reused due to coherence. -pub trait AstDeref { - type Target; - fn ast_deref(&self) -> &Self::Target; - fn ast_deref_mut(&mut self) -> &mut Self::Target; -} - -macro_rules! impl_not_ast_deref { - ($($T:ty),+ $(,)?) => { - $( - impl !AstDeref for $T {} - )+ - }; -} - -impl_not_ast_deref!(AssocItem, Expr, ForeignItem, Item, Stmt); - -impl AstDeref for P { - type Target = T; - fn ast_deref(&self) -> &Self::Target { - self - } - fn ast_deref_mut(&mut self) -> &mut Self::Target { - self - } -} - -/// A trait for AST nodes having an ID. -pub trait HasNodeId { - fn node_id(&self) -> NodeId; - fn node_id_mut(&mut self) -> &mut NodeId; -} - -macro_rules! impl_has_node_id { - ($($T:ty),+ $(,)?) => { - $( - impl HasNodeId for $T { - fn node_id(&self) -> NodeId { - self.id - } - fn node_id_mut(&mut self) -> &mut NodeId { - &mut self.id - } - } - )+ - }; -} - -impl_has_node_id!( - Arm, - AssocItem, - Crate, - Expr, - ExprField, - FieldDef, - ForeignItem, - GenericParam, - Item, - Param, - Pat, - PatField, - Stmt, - Ty, - Variant, -); - -impl> HasNodeId for T { - fn node_id(&self) -> NodeId { - self.ast_deref().node_id() - } - fn node_id_mut(&mut self) -> &mut NodeId { - self.ast_deref_mut().node_id_mut() - } -} - -/// A trait for AST nodes having a span. -pub trait HasSpan { - fn span(&self) -> Span; -} - -macro_rules! impl_has_span { - ($($T:ty),+ $(,)?) => { - $( - impl HasSpan for $T { - fn span(&self) -> Span { - self.span - } - } - )+ - }; -} - -impl_has_span!(AssocItem, Block, Expr, ForeignItem, Item, Pat, Path, Stmt, Ty, Visibility); - -impl> HasSpan for T { - fn span(&self) -> Span { - self.ast_deref().span() - } -} - -impl HasSpan for AttrItem { - fn span(&self) -> Span { - self.span() - } -} - -/// A trait for AST nodes having (or not having) collected tokens. -pub trait HasTokens { - fn tokens(&self) -> Option<&LazyAttrTokenStream>; - fn tokens_mut(&mut self) -> Option<&mut Option>; -} - -macro_rules! impl_has_tokens { - ($($T:ty),+ $(,)?) => { - $( - impl HasTokens for $T { - fn tokens(&self) -> Option<&LazyAttrTokenStream> { - self.tokens.as_ref() - } - fn tokens_mut(&mut self) -> Option<&mut Option> { - Some(&mut self.tokens) - } - } - )+ - }; -} - -macro_rules! impl_has_tokens_none { - ($($T:ty),+ $(,)?) => { - $( - impl HasTokens for $T { - fn tokens(&self) -> Option<&LazyAttrTokenStream> { - None - } - fn tokens_mut(&mut self) -> Option<&mut Option> { - None - } - } - )+ - }; -} - -impl_has_tokens!(AssocItem, AttrItem, Block, Expr, ForeignItem, Item, Pat, Path, Ty, Visibility); -impl_has_tokens_none!(Arm, ExprField, FieldDef, GenericParam, Param, PatField, Variant); - -impl> HasTokens for T { - fn tokens(&self) -> Option<&LazyAttrTokenStream> { - self.ast_deref().tokens() - } - fn tokens_mut(&mut self) -> Option<&mut Option> { - self.ast_deref_mut().tokens_mut() - } -} - -impl HasTokens for Option { - fn tokens(&self) -> Option<&LazyAttrTokenStream> { - self.as_ref().and_then(|inner| inner.tokens()) - } - fn tokens_mut(&mut self) -> Option<&mut Option> { - self.as_mut().and_then(|inner| inner.tokens_mut()) - } -} - -impl HasTokens for StmtKind { - fn tokens(&self) -> Option<&LazyAttrTokenStream> { - match self { - StmtKind::Let(local) => local.tokens.as_ref(), - StmtKind::Item(item) => item.tokens(), - StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.tokens(), - StmtKind::Empty => return None, - StmtKind::MacCall(mac) => mac.tokens.as_ref(), - } - } - fn tokens_mut(&mut self) -> Option<&mut Option> { - match self { - StmtKind::Let(local) => Some(&mut local.tokens), - StmtKind::Item(item) => item.tokens_mut(), - StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.tokens_mut(), - StmtKind::Empty => return None, - StmtKind::MacCall(mac) => Some(&mut mac.tokens), - } - } -} - -impl HasTokens for Stmt { - fn tokens(&self) -> Option<&LazyAttrTokenStream> { - self.kind.tokens() - } - fn tokens_mut(&mut self) -> Option<&mut Option> { - self.kind.tokens_mut() - } -} - -impl HasTokens for Attribute { - fn tokens(&self) -> Option<&LazyAttrTokenStream> { - match &self.kind { - AttrKind::Normal(normal) => normal.tokens.as_ref(), - kind @ AttrKind::DocComment(..) => { - panic!("Called tokens on doc comment attr {kind:?}") - } - } - } - fn tokens_mut(&mut self) -> Option<&mut Option> { - Some(match &mut self.kind { - AttrKind::Normal(normal) => &mut normal.tokens, - kind @ AttrKind::DocComment(..) => { - panic!("Called tokens_mut on doc comment attr {kind:?}") - } - }) - } -} - -impl HasTokens for Nonterminal { - fn tokens(&self) -> Option<&LazyAttrTokenStream> { - match self { - Nonterminal::NtItem(item) => item.tokens(), - Nonterminal::NtStmt(stmt) => stmt.tokens(), - Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens(), - Nonterminal::NtPat(pat) => pat.tokens(), - Nonterminal::NtTy(ty) => ty.tokens(), - Nonterminal::NtMeta(attr_item) => attr_item.tokens(), - Nonterminal::NtPath(path) => path.tokens(), - Nonterminal::NtVis(vis) => vis.tokens(), - Nonterminal::NtBlock(block) => block.tokens(), - Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) => None, - } - } - fn tokens_mut(&mut self) -> Option<&mut Option> { - match self { - Nonterminal::NtItem(item) => item.tokens_mut(), - Nonterminal::NtStmt(stmt) => stmt.tokens_mut(), - Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens_mut(), - Nonterminal::NtPat(pat) => pat.tokens_mut(), - Nonterminal::NtTy(ty) => ty.tokens_mut(), - Nonterminal::NtMeta(attr_item) => attr_item.tokens_mut(), - Nonterminal::NtPath(path) => path.tokens_mut(), - Nonterminal::NtVis(vis) => vis.tokens_mut(), - Nonterminal::NtBlock(block) => block.tokens_mut(), - Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) => None, - } - } -} - -/// A trait for AST nodes having (or not having) attributes. -pub trait HasAttrs { - /// This is `true` if this `HasAttrs` might support 'custom' (proc-macro) inner - /// attributes. Attributes like `#![cfg]` and `#![cfg_attr]` are not - /// considered 'custom' attributes. - /// - /// If this is `false`, then this `HasAttrs` definitely does - /// not support 'custom' inner attributes, which enables some optimizations - /// during token collection. - const SUPPORTS_CUSTOM_INNER_ATTRS: bool; - fn attrs(&self) -> &[Attribute]; - fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)); -} - -macro_rules! impl_has_attrs { - (const SUPPORTS_CUSTOM_INNER_ATTRS: bool = $inner:literal, $($T:ty),+ $(,)?) => { - $( - impl HasAttrs for $T { - const SUPPORTS_CUSTOM_INNER_ATTRS: bool = $inner; - - #[inline] - fn attrs(&self) -> &[Attribute] { - &self.attrs - } - - fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) { - f(&mut self.attrs) - } - } - )+ - }; -} - -macro_rules! impl_has_attrs_none { - ($($T:ty),+ $(,)?) => { - $( - impl HasAttrs for $T { - const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false; - fn attrs(&self) -> &[Attribute] { - &[] - } - fn visit_attrs(&mut self, _f: impl FnOnce(&mut AttrVec)) {} - } - )+ - }; -} - -impl_has_attrs!( - const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true, - AssocItem, - ForeignItem, - Item, -); -impl_has_attrs!( - const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false, - Arm, - Crate, - Expr, - ExprField, - FieldDef, - GenericParam, - Param, - PatField, - Variant, -); -impl_has_attrs_none!(Attribute, AttrItem, Block, Pat, Path, Ty, Visibility); - -impl> HasAttrs for T { - const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::Target::SUPPORTS_CUSTOM_INNER_ATTRS; - fn attrs(&self) -> &[Attribute] { - self.ast_deref().attrs() - } - fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) { - self.ast_deref_mut().visit_attrs(f) - } -} - -impl HasAttrs for Option { - const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::SUPPORTS_CUSTOM_INNER_ATTRS; - fn attrs(&self) -> &[Attribute] { - self.as_ref().map(|inner| inner.attrs()).unwrap_or(&[]) - } - fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) { - if let Some(inner) = self.as_mut() { - inner.visit_attrs(f); - } - } -} - -impl HasAttrs for StmtKind { - // This might be a `StmtKind::Item`, which contains - // an item that supports inner attrs. - const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true; - - fn attrs(&self) -> &[Attribute] { - match self { - StmtKind::Let(local) => &local.attrs, - StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.attrs(), - StmtKind::Item(item) => item.attrs(), - StmtKind::Empty => &[], - StmtKind::MacCall(mac) => &mac.attrs, - } - } - - fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) { - match self { - StmtKind::Let(local) => f(&mut local.attrs), - StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.visit_attrs(f), - StmtKind::Item(item) => item.visit_attrs(f), - StmtKind::Empty => {} - StmtKind::MacCall(mac) => f(&mut mac.attrs), - } - } -} - -impl HasAttrs for Stmt { - const SUPPORTS_CUSTOM_INNER_ATTRS: bool = StmtKind::SUPPORTS_CUSTOM_INNER_ATTRS; - fn attrs(&self) -> &[Attribute] { - self.kind.attrs() - } - fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) { - self.kind.visit_attrs(f); - } -} - -/// A newtype around an AST node that implements the traits above if the node implements them. -pub struct AstNodeWrapper { - pub wrapped: Wrapped, - pub tag: PhantomData, -} - -impl AstNodeWrapper { - pub fn new(wrapped: Wrapped, _tag: Tag) -> AstNodeWrapper { - AstNodeWrapper { wrapped, tag: Default::default() } - } -} - -impl AstDeref for AstNodeWrapper { - type Target = Wrapped; - fn ast_deref(&self) -> &Self::Target { - &self.wrapped - } - fn ast_deref_mut(&mut self) -> &mut Self::Target { - &mut self.wrapped - } -} - -impl fmt::Debug for AstNodeWrapper { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("AstNodeWrapper") - .field("wrapped", &self.wrapped) - .field("tag", &self.tag) - .finish() - } -} +use crate::ptr::P;use crate::token::Nonterminal;use crate::tokenstream:://{();}; +LazyAttrTokenStream;use crate::{Arm, Crate,ExprField,FieldDef,GenericParam,Param +,PatField,Variant};use crate::{AssocItem,Expr,ForeignItem,Item,NodeId};use//{;}; +crate::{AttrItem,AttrKind,Block,Pat,Path,Ty,Visibility};use crate::{AttrVec,//3; +Attribute,Stmt,StmtKind};use rustc_span::Span;use std::fmt;use std::marker:://3; +PhantomData;pub trait AstDeref{type Target;fn ast_deref(&self)->&Self::Target;// +fn ast_deref_mut(&mut self)->& mut Self::Target;}macro_rules!impl_not_ast_deref{ +($($T:ty),+$(,)?)=>{$(impl!AstDeref for$T{})+};}impl_not_ast_deref!(AssocItem,// +Expr,ForeignItem,Item,Stmt);implAstDeref for P{type Target=T;fn ast_deref +(&self)->&Self::Target{self}fn ast_deref_mut (&mut self)->&mut Self::Target{self +}}pub trait HasNodeId{fn node_id(&self) ->NodeId;fn node_id_mut(&mut self)->&mut +NodeId;}macro_rules!impl_has_node_id{($($T:ty),+$(,)?)=>{$(impl HasNodeId for$// +T{fn node_id(&self)->NodeId{self.id} fn node_id_mut(&mut self)->&mut NodeId{&mut +self.id}})+};}impl_has_node_id!(Arm,AssocItem,Crate,Expr,ExprField,FieldDef,//3; +ForeignItem,GenericParam,Item,Param,Pat,PatField,Stmt,Ty,Variant,);impl>HasNodeId for T{fn node_id(&self)->NodeId{self.//{;}; +ast_deref().node_id()}fn node_id_mut(& mut self)->&mut NodeId{self.ast_deref_mut +().node_id_mut()}}pub trait HasSpan{fn span(&self)->Span;}macro_rules!//((),()); +impl_has_span{($($T:ty),+$(,)?)=>{$(impl HasSpan for$T{fn span(&self)->Span{//3; +self.span}})+};}impl_has_span!(AssocItem,Block,Expr,ForeignItem,Item,Pat,Path,// +Stmt,Ty,Visibility);impl>HasSpan for T{fn span(&self +)->Span{self.ast_deref().span()} }impl HasSpan for AttrItem{fn span(&self)->Span +{self.span()}}pub trait HasTokens{fn tokens(&self)->Option<&LazyAttrTokenStream +>;fn tokens_mut(&mut self)->Option<&mut Option>;}//((),()); +macro_rules!impl_has_tokens{($($T:ty),+$(,)?)=>{$(impl HasTokens for$T{fn//({}); +tokens(&self)->Option<&LazyAttrTokenStream>{ self.tokens.as_ref()}fn tokens_mut( +&mut self)->Option<&mut Option>{Some(&mut self.tokens)}})+ +};}macro_rules!impl_has_tokens_none{($($T:ty),+ $(,)?)=>{$(impl HasTokens for$T{ +fn tokens(&self)->Option<&LazyAttrTokenStream>{None}fn tokens_mut(&mut self)->// +Option<&mut Option>{None }})+};}impl_has_tokens!(AssocItem, +AttrItem,Block,Expr,ForeignItem,Item,Pat,Path,Ty,Visibility);//((),());let _=(); +impl_has_tokens_none!(Arm,ExprField,FieldDef,GenericParam,Param,PatField,//({}); +Variant);impl>HasTokens for T{fn tokens(&self)->//; +Option<&LazyAttrTokenStream>{self.ast_deref() .tokens()}fn tokens_mut(&mut self) +->Option<&mut Option>{(self.ast_deref_mut().tokens_mut())}} +implHasTokens for Option{fn tokens(&self)->Option<&//let _=||(); +LazyAttrTokenStream>{(((self.as_ref()).and_then(( |inner|(inner.tokens())))))}fn +tokens_mut(&mut self)->Option<&mut Option>{(self.as_mut()). +and_then((|inner|(inner.tokens_mut())))}}impl HasTokens for StmtKind{fn tokens(& +self)->Option<&LazyAttrTokenStream>{match self{StmtKind::Let(local)=>local.//(); +tokens.as_ref(),StmtKind::Item(item)=> (((item.tokens()))),StmtKind::Expr(expr)| +StmtKind::Semi(expr)=>(expr.tokens() ),StmtKind::Empty=>(return None),StmtKind:: +MacCall(mac)=>(((mac.tokens.as_ref()))), }}fn tokens_mut(&mut self)->Option<&mut +Option>{match self{StmtKind::Let(local)=>Some(&mut local.// +tokens),StmtKind::Item(item)=>item .tokens_mut(),StmtKind::Expr(expr)|StmtKind:: +Semi(expr)=>(expr.tokens_mut()), StmtKind::Empty=>return None,StmtKind::MacCall( +mac)=>Some(&mut mac.tokens),} }}impl HasTokens for Stmt{fn tokens(&self)->Option +<&LazyAttrTokenStream>{self.kind.tokens() }fn tokens_mut(&mut self)->Option<&mut +Option>{((((self.kind. tokens_mut()))))}}impl HasTokens for +Attribute{fn tokens(&self)->Option< &LazyAttrTokenStream>{match(((&self.kind))){ +AttrKind::Normal(normal)=>(normal.tokens.as_ref()),kind@AttrKind::DocComment(..) +=>{((panic!("Called tokens on doc comment attr {kind:?}")))}}}fn tokens_mut(&mut +self)->Option<&mut Option>{ Some(match(((&mut self.kind))){ +AttrKind::Normal(normal)=>(&mut normal. tokens),kind@AttrKind::DocComment(..)=>{ +panic!("Called tokens_mut on doc comment attr {kind:?}")}} )}}impl HasTokens for +Nonterminal{fn tokens(&self)->Option<&LazyAttrTokenStream>{match self{//((),()); +Nonterminal::NtItem(item)=>item.tokens() ,Nonterminal::NtStmt(stmt)=>stmt.tokens +(),Nonterminal::NtExpr(expr)|Nonterminal:: NtLiteral(expr)=>(((expr.tokens()))), +Nonterminal::NtPat(pat)=>((pat.tokens())), Nonterminal::NtTy(ty)=>(ty.tokens()), +Nonterminal::NtMeta(attr_item)=>(attr_item.tokens()),Nonterminal::NtPath(path)=> +path.tokens(),Nonterminal::NtVis(vis)=> vis.tokens(),Nonterminal::NtBlock(block) +=>(block.tokens()),Nonterminal::NtIdent(..)|Nonterminal::NtLifetime(..)=>None,}} +fn tokens_mut(&mut self)->Option<&mut Option>{match self{// +Nonterminal::NtItem(item)=>(item.tokens_mut( )),Nonterminal::NtStmt(stmt)=>stmt. +tokens_mut(),Nonterminal::NtExpr(expr)|Nonterminal::NtLiteral(expr)=>expr.//{;}; +tokens_mut(),Nonterminal::NtPat(pat)=>(pat.tokens_mut()),Nonterminal::NtTy(ty)=> +ty.tokens_mut(),Nonterminal::NtMeta( attr_item)=>((((attr_item.tokens_mut())))), +Nonterminal::NtPath(path)=>(((path.tokens_mut()))),Nonterminal::NtVis(vis)=>vis. +tokens_mut(),Nonterminal::NtBlock(block)=>(((block.tokens_mut()))),Nonterminal:: +NtIdent(..)|Nonterminal::NtLifetime(..)=>None,}}}pub trait HasAttrs{const//({}); +SUPPORTS_CUSTOM_INNER_ATTRS:bool;fn attrs(&self) ->&[Attribute];fn visit_attrs(& +mut self,f:impl FnOnce(&mut AttrVec));}macro_rules!impl_has_attrs{(const//{();}; +SUPPORTS_CUSTOM_INNER_ATTRS:bool=$inner:literal,$($T:ty),+$(,)?)=>{$(impl//({}); +HasAttrs for$T{const SUPPORTS_CUSTOM_INNER_ATTRS:bool =$inner;#[inline]fn attrs( +&self)->&[Attribute]{&self.attrs}fn visit_attrs(&mut self,f:impl FnOnce(&mut//3; +AttrVec)){f(&mut self.attrs)}})+ };}macro_rules!impl_has_attrs_none{($($T:ty),+$ +(,)?)=>{$(impl HasAttrs for$T{const SUPPORTS_CUSTOM_INNER_ATTRS:bool=false;fn//; +attrs(&self)->&[Attribute]{&[]}fn visit_attrs(&mut self,_f:impl FnOnce(&mut//(); +AttrVec)){}})+};}impl_has_attrs!(const SUPPORTS_CUSTOM_INNER_ATTRS:bool=true,//; +AssocItem,ForeignItem,Item,) ;impl_has_attrs!(const SUPPORTS_CUSTOM_INNER_ATTRS: +bool=false,Arm,Crate,Expr,ExprField,FieldDef,GenericParam,Param,PatField,//({}); +Variant,);impl_has_attrs_none!(Attribute,AttrItem ,Block,Pat,Path,Ty,Visibility) +;impl>HasAttrs for T{const//loop{break};loop{break}; +SUPPORTS_CUSTOM_INNER_ATTRS:bool=T::Target::SUPPORTS_CUSTOM_INNER_ATTRS;fn//{;}; +attrs(&self)->&[Attribute]{self.ast_deref() .attrs()}fn visit_attrs(&mut self,f: +impl FnOnce(&mut AttrVec)){self.ast_deref_mut ().visit_attrs(f)}}implHasAttrs for Option{const SUPPORTS_CUSTOM_INNER_ATTRS:bool=T:://loop{break}; +SUPPORTS_CUSTOM_INNER_ATTRS;fn attrs(&self)->&[Attribute] {(self.as_ref()).map(| +inner|inner.attrs()).unwrap_or(&[] )}fn visit_attrs(&mut self,f:impl FnOnce(&mut +AttrVec)){if let Some(inner)=self.as_mut(){({});inner.visit_attrs(f);{;};}}}impl +HasAttrs for StmtKind{const SUPPORTS_CUSTOM_INNER_ATTRS:bool=((true));fn attrs(& +self)->&[Attribute]{match self{StmtKind::Let(local)=>((&local.attrs)),StmtKind:: +Expr(expr)|StmtKind::Semi(expr)=>expr.attrs (),StmtKind::Item(item)=>item.attrs( +),StmtKind::Empty=>&[],StmtKind::MacCall (mac)=>&mac.attrs,}}fn visit_attrs(&mut +self,f:impl FnOnce(&mut AttrVec)){match self{StmtKind::Let(local)=>f(&mut//({}); +local.attrs),StmtKind::Expr(expr)|StmtKind::Semi(expr)=>((expr.visit_attrs(f))), +StmtKind::Item(item)=>item.visit_attrs(f ),StmtKind::Empty=>{}StmtKind::MacCall( +mac)=>((((((f(((((((&mut mac.attrs)))))) ))))))),}}}impl HasAttrs for Stmt{const +SUPPORTS_CUSTOM_INNER_ATTRS:bool=StmtKind ::SUPPORTS_CUSTOM_INNER_ATTRS;fn attrs +(&self)->&[Attribute]{self.kind.attrs( )}fn visit_attrs(&mut self,f:impl FnOnce( +&mut AttrVec)){;self.kind.visit_attrs(f);}}pub struct AstNodeWrapper{pub wrapped:Wrapped,pub tag: PhantomData,}implAstNodeWrapper +{pub fn new(wrapped :Wrapped,_tag:Tag)->AstNodeWrapper +{(AstNodeWrapper{wrapped,tag:Default::default()})}}implAstDeref for +AstNodeWrapper{type Target=Wrapped;fn ast_deref(&self)->&Self:://3; +Target{(&self.wrapped)}fn ast_deref_mut(&mut self)->&mut Self::Target{&mut self. +wrapped}}implfmt::Debug for AstNodeWrapper +{fn fmt(&self,f:&mut fmt::Formatter<'_>)->fmt::Result{f.debug_struct(//let _=(); +"AstNodeWrapper").field("wrapped",&self.wrapped) .field("tag",&self.tag).finish( +)}}//let _=();let _=();let _=();if true{};let _=();if true{};let _=();if true{}; diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 98138cedb24db..fab1c50edddb7 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -1,637 +1,175 @@ -//! Functions dealing with attributes and meta items. - -use crate::ast::{AttrArgs, AttrArgsEq, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute}; -use crate::ast::{DelimArgs, Expr, ExprKind, LitKind, MetaItemLit}; -use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem, NormalAttr}; -use crate::ast::{Path, PathSegment, DUMMY_NODE_ID}; -use crate::ptr::P; -use crate::token::{self, CommentKind, Delimiter, Token}; -use crate::tokenstream::{DelimSpan, Spacing, TokenTree}; -use crate::tokenstream::{LazyAttrTokenStream, TokenStream}; -use crate::util::comments; -use crate::util::literal::escape_string_symbol; -use rustc_index::bit_set::GrowableBitSet; -use rustc_span::symbol::{sym, Ident, Symbol}; -use rustc_span::Span; -use std::iter; -use std::sync::atomic::{AtomicU32, Ordering}; -use thin_vec::{thin_vec, ThinVec}; - -pub struct MarkedAttrs(GrowableBitSet); - -impl MarkedAttrs { - pub fn new() -> Self { - // We have no idea how many attributes there will be, so just - // initiate the vectors with 0 bits. We'll grow them as necessary. - MarkedAttrs(GrowableBitSet::new_empty()) - } - - pub fn mark(&mut self, attr: &Attribute) { - self.0.insert(attr.id); - } - - pub fn is_marked(&self, attr: &Attribute) -> bool { - self.0.contains(attr.id) - } -} - -pub struct AttrIdGenerator(AtomicU32); - -impl AttrIdGenerator { - pub fn new() -> Self { - AttrIdGenerator(AtomicU32::new(0)) - } - - pub fn mk_attr_id(&self) -> AttrId { - let id = self.0.fetch_add(1, Ordering::Relaxed); - assert!(id != u32::MAX); - AttrId::from_u32(id) - } -} - -impl Attribute { - pub fn get_normal_item(&self) -> &AttrItem { - match &self.kind { - AttrKind::Normal(normal) => &normal.item, - AttrKind::DocComment(..) => panic!("unexpected doc comment"), - } - } - - pub fn unwrap_normal_item(self) -> AttrItem { - match self.kind { - AttrKind::Normal(normal) => normal.into_inner().item, - AttrKind::DocComment(..) => panic!("unexpected doc comment"), - } - } - - /// Returns `true` if it is a sugared doc comment (`///` or `//!` for example). - /// So `#[doc = "doc"]` (which is a doc comment) and `#[doc(...)]` (which is not - /// a doc comment) will return `false`. - pub fn is_doc_comment(&self) -> bool { - match self.kind { - AttrKind::Normal(..) => false, - AttrKind::DocComment(..) => true, - } - } - - /// For a single-segment attribute, returns its name; otherwise, returns `None`. - pub fn ident(&self) -> Option { - match &self.kind { - AttrKind::Normal(normal) => { - if let [ident] = &*normal.item.path.segments { - Some(ident.ident) - } else { - None - } - } - AttrKind::DocComment(..) => None, - } - } - pub fn name_or_empty(&self) -> Symbol { - self.ident().unwrap_or_else(Ident::empty).name - } - - #[inline] - pub fn has_name(&self, name: Symbol) -> bool { - match &self.kind { - AttrKind::Normal(normal) => normal.item.path == name, - AttrKind::DocComment(..) => false, - } - } - - pub fn path_matches(&self, name: &[Symbol]) -> bool { - match &self.kind { - AttrKind::Normal(normal) => { - normal.item.path.segments.len() == name.len() - && normal - .item - .path - .segments - .iter() - .zip(name) - .all(|(s, n)| s.args.is_none() && s.ident.name == *n) - } - AttrKind::DocComment(..) => false, - } - } - - pub fn is_word(&self) -> bool { - if let AttrKind::Normal(normal) = &self.kind { - matches!(normal.item.args, AttrArgs::Empty) - } else { - false - } - } - - pub fn meta_item_list(&self) -> Option> { - match &self.kind { - AttrKind::Normal(normal) => normal.item.meta_item_list(), - AttrKind::DocComment(..) => None, - } - } - - pub fn value_str(&self) -> Option { - match &self.kind { - AttrKind::Normal(normal) => normal.item.value_str(), - AttrKind::DocComment(..) => None, - } - } - - /// Returns the documentation and its kind if this is a doc comment or a sugared doc comment. - /// * `///doc` returns `Some(("doc", CommentKind::Line))`. - /// * `/** doc */` returns `Some(("doc", CommentKind::Block))`. - /// * `#[doc = "doc"]` returns `Some(("doc", CommentKind::Line))`. - /// * `#[doc(...)]` returns `None`. - pub fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> { - match &self.kind { - AttrKind::DocComment(kind, data) => Some((*data, *kind)), - AttrKind::Normal(normal) if normal.item.path == sym::doc => { - normal.item.value_str().map(|s| (s, CommentKind::Line)) - } - _ => None, - } - } - - /// Returns the documentation if this is a doc comment or a sugared doc comment. - /// * `///doc` returns `Some("doc")`. - /// * `#[doc = "doc"]` returns `Some("doc")`. - /// * `#[doc(...)]` returns `None`. - pub fn doc_str(&self) -> Option { - match &self.kind { - AttrKind::DocComment(.., data) => Some(*data), - AttrKind::Normal(normal) if normal.item.path == sym::doc => normal.item.value_str(), - _ => None, - } - } - - pub fn may_have_doc_links(&self) -> bool { - self.doc_str().is_some_and(|s| comments::may_have_doc_links(s.as_str())) - } - - pub fn is_proc_macro_attr(&self) -> bool { - [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive] - .iter() - .any(|kind| self.has_name(*kind)) - } - - /// Extracts the MetaItem from inside this Attribute. - pub fn meta(&self) -> Option { - match &self.kind { - AttrKind::Normal(normal) => normal.item.meta(self.span), - AttrKind::DocComment(..) => None, - } - } - - pub fn meta_kind(&self) -> Option { - match &self.kind { - AttrKind::Normal(normal) => normal.item.meta_kind(), - AttrKind::DocComment(..) => None, - } - } - - pub fn tokens(&self) -> TokenStream { - match &self.kind { - AttrKind::Normal(normal) => normal - .tokens - .as_ref() - .unwrap_or_else(|| panic!("attribute is missing tokens: {self:?}")) - .to_attr_token_stream() - .to_tokenstream(), - &AttrKind::DocComment(comment_kind, data) => TokenStream::token_alone( - token::DocComment(comment_kind, self.style, data), - self.span, - ), - } - } -} - -impl AttrItem { - pub fn span(&self) -> Span { - self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span)) - } - - fn meta_item_list(&self) -> Option> { - match &self.args { - AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => { - MetaItemKind::list_from_tokens(args.tokens.clone()) - } - AttrArgs::Delimited(_) | AttrArgs::Eq(..) | AttrArgs::Empty => None, - } - } - - fn value_str(&self) -> Option { - match &self.args { - AttrArgs::Eq(_, args) => args.value_str(), - AttrArgs::Delimited(_) | AttrArgs::Empty => None, - } - } - - pub fn meta(&self, span: Span) -> Option { - Some(MetaItem { path: self.path.clone(), kind: self.meta_kind()?, span }) - } - - pub fn meta_kind(&self) -> Option { - MetaItemKind::from_attr_args(&self.args) - } -} - -impl AttrArgsEq { - fn value_str(&self) -> Option { - match self { - AttrArgsEq::Ast(expr) => match expr.kind { - ExprKind::Lit(token_lit) => { - LitKind::from_token_lit(token_lit).ok().and_then(|lit| lit.str()) - } - _ => None, - }, - AttrArgsEq::Hir(lit) => lit.kind.str(), - } - } -} - -impl MetaItem { - /// For a single-segment meta item, returns its name; otherwise, returns `None`. - pub fn ident(&self) -> Option { - if self.path.segments.len() == 1 { Some(self.path.segments[0].ident) } else { None } - } - - pub fn name_or_empty(&self) -> Symbol { - self.ident().unwrap_or_else(Ident::empty).name - } - - pub fn has_name(&self, name: Symbol) -> bool { - self.path == name - } - - pub fn is_word(&self) -> bool { - matches!(self.kind, MetaItemKind::Word) - } - - pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { - match &self.kind { - MetaItemKind::List(l) => Some(&**l), - _ => None, - } - } - - /// ```text - /// Example: - /// #[attribute(name = "value")] - /// ^^^^^^^^^^^^^^ - /// ``` - pub fn name_value_literal(&self) -> Option<&MetaItemLit> { - match &self.kind { - MetaItemKind::NameValue(v) => Some(v), - _ => None, - } - } - - /// This is used in case you want the value span instead of the whole attribute. Example: - /// - /// ```text - /// #[doc(alias = "foo")] - /// ``` - /// - /// In here, it'll return a span for `"foo"`. - pub fn name_value_literal_span(&self) -> Option { - Some(self.name_value_literal()?.span) - } - - pub fn value_str(&self) -> Option { - self.kind.value_str() - } - - fn from_tokens<'a, I>(tokens: &mut iter::Peekable) -> Option - where - I: Iterator, - { - // FIXME: Share code with `parse_path`. - let path = match tokens.next().map(|tt| TokenTree::uninterpolate(tt)).as_deref() { - Some(&TokenTree::Token( - Token { kind: ref kind @ (token::Ident(..) | token::ModSep), span }, - _, - )) => 'arm: { - let mut segments = if let &token::Ident(name, _) = kind { - if let Some(TokenTree::Token(Token { kind: token::ModSep, .. }, _)) = - tokens.peek() - { - tokens.next(); - thin_vec![PathSegment::from_ident(Ident::new(name, span))] - } else { - break 'arm Path::from_ident(Ident::new(name, span)); - } - } else { - thin_vec![PathSegment::path_root(span)] - }; - loop { - if let Some(&TokenTree::Token(Token { kind: token::Ident(name, _), span }, _)) = - tokens.next().map(|tt| TokenTree::uninterpolate(tt)).as_deref() - { - segments.push(PathSegment::from_ident(Ident::new(name, span))); - } else { - return None; - } - if let Some(TokenTree::Token(Token { kind: token::ModSep, .. }, _)) = - tokens.peek() - { - tokens.next(); - } else { - break; - } - } - let span = span.with_hi(segments.last().unwrap().ident.span.hi()); - Path { span, segments, tokens: None } - } - Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. }, _)) => match &nt.0 { - token::Nonterminal::NtMeta(item) => return item.meta(item.path.span), - token::Nonterminal::NtPath(path) => (**path).clone(), - _ => return None, - }, - _ => return None, - }; - let list_closing_paren_pos = tokens.peek().map(|tt| tt.span().hi()); - let kind = MetaItemKind::from_tokens(tokens)?; - let hi = match &kind { - MetaItemKind::NameValue(lit) => lit.span.hi(), - MetaItemKind::List(..) => list_closing_paren_pos.unwrap_or(path.span.hi()), - _ => path.span.hi(), - }; - let span = path.span.with_hi(hi); - Some(MetaItem { path, kind, span }) - } -} - -impl MetaItemKind { - pub fn value_str(&self) -> Option { - match self { - MetaItemKind::NameValue(v) => v.kind.str(), - _ => None, - } - } - - fn list_from_tokens(tokens: TokenStream) -> Option> { - let mut tokens = tokens.trees().peekable(); - let mut result = ThinVec::new(); - while tokens.peek().is_some() { - let item = NestedMetaItem::from_tokens(&mut tokens)?; - result.push(item); - match tokens.next() { - None | Some(TokenTree::Token(Token { kind: token::Comma, .. }, _)) => {} - _ => return None, - } - } - Some(result) - } - - fn name_value_from_tokens<'a>( - tokens: &mut impl Iterator, - ) -> Option { - match tokens.next() { - Some(TokenTree::Delimited(.., Delimiter::Invisible, inner_tokens)) => { - MetaItemKind::name_value_from_tokens(&mut inner_tokens.trees()) - } - Some(TokenTree::Token(token, _)) => { - MetaItemLit::from_token(token).map(MetaItemKind::NameValue) - } - _ => None, - } - } - - fn from_tokens<'a>( - tokens: &mut iter::Peekable>, - ) -> Option { - match tokens.peek() { - Some(TokenTree::Delimited(.., Delimiter::Parenthesis, inner_tokens)) => { - let inner_tokens = inner_tokens.clone(); - tokens.next(); - MetaItemKind::list_from_tokens(inner_tokens).map(MetaItemKind::List) - } - Some(TokenTree::Delimited(..)) => None, - Some(TokenTree::Token(Token { kind: token::Eq, .. }, _)) => { - tokens.next(); - MetaItemKind::name_value_from_tokens(tokens) - } - _ => Some(MetaItemKind::Word), - } - } - - fn from_attr_args(args: &AttrArgs) -> Option { - match args { - AttrArgs::Empty => Some(MetaItemKind::Word), - AttrArgs::Delimited(DelimArgs { dspan: _, delim: Delimiter::Parenthesis, tokens }) => { - MetaItemKind::list_from_tokens(tokens.clone()).map(MetaItemKind::List) - } - AttrArgs::Delimited(..) => None, - AttrArgs::Eq(_, AttrArgsEq::Ast(expr)) => match expr.kind { - ExprKind::Lit(token_lit) => { - // Turn failures to `None`, we'll get parse errors elsewhere. - MetaItemLit::from_token_lit(token_lit, expr.span) - .ok() - .map(|lit| MetaItemKind::NameValue(lit)) - } - _ => None, - }, - AttrArgs::Eq(_, AttrArgsEq::Hir(lit)) => Some(MetaItemKind::NameValue(lit.clone())), - } - } -} - -impl NestedMetaItem { - pub fn span(&self) -> Span { - match self { - NestedMetaItem::MetaItem(item) => item.span, - NestedMetaItem::Lit(lit) => lit.span, - } - } - - /// For a single-segment meta item, returns its name; otherwise, returns `None`. - pub fn ident(&self) -> Option { - self.meta_item().and_then(|meta_item| meta_item.ident()) - } - - pub fn name_or_empty(&self) -> Symbol { - self.ident().unwrap_or_else(Ident::empty).name - } - - /// Returns `true` if this list item is a MetaItem with a name of `name`. - pub fn has_name(&self, name: Symbol) -> bool { - self.meta_item().is_some_and(|meta_item| meta_item.has_name(name)) - } - - /// Returns `true` if `self` is a `MetaItem` and the meta item is a word. - pub fn is_word(&self) -> bool { - self.meta_item().is_some_and(|meta_item| meta_item.is_word()) - } - - /// Gets a list of inner meta items from a list `MetaItem` type. - pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { - self.meta_item().and_then(|meta_item| meta_item.meta_item_list()) - } - - /// Returns a name and single literal value tuple of the `MetaItem`. - pub fn name_value_literal(&self) -> Option<(Symbol, &MetaItemLit)> { - self.meta_item().and_then(|meta_item| { - meta_item.meta_item_list().and_then(|meta_item_list| { - if meta_item_list.len() == 1 - && let Some(ident) = meta_item.ident() - && let Some(lit) = meta_item_list[0].lit() - { - return Some((ident.name, lit)); - } - None - }) - }) - } - - /// See [`MetaItem::name_value_literal_span`]. - pub fn name_value_literal_span(&self) -> Option { - self.meta_item()?.name_value_literal_span() - } - - /// Gets the string value if `self` is a `MetaItem` and the `MetaItem` is a - /// `MetaItemKind::NameValue` variant containing a string, otherwise `None`. - pub fn value_str(&self) -> Option { - self.meta_item().and_then(|meta_item| meta_item.value_str()) - } - - /// Returns the `MetaItemLit` if `self` is a `NestedMetaItem::Literal`s. - pub fn lit(&self) -> Option<&MetaItemLit> { - match self { - NestedMetaItem::Lit(lit) => Some(lit), - _ => None, - } - } - - /// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem`. - pub fn meta_item(&self) -> Option<&MetaItem> { - match self { - NestedMetaItem::MetaItem(item) => Some(item), - _ => None, - } - } - - /// Returns `true` if the variant is `MetaItem`. - pub fn is_meta_item(&self) -> bool { - self.meta_item().is_some() - } - - fn from_tokens<'a, I>(tokens: &mut iter::Peekable) -> Option - where - I: Iterator, - { - match tokens.peek() { - Some(TokenTree::Token(token, _)) if let Some(lit) = MetaItemLit::from_token(token) => { - tokens.next(); - return Some(NestedMetaItem::Lit(lit)); - } - Some(TokenTree::Delimited(.., Delimiter::Invisible, inner_tokens)) => { - tokens.next(); - return NestedMetaItem::from_tokens(&mut inner_tokens.trees().peekable()); - } - _ => {} - } - MetaItem::from_tokens(tokens).map(NestedMetaItem::MetaItem) - } -} - -pub fn mk_doc_comment( - g: &AttrIdGenerator, - comment_kind: CommentKind, - style: AttrStyle, - data: Symbol, - span: Span, -) -> Attribute { - Attribute { kind: AttrKind::DocComment(comment_kind, data), id: g.mk_attr_id(), style, span } -} - -pub fn mk_attr( - g: &AttrIdGenerator, - style: AttrStyle, - path: Path, - args: AttrArgs, - span: Span, -) -> Attribute { - mk_attr_from_item(g, AttrItem { path, args, tokens: None }, None, style, span) -} - -pub fn mk_attr_from_item( - g: &AttrIdGenerator, - item: AttrItem, - tokens: Option, - style: AttrStyle, - span: Span, -) -> Attribute { - Attribute { - kind: AttrKind::Normal(P(NormalAttr { item, tokens })), - id: g.mk_attr_id(), - style, - span, - } -} - -pub fn mk_attr_word(g: &AttrIdGenerator, style: AttrStyle, name: Symbol, span: Span) -> Attribute { - let path = Path::from_ident(Ident::new(name, span)); - let args = AttrArgs::Empty; - mk_attr(g, style, path, args, span) -} - -pub fn mk_attr_nested_word( - g: &AttrIdGenerator, - style: AttrStyle, - outer: Symbol, - inner: Symbol, - span: Span, -) -> Attribute { - let inner_tokens = TokenStream::new(vec![TokenTree::Token( - Token::from_ast_ident(Ident::new(inner, span)), - Spacing::Alone, - )]); - let outer_ident = Ident::new(outer, span); - let path = Path::from_ident(outer_ident); - let attr_args = AttrArgs::Delimited(DelimArgs { - dspan: DelimSpan::from_single(span), - delim: Delimiter::Parenthesis, - tokens: inner_tokens, - }); - mk_attr(g, style, path, attr_args, span) -} - -pub fn mk_attr_name_value_str( - g: &AttrIdGenerator, - style: AttrStyle, - name: Symbol, - val: Symbol, - span: Span, -) -> Attribute { - let lit = token::Lit::new(token::Str, escape_string_symbol(val), None); - let expr = P(Expr { - id: DUMMY_NODE_ID, - kind: ExprKind::Lit(lit), - span, - attrs: AttrVec::new(), - tokens: None, - }); - let path = Path::from_ident(Ident::new(name, span)); - let args = AttrArgs::Eq(span, AttrArgsEq::Ast(expr)); - mk_attr(g, style, path, args, span) -} - -pub fn filter_by_name(attrs: &[Attribute], name: Symbol) -> impl Iterator { - attrs.iter().filter(move |attr| attr.has_name(name)) -} - -pub fn find_by_name(attrs: &[Attribute], name: Symbol) -> Option<&Attribute> { - filter_by_name(attrs, name).next() -} - -pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: Symbol) -> Option { - find_by_name(attrs, name).and_then(|attr| attr.value_str()) -} - -pub fn contains_name(attrs: &[Attribute], name: Symbol) -> bool { - find_by_name(attrs, name).is_some() -} - -pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool { - items.iter().any(|item| item.has_name(name)) -} +use crate::ast::{AttrArgs,AttrArgsEq ,AttrId,AttrItem,AttrKind,AttrStyle,AttrVec +,Attribute};use crate::ast::{DelimArgs,Expr,ExprKind,LitKind,MetaItemLit};use//; +crate::ast::{MetaItem,MetaItemKind,NestedMetaItem ,NormalAttr};use crate::ast::{ +Path,PathSegment,DUMMY_NODE_ID};use crate::ptr::P;use crate::token::{self,//{;}; +CommentKind,Delimiter,Token};use crate::tokenstream::{DelimSpan,Spacing,//{();}; +TokenTree};use crate::tokenstream::{LazyAttrTokenStream,TokenStream};use crate// +::util::comments;use crate:: util::literal::escape_string_symbol;use rustc_index +::bit_set::GrowableBitSet;use rustc_span::symbol::{sym,Ident,Symbol};use//{();}; +rustc_span::Span;use std::iter;use std::sync::atomic::{AtomicU32,Ordering};use// +thin_vec::{thin_vec,ThinVec};pub struct MarkedAttrs(GrowableBitSet);//3; +impl MarkedAttrs{pub fn new()->Self {(MarkedAttrs(GrowableBitSet::new_empty()))} +pub fn mark(&mut self,attr:&Attribute){;self.0.insert(attr.id);}pub fn is_marked +(&self,attr:&Attribute)->bool{(((((((self.0.contains(attr.id))))))))}}pub struct +AttrIdGenerator(AtomicU32);impl AttrIdGenerator{pub fn new()->Self{//let _=||(); +AttrIdGenerator(AtomicU32::new(0))}pub fn mk_attr_id(&self)->AttrId{;let id=self +.0.fetch_add(1,Ordering::Relaxed);;;assert!(id!=u32::MAX);AttrId::from_u32(id)}} +impl Attribute{pub fn get_normal_item(&self)->&AttrItem{match((((&self.kind)))){ +AttrKind::Normal(normal)=>((((&normal.item)))),AttrKind::DocComment(..)=>panic!( +"unexpected doc comment"),}}pub fn unwrap_normal_item(self)->AttrItem{match//(); +self.kind{AttrKind::Normal(normal)=> ((((normal.into_inner())))).item,AttrKind:: +DocComment(..)=>panic!("unexpected doc comment") ,}}pub fn is_doc_comment(&self) +->bool{match self.kind{AttrKind::Normal(.. )=>(false),AttrKind::DocComment(..)=> +true,}}pub fn ident(&self)->Option {match((&self.kind)){AttrKind::Normal( +normal)=>{if let[ident]=&*normal.item .path.segments{Some(ident.ident)}else{None +}}AttrKind::DocComment(..)=>None,}}pub fn name_or_empty(&self)->Symbol{self.//3; +ident().unwrap_or_else(Ident::empty).name}#[inline]pub fn has_name(&self,name:// +Symbol)->bool{match&self.kind{AttrKind:: Normal(normal)=>normal.item.path==name, +AttrKind::DocComment(..)=>(false),}}pub fn path_matches(&self,name:&[Symbol])-> +bool{match&self.kind{AttrKind::Normal(normal) =>{normal.item.path.segments.len() +==(name.len())&&(normal.item.path.segments.iter() .zip(name)).all(|(s,n)|s.args. +is_none()&&s.ident.name==*n) }AttrKind::DocComment(..)=>false,}}pub fn is_word(& +self)->bool{if let AttrKind::Normal(normal)=((&self.kind)){matches!(normal.item. +args,AttrArgs::Empty)}else{false} }pub fn meta_item_list(&self)->Option>{match((((&self.kind)))){ AttrKind::Normal(normal)=>normal.item. +meta_item_list(),AttrKind::DocComment(..)=>None,}}pub fn value_str(&self)->//(); +Option{match&self.kind{ AttrKind::Normal(normal)=>normal.item.value_str( +),AttrKind::DocComment(..)=>None,}}pub fn doc_str_and_comment_kind(&self)->//(); +Option<(Symbol,CommentKind)>{match(&self.kind){AttrKind::DocComment(kind,data)=> +Some((((*data),*kind))),AttrKind::Normal(normal)if normal.item.path==sym::doc=>{ +normal.item.value_str().map(|s|(s,CommentKind ::Line))}_=>None,}}pub fn doc_str( +&self)->Option{match((&self.kind)){AttrKind::DocComment(..,data)=>Some(* +data),AttrKind::Normal(normal)if (((normal .item.path==sym::doc)))=>normal.item. +value_str(),_=>None,}}pub fn may_have_doc_links(&self)->bool{((self.doc_str())). +is_some_and((((|s|(((comments::may_have_doc_links(((s .as_str()))))))))))}pub fn +is_proc_macro_attr(&self)->bool{[sym::proc_macro,sym::proc_macro_attribute,sym// +::proc_macro_derive].iter().any((|kind|self.has_name(*kind)))}pub fn meta(&self) +->Option{match(&self.kind){AttrKind::Normal(normal)=>normal.item.meta( +self.span),AttrKind::DocComment(..)=>None,}}pub fn meta_kind(&self)->Option{match&self.kind{AttrKind:: Normal(normal)=>normal.item.meta_kind() +,AttrKind::DocComment(..)=>None,}}pub fn tokens(&self)->TokenStream{match&self. +kind{AttrKind::Normal(normal)=>(normal.tokens.as_ref()).unwrap_or_else(||panic!( +"attribute is missing tokens: {self:?}")) .to_attr_token_stream().to_tokenstream +(),&AttrKind::DocComment(comment_kind,data)=>TokenStream::token_alone(token:://; +DocComment(comment_kind,self.style,data),self.span,),}}}impl AttrItem{pub fn//3; +span(&self)->Span{(self.args.span()).map_or(self.path.span,|args_span|self.path. +span.to(args_span))}fn meta_item_list(&self)->Option>{// +match(&self.args){AttrArgs::Delimited(args)if args.delim==Delimiter::Parenthesis +=>{(MetaItemKind::list_from_tokens(args.tokens.clone()))}AttrArgs::Delimited(_)| +AttrArgs::Eq(..)|AttrArgs::Empty=>None,}}fn value_str(&self)->Option{//; +match(&self.args){AttrArgs::Eq(_,args)=>args.value_str(),AttrArgs::Delimited(_)| +AttrArgs::Empty=>None,}}pub fn meta(&self,span:Span)->Option{Some(//3; +MetaItem{path:self.path.clone(),kind:self .meta_kind()?,span})}pub fn meta_kind( +&self)->Option{(MetaItemKind:: from_attr_args((&self.args)))}}impl +AttrArgsEq{fn value_str(&self)->Option< Symbol>{match self{AttrArgsEq::Ast(expr) +=>match expr.kind{ExprKind::Lit(token_lit )=>{LitKind::from_token_lit(token_lit) +.ok().and_then(|lit|lit.str())} _=>None,},AttrArgsEq::Hir(lit)=>lit.kind.str(),} +}}impl MetaItem{pub fn ident(&self)->Option{if (self.path.segments.len()) +==(1){Some(self.path.segments[0].ident)}else{None}}pub fn name_or_empty(&self)-> +Symbol{((self.ident()).unwrap_or_else(Ident::empty)).name}pub fn has_name(&self, +name:Symbol)->bool{(self.path==name)}pub fn is_word(&self)->bool{matches!(self. +kind,MetaItemKind::Word)}pub fn meta_item_list(&self)->Option<&[NestedMetaItem] +>{match((&self.kind)){MetaItemKind::List(l)=>(Some((&(*(*l))))),_=>None,}}pub fn +name_value_literal(&self)->Option<&MetaItemLit>{match(&self.kind){MetaItemKind:: +NameValue(v)=>(Some(v)),_=>None,}}pub fn name_value_literal_span(&self)->Option< +Span>{(Some((self.name_value_literal()?).span))}pub fn value_str(&self)->Option< +Symbol>{self.kind.value_str()}fn from_tokens <'a,I>(tokens:&mut iter::Peekable)->Optionwhere I:Iterator,{;let path=match tokens +.next().map(|tt|TokenTree::uninterpolate( tt)).as_deref(){Some(&TokenTree::Token +(Token{kind:ref kind@(token::Ident(..)|token::ModSep),span},_,))=>'arm:{;let mut +segments=if let&token::Ident(name,_)=kind{if let Some(TokenTree::Token(Token{//; +kind:token::ModSep,..},_))=tokens.peek(){;tokens.next();;thin_vec![PathSegment:: +from_ident(Ident::new(name,span))]}else{;break 'arm Path::from_ident(Ident::new( +name,span));;}}else{thin_vec![PathSegment::path_root(span)]};;loop{if let Some(& +TokenTree::Token(Token{kind:token::Ident(name,_),span},_))=(tokens.next()).map(| +tt|TokenTree::uninterpolate(tt)).as_deref(){let _=();segments.push(PathSegment:: +from_ident(Ident::new(name,span)));;}else{;return None;;}if let Some(TokenTree:: +Token(Token{kind:token::ModSep,..},_))=tokens.peek(){;tokens.next();}else{break; +}}3;let span=span.with_hi(segments.last().unwrap().ident.span.hi());3;Path{span, +segments,tokens:None}}Some(TokenTree:: Token(Token{kind:token::Interpolated(nt), +..},_))=>match((&nt.0)){token::Nonterminal::NtMeta(item)=>return item.meta(item. +path.span),token::Nonterminal::NtPath(path)=>(* *path).clone(),_=>return None,}, +_=>return None,};;let list_closing_paren_pos=tokens.peek().map(|tt|tt.span().hi( +));;let kind=MetaItemKind::from_tokens(tokens)?;let hi=match&kind{MetaItemKind:: +NameValue(lit)=>(lit.span.hi( )),MetaItemKind::List(..)=>list_closing_paren_pos. +unwrap_or(path.span.hi()),_=>path.span.hi(),};;;let span=path.span.with_hi(hi);; +Some(((MetaItem{path,kind,span})))} }impl MetaItemKind{pub fn value_str(&self)-> +Option{match self{MetaItemKind::NameValue(v)=> v.kind.str(),_=>None,}}fn +list_from_tokens(tokens:TokenStream)->Option>{();let mut +tokens=tokens.trees().peekable();3;;let mut result=ThinVec::new();;while tokens. +peek().is_some(){;let item=NestedMetaItem::from_tokens(&mut tokens)?;result.push +(item);3;match tokens.next(){None|Some(TokenTree::Token(Token{kind:token::Comma, +..},_))=>{}_=>return None,} }Some(result)}fn name_value_from_tokens<'a>(tokens:& +mut impl Iterator ,)->Option{match tokens.next +(){Some(TokenTree::Delimited(..,Delimiter::Invisible,inner_tokens))=>{//((),()); +MetaItemKind::name_value_from_tokens((&mut inner_tokens.trees()))}Some(TokenTree +::Token(token,_))=>{MetaItemLit ::from_token(token).map(MetaItemKind::NameValue) +}_=>None,}}fn from_tokens<'a>(tokens :&mut iter::Peekable>,)->Option{match ((((tokens.peek())))){Some(TokenTree:: +Delimited(..,Delimiter::Parenthesis,inner_tokens))=>{if true{};let inner_tokens= +inner_tokens.clone();;tokens.next();MetaItemKind::list_from_tokens(inner_tokens) +.map(MetaItemKind::List)}Some(TokenTree::Delimited(..))=>None,Some(TokenTree::// +Token(Token{kind:token::Eq,..},_))=>{((),());tokens.next();*&*&();MetaItemKind:: +name_value_from_tokens(tokens)}_=>Some( MetaItemKind::Word),}}fn from_attr_args( +args:&AttrArgs)->Option{match args{AttrArgs::Empty=>Some(//*&*&(); +MetaItemKind::Word),AttrArgs::Delimited(DelimArgs{dspan:_,delim:Delimiter:://(); +Parenthesis,tokens})=>{((MetaItemKind::list_from_tokens((tokens.clone())))).map( +MetaItemKind::List)}AttrArgs::Delimited(..)=>None,AttrArgs::Eq(_,AttrArgsEq:://; +Ast(expr))=>match expr.kind{ExprKind::Lit(token_lit)=>{MetaItemLit:://if true{}; +from_token_lit(token_lit,expr.span).ok().map (|lit|MetaItemKind::NameValue(lit)) +}_=>None,},AttrArgs::Eq(_,AttrArgsEq::Hir(lit))=>Some(MetaItemKind::NameValue(// +lit.clone())),}}}impl NestedMetaItem{pub fn span(&self)->Span{match self{//({}); +NestedMetaItem::MetaItem(item)=>item.span,NestedMetaItem ::Lit(lit)=>lit.span,}} +pub fn ident(&self)->Option{((((self.meta_item())))).and_then(|meta_item| +meta_item.ident())}pub fn name_or_empty(&self)->Symbol{((((((self.ident())))))). +unwrap_or_else(Ident::empty).name}pub fn has_name(&self,name:Symbol)->bool{self +.meta_item().is_some_and((|meta_item|meta_item.has_name(name)))}pub fn is_word(& +self)->bool{self.meta_item().is_some_and( |meta_item|meta_item.is_word())}pub fn +meta_item_list(&self)->Option<&[NestedMetaItem]>{((self.meta_item())).and_then(| +meta_item|meta_item.meta_item_list()) }pub fn name_value_literal(&self)->Option< +(Symbol,&MetaItemLit)>{((((self.meta_item( ))))).and_then(|meta_item|{meta_item. +meta_item_list().and_then(|meta_item_list|{if meta_item_list.len()==1&&let Some +(ident)=meta_item.ident()&&let Some(lit)=meta_item_list[0].lit(){3;return Some(( +ident.name,lit));;}None})})}pub fn name_value_literal_span(&self)->Option{ +self.meta_item()?.name_value_literal_span()}pub fn value_str(&self)->Option{self.meta_item().and_then(|meta_item |meta_item.value_str())}pub fn lit( +&self)->Option<&MetaItemLit>{match self{NestedMetaItem ::Lit(lit)=>Some(lit),_=> +None,}}pub fn meta_item(&self)->Option<&MetaItem>{match self{NestedMetaItem:://; +MetaItem(item)=>((Some(item))),_=>None,} }pub fn is_meta_item(&self)->bool{self. +meta_item().is_some()}fn from_tokens<'a,I>(tokens:&mut iter::Peekable)->//(); +Optionwhere I:Iterator,{match tokens.peek() +{Some(TokenTree::Token(token,_))if let Some(lit)=MetaItemLit::from_token(token) +=>{3;tokens.next();3;3;return Some(NestedMetaItem::Lit(lit));3;}Some(TokenTree:: +Delimited(..,Delimiter::Invisible,inner_tokens))=>{();tokens.next();();3;return +NestedMetaItem::from_tokens(&mut inner_tokens.trees().peekable());*&*&();}_=>{}} +MetaItem::from_tokens(tokens).map(NestedMetaItem::MetaItem)}}pub fn//let _=||(); +mk_doc_comment(g:&AttrIdGenerator,comment_kind :CommentKind,style:AttrStyle,data +:Symbol,span:Span,)->Attribute{ Attribute{kind:AttrKind::DocComment(comment_kind +,data),id:(g.mk_attr_id()),style, span}}pub fn mk_attr(g:&AttrIdGenerator,style: +AttrStyle,path:Path,args:AttrArgs,span:Span,)->Attribute{mk_attr_from_item(g,//; +AttrItem{path,args,tokens:None},None,style,span)}pub fn mk_attr_from_item(g:&//; +AttrIdGenerator,item:AttrItem,tokens:Option,style://*&*&(); +AttrStyle,span:Span,)->Attribute{Attribute{kind:AttrKind::Normal(P(NormalAttr{// +item,tokens})),id:(((((g.mk_attr_id() ))))),style,span,}}pub fn mk_attr_word(g:& +AttrIdGenerator,style:AttrStyle,name:Symbol,span:Span)->Attribute{;let path=Path +::from_ident(Ident::new(name,span));;;let args=AttrArgs::Empty;;mk_attr(g,style, +path,args,span)}pub fn mk_attr_nested_word(g:&AttrIdGenerator,style:AttrStyle,// +outer:Symbol,inner:Symbol,span:Span,)->Attribute{;let inner_tokens=TokenStream:: +new(vec![TokenTree::Token(Token:: from_ast_ident(Ident::new(inner,span)),Spacing +::Alone,)]);;;let outer_ident=Ident::new(outer,span);;let path=Path::from_ident( +outer_ident);();();let attr_args=AttrArgs::Delimited(DelimArgs{dspan:DelimSpan:: +from_single(span),delim:Delimiter::Parenthesis,tokens:inner_tokens,});;mk_attr(g +,style,path,attr_args,span)}pub fn mk_attr_name_value_str(g:&AttrIdGenerator,//; +style:AttrStyle,name:Symbol,val:Symbol,span:Span,)->Attribute{();let lit=token:: +Lit::new(token::Str,escape_string_symbol(val),None);({});{;};let expr=P(Expr{id: +DUMMY_NODE_ID,kind:ExprKind::Lit(lit),span,attrs:AttrVec::new(),tokens:None,});; +let path=Path::from_ident(Ident::new(name,span));3;3;let args=AttrArgs::Eq(span, +AttrArgsEq::Ast(expr));();mk_attr(g,style,path,args,span)}pub fn filter_by_name( +attrs:&[Attribute],name:Symbol)->impl Iterator {(attrs.iter()). +filter((move|attr|attr.has_name(name)) )}pub fn find_by_name(attrs:&[Attribute], +name:Symbol)->Option<&Attribute>{(((filter_by_name (attrs,name)).next()))}pub fn +first_attr_value_str_by_name(attrs:&[Attribute],name:Symbol)->Option{//; +find_by_name(attrs,name).and_then(|attr| attr.value_str())}pub fn contains_name( +attrs:&[Attribute],name:Symbol)->bool{ find_by_name(attrs,name).is_some()}pub fn +list_contains_name(items:&[NestedMetaItem],name:Symbol)->bool{(items.iter()).any +((((((((((((((|item|(((((((((((((item.has_name(name))))))))))))))))))))))))))))} diff --git a/compiler/rustc_ast/src/expand/allocator.rs b/compiler/rustc_ast/src/expand/allocator.rs index f825b10f489b0..2b1f85ea70460 100644 --- a/compiler/rustc_ast/src/expand/allocator.rs +++ b/compiler/rustc_ast/src/expand/allocator.rs @@ -1,73 +1,21 @@ -use rustc_span::symbol::{sym, Symbol}; - -#[derive(Clone, Debug, Copy, Eq, PartialEq, HashStable_Generic)] -pub enum AllocatorKind { - Global, - Default, -} - -pub fn global_fn_name(base: Symbol) -> String { - format!("__rust_{base}") -} - -pub fn default_fn_name(base: Symbol) -> String { - format!("__rdl_{base}") -} - -pub fn alloc_error_handler_name(alloc_error_handler_kind: AllocatorKind) -> &'static str { - match alloc_error_handler_kind { - AllocatorKind::Global => "__rg_oom", - AllocatorKind::Default => "__rdl_oom", - } -} - -pub const NO_ALLOC_SHIM_IS_UNSTABLE: &str = "__rust_no_alloc_shim_is_unstable"; - -pub enum AllocatorTy { - Layout, - Ptr, - ResultPtr, - Unit, - Usize, -} - -pub struct AllocatorMethod { - pub name: Symbol, - pub inputs: &'static [AllocatorMethodInput], - pub output: AllocatorTy, -} - -pub struct AllocatorMethodInput { - pub name: &'static str, - pub ty: AllocatorTy, -} - -pub static ALLOCATOR_METHODS: &[AllocatorMethod] = &[ - AllocatorMethod { - name: sym::alloc, - inputs: &[AllocatorMethodInput { name: "layout", ty: AllocatorTy::Layout }], - output: AllocatorTy::ResultPtr, - }, - AllocatorMethod { - name: sym::dealloc, - inputs: &[ - AllocatorMethodInput { name: "ptr", ty: AllocatorTy::Ptr }, - AllocatorMethodInput { name: "layout", ty: AllocatorTy::Layout }, - ], - output: AllocatorTy::Unit, - }, - AllocatorMethod { - name: sym::realloc, - inputs: &[ - AllocatorMethodInput { name: "ptr", ty: AllocatorTy::Ptr }, - AllocatorMethodInput { name: "layout", ty: AllocatorTy::Layout }, - AllocatorMethodInput { name: "new_size", ty: AllocatorTy::Usize }, - ], - output: AllocatorTy::ResultPtr, - }, - AllocatorMethod { - name: sym::alloc_zeroed, - inputs: &[AllocatorMethodInput { name: "layout", ty: AllocatorTy::Layout }], - output: AllocatorTy::ResultPtr, - }, -]; +use rustc_span::symbol::{sym,Symbol};#[derive(Clone,Debug,Copy,Eq,PartialEq,//3; +HashStable_Generic)]pub enum AllocatorKind{Global,Default,}pub fn//loop{break;}; +global_fn_name(base:Symbol)->String{(((((( format!("__rust_{base}")))))))}pub fn +default_fn_name(base:Symbol)->String{(((((( format!("__rdl_{base}")))))))}pub fn +alloc_error_handler_name(alloc_error_handler_kind:AllocatorKind) ->&'static str{ +match alloc_error_handler_kind{AllocatorKind::Global=>("__rg_oom"),AllocatorKind +::Default=>((((((("__rdl_oom"))))))),}}pub const NO_ALLOC_SHIM_IS_UNSTABLE:&str= +"__rust_no_alloc_shim_is_unstable";pub enum AllocatorTy{Layout,Ptr,ResultPtr,//; +Unit,Usize,}pub struct AllocatorMethod{pub name:Symbol,pub inputs:&'static[//(); +AllocatorMethodInput],pub output:AllocatorTy,}pub struct AllocatorMethodInput{// +pub name:&'static str,pub ty:AllocatorTy,}pub static ALLOCATOR_METHODS:&[//({}); +AllocatorMethod]=&[AllocatorMethod{name:sym::alloc,inputs:&[//let _=();let _=(); +AllocatorMethodInput{name:("layout"),ty:AllocatorTy::Layout}],output:AllocatorTy +::ResultPtr,},AllocatorMethod{name:sym::dealloc,inputs:&[AllocatorMethodInput{// +name:((("ptr"))),ty:AllocatorTy::Ptr},AllocatorMethodInput{name:(("layout")),ty: +AllocatorTy::Layout},],output:AllocatorTy::Unit,},AllocatorMethod{name:sym:://3; +realloc,inputs:&[(((AllocatorMethodInput{name:(("ptr")),ty:AllocatorTy::Ptr}))), +AllocatorMethodInput{name:"layout",ty :AllocatorTy::Layout},AllocatorMethodInput +{name:((("new_size"))),ty:AllocatorTy::Usize},],output:AllocatorTy::ResultPtr,}, +AllocatorMethod{name:sym::alloc_zeroed,inputs:&[AllocatorMethodInput{name://{;}; +"layout",ty:AllocatorTy::Layout}],output:AllocatorTy::ResultPtr,},];//if true{}; diff --git a/compiler/rustc_ast/src/expand/mod.rs b/compiler/rustc_ast/src/expand/mod.rs index 942347383ce31..6e344db27b11a 100644 --- a/compiler/rustc_ast/src/expand/mod.rs +++ b/compiler/rustc_ast/src/expand/mod.rs @@ -1,20 +1,6 @@ -//! Definitions shared by macros / syntax extensions and e.g. `rustc_middle`. - -use rustc_span::{def_id::DefId, symbol::Ident}; - -use crate::MetaItem; - -pub mod allocator; - -#[derive(Debug, Clone, Encodable, Decodable, HashStable_Generic)] -pub struct StrippedCfgItem { - pub parent_module: ModId, - pub name: Ident, - pub cfg: MetaItem, -} - -impl StrippedCfgItem { - pub fn map_mod_id(self, f: impl FnOnce(ModId) -> New) -> StrippedCfgItem { - StrippedCfgItem { parent_module: f(self.parent_module), name: self.name, cfg: self.cfg } - } -} +use rustc_span::{def_id::DefId,symbol::Ident};use crate::MetaItem;pub mod//({}); +allocator;#[derive(Debug,Clone,Encodable,Decodable,HashStable_Generic)]pub//{;}; +struct StrippedCfgItem{pub parent_module:ModId,pub name:Ident,pub// +cfg:MetaItem,}implStrippedCfgItem{pub fn map_mod_id(self,f:// +impl FnOnce(ModId)->New)->StrippedCfgItem {StrippedCfgItem{parent_module:f( +self.parent_module),name:self.name,cfg:self.cfg}}}//if let _=(){};if let _=(){}; diff --git a/compiler/rustc_ast/src/format.rs b/compiler/rustc_ast/src/format.rs index 805596ff00a98..caa40ca1b6fff 100644 --- a/compiler/rustc_ast/src/format.rs +++ b/compiler/rustc_ast/src/format.rs @@ -1,266 +1,47 @@ -use crate::ptr::P; -use crate::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, Encodable, Decodable, Debug)] -pub struct FormatArgs { - pub span: Span, - pub template: Vec, - pub arguments: FormatArguments, -} - -/// A piece of a format template string. -/// -/// E.g. "hello" or "{name}". -#[derive(Clone, Encodable, Decodable, 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, Encodable, Decodable, Debug)] -pub struct FormatArguments { - arguments: Vec, - num_unnamed_args: usize, - num_explicit_args: usize, - names: FxHashMap, -} - -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 explicit. - 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 all_args(&self) -> &[FormatArgument] { - &self.arguments[..] - } - - pub fn all_args_mut(&mut self) -> &mut Vec { - &mut self.arguments - } -} - -#[derive(Clone, Encodable, Decodable, Debug)] -pub struct FormatArgument { - pub kind: FormatArgumentKind, - pub expr: P, -} - -#[derive(Clone, Encodable, Decodable, 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 { - match self { - &Self::Normal => None, - &Self::Named(id) => Some(id), - &Self::Captured(id) => Some(id), - } - } -} - -#[derive(Clone, Encodable, Decodable, 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, - /// `{}`, `{:?}`, or `{:x}`, etc. - pub format_trait: FormatTrait, - /// `{}` or `{:.5}` or `{:-^20}`, etc. - pub format_options: FormatOptions, -} - -#[derive(Clone, Encodable, Decodable, 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, - /// What kind of position this is. See [`FormatArgPositionKind`]. - pub kind: FormatArgPositionKind, - /// The span of the name or number. - pub span: Option, -} - -#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)] -pub enum FormatArgPositionKind { - /// `{}` or `{:.*}` - Implicit, - /// `{1}` or `{:1$}` or `{:.1$}` - Number, - /// `{a}` or `{:a$}` or `{:.a$}` - Named, -} - -#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq, Hash)] -pub enum FormatTrait { - /// `{}` - Display, - /// `{:?}` - Debug, - /// `{:e}` - LowerExp, - /// `{:E}` - UpperExp, - /// `{:o}` - Octal, - /// `{:p}` - Pointer, - /// `{:b}` - Binary, - /// `{:x}` - LowerHex, - /// `{:X}` - UpperHex, -} - -#[derive(Clone, Encodable, Decodable, Default, Debug, PartialEq, Eq)] -pub struct FormatOptions { - /// The width. E.g. `{:5}` or `{:width$}`. - pub width: Option, - /// The precision. E.g. `{:.5}` or `{:.precision$}`. - pub precision: Option, - /// The alignment. E.g. `{:>}` or `{:<}` or `{:^}`. - pub alignment: Option, - /// The fill character. E.g. the `.` in `{:.>10}`. - pub fill: Option, - /// The `+` or `-` flag. - pub sign: Option, - /// The `#` flag. - pub alternate: bool, - /// The `0` flag. E.g. the `0` in `{:02x}`. - pub zero_pad: bool, - /// The `x` or `X` flag (for `Debug` only). E.g. the `x` in `{:x?}`. - pub debug_hex: Option, -} - -#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)] -pub enum FormatSign { - /// The `+` flag. - Plus, - /// The `-` flag. - Minus, -} - -#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)] -pub enum FormatDebugHex { - /// The `x` flag in `{:x?}`. - Lower, - /// The `X` flag in `{:X?}`. - Upper, -} - -#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)] -pub enum FormatAlignment { - /// `{:<}` - Left, - /// `{:>}` - Right, - /// `{:^}` - Center, -} - -#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)] -pub enum FormatCount { - /// `{:5}` or `{:.5}` - Literal(usize), - /// `{:.*}`, `{:.5$}`, or `{:a$}`, etc. - Argument(FormatArgPosition), -} +use crate::ptr::P;use crate::Expr;use rustc_data_structures::fx::FxHashMap;use// +rustc_span::symbol::{Ident,Symbol};use rustc_span::Span;#[derive(Clone,//*&*&(); +Encodable,Decodable,Debug)]pub struct FormatArgs {pub span:Span,pub template:Vec +,pub arguments:FormatArguments,}#[derive(Clone,Encodable,//{;}; +Decodable,Debug)]pub enum FormatArgsPiece{Literal(Symbol),Placeholder(//((),()); +FormatPlaceholder),}#[derive(Clone,Encodable,Decodable,Debug)]pub struct//{();}; +FormatArguments{arguments:Vec,num_unnamed_args:usize,//let _=(); +num_explicit_args:usize,names:FxHashMap,}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{3;let index=self.arguments.len();3;if let Some(name)=arg. +kind.ident(){;self.names.insert(name.name,index);}else if self.names.is_empty(){ +self.num_unnamed_args+=1;;}if!matches!(arg.kind,FormatArgumentKind::Captured(..) +){let _=||();loop{break};assert_eq!(self.num_explicit_args,self.arguments.len(), +"captured arguments must be added last");3;3;self.num_explicit_args+=1;3;};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&[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 all_args(&self) ->&[FormatArgument]{&self.arguments[.. +]}pub fn all_args_mut(&mut self)-> &mut Vec{&mut self.arguments} +}#[derive(Clone,Encodable,Decodable,Debug)]pub struct FormatArgument{pub kind:// +FormatArgumentKind,pub expr:P,} #[derive(Clone,Encodable,Decodable,Debug)] +pub enum FormatArgumentKind{Normal,Named(Ident),Captured(Ident),}impl//let _=(); +FormatArgumentKind{pub fn ident(&self)->Option{match self{&Self::Normal// +=>None,&Self::Named(id)=>(Some(id)),&Self::Captured(id)=>(Some(id)),}}}#[derive( +Clone,Encodable,Decodable,Debug,PartialEq,Eq)]pub struct FormatPlaceholder{pub// +argument:FormatArgPosition,pub span:Option,pub format_trait:FormatTrait,// +pub format_options:FormatOptions,}#[derive(Clone,Encodable,Decodable,Debug,//(); +PartialEq,Eq)]pub struct FormatArgPosition{pub index:Result,pub//3; +kind:FormatArgPositionKind,pub span:Option,}#[derive(Copy,Clone,Encodable +,Decodable,Debug,PartialEq,Eq)]pub enum FormatArgPositionKind{Implicit,Number,// +Named,}#[derive(Copy,Clone,Encodable,Decodable,Debug,PartialEq,Eq,Hash)]pub//(); +enum FormatTrait{Display,Debug,LowerExp, UpperExp,Octal,Pointer,Binary,LowerHex, +UpperHex,}#[derive(Clone,Encodable,Decodable,Default,Debug,PartialEq,Eq)]pub//3; +struct FormatOptions{pub width:Option,pub precision:Option,pub alignment:Option,pub fill:Option,pub//3; +sign:Option,pub alternate:bool,pub zero_pad:bool,pub debug_hex://(); +Option,}#[derive( Copy,Clone,Encodable,Decodable,Debug,PartialEq +,Eq)]pub enum FormatSign{Plus,Minus,}#[derive(Copy,Clone,Encodable,Decodable,//; +Debug,PartialEq,Eq)]pub enum FormatDebugHex{Lower,Upper,}#[derive(Copy,Clone,//; +Encodable,Decodable,Debug,PartialEq,Eq)]pub enum FormatAlignment{Left,Right,//3; +Center,}#[derive(Clone,Encodable,Decodable,Debug,PartialEq,Eq)]pub enum//*&*&(); +FormatCount{Literal(usize),Argument(FormatArgPosition),}//let _=||();let _=||(); diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 4f21ff4152909..892e1e849f3a4 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -1,67 +1,17 @@ -//! The Rust Abstract Syntax Tree (AST). -//! -//! # Note -//! -//! This API is completely unstable and subject to change. - -#![doc( - html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", - test(attr(deny(warnings))) -)] -#![doc(rust_logo)] -#![allow(internal_features)] -#![feature(rustdoc_internals)] -#![cfg_attr(bootstrap, feature(associated_type_bounds))] -#![feature(associated_type_defaults)] -#![feature(box_patterns)] -#![feature(if_let_guard)] -#![feature(let_chains)] -#![feature(never_type)] -#![feature(negative_impls)] -#![feature(stmt_expr_attributes)] - -#[macro_use] -extern crate rustc_macros; - -#[macro_use] -extern crate tracing; - -pub mod util { - pub mod case; - pub mod classify; - pub mod comments; - pub mod literal; - pub mod parser; - pub mod unicode; -} - -pub mod ast; -pub mod ast_traits; -pub mod attr; -pub mod entry; -pub mod expand; -pub mod format; -pub mod mut_visit; -pub mod node_id; -pub mod ptr; -pub mod token; -pub mod tokenstream; -pub mod visit; - -pub use self::ast::*; -pub use self::ast_traits::{AstDeref, AstNodeWrapper, HasAttrs, HasNodeId, HasSpan, HasTokens}; - -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; - -/// Requirements for a `StableHashingContext` to be used in this crate. -/// This is a hack to allow using the `HashStable_Generic` derive macro -/// instead of implementing everything in `rustc_middle`. -pub trait HashStableContext: rustc_span::HashStableContext { - fn hash_attr(&mut self, _: &ast::Attribute, hasher: &mut StableHasher); -} - -impl HashStable for ast::Attribute { - fn hash_stable(&self, hcx: &mut AstCtx, hasher: &mut StableHasher) { - hcx.hash_attr(self, hasher) - } -} +#![doc(html_root_url="https://doc.rust-lang.org/nightly/nightly-rustc/",test(//; +attr(deny(warnings))))]#![doc( rust_logo)]#![allow(internal_features)]#![feature +(rustdoc_internals)]#![cfg_attr(bootstrap,feature(associated_type_bounds))]#![// +feature(associated_type_defaults)]#![feature(box_patterns)]#![feature(//((),()); +if_let_guard)]#![feature(let_chains)]#![feature(never_type)]#![feature(//*&*&(); +negative_impls)]#![feature(stmt_expr_attributes)]#[macro_use]extern crate//({}); +rustc_macros;#[macro_use]extern crate tracing;pub mod util{pub mod case;pub mod +classify;pub mod comments;pub mod literal;pub mod parser;pub mod unicode;}pub//; +mod ast;pub mod ast_traits;pub mod attr;pub mod entry;pub mod expand;pub mod//3; +format;pub mod mut_visit;pub mod node_id;pub mod ptr;pub mod token;pub mod//{;}; +tokenstream;pub mod visit;pub use self::ast::*;pub use self::ast_traits::{//{;}; +AstDeref,AstNodeWrapper,HasAttrs,HasNodeId,HasSpan,HasTokens};use//loop{break;}; +rustc_data_structures::stable_hasher::{HashStable,StableHasher};pub trait//({}); +HashStableContext:rustc_span::HashStableContext{fn hash_attr( &mut self,_:&ast:: +Attribute,hasher:&mut StableHasher);}impl//{;}; +HashStablefor ast::Attribute{fn hash_stable(&self,hcx:&mut AstCtx,//{;}; +hasher:&mut StableHasher){(((((((((((((hcx.hash_attr(self,hasher))))))))))))))}} diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 7337b969242c5..145bfa2f2533b 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1,1703 +1,517 @@ -//! A `MutVisitor` represents an AST modification; it accepts an AST piece and -//! mutates it in place. So, for instance, macro expansion is a `MutVisitor` -//! that walks over an AST and modifies it. -//! -//! Note: using a `MutVisitor` (other than the `MacroExpander` `MutVisitor`) on -//! an AST before macro expansion is probably a bad idea. For instance, -//! a `MutVisitor` renaming item names in a module will miss all of those -//! that are created by the expansion of a macro. - -use crate::ast::*; -use crate::ptr::P; -use crate::token::{self, Token}; -use crate::tokenstream::*; - -use rustc_data_structures::flat_map_in_place::FlatMapInPlace; -use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_data_structures::sync::Lrc; -use rustc_span::source_map::Spanned; -use rustc_span::symbol::Ident; -use rustc_span::Span; -use smallvec::{smallvec, Array, SmallVec}; -use std::ops::DerefMut; -use std::{panic, ptr}; -use thin_vec::ThinVec; - -pub trait ExpectOne { - fn expect_one(self, err: &'static str) -> A::Item; -} - -impl ExpectOne for SmallVec { - fn expect_one(self, err: &'static str) -> A::Item { - assert!(self.len() == 1, "{}", err); - self.into_iter().next().unwrap() - } -} - -pub trait MutVisitor: Sized { - /// Mutable token visiting only exists for the `macro_rules` token marker and should not be - /// used otherwise. Token visitor would be entirely separate from the regular visitor if - /// the marker didn't have to visit AST fragments in nonterminal tokens. - const VISIT_TOKENS: bool = false; - - // Methods in this trait have one of three forms: - // - // fn visit_t(&mut self, t: &mut T); // common - // fn flat_map_t(&mut self, t: T) -> SmallVec<[T; 1]>; // rare - // fn filter_map_t(&mut self, t: T) -> Option; // rarest - // - // Any additions to this trait should happen in form of a call to a public - // `noop_*` function that only calls out to the visitor again, not other - // `noop_*` functions. This is a necessary API workaround to the problem of - // not being able to call out to the super default method in an overridden - // default method. - // - // When writing these methods, it is better to use destructuring like this: - // - // fn visit_abc(&mut self, ABC { a, b, c: _ }: &mut ABC) { - // visit_a(a); - // visit_b(b); - // } - // - // than to use field access like this: - // - // fn visit_abc(&mut self, abc: &mut ABC) { - // visit_a(&mut abc.a); - // visit_b(&mut abc.b); - // // ignore abc.c - // } - // - // As well as being more concise, the former is explicit about which fields - // are skipped. Furthermore, if a new field is added, the destructuring - // version will cause a compile error, which is good. In comparison, the - // field access version will continue working and it would be easy to - // forget to add handling for it. - - fn visit_crate(&mut self, c: &mut Crate) { - noop_visit_crate(c, self) - } - - fn visit_meta_list_item(&mut self, list_item: &mut NestedMetaItem) { - noop_visit_meta_list_item(list_item, self); - } - - fn visit_meta_item(&mut self, meta_item: &mut MetaItem) { - noop_visit_meta_item(meta_item, self); - } - - fn visit_use_tree(&mut self, use_tree: &mut UseTree) { - noop_visit_use_tree(use_tree, self); - } - - fn flat_map_foreign_item(&mut self, ni: P) -> SmallVec<[P; 1]> { - noop_flat_map_foreign_item(ni, self) - } - - fn flat_map_item(&mut self, i: P) -> SmallVec<[P; 1]> { - noop_flat_map_item(i, self) - } - - fn visit_fn_header(&mut self, header: &mut FnHeader) { - noop_visit_fn_header(header, self); - } - - fn flat_map_field_def(&mut self, fd: FieldDef) -> SmallVec<[FieldDef; 1]> { - noop_flat_map_field_def(fd, self) - } - - fn visit_item_kind(&mut self, i: &mut ItemKind) { - noop_visit_item_kind(i, self); - } - - fn flat_map_trait_item(&mut self, i: P) -> SmallVec<[P; 1]> { - noop_flat_map_assoc_item(i, self) - } - - fn flat_map_impl_item(&mut self, i: P) -> SmallVec<[P; 1]> { - noop_flat_map_assoc_item(i, self) - } - - fn visit_fn_decl(&mut self, d: &mut P) { - noop_visit_fn_decl(d, self); - } - - fn visit_coroutine_kind(&mut self, a: &mut CoroutineKind) { - noop_visit_coroutine_kind(a, self); - } - - fn visit_closure_binder(&mut self, b: &mut ClosureBinder) { - noop_visit_closure_binder(b, self); - } - - fn visit_block(&mut self, b: &mut P) { - noop_visit_block(b, self); - } - - fn flat_map_stmt(&mut self, s: Stmt) -> SmallVec<[Stmt; 1]> { - noop_flat_map_stmt(s, self) - } - - fn flat_map_arm(&mut self, arm: Arm) -> SmallVec<[Arm; 1]> { - noop_flat_map_arm(arm, self) - } - - fn visit_pat(&mut self, p: &mut P) { - noop_visit_pat(p, self); - } - - fn visit_anon_const(&mut self, c: &mut AnonConst) { - noop_visit_anon_const(c, self); - } - - fn visit_expr(&mut self, e: &mut P) { - 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) { - self.visit_expr(ex) - } - - fn filter_map_expr(&mut self, e: P) -> Option> { - noop_filter_map_expr(e, self) - } - - fn visit_generic_arg(&mut self, arg: &mut GenericArg) { - noop_visit_generic_arg(arg, self); - } - - fn visit_ty(&mut self, t: &mut P) { - noop_visit_ty(t, self); - } - - fn visit_lifetime(&mut self, l: &mut Lifetime) { - noop_visit_lifetime(l, self); - } - - fn visit_constraint(&mut self, t: &mut AssocConstraint) { - noop_visit_constraint(t, self); - } - - fn visit_foreign_mod(&mut self, nm: &mut ForeignMod) { - noop_visit_foreign_mod(nm, self); - } - - fn flat_map_variant(&mut self, v: Variant) -> SmallVec<[Variant; 1]> { - noop_flat_map_variant(v, self) - } - - fn visit_ident(&mut self, i: &mut Ident) { - noop_visit_ident(i, self); - } - - fn visit_path(&mut self, p: &mut Path) { - noop_visit_path(p, self); - } - - fn visit_qself(&mut self, qs: &mut Option>) { - noop_visit_qself(qs, self); - } - - fn visit_generic_args(&mut self, p: &mut GenericArgs) { - noop_visit_generic_args(p, self); - } - - fn visit_angle_bracketed_parameter_data(&mut self, p: &mut AngleBracketedArgs) { - noop_visit_angle_bracketed_parameter_data(p, self); - } - - fn visit_parenthesized_parameter_data(&mut self, p: &mut ParenthesizedArgs) { - noop_visit_parenthesized_parameter_data(p, self); - } - - fn visit_local(&mut self, l: &mut P) { - noop_visit_local(l, self); - } - - fn visit_mac_call(&mut self, mac: &mut MacCall) { - noop_visit_mac(mac, self); - } - - fn visit_macro_def(&mut self, def: &mut MacroDef) { - noop_visit_macro_def(def, self); - } - - fn visit_label(&mut self, label: &mut Label) { - noop_visit_label(label, self); - } - - fn visit_attribute(&mut self, at: &mut Attribute) { - noop_visit_attribute(at, self); - } - - fn flat_map_param(&mut self, param: Param) -> SmallVec<[Param; 1]> { - noop_flat_map_param(param, self) - } - - fn visit_generics(&mut self, generics: &mut Generics) { - noop_visit_generics(generics, self); - } - - fn visit_trait_ref(&mut self, tr: &mut TraitRef) { - noop_visit_trait_ref(tr, self); - } - - fn visit_poly_trait_ref(&mut self, p: &mut PolyTraitRef) { - noop_visit_poly_trait_ref(p, self); - } - - fn visit_variant_data(&mut self, vdata: &mut VariantData) { - noop_visit_variant_data(vdata, self); - } - - fn flat_map_generic_param(&mut self, param: GenericParam) -> SmallVec<[GenericParam; 1]> { - noop_flat_map_generic_param(param, self) - } - - fn visit_param_bound(&mut self, tpb: &mut GenericBound) { - noop_visit_param_bound(tpb, self); - } - - fn visit_mt(&mut self, mt: &mut MutTy) { - noop_visit_mt(mt, self); - } - - fn flat_map_expr_field(&mut self, f: ExprField) -> SmallVec<[ExprField; 1]> { - noop_flat_map_expr_field(f, self) - } - - fn visit_where_clause(&mut self, where_clause: &mut WhereClause) { - noop_visit_where_clause(where_clause, self); - } - - fn visit_where_predicate(&mut self, where_predicate: &mut WherePredicate) { - noop_visit_where_predicate(where_predicate, self); - } - - fn visit_vis(&mut self, vis: &mut Visibility) { - noop_visit_vis(vis, self); - } - - fn visit_id(&mut self, _id: &mut NodeId) { - // Do nothing. - } - - fn visit_span(&mut self, _sp: &mut Span) { - // Do nothing. - } - - fn flat_map_pat_field(&mut self, fp: PatField) -> SmallVec<[PatField; 1]> { - noop_flat_map_pat_field(fp, self) - } - - fn visit_inline_asm(&mut self, asm: &mut InlineAsm) { - noop_visit_inline_asm(asm, self) - } - - fn visit_inline_asm_sym(&mut self, sym: &mut InlineAsmSym) { - noop_visit_inline_asm_sym(sym, self) - } - - fn visit_format_args(&mut self, fmt: &mut FormatArgs) { - noop_visit_format_args(fmt, self) - } - - fn visit_capture_by(&mut self, capture_by: &mut CaptureBy) { - noop_visit_capture_by(capture_by, self) - } -} - -/// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful -/// when using a `flat_map_*` or `filter_map_*` method within a `visit_` -/// method. -// -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_clobber(t: &mut T, f: impl FnOnce(T) -> T) { - unsafe { - // Safe because `t` is used in a read-only fashion by `read()` before - // being overwritten by `write()`. - let old_t = ptr::read(t); - let new_t = - panic::catch_unwind(panic::AssertUnwindSafe(|| f(old_t))).unwrap_or_else(|err| { - // Set `t` to some valid but possible meaningless value, - // and pass the fatal error further. - ptr::write(t, T::dummy()); - panic::resume_unwind(err); - }); - ptr::write(t, new_t); - } -} - -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -#[inline] -pub fn visit_vec(elems: &mut Vec, mut visit_elem: F) -where - F: FnMut(&mut T), -{ - for elem in elems { - visit_elem(elem); - } -} - -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -#[inline] -pub fn visit_thin_vec(elems: &mut ThinVec, mut visit_elem: F) -where - F: FnMut(&mut T), -{ - for elem in elems { - visit_elem(elem); - } -} - -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -#[inline] -pub fn visit_opt(opt: &mut Option, mut visit_elem: F) -where - F: FnMut(&mut T), -{ - if let Some(elem) = opt { - visit_elem(elem); - } -} - -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_attrs(attrs: &mut AttrVec, vis: &mut T) { - for attr in attrs.iter_mut() { - vis.visit_attribute(attr); - } -} - -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_exprs(exprs: &mut Vec>, vis: &mut T) { - exprs.flat_map_in_place(|expr| vis.filter_map_expr(expr)) -} - -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_thin_exprs(exprs: &mut ThinVec>, vis: &mut T) { - exprs.flat_map_in_place(|expr| vis.filter_map_expr(expr)) -} - -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_bounds(bounds: &mut GenericBounds, vis: &mut T) { - visit_vec(bounds, |bound| vis.visit_param_bound(bound)); -} - -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_fn_sig(FnSig { header, decl, span }: &mut FnSig, vis: &mut T) { - vis.visit_fn_header(header); - vis.visit_fn_decl(decl); - vis.visit_span(span); -} - -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_attr_args(args: &mut AttrArgs, vis: &mut T) { - match args { - AttrArgs::Empty => {} - AttrArgs::Delimited(args) => visit_delim_args(args, vis), - AttrArgs::Eq(eq_span, AttrArgsEq::Ast(expr)) => { - vis.visit_span(eq_span); - vis.visit_expr(expr); - } - AttrArgs::Eq(_, AttrArgsEq::Hir(lit)) => { - unreachable!("in literal form when visiting mac args eq: {:?}", lit) - } - } -} - -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_delim_args(args: &mut DelimArgs, vis: &mut T) { - let DelimArgs { dspan, delim: _, tokens } = args; - visit_delim_span(dspan, vis); - visit_tts(tokens, vis); -} - -pub fn visit_delim_span(dspan: &mut DelimSpan, vis: &mut T) { - vis.visit_span(&mut dspan.open); - vis.visit_span(&mut dspan.close); -} - -pub fn noop_flat_map_pat_field( - mut fp: PatField, - vis: &mut T, -) -> SmallVec<[PatField; 1]> { - let PatField { attrs, id, ident, is_placeholder: _, is_shorthand: _, pat, span } = &mut fp; - vis.visit_id(id); - vis.visit_ident(ident); - vis.visit_pat(pat); - vis.visit_span(span); - visit_attrs(attrs, vis); - smallvec![fp] -} - -pub fn noop_visit_use_tree(use_tree: &mut UseTree, vis: &mut T) { - let UseTree { prefix, kind, span } = use_tree; - vis.visit_path(prefix); - match kind { - UseTreeKind::Simple(rename) => visit_opt(rename, |rename| vis.visit_ident(rename)), - UseTreeKind::Nested(items) => { - for (tree, id) in items { - vis.visit_use_tree(tree); - vis.visit_id(id); - } - } - UseTreeKind::Glob => {} - } - vis.visit_span(span); -} - -pub fn noop_flat_map_arm(mut arm: Arm, vis: &mut T) -> SmallVec<[Arm; 1]> { - let Arm { attrs, pat, guard, body, span, id, is_placeholder: _ } = &mut arm; - visit_attrs(attrs, vis); - vis.visit_id(id); - vis.visit_pat(pat); - visit_opt(guard, |guard| vis.visit_expr(guard)); - visit_opt(body, |body| vis.visit_expr(body)); - vis.visit_span(span); - smallvec![arm] -} - -pub fn noop_visit_constraint( - AssocConstraint { id, ident, gen_args, kind, span }: &mut AssocConstraint, - vis: &mut T, -) { - vis.visit_id(id); - vis.visit_ident(ident); - if let Some(gen_args) = gen_args { - vis.visit_generic_args(gen_args); - } - match kind { - AssocConstraintKind::Equality { term } => match term { - Term::Ty(ty) => vis.visit_ty(ty), - Term::Const(c) => vis.visit_anon_const(c), - }, - AssocConstraintKind::Bound { bounds } => visit_bounds(bounds, vis), - } - vis.visit_span(span); -} - -pub fn noop_visit_ty(ty: &mut P, vis: &mut T) { - let Ty { id, kind, span, tokens } = ty.deref_mut(); - vis.visit_id(id); - match kind { - TyKind::Infer - | TyKind::ImplicitSelf - | TyKind::Err(_) - | TyKind::Dummy - | TyKind::Never - | TyKind::CVarArgs => {} - TyKind::Slice(ty) => vis.visit_ty(ty), - TyKind::Ptr(mt) => vis.visit_mt(mt), - TyKind::Ref(lt, mt) => { - visit_opt(lt, |lt| noop_visit_lifetime(lt, vis)); - vis.visit_mt(mt); - } - TyKind::BareFn(bft) => { - let BareFnTy { unsafety, ext: _, generic_params, decl, decl_span } = bft.deref_mut(); - visit_unsafety(unsafety, vis); - generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); - vis.visit_fn_decl(decl); - vis.visit_span(decl_span); - } - TyKind::Tup(tys) => visit_thin_vec(tys, |ty| vis.visit_ty(ty)), - TyKind::Paren(ty) => vis.visit_ty(ty), - TyKind::Path(qself, path) => { - vis.visit_qself(qself); - vis.visit_path(path); - } - TyKind::Array(ty, length) => { - vis.visit_ty(ty); - vis.visit_anon_const(length); - } - TyKind::Typeof(expr) => vis.visit_anon_const(expr), - TyKind::TraitObject(bounds, _syntax) => { - visit_vec(bounds, |bound| vis.visit_param_bound(bound)) - } - TyKind::ImplTrait(id, bounds) => { - vis.visit_id(id); - visit_vec(bounds, |bound| vis.visit_param_bound(bound)); - } - TyKind::MacCall(mac) => vis.visit_mac_call(mac), - TyKind::AnonStruct(id, fields) | TyKind::AnonUnion(id, fields) => { - vis.visit_id(id); - fields.flat_map_in_place(|field| vis.flat_map_field_def(field)); - } - } - vis.visit_span(span); - visit_lazy_tts(tokens, vis); -} - -pub fn noop_visit_foreign_mod(foreign_mod: &mut ForeignMod, vis: &mut T) { - let ForeignMod { unsafety, abi: _, items } = foreign_mod; - visit_unsafety(unsafety, vis); - items.flat_map_in_place(|item| vis.flat_map_foreign_item(item)); -} - -pub fn noop_flat_map_variant( - mut variant: Variant, - visitor: &mut T, -) -> SmallVec<[Variant; 1]> { - let Variant { ident, vis, attrs, id, data, disr_expr, span, is_placeholder: _ } = &mut variant; - visitor.visit_ident(ident); - visitor.visit_vis(vis); - visit_attrs(attrs, visitor); - visitor.visit_id(id); - visitor.visit_variant_data(data); - visit_opt(disr_expr, |disr_expr| visitor.visit_anon_const(disr_expr)); - visitor.visit_span(span); - smallvec![variant] -} - -pub fn noop_visit_ident(Ident { name: _, span }: &mut Ident, vis: &mut T) { - vis.visit_span(span); -} - -pub fn noop_visit_path(Path { segments, span, tokens }: &mut Path, vis: &mut T) { - vis.visit_span(span); - for PathSegment { ident, id, args } in segments { - vis.visit_ident(ident); - vis.visit_id(id); - visit_opt(args, |args| vis.visit_generic_args(args)); - } - visit_lazy_tts(tokens, vis); -} - -pub fn noop_visit_qself(qself: &mut Option>, vis: &mut T) { - visit_opt(qself, |qself| { - let QSelf { ty, path_span, position: _ } = &mut **qself; - vis.visit_ty(ty); - vis.visit_span(path_span); - }) -} - -pub fn noop_visit_generic_args(generic_args: &mut GenericArgs, vis: &mut T) { - match generic_args { - GenericArgs::AngleBracketed(data) => vis.visit_angle_bracketed_parameter_data(data), - GenericArgs::Parenthesized(data) => vis.visit_parenthesized_parameter_data(data), - } -} - -pub fn noop_visit_generic_arg(arg: &mut GenericArg, vis: &mut T) { - match arg { - GenericArg::Lifetime(lt) => vis.visit_lifetime(lt), - GenericArg::Type(ty) => vis.visit_ty(ty), - GenericArg::Const(ct) => vis.visit_anon_const(ct), - } -} - -pub fn noop_visit_angle_bracketed_parameter_data( - data: &mut AngleBracketedArgs, - vis: &mut T, -) { - let AngleBracketedArgs { args, span } = data; - visit_thin_vec(args, |arg| match arg { - AngleBracketedArg::Arg(arg) => vis.visit_generic_arg(arg), - AngleBracketedArg::Constraint(constraint) => vis.visit_constraint(constraint), - }); - vis.visit_span(span); -} - -pub fn noop_visit_parenthesized_parameter_data( - args: &mut ParenthesizedArgs, - vis: &mut T, -) { - let ParenthesizedArgs { inputs, output, span, .. } = args; - visit_thin_vec(inputs, |input| vis.visit_ty(input)); - noop_visit_fn_ret_ty(output, vis); - vis.visit_span(span); -} - -pub fn noop_visit_local(local: &mut P, vis: &mut T) { - let Local { id, pat, ty, kind, span, colon_sp, attrs, tokens } = local.deref_mut(); - vis.visit_id(id); - vis.visit_pat(pat); - visit_opt(ty, |ty| vis.visit_ty(ty)); - match kind { - LocalKind::Decl => {} - LocalKind::Init(init) => { - vis.visit_expr(init); - } - LocalKind::InitElse(init, els) => { - vis.visit_expr(init); - vis.visit_block(els); - } - } - vis.visit_span(span); - visit_opt(colon_sp, |sp| vis.visit_span(sp)); - visit_attrs(attrs, vis); - visit_lazy_tts(tokens, vis); -} - -pub fn noop_visit_attribute(attr: &mut Attribute, vis: &mut T) { - let Attribute { kind, id: _, style: _, span } = attr; - match kind { - AttrKind::Normal(normal) => { - let NormalAttr { item: AttrItem { path, args, tokens }, tokens: attr_tokens } = - &mut **normal; - vis.visit_path(path); - visit_attr_args(args, vis); - visit_lazy_tts(tokens, vis); - visit_lazy_tts(attr_tokens, vis); - } - AttrKind::DocComment(..) => {} - } - vis.visit_span(span); -} - -pub fn noop_visit_mac(mac: &mut MacCall, vis: &mut T) { - let MacCall { path, args } = mac; - vis.visit_path(path); - visit_delim_args(args, vis); -} - -pub fn noop_visit_macro_def(macro_def: &mut MacroDef, vis: &mut T) { - let MacroDef { body, macro_rules: _ } = macro_def; - visit_delim_args(body, vis); -} - -pub fn noop_visit_meta_list_item(li: &mut NestedMetaItem, vis: &mut T) { - match li { - NestedMetaItem::MetaItem(mi) => vis.visit_meta_item(mi), - NestedMetaItem::Lit(_lit) => {} - } -} - -pub fn noop_visit_meta_item(mi: &mut MetaItem, vis: &mut T) { - let MetaItem { path: _, kind, span } = mi; - match kind { - MetaItemKind::Word => {} - MetaItemKind::List(mis) => visit_thin_vec(mis, |mi| vis.visit_meta_list_item(mi)), - MetaItemKind::NameValue(_s) => {} - } - vis.visit_span(span); -} - -pub fn noop_flat_map_param(mut param: Param, vis: &mut T) -> SmallVec<[Param; 1]> { - let Param { attrs, id, pat, span, ty, is_placeholder: _ } = &mut param; - vis.visit_id(id); - visit_attrs(attrs, vis); - vis.visit_pat(pat); - vis.visit_span(span); - vis.visit_ty(ty); - smallvec![param] -} - -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_attr_tt(tt: &mut AttrTokenTree, vis: &mut T) { - match tt { - AttrTokenTree::Token(token, _) => { - visit_token(token, vis); - } - AttrTokenTree::Delimited(DelimSpan { open, close }, _spacing, _delim, tts) => { - vis.visit_span(open); - vis.visit_span(close); - visit_attr_tts(tts, vis); - } - AttrTokenTree::Attributes(data) => { - for attr in &mut *data.attrs { - match &mut attr.kind { - AttrKind::Normal(normal) => { - visit_lazy_tts(&mut normal.tokens, vis); - } - AttrKind::DocComment(..) => { - vis.visit_span(&mut attr.span); - } - } - } - visit_lazy_tts_opt_mut(Some(&mut data.tokens), vis); - } - } -} - -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_tt(tt: &mut TokenTree, vis: &mut T) { - match tt { - TokenTree::Token(token, _) => { - visit_token(token, vis); - } - TokenTree::Delimited(DelimSpan { open, close }, _spacing, _delim, tts) => { - vis.visit_span(open); - vis.visit_span(close); - visit_tts(tts, vis); - } - } -} - -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_tts(TokenStream(tts): &mut TokenStream, vis: &mut T) { - if T::VISIT_TOKENS && !tts.is_empty() { - let tts = Lrc::make_mut(tts); - visit_vec(tts, |tree| visit_tt(tree, vis)); - } -} - -pub fn visit_attr_tts(AttrTokenStream(tts): &mut AttrTokenStream, vis: &mut T) { - if T::VISIT_TOKENS && !tts.is_empty() { - let tts = Lrc::make_mut(tts); - visit_vec(tts, |tree| visit_attr_tt(tree, vis)); - } -} - -pub fn visit_lazy_tts_opt_mut( - lazy_tts: Option<&mut LazyAttrTokenStream>, - vis: &mut T, -) { - if T::VISIT_TOKENS { - if let Some(lazy_tts) = lazy_tts { - let mut tts = lazy_tts.to_attr_token_stream(); - visit_attr_tts(&mut tts, vis); - *lazy_tts = LazyAttrTokenStream::new(tts); - } - } -} - -pub fn visit_lazy_tts(lazy_tts: &mut Option, vis: &mut T) { - visit_lazy_tts_opt_mut(lazy_tts.as_mut(), vis); -} - -/// Applies ident visitor if it's an ident; applies other visits to interpolated nodes. -/// In practice the ident part is not actually used by specific visitors right now, -/// but there's a test below checking that it works. -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_token(t: &mut Token, vis: &mut T) { - let Token { kind, span } = t; - match kind { - token::Ident(name, _) | token::Lifetime(name) => { - let mut ident = Ident::new(*name, *span); - vis.visit_ident(&mut ident); - *name = ident.name; - *span = ident.span; - return; // Avoid visiting the span for the second time. - } - token::Interpolated(nt) => { - let nt = Lrc::make_mut(nt); - let (nt, sp) = (&mut nt.0, &mut nt.1); - vis.visit_span(sp); - visit_nonterminal(nt, vis); - } - _ => {} - } - vis.visit_span(span); -} - -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -/// Applies the visitor to elements of interpolated nodes. -// -// N.B., this can occur only when applying a visitor to partially expanded -// code, where parsed pieces have gotten implanted ito *other* macro -// invocations. This is relevant for macro hygiene, but possibly not elsewhere. -// -// One problem here occurs because the types for flat_map_item, flat_map_stmt, -// etc., allow the visitor to return *multiple* items; this is a problem for the -// nodes here, because they insist on having exactly one piece. One solution -// would be to mangle the MutVisitor trait to include one-to-many and -// one-to-one versions of these entry points, but that would probably confuse a -// lot of people and help very few. Instead, I'm just going to put in dynamic -// checks. I think the performance impact of this will be pretty much -// nonexistent. The danger is that someone will apply a `MutVisitor` to a -// partially expanded node, and will be confused by the fact that their -// `flat_map_item` or `flat_map_stmt` isn't getting called on `NtItem` or `NtStmt` -// nodes. Hopefully they'll wind up reading this comment, and doing something -// appropriate. -// -// BTW, design choice: I considered just changing the type of, e.g., `NtItem` to -// contain multiple items, but decided against it when I looked at -// `parse_item_or_view_item` and tried to figure out what I would do with -// multiple items there.... -pub fn visit_nonterminal(nt: &mut token::Nonterminal, vis: &mut T) { - match nt { - token::NtItem(item) => visit_clobber(item, |item| { - // This is probably okay, because the only visitors likely to - // peek inside interpolated nodes will be renamings/markings, - // which map single items to single items. - vis.flat_map_item(item).expect_one("expected visitor to produce exactly one item") - }), - token::NtBlock(block) => vis.visit_block(block), - token::NtStmt(stmt) => visit_clobber(stmt, |stmt| { - // See reasoning above. - stmt.map(|stmt| { - vis.flat_map_stmt(stmt).expect_one("expected visitor to produce exactly one item") - }) - }), - token::NtPat(pat) => vis.visit_pat(pat), - token::NtExpr(expr) => vis.visit_expr(expr), - token::NtTy(ty) => vis.visit_ty(ty), - token::NtIdent(ident, _is_raw) => vis.visit_ident(ident), - token::NtLifetime(ident) => vis.visit_ident(ident), - token::NtLiteral(expr) => vis.visit_expr(expr), - token::NtMeta(item) => { - let AttrItem { path, args, tokens } = item.deref_mut(); - vis.visit_path(path); - visit_attr_args(args, vis); - visit_lazy_tts(tokens, vis); - } - token::NtPath(path) => vis.visit_path(path), - token::NtVis(visib) => vis.visit_vis(visib), - } -} - -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_defaultness(defaultness: &mut Defaultness, vis: &mut T) { - match defaultness { - Defaultness::Default(span) => vis.visit_span(span), - Defaultness::Final => {} - } -} - -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_unsafety(unsafety: &mut Unsafe, vis: &mut T) { - match unsafety { - Unsafe::Yes(span) => vis.visit_span(span), - Unsafe::No => {} - } -} - -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_polarity(polarity: &mut ImplPolarity, vis: &mut T) { - match polarity { - ImplPolarity::Positive => {} - ImplPolarity::Negative(span) => vis.visit_span(span), - } -} - -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_constness(constness: &mut Const, vis: &mut T) { - match constness { - Const::Yes(span) => vis.visit_span(span), - Const::No => {} - } -} - -pub fn noop_visit_closure_binder(binder: &mut ClosureBinder, vis: &mut T) { - match binder { - ClosureBinder::NotPresent => {} - ClosureBinder::For { span: _, generic_params } => { - generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); - } - } -} - -pub fn noop_visit_coroutine_kind(coroutine_kind: &mut CoroutineKind, vis: &mut T) { - match coroutine_kind { - CoroutineKind::Async { span, closure_id, return_impl_trait_id } - | CoroutineKind::Gen { span, closure_id, return_impl_trait_id } - | CoroutineKind::AsyncGen { span, closure_id, return_impl_trait_id } => { - vis.visit_span(span); - vis.visit_id(closure_id); - vis.visit_id(return_impl_trait_id); - } - } -} - -pub fn noop_visit_fn_decl(decl: &mut P, vis: &mut T) { - let FnDecl { inputs, output } = decl.deref_mut(); - inputs.flat_map_in_place(|param| vis.flat_map_param(param)); - noop_visit_fn_ret_ty(output, vis); -} - -pub fn noop_visit_fn_ret_ty(fn_ret_ty: &mut FnRetTy, vis: &mut T) { - match fn_ret_ty { - FnRetTy::Default(span) => vis.visit_span(span), - FnRetTy::Ty(ty) => vis.visit_ty(ty), - } -} - -pub fn noop_visit_param_bound(pb: &mut GenericBound, vis: &mut T) { - match pb { - GenericBound::Trait(ty, _modifier) => vis.visit_poly_trait_ref(ty), - GenericBound::Outlives(lifetime) => noop_visit_lifetime(lifetime, vis), - } -} - -pub fn noop_flat_map_generic_param( - mut param: GenericParam, - vis: &mut T, -) -> SmallVec<[GenericParam; 1]> { - let GenericParam { id, ident, attrs, bounds, kind, colon_span, is_placeholder: _ } = &mut param; - vis.visit_id(id); - vis.visit_ident(ident); - if let Some(colon_span) = colon_span { - vis.visit_span(colon_span); - } - visit_attrs(attrs, vis); - visit_vec(bounds, |bound| noop_visit_param_bound(bound, vis)); - match kind { - GenericParamKind::Lifetime => {} - GenericParamKind::Type { default } => { - visit_opt(default, |default| vis.visit_ty(default)); - } - GenericParamKind::Const { ty, kw_span: _, default } => { - vis.visit_ty(ty); - visit_opt(default, |default| vis.visit_anon_const(default)); - } - } - smallvec![param] -} - -pub fn noop_visit_label(Label { ident }: &mut Label, vis: &mut T) { - vis.visit_ident(ident); -} - -fn noop_visit_lifetime(Lifetime { id, ident }: &mut Lifetime, vis: &mut T) { - vis.visit_id(id); - vis.visit_ident(ident); -} - -pub fn noop_visit_generics(generics: &mut Generics, vis: &mut T) { - let Generics { params, where_clause, span } = generics; - params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); - vis.visit_where_clause(where_clause); - vis.visit_span(span); -} - -pub fn noop_visit_where_clause(wc: &mut WhereClause, vis: &mut T) { - let WhereClause { has_where_token: _, predicates, span } = wc; - visit_thin_vec(predicates, |predicate| vis.visit_where_predicate(predicate)); - vis.visit_span(span); -} - -pub fn noop_visit_where_predicate(pred: &mut WherePredicate, vis: &mut T) { - match pred { - WherePredicate::BoundPredicate(bp) => { - let WhereBoundPredicate { span, bound_generic_params, bounded_ty, bounds } = bp; - vis.visit_span(span); - bound_generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); - vis.visit_ty(bounded_ty); - visit_vec(bounds, |bound| vis.visit_param_bound(bound)); - } - WherePredicate::RegionPredicate(rp) => { - let WhereRegionPredicate { span, lifetime, bounds } = rp; - vis.visit_span(span); - noop_visit_lifetime(lifetime, vis); - visit_vec(bounds, |bound| noop_visit_param_bound(bound, vis)); - } - WherePredicate::EqPredicate(ep) => { - let WhereEqPredicate { span, lhs_ty, rhs_ty } = ep; - vis.visit_span(span); - vis.visit_ty(lhs_ty); - vis.visit_ty(rhs_ty); - } - } -} - -pub fn noop_visit_variant_data(vdata: &mut VariantData, vis: &mut T) { - match vdata { - VariantData::Struct { fields, .. } => { - fields.flat_map_in_place(|field| vis.flat_map_field_def(field)); - } - VariantData::Tuple(fields, id) => { - fields.flat_map_in_place(|field| vis.flat_map_field_def(field)); - vis.visit_id(id); - } - VariantData::Unit(id) => vis.visit_id(id), - } -} - -pub fn noop_visit_trait_ref(TraitRef { path, ref_id }: &mut TraitRef, vis: &mut T) { - vis.visit_path(path); - vis.visit_id(ref_id); -} - -pub fn noop_visit_poly_trait_ref(p: &mut PolyTraitRef, vis: &mut T) { - let PolyTraitRef { bound_generic_params, trait_ref, span } = p; - bound_generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); - vis.visit_trait_ref(trait_ref); - vis.visit_span(span); -} - -pub fn noop_flat_map_field_def( - mut fd: FieldDef, - visitor: &mut T, -) -> SmallVec<[FieldDef; 1]> { - let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _ } = &mut fd; - visitor.visit_span(span); - visit_opt(ident, |ident| visitor.visit_ident(ident)); - visitor.visit_vis(vis); - visitor.visit_id(id); - visitor.visit_ty(ty); - visit_attrs(attrs, visitor); - smallvec![fd] -} - -pub fn noop_flat_map_expr_field( - mut f: ExprField, - vis: &mut T, -) -> SmallVec<[ExprField; 1]> { - let ExprField { ident, expr, span, is_shorthand: _, attrs, id, is_placeholder: _ } = &mut f; - vis.visit_ident(ident); - vis.visit_expr(expr); - vis.visit_id(id); - vis.visit_span(span); - visit_attrs(attrs, vis); - smallvec![f] -} - -pub fn noop_visit_mt(MutTy { ty, mutbl: _ }: &mut MutTy, vis: &mut T) { - vis.visit_ty(ty); -} - -pub fn noop_visit_block(block: &mut P, vis: &mut T) { - let Block { id, stmts, rules: _, span, tokens, could_be_bare_literal: _ } = block.deref_mut(); - vis.visit_id(id); - stmts.flat_map_in_place(|stmt| vis.flat_map_stmt(stmt)); - vis.visit_span(span); - visit_lazy_tts(tokens, vis); -} - -pub fn noop_visit_item_kind(kind: &mut ItemKind, vis: &mut T) { - match kind { - ItemKind::ExternCrate(_orig_name) => {} - ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree), - ItemKind::Static(box StaticItem { ty, mutability: _, expr }) => { - vis.visit_ty(ty); - visit_opt(expr, |expr| vis.visit_expr(expr)); - } - ItemKind::Const(item) => { - visit_const_item(item, vis); - } - ItemKind::Fn(box Fn { defaultness, generics, sig, body }) => { - visit_defaultness(defaultness, vis); - visit_fn_sig(sig, vis); - vis.visit_generics(generics); - visit_opt(body, |body| vis.visit_block(body)); - } - ItemKind::Mod(unsafety, mod_kind) => { - visit_unsafety(unsafety, vis); - match mod_kind { - ModKind::Loaded(items, _inline, ModSpans { inner_span, inject_use_span }) => { - vis.visit_span(inner_span); - vis.visit_span(inject_use_span); - items.flat_map_in_place(|item| vis.flat_map_item(item)); - } - ModKind::Unloaded => {} - } - } - ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm), - ItemKind::GlobalAsm(asm) => vis.visit_inline_asm(asm), - ItemKind::TyAlias(box TyAlias { - defaultness, generics, where_clauses, bounds, ty, .. - }) => { - visit_defaultness(defaultness, vis); - vis.visit_generics(generics); - vis.visit_span(&mut where_clauses.before.span); - vis.visit_span(&mut where_clauses.after.span); - visit_bounds(bounds, vis); - visit_opt(ty, |ty| vis.visit_ty(ty)); - } - ItemKind::Enum(EnumDef { variants }, generics) => { - variants.flat_map_in_place(|variant| vis.flat_map_variant(variant)); - vis.visit_generics(generics); - } - ItemKind::Struct(variant_data, generics) | ItemKind::Union(variant_data, generics) => { - vis.visit_variant_data(variant_data); - vis.visit_generics(generics); - } - ItemKind::Impl(box Impl { - defaultness, - unsafety, - generics, - constness, - polarity, - of_trait, - self_ty, - items, - }) => { - visit_defaultness(defaultness, vis); - visit_unsafety(unsafety, vis); - vis.visit_generics(generics); - visit_constness(constness, vis); - visit_polarity(polarity, vis); - visit_opt(of_trait, |trait_ref| vis.visit_trait_ref(trait_ref)); - vis.visit_ty(self_ty); - items.flat_map_in_place(|item| vis.flat_map_impl_item(item)); - } - ItemKind::Trait(box Trait { unsafety, is_auto: _, generics, bounds, items }) => { - visit_unsafety(unsafety, vis); - vis.visit_generics(generics); - visit_bounds(bounds, vis); - items.flat_map_in_place(|item| vis.flat_map_trait_item(item)); - } - ItemKind::TraitAlias(generics, bounds) => { - vis.visit_generics(generics); - visit_bounds(bounds, vis); - } - ItemKind::MacCall(m) => vis.visit_mac_call(m), - ItemKind::MacroDef(def) => vis.visit_macro_def(def), - ItemKind::Delegation(box Delegation { id, qself, path, body }) => { - vis.visit_id(id); - vis.visit_qself(qself); - vis.visit_path(path); - if let Some(body) = body { - vis.visit_block(body); - } - } - } -} - -pub fn noop_flat_map_assoc_item( - mut item: P, - visitor: &mut T, -) -> SmallVec<[P; 1]> { - let Item { id, ident, vis, attrs, kind, span, tokens } = item.deref_mut(); - visitor.visit_id(id); - visitor.visit_ident(ident); - visitor.visit_vis(vis); - visit_attrs(attrs, visitor); - match kind { - AssocItemKind::Const(item) => { - visit_const_item(item, visitor); - } - AssocItemKind::Fn(box Fn { defaultness, generics, sig, body }) => { - visit_defaultness(defaultness, visitor); - visitor.visit_generics(generics); - visit_fn_sig(sig, visitor); - visit_opt(body, |body| visitor.visit_block(body)); - } - AssocItemKind::Type(box TyAlias { - defaultness, - generics, - where_clauses, - bounds, - ty, - .. - }) => { - visit_defaultness(defaultness, visitor); - visitor.visit_generics(generics); - visitor.visit_span(&mut where_clauses.before.span); - visitor.visit_span(&mut where_clauses.after.span); - visit_bounds(bounds, visitor); - visit_opt(ty, |ty| visitor.visit_ty(ty)); - } - AssocItemKind::MacCall(mac) => visitor.visit_mac_call(mac), - AssocItemKind::Delegation(box Delegation { id, qself, path, body }) => { - visitor.visit_id(id); - visitor.visit_qself(qself); - visitor.visit_path(path); - if let Some(body) = body { - visitor.visit_block(body); - } - } - } - visitor.visit_span(span); - visit_lazy_tts(tokens, visitor); - smallvec![item] -} - -fn visit_const_item( - ConstItem { defaultness, generics, ty, expr }: &mut ConstItem, - visitor: &mut T, -) { - visit_defaultness(defaultness, visitor); - visitor.visit_generics(generics); - visitor.visit_ty(ty); - visit_opt(expr, |expr| visitor.visit_expr(expr)); -} - -pub fn noop_visit_fn_header(header: &mut FnHeader, vis: &mut T) { - let FnHeader { unsafety, coroutine_kind, constness, ext: _ } = header; - visit_constness(constness, vis); - coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind)); - visit_unsafety(unsafety, vis); -} - -pub fn noop_visit_crate(krate: &mut Crate, vis: &mut T) { - let Crate { attrs, items, spans, id, is_placeholder: _ } = krate; - vis.visit_id(id); - visit_attrs(attrs, vis); - items.flat_map_in_place(|item| vis.flat_map_item(item)); - let ModSpans { inner_span, inject_use_span } = spans; - vis.visit_span(inner_span); - vis.visit_span(inject_use_span); -} - -// Mutates one item into possibly many items. -pub fn noop_flat_map_item( - mut item: P, - visitor: &mut T, -) -> SmallVec<[P; 1]> { - let Item { ident, attrs, id, kind, vis, span, tokens } = item.deref_mut(); - visitor.visit_ident(ident); - visit_attrs(attrs, visitor); - visitor.visit_id(id); - visitor.visit_item_kind(kind); - visitor.visit_vis(vis); - visitor.visit_span(span); - visit_lazy_tts(tokens, visitor); - - smallvec![item] -} - -pub fn noop_flat_map_foreign_item( - mut item: P, - visitor: &mut T, -) -> SmallVec<[P; 1]> { - let Item { ident, attrs, id, kind, vis, span, tokens } = item.deref_mut(); - visitor.visit_id(id); - visitor.visit_ident(ident); - visitor.visit_vis(vis); - visit_attrs(attrs, visitor); - match kind { - ForeignItemKind::Static(ty, _, expr) => { - visitor.visit_ty(ty); - visit_opt(expr, |expr| visitor.visit_expr(expr)); - } - ForeignItemKind::Fn(box Fn { defaultness, generics, sig, body }) => { - visit_defaultness(defaultness, visitor); - visitor.visit_generics(generics); - visit_fn_sig(sig, visitor); - visit_opt(body, |body| visitor.visit_block(body)); - } - ForeignItemKind::TyAlias(box TyAlias { - defaultness, - generics, - where_clauses, - bounds, - ty, - .. - }) => { - visit_defaultness(defaultness, visitor); - visitor.visit_generics(generics); - visitor.visit_span(&mut where_clauses.before.span); - visitor.visit_span(&mut where_clauses.after.span); - visit_bounds(bounds, visitor); - visit_opt(ty, |ty| visitor.visit_ty(ty)); - } - ForeignItemKind::MacCall(mac) => visitor.visit_mac_call(mac), - } - visitor.visit_span(span); - visit_lazy_tts(tokens, visitor); - smallvec![item] -} - -pub fn noop_visit_pat(pat: &mut P, vis: &mut T) { - let Pat { id, kind, span, tokens } = pat.deref_mut(); - vis.visit_id(id); - match kind { - PatKind::Wild | PatKind::Rest | PatKind::Never | PatKind::Err(_) => {} - PatKind::Ident(_binding_mode, ident, sub) => { - vis.visit_ident(ident); - visit_opt(sub, |sub| vis.visit_pat(sub)); - } - PatKind::Lit(e) => vis.visit_expr(e), - PatKind::TupleStruct(qself, path, elems) => { - vis.visit_qself(qself); - vis.visit_path(path); - visit_thin_vec(elems, |elem| vis.visit_pat(elem)); - } - PatKind::Path(qself, path) => { - vis.visit_qself(qself); - vis.visit_path(path); - } - PatKind::Struct(qself, path, fields, _etc) => { - vis.visit_qself(qself); - vis.visit_path(path); - fields.flat_map_in_place(|field| vis.flat_map_pat_field(field)); - } - PatKind::Box(inner) => vis.visit_pat(inner), - PatKind::Deref(inner) => vis.visit_pat(inner), - PatKind::Ref(inner, _mutbl) => vis.visit_pat(inner), - PatKind::Range(e1, e2, Spanned { span: _, node: _ }) => { - visit_opt(e1, |e| vis.visit_expr(e)); - visit_opt(e2, |e| vis.visit_expr(e)); - vis.visit_span(span); - } - PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => { - visit_thin_vec(elems, |elem| vis.visit_pat(elem)) - } - PatKind::Paren(inner) => vis.visit_pat(inner), - PatKind::MacCall(mac) => vis.visit_mac_call(mac), - } - vis.visit_span(span); - visit_lazy_tts(tokens, vis); -} - -pub fn noop_visit_anon_const(AnonConst { id, value }: &mut AnonConst, vis: &mut T) { - vis.visit_id(id); - vis.visit_expr(value); -} - -pub fn noop_visit_inline_asm(asm: &mut InlineAsm, vis: &mut T) { - for (op, _) in &mut asm.operands { - match op { - InlineAsmOperand::In { expr, .. } - | InlineAsmOperand::Out { expr: Some(expr), .. } - | InlineAsmOperand::InOut { expr, .. } => vis.visit_expr(expr), - InlineAsmOperand::Out { expr: None, .. } => {} - InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => { - vis.visit_expr(in_expr); - if let Some(out_expr) = out_expr { - vis.visit_expr(out_expr); - } - } - InlineAsmOperand::Const { anon_const } => vis.visit_anon_const(anon_const), - InlineAsmOperand::Sym { sym } => vis.visit_inline_asm_sym(sym), - InlineAsmOperand::Label { block } => vis.visit_block(block), - } - } -} - -pub fn noop_visit_inline_asm_sym( - InlineAsmSym { id, qself, path }: &mut InlineAsmSym, - vis: &mut T, -) { - vis.visit_id(id); - vis.visit_qself(qself); - vis.visit_path(path); -} - -pub fn noop_visit_format_args(fmt: &mut FormatArgs, vis: &mut T) { - for arg in fmt.arguments.all_args_mut() { - if let FormatArgumentKind::Named(name) = &mut arg.kind { - vis.visit_ident(name); - } - vis.visit_expr(&mut arg.expr); - } -} - -pub fn noop_visit_expr( - Expr { kind, id, span, attrs, tokens }: &mut Expr, - vis: &mut T, -) { - match kind { - ExprKind::Array(exprs) => visit_thin_exprs(exprs, vis), - ExprKind::ConstBlock(anon_const) => { - vis.visit_anon_const(anon_const); - } - ExprKind::Repeat(expr, count) => { - vis.visit_expr(expr); - vis.visit_anon_const(count); - } - ExprKind::Tup(exprs) => visit_thin_exprs(exprs, vis), - ExprKind::Call(f, args) => { - vis.visit_expr(f); - visit_thin_exprs(args, vis); - } - ExprKind::MethodCall(box MethodCall { - seg: PathSegment { ident, id, args: seg_args }, - receiver, - args: call_args, - span, - }) => { - vis.visit_ident(ident); - vis.visit_id(id); - visit_opt(seg_args, |args| vis.visit_generic_args(args)); - vis.visit_method_receiver_expr(receiver); - visit_thin_exprs(call_args, vis); - vis.visit_span(span); - } - ExprKind::Binary(_binop, lhs, rhs) => { - vis.visit_expr(lhs); - vis.visit_expr(rhs); - } - ExprKind::Unary(_unop, ohs) => vis.visit_expr(ohs), - ExprKind::Cast(expr, ty) => { - vis.visit_expr(expr); - vis.visit_ty(ty); - } - ExprKind::Type(expr, ty) => { - vis.visit_expr(expr); - vis.visit_ty(ty); - } - ExprKind::AddrOf(_, _, ohs) => vis.visit_expr(ohs), - ExprKind::Let(pat, scrutinee, _, _) => { - vis.visit_pat(pat); - vis.visit_expr(scrutinee); - } - ExprKind::If(cond, tr, fl) => { - vis.visit_expr(cond); - vis.visit_block(tr); - visit_opt(fl, |fl| ensure_sufficient_stack(|| vis.visit_expr(fl))); - } - ExprKind::While(cond, body, label) => { - vis.visit_expr(cond); - vis.visit_block(body); - visit_opt(label, |label| vis.visit_label(label)); - } - ExprKind::ForLoop { pat, iter, body, label, kind: _ } => { - vis.visit_pat(pat); - vis.visit_expr(iter); - vis.visit_block(body); - visit_opt(label, |label| vis.visit_label(label)); - } - ExprKind::Loop(body, label, span) => { - vis.visit_block(body); - visit_opt(label, |label| vis.visit_label(label)); - vis.visit_span(span); - } - ExprKind::Match(expr, arms, _kind) => { - vis.visit_expr(expr); - arms.flat_map_in_place(|arm| vis.flat_map_arm(arm)); - } - ExprKind::Closure(box Closure { - binder, - capture_clause, - constness, - coroutine_kind, - movability: _, - fn_decl, - body, - fn_decl_span, - fn_arg_span, - }) => { - vis.visit_closure_binder(binder); - visit_constness(constness, vis); - coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind)); - vis.visit_capture_by(capture_clause); - vis.visit_fn_decl(fn_decl); - vis.visit_expr(body); - vis.visit_span(fn_decl_span); - vis.visit_span(fn_arg_span); - } - ExprKind::Block(blk, label) => { - vis.visit_block(blk); - visit_opt(label, |label| vis.visit_label(label)); - } - ExprKind::Gen(_capture_by, body, _) => { - vis.visit_block(body); - } - ExprKind::Await(expr, await_kw_span) => { - vis.visit_expr(expr); - vis.visit_span(await_kw_span); - } - ExprKind::Assign(el, er, span) => { - vis.visit_expr(el); - vis.visit_expr(er); - vis.visit_span(span); - } - ExprKind::AssignOp(_op, el, er) => { - vis.visit_expr(el); - vis.visit_expr(er); - } - ExprKind::Field(el, ident) => { - vis.visit_expr(el); - vis.visit_ident(ident); - } - ExprKind::Index(el, er, brackets_span) => { - vis.visit_expr(el); - vis.visit_expr(er); - vis.visit_span(brackets_span); - } - ExprKind::Range(e1, e2, _lim) => { - visit_opt(e1, |e1| vis.visit_expr(e1)); - visit_opt(e2, |e2| vis.visit_expr(e2)); - } - ExprKind::Underscore => {} - ExprKind::Path(qself, path) => { - vis.visit_qself(qself); - vis.visit_path(path); - } - ExprKind::Break(label, expr) => { - visit_opt(label, |label| vis.visit_label(label)); - visit_opt(expr, |expr| vis.visit_expr(expr)); - } - ExprKind::Continue(label) => { - visit_opt(label, |label| vis.visit_label(label)); - } - ExprKind::Ret(expr) => { - visit_opt(expr, |expr| vis.visit_expr(expr)); - } - ExprKind::Yeet(expr) => { - visit_opt(expr, |expr| vis.visit_expr(expr)); - } - ExprKind::Become(expr) => vis.visit_expr(expr), - ExprKind::InlineAsm(asm) => vis.visit_inline_asm(asm), - ExprKind::FormatArgs(fmt) => vis.visit_format_args(fmt), - ExprKind::OffsetOf(container, fields) => { - vis.visit_ty(container); - for field in fields.iter_mut() { - vis.visit_ident(field); - } - } - ExprKind::MacCall(mac) => vis.visit_mac_call(mac), - ExprKind::Struct(se) => { - let StructExpr { qself, path, fields, rest } = se.deref_mut(); - vis.visit_qself(qself); - vis.visit_path(path); - fields.flat_map_in_place(|field| vis.flat_map_expr_field(field)); - match rest { - StructRest::Base(expr) => vis.visit_expr(expr), - StructRest::Rest(_span) => {} - StructRest::None => {} - } - } - ExprKind::Paren(expr) => { - vis.visit_expr(expr); - } - ExprKind::Yield(expr) => { - visit_opt(expr, |expr| vis.visit_expr(expr)); - } - ExprKind::Try(expr) => vis.visit_expr(expr), - ExprKind::TryBlock(body) => vis.visit_block(body), - ExprKind::Lit(_) | ExprKind::IncludedBytes(..) | ExprKind::Err(_) | ExprKind::Dummy => {} - } - vis.visit_id(id); - vis.visit_span(span); - visit_attrs(attrs, vis); - visit_lazy_tts(tokens, vis); -} - -pub fn noop_filter_map_expr(mut e: P, vis: &mut T) -> Option> { - Some({ - vis.visit_expr(&mut e); - e - }) -} - -pub fn noop_flat_map_stmt( - Stmt { kind, mut span, mut id }: Stmt, - vis: &mut T, -) -> SmallVec<[Stmt; 1]> { - vis.visit_id(&mut id); - vis.visit_span(&mut span); - let stmts: SmallVec<_> = noop_flat_map_stmt_kind(kind, vis) - .into_iter() - .map(|kind| Stmt { id, kind, span }) - .collect(); - if stmts.len() > 1 { - panic!( - "cloning statement `NodeId`s is prohibited by default, \ +use crate::ast::*;use crate::ptr::P;use crate::token::{self,Token};use crate::// +tokenstream::*;use rustc_data_structures::flat_map_in_place::FlatMapInPlace;use +rustc_data_structures::stack::ensure_sufficient_stack;use//if true{};let _=||(); +rustc_data_structures::sync::Lrc;use rustc_span::source_map::Spanned;use//{();}; +rustc_span::symbol::Ident;use rustc_span::Span;use smallvec::{smallvec,Array,//; +SmallVec};use std::ops::DerefMut;use std ::{panic,ptr};use thin_vec::ThinVec;pub +trait ExpectOne{fn expect_one(self,err:&'static str)->A::Item;}implExpectOnefor SmallVec{fn expect_one(self,err:&'static str)->A:://3; +Item{();assert!(self.len()==1,"{}",err);();self.into_iter().next().unwrap()}}pub +trait MutVisitor:Sized{const VISIT_TOKENS:bool= false;fn visit_crate(&mut self,c +:&mut Crate){((((noop_visit_crate(c,self)))))}fn visit_meta_list_item(&mut self, +list_item:&mut NestedMetaItem){3;noop_visit_meta_list_item(list_item,self);3;}fn +visit_meta_item(&mut self,meta_item:&mut MetaItem){((),());noop_visit_meta_item( +meta_item,self);{();};}fn visit_use_tree(&mut self,use_tree:&mut UseTree){{();}; +noop_visit_use_tree(use_tree,self);{;};}fn flat_map_foreign_item(&mut self,ni:P< +ForeignItem>)->SmallVec<[P; 1]>{noop_flat_map_foreign_item(ni,self) +}fn flat_map_item(&mut self,i:P)->SmallVec<[P;(((((((((1)))))))))]>{ +noop_flat_map_item(i,self)}fn visit_fn_header(&mut self,header:&mut FnHeader){3; +noop_visit_fn_header(header,self);;}fn flat_map_field_def(&mut self,fd:FieldDef) +->SmallVec<[FieldDef;(1)]>{noop_flat_map_field_def(fd,self)}fn visit_item_kind(& +mut self,i:&mut ItemKind){;noop_visit_item_kind(i,self);}fn flat_map_trait_item( +&mut self,i:P)->SmallVec< [P;1]>{noop_flat_map_assoc_item( +i,self)}fn flat_map_impl_item(&mut self, i:P)->SmallVec<[P +;((1))]>{(noop_flat_map_assoc_item(i,self))}fn visit_fn_decl(&mut self,d:&mut P< +FnDecl>){3;noop_visit_fn_decl(d,self);;}fn visit_coroutine_kind(&mut self,a:&mut +CoroutineKind){;noop_visit_coroutine_kind(a,self);;}fn visit_closure_binder(&mut +self,b:&mut ClosureBinder){;noop_visit_closure_binder(b,self);;}fn visit_block(& +mut self,b:&mut P){;noop_visit_block(b,self);}fn flat_map_stmt(&mut self, +s:Stmt)->SmallVec<[Stmt;(1)]> {(noop_flat_map_stmt(s,self))}fn flat_map_arm(&mut +self,arm:Arm)->SmallVec<[Arm;(1)]>{noop_flat_map_arm(arm,self)}fn visit_pat(&mut +self,p:&mut P){3;noop_visit_pat(p,self);;}fn visit_anon_const(&mut self,c:& +mut AnonConst){;noop_visit_anon_const(c,self);}fn visit_expr(&mut self,e:&mut P< +Expr>){;noop_visit_expr(e,self);}fn visit_method_receiver_expr(&mut self,ex:&mut +P){(self.visit_expr(ex))}fn filter_map_expr(&mut self,e:P)->Option

>{((noop_filter_map_expr(e,self)))}fn visit_generic_arg(&mut self,arg:&mut +GenericArg){;noop_visit_generic_arg(arg,self);}fn visit_ty(&mut self,t:&mut P){();noop_visit_ty(t,self);();}fn visit_lifetime(&mut self,l:&mut Lifetime){(); +noop_visit_lifetime(l,self);*&*&();((),());}fn visit_constraint(&mut self,t:&mut +AssocConstraint){;noop_visit_constraint(t,self);}fn visit_foreign_mod(&mut self, +nm:&mut ForeignMod){3;noop_visit_foreign_mod(nm,self);;}fn flat_map_variant(&mut +self,v:Variant)->SmallVec<[Variant;((1 ))]>{((noop_flat_map_variant(v,self)))}fn +visit_ident(&mut self,i:&mut Ident){3;noop_visit_ident(i,self);;}fn visit_path(& +mut self,p:&mut Path){;noop_visit_path(p,self);}fn visit_qself(&mut self,qs:&mut +Option>){;noop_visit_qself(qs,self);;}fn visit_generic_args(&mut self,p +:&mut GenericArgs){loop{break;};noop_visit_generic_args(p,self);loop{break;};}fn +visit_angle_bracketed_parameter_data(&mut self,p:&mut AngleBracketedArgs){{();}; +noop_visit_angle_bracketed_parameter_data(p,self);loop{break;};if let _=(){};}fn +visit_parenthesized_parameter_data(&mut self,p:&mut ParenthesizedArgs){let _=(); +noop_visit_parenthesized_parameter_data(p,self);();}fn visit_local(&mut self,l:& +mut P){3;noop_visit_local(l,self);3;}fn visit_mac_call(&mut self,mac:&mut +MacCall){{;};noop_visit_mac(mac,self);{;};}fn visit_macro_def(&mut self,def:&mut +MacroDef){3;noop_visit_macro_def(def,self);;}fn visit_label(&mut self,label:&mut +Label){{;};noop_visit_label(label,self);();}fn visit_attribute(&mut self,at:&mut +Attribute){3;noop_visit_attribute(at,self);3;}fn flat_map_param(&mut self,param: +Param)->SmallVec<[Param;1]>{ noop_flat_map_param(param,self)}fn visit_generics(& +mut self,generics:&mut Generics){({});noop_visit_generics(generics,self);{;};}fn +visit_trait_ref(&mut self,tr:&mut TraitRef){3;noop_visit_trait_ref(tr,self);;}fn +visit_poly_trait_ref(&mut self,p:&mut PolyTraitRef){;noop_visit_poly_trait_ref(p +,self);((),());}fn visit_variant_data(&mut self,vdata:&mut VariantData){((),()); +noop_visit_variant_data(vdata,self);;}fn flat_map_generic_param(&mut self,param: +GenericParam)->SmallVec<[GenericParam;((1))]>{noop_flat_map_generic_param(param, +self)}fn visit_param_bound(&mut self,tpb:&mut GenericBound){if true{};if true{}; +noop_visit_param_bound(tpb,self);({});}fn visit_mt(&mut self,mt:&mut MutTy){{;}; +noop_visit_mt(mt,self);;}fn flat_map_expr_field(&mut self,f:ExprField)->SmallVec +<[ExprField;(1)]>{(noop_flat_map_expr_field (f,self))}fn visit_where_clause(&mut +self,where_clause:&mut WhereClause){;noop_visit_where_clause(where_clause,self); +}fn visit_where_predicate(&mut self,where_predicate:&mut WherePredicate){*&*&(); +noop_visit_where_predicate(where_predicate,self);3;}fn visit_vis(&mut self,vis:& +mut Visibility){;noop_visit_vis(vis,self);}fn visit_id(&mut self,_id:&mut NodeId +){}fn visit_span(&mut self,_sp:&mut Span){}fn flat_map_pat_field(&mut self,fp:// +PatField)->SmallVec<[PatField;(((1)))] >{((noop_flat_map_pat_field(fp,self)))}fn +visit_inline_asm(&mut self,asm:&mut InlineAsm){noop_visit_inline_asm(asm,self)} +fn visit_inline_asm_sym(&mut self,sym:&mut InlineAsmSym){//if true{};let _=||(); +noop_visit_inline_asm_sym(sym,self)}fn visit_format_args(&mut self,fmt:&mut//(); +FormatArgs){((noop_visit_format_args(fmt,self) ))}fn visit_capture_by(&mut self, +capture_by:&mut CaptureBy){(((noop_visit_capture_by (capture_by,self))))}}pub fn +visit_clobber(t:&mut T,f:impl FnOnce(T)->T){unsafe{();let old_t= +ptr::read(t);;let new_t=panic::catch_unwind(panic::AssertUnwindSafe(||f(old_t))) +.unwrap_or_else(|err|{;ptr::write(t,T::dummy());panic::resume_unwind(err);});ptr +::write(t,new_t);let _=();}}#[inline]pub fn visit_vec(elems:&mut Vec,mut +visit_elem:F)where F:FnMut(&mut T),{for elem in elems{();visit_elem(elem);3;}}#[ +inline]pub fn visit_thin_vec(elems:&mut ThinVec,mut visit_elem:F)where// +F:FnMut(&mut T),{for elem in elems{;visit_elem(elem);}}#[inline]pub fn visit_opt +(opt:&mut Option,mut visit_elem:F)where F:FnMut(&mut T),{if let Some(//; +elem)=opt{{;};visit_elem(elem);{;};}}pub fn visit_attrs(attrs:&mut +AttrVec,vis:&mut T){for attr in attrs.iter_mut(){3;vis.visit_attribute(attr);;}} +pub fn visit_exprs(exprs:&mut Vec>,vis:&mut T){exprs.//(); +flat_map_in_place((|expr|vis.filter_map_expr(expr) ))}pub fn visit_thin_exprs(exprs:&mut ThinVec>,vis:&mut T){exprs.flat_map_in_place(|//; +expr|(vis.filter_map_expr(expr)))} pub fn visit_bounds(bounds:&mut +GenericBounds,vis:&mut T){;visit_vec(bounds,|bound|vis.visit_param_bound(bound)) +;;}pub fn visit_fn_sig(FnSig{header,decl,span}:&mut FnSig,vis:&mut +T){;vis.visit_fn_header(header);;;vis.visit_fn_decl(decl);vis.visit_span(span);} +pub fn visit_attr_args(args:&mut AttrArgs,vis:&mut T){match args{ +AttrArgs::Empty=>{}AttrArgs::Delimited(args )=>(((visit_delim_args(args,vis)))), +AttrArgs::Eq(eq_span,AttrArgsEq::Ast(expr))=>{3;vis.visit_span(eq_span);3;3;vis. +visit_expr(expr);if true{};}AttrArgs::Eq(_,AttrArgsEq::Hir(lit))=>{unreachable!( +"in literal form when visiting mac args eq: {:?}",lit)}}}pub fn//*&*&();((),()); +visit_delim_args(args:&mut DelimArgs,vis:&mut T){();let DelimArgs{ +dspan,delim:_,tokens}=args;;;visit_delim_span(dspan,vis);visit_tts(tokens,vis);} +pub fn visit_delim_span(dspan:&mut DelimSpan,vis:&mut T){({});vis. +visit_span(&mut dspan.open);{;};{;};vis.visit_span(&mut dspan.close);{;};}pub fn +noop_flat_map_pat_field(mut fp:PatField,vis:&mut T,)->SmallVec<[// +PatField;1]>{();let PatField{attrs,id,ident,is_placeholder:_,is_shorthand:_,pat, +span}=&mut fp;;;vis.visit_id(id);;vis.visit_ident(ident);vis.visit_pat(pat);vis. +visit_span(span);*&*&();*&*&();visit_attrs(attrs,vis);{();};smallvec![fp]}pub fn +noop_visit_use_tree(use_tree:&mut UseTree,vis:&mut T){;let UseTree +{prefix,kind,span}=use_tree;3;3;vis.visit_path(prefix);;match kind{UseTreeKind:: +Simple(rename)=>visit_opt(rename,|rename| vis.visit_ident(rename)),UseTreeKind:: +Nested(items)=>{for(tree,id)in items{;vis.visit_use_tree(tree);vis.visit_id(id); +}}UseTreeKind::Glob=>{}}{;};vis.visit_span(span);();}pub fn noop_flat_map_arm(mut arm:Arm,vis:&mut T)->SmallVec<[Arm;1]>{;let Arm{attrs,pat,guard, +body,span,id,is_placeholder:_}=&mut arm;;visit_attrs(attrs,vis);vis.visit_id(id) +;;;vis.visit_pat(pat);;;visit_opt(guard,|guard|vis.visit_expr(guard));visit_opt( +body,|body|vis.visit_expr(body));3;3;vis.visit_span(span);;smallvec![arm]}pub fn +noop_visit_constraint(AssocConstraint{ id,ident,gen_args,kind,span +}:&mut AssocConstraint,vis:&mut T,){;vis.visit_id(id);;vis.visit_ident(ident);if +let Some(gen_args)=gen_args{{;};vis.visit_generic_args(gen_args);();}match kind{ +AssocConstraintKind::Equality{term}=>match term{Term:: Ty(ty)=>vis.visit_ty(ty), +Term::Const(c)=>(vis.visit_anon_const(c)),},AssocConstraintKind::Bound{bounds}=> +visit_bounds(bounds,vis),}({});vis.visit_span(span);{;};}pub fn noop_visit_ty(ty:&mut P,vis:&mut T){;let Ty{id,kind,span,tokens}=ty.deref_mut( +);;vis.visit_id(id);match kind{TyKind::Infer|TyKind::ImplicitSelf|TyKind::Err(_) +|TyKind::Dummy|TyKind::Never|TyKind::CVarArgs=>{}TyKind::Slice(ty)=>vis.//{();}; +visit_ty(ty),TyKind::Ptr(mt)=>vis.visit_mt(mt),TyKind::Ref(lt,mt)=>{3;visit_opt( +lt,|lt|noop_visit_lifetime(lt,vis));;vis.visit_mt(mt);}TyKind::BareFn(bft)=>{let +BareFnTy{unsafety,ext:_,generic_params,decl,decl_span}=bft.deref_mut();({});{;}; +visit_unsafety(unsafety,vis);{;};();generic_params.flat_map_in_place(|param|vis. +flat_map_generic_param(param));;vis.visit_fn_decl(decl);vis.visit_span(decl_span +);;}TyKind::Tup(tys)=>visit_thin_vec(tys,|ty|vis.visit_ty(ty)),TyKind::Paren(ty) +=>vis.visit_ty(ty),TyKind::Path(qself,path)=>{();vis.visit_qself(qself);3;3;vis. +visit_path(path);{;};}TyKind::Array(ty,length)=>{{;};vis.visit_ty(ty);();();vis. +visit_anon_const(length);({});}TyKind::Typeof(expr)=>vis.visit_anon_const(expr), +TyKind::TraitObject(bounds,_syntax)=>{visit_vec(bounds,|bound|vis.//loop{break}; +visit_param_bound(bound))}TyKind::ImplTrait(id,bounds)=>{3;vis.visit_id(id);3;3; +visit_vec(bounds,|bound|vis.visit_param_bound(bound));();}TyKind::MacCall(mac)=> +vis.visit_mac_call(mac),TyKind::AnonStruct(id,fields)|TyKind::AnonUnion(id,//(); +fields)=>{{();};vis.visit_id(id);{();};({});fields.flat_map_in_place(|field|vis. +flat_map_field_def(field));;}};vis.visit_span(span);visit_lazy_tts(tokens,vis);} +pub fn noop_visit_foreign_mod(foreign_mod:&mut ForeignMod,vis:&//; +mut T){;let ForeignMod{unsafety,abi:_,items}=foreign_mod;visit_unsafety(unsafety +,vis);3;;items.flat_map_in_place(|item|vis.flat_map_foreign_item(item));;}pub fn +noop_flat_map_variant(mut variant:Variant,visitor:&mut T,)->//{;}; +SmallVec<[Variant;1]>{*&*&();let Variant{ident,vis,attrs,id,data,disr_expr,span, +is_placeholder:_}=&mut variant;;visitor.visit_ident(ident);visitor.visit_vis(vis +);;;visit_attrs(attrs,visitor);;visitor.visit_id(id);visitor.visit_variant_data( +data);3;3;visit_opt(disr_expr,|disr_expr|visitor.visit_anon_const(disr_expr));;; +visitor.visit_span(span);if true{};smallvec![variant]}pub fn noop_visit_ident(Ident{name:_,span}:&mut Ident,vis:&mut T){;vis.visit_span(span);}pub +fn noop_visit_path(Path{segments,span,tokens}:&mut Path,vis:&mut// +T){{;};vis.visit_span(span);();for PathSegment{ident,id,args}in segments{();vis. +visit_ident(ident);;vis.visit_id(id);visit_opt(args,|args|vis.visit_generic_args +(args));3;}3;visit_lazy_tts(tokens,vis);;}pub fn noop_visit_qself( +qself:&mut Option>,vis:&mut T){visit_opt(qself,|qself|{();let QSelf{ty, +path_span,position:_}=&mut**qself;;vis.visit_ty(ty);vis.visit_span(path_span);}) +}pub fn noop_visit_generic_args(generic_args:&mut GenericArgs,vis +:&mut T){match generic_args{GenericArgs::AngleBracketed(data)=>vis.//let _=||(); +visit_angle_bracketed_parameter_data(data),GenericArgs::Parenthesized(data)=>//; +vis.visit_parenthesized_parameter_data(data),} }pub fn noop_visit_generic_arg(arg:&mut GenericArg,vis:&mut T){match arg{GenericArg::Lifetime(lt)// +=>(vis.visit_lifetime(lt)),GenericArg::Type(ty)=>(vis.visit_ty(ty)),GenericArg:: +Const(ct)=>((((((((((((((((((vis.visit_anon_const(ct))))))))))))))))))),}}pub fn +noop_visit_angle_bracketed_parameter_data(data:&mut//loop{break;}; +AngleBracketedArgs,vis:&mut T,){();let AngleBracketedArgs{args,span}=data;();(); +visit_thin_vec(args,|arg|match arg{AngleBracketedArg::Arg(arg)=>vis.//if true{}; +visit_generic_arg(arg),AngleBracketedArg::Constraint(constraint)=>vis.//((),()); +visit_constraint(constraint),});*&*&();*&*&();vis.visit_span(span);{();};}pub fn +noop_visit_parenthesized_parameter_data(args:&mut//*&*&();((),()); +ParenthesizedArgs,vis:&mut T,){{;};let ParenthesizedArgs{inputs,output,span,..}= +args;;;visit_thin_vec(inputs,|input|vis.visit_ty(input));;;noop_visit_fn_ret_ty( +output,vis);;vis.visit_span(span);}pub fn noop_visit_local(local:& +mut P,vis:&mut T){3;let Local{id,pat,ty,kind,span,colon_sp,attrs,tokens}= +local.deref_mut();;;vis.visit_id(id);;;vis.visit_pat(pat);;visit_opt(ty,|ty|vis. +visit_ty(ty));{;};match kind{LocalKind::Decl=>{}LocalKind::Init(init)=>{{;};vis. +visit_expr(init);3;}LocalKind::InitElse(init,els)=>{;vis.visit_expr(init);;;vis. +visit_block(els);;}};vis.visit_span(span);visit_opt(colon_sp,|sp|vis.visit_span( +sp));{;};{;};visit_attrs(attrs,vis);{;};();visit_lazy_tts(tokens,vis);();}pub fn +noop_visit_attribute(attr:&mut Attribute,vis:&mut T){if true{};let +Attribute{kind,id:_,style:_,span}=attr;3;match kind{AttrKind::Normal(normal)=>{; +let NormalAttr{item:AttrItem{path,args,tokens}, tokens:attr_tokens}=&mut**normal +;;;vis.visit_path(path);;;visit_attr_args(args,vis);;visit_lazy_tts(tokens,vis); +visit_lazy_tts(attr_tokens,vis);3;}AttrKind::DocComment(..)=>{}};vis.visit_span( +span);();}pub fn noop_visit_mac(mac:&mut MacCall,vis:&mut T){3;let +MacCall{path,args}=mac;;;vis.visit_path(path);visit_delim_args(args,vis);}pub fn +noop_visit_macro_def(macro_def:&mut MacroDef,vis:&mut T){{();};let +MacroDef{body,macro_rules:_}=macro_def;();3;visit_delim_args(body,vis);3;}pub fn +noop_visit_meta_list_item(li:&mut NestedMetaItem,vis:&mut T){//(); +match li{NestedMetaItem::MetaItem(mi)=> vis.visit_meta_item(mi),NestedMetaItem:: +Lit(_lit)=>{}}}pub fn noop_visit_meta_item< T:MutVisitor>(mi:&mut MetaItem,vis:& +mut T){();let MetaItem{path:_,kind,span}=mi;();match kind{MetaItemKind::Word=>{} +MetaItemKind::List(mis)=>(visit_thin_vec(mis,|mi|vis.visit_meta_list_item(mi))), +MetaItemKind::NameValue(_s)=>{}}if true{};vis.visit_span(span);if true{};}pub fn +noop_flat_map_param(mut param:Param, vis:&mut T)->SmallVec<[Param; +1]>{;let Param{attrs,id,pat,span,ty,is_placeholder:_}=&mut param;vis.visit_id(id +);;;visit_attrs(attrs,vis);vis.visit_pat(pat);vis.visit_span(span);vis.visit_ty( +ty);3;smallvec![param]}pub fn visit_attr_tt(tt:&mut AttrTokenTree, +vis:&mut T){match tt{AttrTokenTree::Token(token,_)=>{3;visit_token(token,vis);;} +AttrTokenTree::Delimited(DelimSpan{open,close},_spacing,_delim,tts)=>{{();};vis. +visit_span(open);;vis.visit_span(close);visit_attr_tts(tts,vis);}AttrTokenTree:: +Attributes(data)=>{for attr in(&mut(*data.attrs)){match&mut attr.kind{AttrKind:: +Normal(normal)=>{;visit_lazy_tts(&mut normal.tokens,vis);;}AttrKind::DocComment( +..)=>{;vis.visit_span(&mut attr.span);;}}}visit_lazy_tts_opt_mut(Some(&mut data. +tokens),vis);{;};}}}pub fn visit_tt(tt:&mut TokenTree,vis:&mut T){ +match tt{TokenTree::Token(token,_)=>{{;};visit_token(token,vis);{;};}TokenTree:: +Delimited(DelimSpan{open,close},_spacing,_delim,tts)=>{;vis.visit_span(open);vis +.visit_span(close);();();visit_tts(tts,vis);3;}}}pub fn visit_tts( +TokenStream(tts):&mut TokenStream,vis:&mut T){if T::VISIT_TOKENS&&!tts.is_empty +(){;let tts=Lrc::make_mut(tts);;visit_vec(tts,|tree|visit_tt(tree,vis));}}pub fn +visit_attr_tts(AttrTokenStream(tts ):&mut AttrTokenStream,vis:&mut +T){if T::VISIT_TOKENS&&!tts.is_empty(){3;let tts=Lrc::make_mut(tts);;;visit_vec( +tts,|tree|visit_attr_tt(tree,vis));;}}pub fn visit_lazy_tts_opt_mut(lazy_tts:Option<&mut LazyAttrTokenStream>,vis:&mut T,){if T::VISIT_TOKENS{if// +let Some(lazy_tts)=lazy_tts{();let mut tts=lazy_tts.to_attr_token_stream();();3; +visit_attr_tts(&mut tts,vis);;;*lazy_tts=LazyAttrTokenStream::new(tts);}}}pub fn +visit_lazy_tts(lazy_tts:& mut Option,vis:&mut +T){({});visit_lazy_tts_opt_mut(lazy_tts.as_mut(),vis);{;};}pub fn visit_token(t:&mut Token,vis:&mut T){;let Token{kind,span}=t;;match kind{token:: +Ident(name,_)|token::Lifetime(name)=>{;let mut ident=Ident::new(*name,*span);vis +.visit_ident(&mut ident);;;*name=ident.name;;;*span=ident.span;;;return;}token:: +Interpolated(nt)=>{;let nt=Lrc::make_mut(nt);;;let(nt,sp)=(&mut nt.0,&mut nt.1); +vis.visit_span(sp);;;visit_nonterminal(nt,vis);;}_=>{}}vis.visit_span(span);}pub +fn visit_nonterminal(nt:&mut token::Nonterminal,vis:&mut T){match +nt{token::NtItem(item)=>visit_clobber(item,|item|{(((vis.flat_map_item(item)))). +expect_one((("expected visitor to produce exactly one item")))}),token::NtBlock( +block)=>(vis.visit_block(block)),token::NtStmt(stmt)=>visit_clobber(stmt,|stmt|{ +stmt.map(|stmt|{(((((((((((((( vis.flat_map_stmt(stmt))))))))))))))).expect_one( +"expected visitor to produce exactly one item")})}),token::NtPat(pat)=>vis.//(); +visit_pat(pat),token::NtExpr(expr)=>(vis.visit_expr(expr)),token::NtTy(ty)=>vis. +visit_ty(ty),token::NtIdent(ident,_is_raw)=>(((vis.visit_ident(ident)))),token:: +NtLifetime(ident)=>(((((vis.visit_ident(ident)))))),token::NtLiteral(expr)=>vis. +visit_expr(expr),token::NtMeta(item)=>{({});let AttrItem{path,args,tokens}=item. +deref_mut();;;vis.visit_path(path);;;visit_attr_args(args,vis);;;visit_lazy_tts( +tokens,vis);;}token::NtPath(path)=>vis.visit_path(path),token::NtVis(visib)=>vis +.visit_vis(visib),}}pub fn visit_defaultness(defaultness:&mut//(); +Defaultness,vis:&mut T){match defaultness{Defaultness::Default(span)=>vis.//{;}; +visit_span(span),Defaultness::Final=>{}}}pub fn visit_unsafety(//; +unsafety:&mut Unsafe,vis:&mut T){match unsafety{Unsafe::Yes(span)=>vis.//*&*&(); +visit_span(span),Unsafe::No=>{}}} pub fn visit_polarity(polarity:& +mut ImplPolarity,vis:&mut T){match polarity{ImplPolarity::Positive=>{}//((),()); +ImplPolarity::Negative(span)=>(vis.visit_span(span)),}}pub fn visit_constness(constness:&mut Const,vis:&mut T){match constness{Const::Yes(span)=> +vis.visit_span(span),Const::No=>{}}}pub fn noop_visit_closure_binder(binder:&mut ClosureBinder,vis:&mut T){match binder{ClosureBinder::// +NotPresent=>{}ClosureBinder::For{span:_,generic_params}=>{*&*&();generic_params. +flat_map_in_place(|param|vis.flat_map_generic_param(param));let _=||();}}}pub fn +noop_visit_coroutine_kind(coroutine_kind :&mut CoroutineKind,vis:& +mut T){match coroutine_kind{CoroutineKind::Async{span,closure_id,//loop{break;}; +return_impl_trait_id}|CoroutineKind::Gen{ span,closure_id,return_impl_trait_id}| +CoroutineKind::AsyncGen{span,closure_id,return_impl_trait_id}=>{;vis.visit_span( +span);;;vis.visit_id(closure_id);;;vis.visit_id(return_impl_trait_id);;}}}pub fn +noop_visit_fn_decl(decl:&mut P,vis:&mut T){{;};let FnDecl{ +inputs,output}=decl.deref_mut();{();};{();};inputs.flat_map_in_place(|param|vis. +flat_map_param(param));{();};{();};noop_visit_fn_ret_ty(output,vis);({});}pub fn +noop_visit_fn_ret_ty(fn_ret_ty:&mut FnRetTy,vis:&mut T){match//(); +fn_ret_ty{FnRetTy::Default(span)=>((vis.visit_span(span))),FnRetTy::Ty(ty)=>vis. +visit_ty(ty),}}pub fn noop_visit_param_bound(pb:&mut GenericBound +,vis:&mut T){match pb{GenericBound::Trait(ty,_modifier)=>vis.//((),());let _=(); +visit_poly_trait_ref(ty),GenericBound:: Outlives(lifetime)=>noop_visit_lifetime( +lifetime,vis),}}pub fn noop_flat_map_generic_param(mut param://(); +GenericParam,vis:&mut T,)->SmallVec<[GenericParam;1]>{;let GenericParam{id,ident +,attrs,bounds,kind,colon_span,is_placeholder:_}=&mut param;;vis.visit_id(id);vis +.visit_ident(ident);({});if let Some(colon_span)=colon_span{({});vis.visit_span( +colon_span);({});}({});visit_attrs(attrs,vis);({});({});visit_vec(bounds,|bound| +noop_visit_param_bound(bound,vis));{;};match kind{GenericParamKind::Lifetime=>{} +GenericParamKind::Type{default}=>{{();};visit_opt(default,|default|vis.visit_ty( +default));;}GenericParamKind::Const{ty,kw_span:_,default}=>{;vis.visit_ty(ty);;; +visit_opt(default,|default|vis.visit_anon_const(default));();}}smallvec![param]} +pub fn noop_visit_label(Label{ident}:&mut Label,vis:&mut T){3;vis. +visit_ident(ident);();}fn noop_visit_lifetime(Lifetime{id,ident}:& +mut Lifetime,vis:&mut T){3;vis.visit_id(id);3;3;vis.visit_ident(ident);3;}pub fn +noop_visit_generics(generics:&mut Generics,vis:&mut T){((),());let +Generics{params,where_clause,span}=generics;;params.flat_map_in_place(|param|vis +.flat_map_generic_param(param));3;3;vis.visit_where_clause(where_clause);3;;vis. +visit_span(span);if true{};}pub fn noop_visit_where_clause(wc:&mut +WhereClause,vis:&mut T){;let WhereClause{has_where_token:_,predicates,span}=wc;; +visit_thin_vec(predicates,|predicate|vis.visit_where_predicate(predicate));;vis. +visit_span(span);({});}pub fn noop_visit_where_predicate(pred:&mut +WherePredicate,vis:&mut T){match pred{WherePredicate::BoundPredicate(bp)=>{3;let +WhereBoundPredicate{span,bound_generic_params,bounded_ty,bounds}=bp;{;};{;};vis. +visit_span(span);*&*&();{();};bound_generic_params.flat_map_in_place(|param|vis. +flat_map_generic_param(param));;vis.visit_ty(bounded_ty);visit_vec(bounds,|bound +|vis.visit_param_bound(bound));{;};}WherePredicate::RegionPredicate(rp)=>{();let +WhereRegionPredicate{span,lifetime,bounds}=rp;{;};();vis.visit_span(span);();(); +noop_visit_lifetime(lifetime,vis);let _=||();let _=||();visit_vec(bounds,|bound| +noop_visit_param_bound(bound,vis));{;};}WherePredicate::EqPredicate(ep)=>{();let +WhereEqPredicate{span,lhs_ty,rhs_ty}=ep;3;3;vis.visit_span(span);;;vis.visit_ty( +lhs_ty);;;vis.visit_ty(rhs_ty);;}}}pub fn noop_visit_variant_data( +vdata:&mut VariantData,vis:&mut T) {match vdata{VariantData::Struct{fields,..}=> +{;fields.flat_map_in_place(|field|vis.flat_map_field_def(field));;}VariantData:: +Tuple(fields,id)=>{;fields.flat_map_in_place(|field|vis.flat_map_field_def(field +));{;};{;};vis.visit_id(id);();}VariantData::Unit(id)=>vis.visit_id(id),}}pub fn +noop_visit_trait_ref(TraitRef{path, ref_id}:&mut TraitRef,vis:&mut +T){;vis.visit_path(path);;vis.visit_id(ref_id);}pub fn noop_visit_poly_trait_ref +(p:&mut PolyTraitRef,vis:&mut T){((),());((),());let PolyTraitRef{ +bound_generic_params,trait_ref,span}=p;;bound_generic_params.flat_map_in_place(| +param|vis.flat_map_generic_param(param));;;vis.visit_trait_ref(trait_ref);;;vis. +visit_span(span);;}pub fn noop_flat_map_field_def(mut fd:FieldDef, +visitor:&mut T,)->SmallVec<[FieldDef;1]>{({});let FieldDef{span,ident,vis,id,ty, +attrs,is_placeholder:_}=&mut fd;;visitor.visit_span(span);visit_opt(ident,|ident +|visitor.visit_ident(ident));3;;visitor.visit_vis(vis);;;visitor.visit_id(id);;; +visitor.visit_ty(ty);{;};{;};visit_attrs(attrs,visitor);{;};smallvec![fd]}pub fn +noop_flat_map_expr_field(mut f:ExprField ,vis:&mut T,)->SmallVec<[ +ExprField;1]>{loop{break};let ExprField{ident,expr,span,is_shorthand:_,attrs,id, +is_placeholder:_}=&mut f;3;;vis.visit_ident(ident);;;vis.visit_expr(expr);;;vis. +visit_id(id);;;vis.visit_span(span);;;visit_attrs(attrs,vis);smallvec![f]}pub fn +noop_visit_mt(MutTy{ty,mutbl:_}:&mut MutTy,vis:&mut T){*&*&();vis. +visit_ty(ty);();}pub fn noop_visit_block(block:&mut P,vis:& +mut T){();let Block{id,stmts,rules:_,span,tokens,could_be_bare_literal:_}=block. +deref_mut();;;vis.visit_id(id);;stmts.flat_map_in_place(|stmt|vis.flat_map_stmt( +stmt));{;};{;};vis.visit_span(span);{;};();visit_lazy_tts(tokens,vis);();}pub fn +noop_visit_item_kind(kind:&mut ItemKind,vis:&mut T){match kind{//; +ItemKind::ExternCrate(_orig_name)=>{}ItemKind::Use(use_tree)=>vis.//loop{break}; +visit_use_tree(use_tree),ItemKind::Static(box StaticItem{ty,mutability:_,expr}) +=>{;vis.visit_ty(ty);visit_opt(expr,|expr|vis.visit_expr(expr));}ItemKind::Const +(item)=>{;visit_const_item(item,vis);;}ItemKind::Fn(box Fn{defaultness,generics, +sig,body})=>{3;visit_defaultness(defaultness,vis);;;visit_fn_sig(sig,vis);;;vis. +visit_generics(generics);;;visit_opt(body,|body|vis.visit_block(body));}ItemKind +::Mod(unsafety,mod_kind)=>{;visit_unsafety(unsafety,vis);;match mod_kind{ModKind +::Loaded(items,_inline,ModSpans{inner_span,inject_use_span})=>{3;vis.visit_span( +inner_span);;;vis.visit_span(inject_use_span);items.flat_map_in_place(|item|vis. +flat_map_item(item));({});}ModKind::Unloaded=>{}}}ItemKind::ForeignMod(nm)=>vis. +visit_foreign_mod(nm),ItemKind::GlobalAsm(asm)=>(((vis.visit_inline_asm(asm)))), +ItemKind::TyAlias(box TyAlias{defaultness, generics,where_clauses,bounds,ty,..}) +=>{3;visit_defaultness(defaultness,vis);3;3;vis.visit_generics(generics);3;;vis. +visit_span(&mut where_clauses.before.span);3;;vis.visit_span(&mut where_clauses. +after.span);3;3;visit_bounds(bounds,vis);;;visit_opt(ty,|ty|vis.visit_ty(ty));;} +ItemKind::Enum(EnumDef{variants},generics)=>{*&*&();variants.flat_map_in_place(| +variant|vis.flat_map_variant(variant));;vis.visit_generics(generics);}ItemKind:: +Struct(variant_data,generics)|ItemKind::Union(variant_data,generics)=>{({});vis. +visit_variant_data(variant_data);;;vis.visit_generics(generics);}ItemKind::Impl( +box Impl{defaultness,unsafety,generics,constness,polarity,of_trait,self_ty,//(); +items,})=>{;visit_defaultness(defaultness,vis);visit_unsafety(unsafety,vis);vis. +visit_generics(generics);;visit_constness(constness,vis);visit_polarity(polarity +,vis);3;3;visit_opt(of_trait,|trait_ref|vis.visit_trait_ref(trait_ref));3;3;vis. +visit_ty(self_ty);;items.flat_map_in_place(|item|vis.flat_map_impl_item(item));} +ItemKind::Trait(box Trait{unsafety,is_auto:_,generics,bounds,items})=>{let _=(); +visit_unsafety(unsafety,vis);;;vis.visit_generics(generics);visit_bounds(bounds, +vis);;;items.flat_map_in_place(|item|vis.flat_map_trait_item(item));;}ItemKind:: +TraitAlias(generics,bounds)=>{;vis.visit_generics(generics);visit_bounds(bounds, +vis);;}ItemKind::MacCall(m)=>vis.visit_mac_call(m),ItemKind::MacroDef(def)=>vis. +visit_macro_def(def),ItemKind::Delegation(box Delegation{id,qself,path,body})=> +{;vis.visit_id(id);vis.visit_qself(qself);vis.visit_path(path);if let Some(body) +=body{;vis.visit_block(body);;}}}}pub fn noop_flat_map_assoc_item( +mut item:P,visitor:&mut T,)->SmallVec<[P;1]>{;let Item{id, +ident,vis,attrs,kind,span,tokens}=item.deref_mut();;visitor.visit_id(id);visitor +.visit_ident(ident);;;visitor.visit_vis(vis);;;visit_attrs(attrs,visitor);;match +kind{AssocItemKind::Const(item)=>{;visit_const_item(item,visitor);}AssocItemKind +::Fn(box Fn{defaultness,generics,sig,body})=>{{;};visit_defaultness(defaultness, +visitor);;;visitor.visit_generics(generics);visit_fn_sig(sig,visitor);visit_opt( +body,|body|visitor.visit_block(body));let _=();}AssocItemKind::Type(box TyAlias{ +defaultness,generics,where_clauses,bounds,ty,..})=>{if true{};visit_defaultness( +defaultness,visitor);;;visitor.visit_generics(generics);;visitor.visit_span(&mut +where_clauses.before.span);;;visitor.visit_span(&mut where_clauses.after.span);; +visit_bounds(bounds,visitor);{;};{;};visit_opt(ty,|ty|visitor.visit_ty(ty));();} +AssocItemKind::MacCall(mac)=>((((visitor.visit_mac_call(mac))))),AssocItemKind:: +Delegation(box Delegation{id,qself,path,body})=>{;visitor.visit_id(id);;visitor. +visit_qself(qself);3;;visitor.visit_path(path);;if let Some(body)=body{;visitor. +visit_block(body);;}}};visitor.visit_span(span);;visit_lazy_tts(tokens,visitor); +smallvec![item]}fn visit_const_item(ConstItem{defaultness,//{();}; +generics,ty,expr}:&mut ConstItem,visitor:&mut T,){;visit_defaultness(defaultness +,visitor);;visitor.visit_generics(generics);visitor.visit_ty(ty);visit_opt(expr, +|expr|visitor.visit_expr(expr));({});}pub fn noop_visit_fn_header( +header:&mut FnHeader,vis:&mut T){;let FnHeader{unsafety,coroutine_kind,constness +,ext:_}=header;3;;visit_constness(constness,vis);;;coroutine_kind.as_mut().map(| +coroutine_kind|vis.visit_coroutine_kind(coroutine_kind));{;};{;};visit_unsafety( +unsafety,vis);3;}pub fn noop_visit_crate(krate:&mut Crate,vis:&mut +T){;let Crate{attrs,items,spans,id,is_placeholder:_}=krate;;;vis.visit_id(id);;; +visit_attrs(attrs,vis);;;items.flat_map_in_place(|item|vis.flat_map_item(item)); +let ModSpans{inner_span,inject_use_span}=spans;;;vis.visit_span(inner_span);vis. +visit_span(inject_use_span);;}pub fn noop_flat_map_item(mut item:P +,visitor:&mut T,)->SmallVec<[P;1]>{;let Item{ident,attrs,id,kind,vis +,span,tokens}=item.deref_mut();;;visitor.visit_ident(ident);;;visit_attrs(attrs, +visitor);;;visitor.visit_id(id);visitor.visit_item_kind(kind);visitor.visit_vis( +vis);;;visitor.visit_span(span);;visit_lazy_tts(tokens,visitor);smallvec![item]} +pub fn noop_flat_map_foreign_item (mut item:P,visitor +:&mut T,)->SmallVec<[P;1]>{3;let Item{ident,attrs,id,kind,vis,span, +tokens}=item.deref_mut();3;;visitor.visit_id(id);;;visitor.visit_ident(ident);;; +visitor.visit_vis(vis);;;visit_attrs(attrs,visitor);match kind{ForeignItemKind:: +Static(ty,_,expr)=>{{;};visitor.visit_ty(ty);();();visit_opt(expr,|expr|visitor. +visit_expr(expr));;}ForeignItemKind::Fn(box Fn{defaultness,generics,sig,body})=> +{3;visit_defaultness(defaultness,visitor);3;;visitor.visit_generics(generics);;; +visit_fn_sig(sig,visitor);3;3;visit_opt(body,|body|visitor.visit_block(body));;} +ForeignItemKind::TyAlias(box TyAlias{ defaultness,generics,where_clauses,bounds, +ty,..})=>{();visit_defaultness(defaultness,visitor);();3;visitor.visit_generics( +generics);;visitor.visit_span(&mut where_clauses.before.span);visitor.visit_span +(&mut where_clauses.after.span);;;visit_bounds(bounds,visitor);visit_opt(ty,|ty| +visitor.visit_ty(ty));();}ForeignItemKind::MacCall(mac)=>visitor.visit_mac_call( +mac),};visitor.visit_span(span);;visit_lazy_tts(tokens,visitor);smallvec![item]} +pub fn noop_visit_pat(pat:&mut P,vis:&mut T){;let Pat{id,kind +,span,tokens}=pat.deref_mut();;vis.visit_id(id);match kind{PatKind::Wild|PatKind +::Rest|PatKind::Never|PatKind::Err(_ )=>{}PatKind::Ident(_binding_mode,ident,sub +)=>{;vis.visit_ident(ident);visit_opt(sub,|sub|vis.visit_pat(sub));}PatKind::Lit +(e)=>vis.visit_expr(e),PatKind::TupleStruct(qself,path,elems)=>{;vis.visit_qself +(qself);;;vis.visit_path(path);visit_thin_vec(elems,|elem|vis.visit_pat(elem));} +PatKind::Path(qself,path)=>{3;vis.visit_qself(qself);3;3;vis.visit_path(path);;} +PatKind::Struct(qself,path,fields,_etc)=>{;vis.visit_qself(qself);vis.visit_path +(path);;;fields.flat_map_in_place(|field|vis.flat_map_pat_field(field));}PatKind +::Box(inner)=>vis.visit_pat(inner), PatKind::Deref(inner)=>vis.visit_pat(inner), +PatKind::Ref(inner,_mutbl)=>(vis.visit_pat(inner)),PatKind::Range(e1,e2,Spanned{ +span:_,node:_})=>{();visit_opt(e1,|e|vis.visit_expr(e));3;3;visit_opt(e2,|e|vis. +visit_expr(e));;vis.visit_span(span);}PatKind::Tuple(elems)|PatKind::Slice(elems +)|PatKind::Or(elems)=>{(visit_thin_vec(elems,|elem|vis.visit_pat(elem)))}PatKind +::Paren(inner)=>vis.visit_pat(inner) ,PatKind::MacCall(mac)=>vis.visit_mac_call( +mac),}({});vis.visit_span(span);({});({});visit_lazy_tts(tokens,vis);{;};}pub fn +noop_visit_anon_const(AnonConst{id, value}:&mut AnonConst,vis:&mut +T){3;vis.visit_id(id);3;;vis.visit_expr(value);;}pub fn noop_visit_inline_asm(asm:&mut InlineAsm,vis:&mut T) {for(op,_)in(&mut asm.operands){match +op{InlineAsmOperand::In{expr,..}|InlineAsmOperand::Out{expr:Some(expr),..}|//(); +InlineAsmOperand::InOut{expr,..}=>(vis .visit_expr(expr)),InlineAsmOperand::Out{ +expr:None,..}=>{}InlineAsmOperand::SplitInOut{in_expr,out_expr,..}=>{*&*&();vis. +visit_expr(in_expr);;if let Some(out_expr)=out_expr{;vis.visit_expr(out_expr);}} +InlineAsmOperand::Const{anon_const}=>(((((vis.visit_anon_const(anon_const)))))), +InlineAsmOperand::Sym{sym}=>((vis.visit_inline_asm_sym(sym))),InlineAsmOperand:: +Label{block}=>((vis.visit_block(block) )),}}}pub fn noop_visit_inline_asm_sym(InlineAsmSym{id,qself,path}:&mut InlineAsmSym,vis:&mut T,){({});vis. +visit_id(id);{;};();vis.visit_qself(qself);();();vis.visit_path(path);();}pub fn +noop_visit_format_args(fmt:&mut FormatArgs ,vis:&mut T){for arg in +(fmt.arguments.all_args_mut()){if let FormatArgumentKind::Named(name)=&mut arg. +kind{{;};vis.visit_ident(name);{;};}();vis.visit_expr(&mut arg.expr);();}}pub fn +noop_visit_expr(Expr{kind,id,span,attrs,tokens}:&mut Expr,vis:&//; +mut T,){match kind{ExprKind::Array (exprs)=>visit_thin_exprs(exprs,vis),ExprKind +::ConstBlock(anon_const)=>{;vis.visit_anon_const(anon_const);;}ExprKind::Repeat( +expr,count)=>{;vis.visit_expr(expr);;vis.visit_anon_const(count);}ExprKind::Tup( +exprs)=>visit_thin_exprs(exprs,vis),ExprKind::Call(f,args)=>{;vis.visit_expr(f); +visit_thin_exprs(args,vis);;}ExprKind::MethodCall(box MethodCall{seg:PathSegment +{ident,id,args:seg_args},receiver,args:call_args,span,})=>{({});vis.visit_ident( +ident);;vis.visit_id(id);visit_opt(seg_args,|args|vis.visit_generic_args(args)); +vis.visit_method_receiver_expr(receiver);;;visit_thin_exprs(call_args,vis);;vis. +visit_span(span);;}ExprKind::Binary(_binop,lhs,rhs)=>{;vis.visit_expr(lhs);;vis. +visit_expr(rhs);;}ExprKind::Unary(_unop,ohs)=>vis.visit_expr(ohs),ExprKind::Cast +(expr,ty)=>{;vis.visit_expr(expr);;;vis.visit_ty(ty);}ExprKind::Type(expr,ty)=>{ +vis.visit_expr(expr);{;};();vis.visit_ty(ty);();}ExprKind::AddrOf(_,_,ohs)=>vis. +visit_expr(ohs),ExprKind::Let(pat,scrutinee,_,_)=>{3;vis.visit_pat(pat);3;3;vis. +visit_expr(scrutinee);3;}ExprKind::If(cond,tr,fl)=>{;vis.visit_expr(cond);;;vis. +visit_block(tr);;visit_opt(fl,|fl|ensure_sufficient_stack(||vis.visit_expr(fl))) +;;}ExprKind::While(cond,body,label)=>{vis.visit_expr(cond);vis.visit_block(body) +;3;;visit_opt(label,|label|vis.visit_label(label));;}ExprKind::ForLoop{pat,iter, +body,label,kind:_}=>{;vis.visit_pat(pat);;;vis.visit_expr(iter);vis.visit_block( +body);;visit_opt(label,|label|vis.visit_label(label));}ExprKind::Loop(body,label +,span)=>{;vis.visit_block(body);;visit_opt(label,|label|vis.visit_label(label)); +vis.visit_span(span);;}ExprKind::Match(expr,arms,_kind)=>{;vis.visit_expr(expr); +arms.flat_map_in_place(|arm|vis.flat_map_arm(arm));*&*&();}ExprKind::Closure(box +Closure{binder,capture_clause,constness,coroutine_kind,movability:_,fn_decl,//3; +body,fn_decl_span,fn_arg_span,})=>{{;};vis.visit_closure_binder(binder);{;};{;}; +visit_constness(constness,vis);;coroutine_kind.as_mut().map(|coroutine_kind|vis. +visit_coroutine_kind(coroutine_kind));;vis.visit_capture_by(capture_clause);vis. +visit_fn_decl(fn_decl);;;vis.visit_expr(body);;vis.visit_span(fn_decl_span);vis. +visit_span(fn_arg_span);3;}ExprKind::Block(blk,label)=>{;vis.visit_block(blk);;; +visit_opt(label,|label|vis.visit_label(label));;}ExprKind::Gen(_capture_by,body, +_)=>{{;};vis.visit_block(body);();}ExprKind::Await(expr,await_kw_span)=>{();vis. +visit_expr(expr);;vis.visit_span(await_kw_span);}ExprKind::Assign(el,er,span)=>{ +vis.visit_expr(el);;vis.visit_expr(er);vis.visit_span(span);}ExprKind::AssignOp( +_op,el,er)=>{;vis.visit_expr(el);vis.visit_expr(er);}ExprKind::Field(el,ident)=> +{;vis.visit_expr(el);vis.visit_ident(ident);}ExprKind::Index(el,er,brackets_span +)=>{3;vis.visit_expr(el);;;vis.visit_expr(er);;;vis.visit_span(brackets_span);;} +ExprKind::Range(e1,e2,_lim)=>{;visit_opt(e1,|e1|vis.visit_expr(e1));visit_opt(e2 +,|e2|vis.visit_expr(e2));;}ExprKind::Underscore=>{}ExprKind::Path(qself,path)=>{ +vis.visit_qself(qself);3;;vis.visit_path(path);;}ExprKind::Break(label,expr)=>{; +visit_opt(label,|label|vis.visit_label(label));{;};{;};visit_opt(expr,|expr|vis. +visit_expr(expr));();}ExprKind::Continue(label)=>{();visit_opt(label,|label|vis. +visit_label(label));;}ExprKind::Ret(expr)=>{visit_opt(expr,|expr|vis.visit_expr( +expr));3;}ExprKind::Yeet(expr)=>{3;visit_opt(expr,|expr|vis.visit_expr(expr));;} +ExprKind::Become(expr)=>((vis.visit_expr(expr ))),ExprKind::InlineAsm(asm)=>vis. +visit_inline_asm(asm),ExprKind::FormatArgs(fmt)=>((vis.visit_format_args(fmt))), +ExprKind::OffsetOf(container,fields)=>{3;vis.visit_ty(container);3;for field in +fields.iter_mut(){({});vis.visit_ident(field);{;};}}ExprKind::MacCall(mac)=>vis. +visit_mac_call(mac),ExprKind::Struct(se)=>{{;};let StructExpr{qself,path,fields, +rest}=se.deref_mut();3;3;vis.visit_qself(qself);;;vis.visit_path(path);;;fields. +flat_map_in_place(|field|vis.flat_map_expr_field(field));3;match rest{StructRest +::Base(expr)=>(vis.visit_expr(expr)),StructRest::Rest(_span)=>{}StructRest::None +=>{}}}ExprKind::Paren(expr)=>{3;vis.visit_expr(expr);;}ExprKind::Yield(expr)=>{; +visit_opt(expr,|expr|vis.visit_expr(expr));;}ExprKind::Try(expr)=>vis.visit_expr +(expr),ExprKind::TryBlock(body)=>((((vis.visit_block(body))))),ExprKind::Lit(_)| +ExprKind::IncludedBytes(..)|ExprKind::Err(_)|ExprKind::Dummy=>{}}3;vis.visit_id( +id);;vis.visit_span(span);visit_attrs(attrs,vis);visit_lazy_tts(tokens,vis);}pub +fn noop_filter_map_expr(mut e:P,vis:&mut T)->Option>{Some({3;vis.visit_expr(&mut e);3;e})}pub fn noop_flat_map_stmt( +Stmt{kind,mut span,mut id}:Stmt,vis:&mut T,)->SmallVec<[Stmt;1]>{;vis.visit_id(& +mut id);;vis.visit_span(&mut span);let stmts:SmallVec<_>=noop_flat_map_stmt_kind +(kind,vis).into_iter().map(|kind|Stmt{id,kind,span}).collect();;if stmts.len()>1 +{let _=();let _=();let _=();let _=();let _=();let _=();let _=();let _=();panic!( +"cloning statement `NodeId`s is prohibited by default, \ the visitor should implement custom statement visiting" - ); - } - stmts -} - -pub fn noop_flat_map_stmt_kind( - kind: StmtKind, - vis: &mut T, -) -> SmallVec<[StmtKind; 1]> { - match kind { - StmtKind::Let(mut local) => smallvec![StmtKind::Let({ - vis.visit_local(&mut local); - local - })], - StmtKind::Item(item) => vis.flat_map_item(item).into_iter().map(StmtKind::Item).collect(), - StmtKind::Expr(expr) => vis.filter_map_expr(expr).into_iter().map(StmtKind::Expr).collect(), - StmtKind::Semi(expr) => vis.filter_map_expr(expr).into_iter().map(StmtKind::Semi).collect(), - StmtKind::Empty => smallvec![StmtKind::Empty], - StmtKind::MacCall(mut mac) => { - let MacCallStmt { mac: mac_, style: _, attrs, tokens } = mac.deref_mut(); - vis.visit_mac_call(mac_); - visit_attrs(attrs, vis); - visit_lazy_tts(tokens, vis); - smallvec![StmtKind::MacCall(mac)] - } - } -} - -pub fn noop_visit_vis(visibility: &mut Visibility, vis: &mut T) { - match &mut visibility.kind { - VisibilityKind::Public | VisibilityKind::Inherited => {} - VisibilityKind::Restricted { path, id, shorthand: _ } => { - vis.visit_path(path); - vis.visit_id(id); - } - } - vis.visit_span(&mut visibility.span); -} - -pub fn noop_visit_capture_by(capture_by: &mut CaptureBy, vis: &mut T) { - match capture_by { - CaptureBy::Ref => {} - CaptureBy::Value { move_kw } => { - vis.visit_span(move_kw); - } - } -} - -/// Some value for the AST node that is valid but possibly meaningless. Similar -/// to `Default` but not intended for wide use. The value will never be used -/// meaningfully, it exists just to support unwinding in `visit_clobber` in the -/// case where its closure panics. -pub trait DummyAstNode { - fn dummy() -> Self; -} - -impl DummyAstNode for Option { - fn dummy() -> Self { - Default::default() - } -} - -impl DummyAstNode for P { - fn dummy() -> Self { - P(DummyAstNode::dummy()) - } -} - -impl DummyAstNode for Item { - fn dummy() -> Self { - Item { - attrs: Default::default(), - id: DUMMY_NODE_ID, - span: Default::default(), - vis: Visibility { - kind: VisibilityKind::Public, - span: Default::default(), - tokens: Default::default(), - }, - ident: Ident::empty(), - kind: ItemKind::ExternCrate(None), - tokens: Default::default(), - } - } -} - -impl DummyAstNode for Expr { - fn dummy() -> Self { - Expr { - id: DUMMY_NODE_ID, - kind: ExprKind::Dummy, - span: Default::default(), - attrs: Default::default(), - tokens: Default::default(), - } - } -} - -impl DummyAstNode for Ty { - fn dummy() -> Self { - Ty { - id: DUMMY_NODE_ID, - kind: TyKind::Dummy, - span: Default::default(), - tokens: Default::default(), - } - } -} - -impl DummyAstNode for Pat { - fn dummy() -> Self { - Pat { - id: DUMMY_NODE_ID, - kind: PatKind::Wild, - span: Default::default(), - tokens: Default::default(), - } - } -} - -impl DummyAstNode for Stmt { - fn dummy() -> Self { - Stmt { id: DUMMY_NODE_ID, kind: StmtKind::Empty, span: Default::default() } - } -} - -impl DummyAstNode for Crate { - fn dummy() -> Self { - Crate { - attrs: Default::default(), - items: Default::default(), - spans: Default::default(), - id: DUMMY_NODE_ID, - is_placeholder: Default::default(), - } - } -} - -impl DummyAstNode for crate::ast_traits::AstNodeWrapper { - fn dummy() -> Self { - crate::ast_traits::AstNodeWrapper::new(N::dummy(), T::dummy()) - } -} +);;}stmts}pub fn noop_flat_map_stmt_kind(kind:StmtKind,vis:&mut T, +)->SmallVec<[StmtKind;(((1)))]>{match kind{StmtKind::Let(mut local)=>smallvec![ +StmtKind::Let({vis.visit_local(&mut local);local})],StmtKind::Item(item)=>vis.// +flat_map_item(item).into_iter().map(StmtKind::Item).collect(),StmtKind::Expr(//; +expr)=>((vis.filter_map_expr(expr).into_iter ().map(StmtKind::Expr)).collect()), +StmtKind::Semi(expr)=>vis.filter_map_expr( expr).into_iter().map(StmtKind::Semi) +.collect(),StmtKind::Empty=>((smallvec![StmtKind::Empty])),StmtKind::MacCall(mut +mac)=>{3;let MacCallStmt{mac:mac_,style:_,attrs,tokens}=mac.deref_mut();3;3;vis. +visit_mac_call(mac_);;visit_attrs(attrs,vis);visit_lazy_tts(tokens,vis);smallvec +![StmtKind::MacCall(mac)]}}}pub fn noop_visit_vis(visibility:&mut +Visibility,vis:&mut T){match((((&mut visibility.kind)))){VisibilityKind::Public| +VisibilityKind::Inherited=>{}VisibilityKind::Restricted{path,id,shorthand:_}=>{; +vis.visit_path(path);;;vis.visit_id(id);}}vis.visit_span(&mut visibility.span);} +pub fn noop_visit_capture_by(capture_by :&mut CaptureBy,vis:&mut T +){match capture_by{CaptureBy::Ref=>{}CaptureBy::Value{move_kw}=>{;vis.visit_span +(move_kw);();}}}pub trait DummyAstNode{fn dummy()->Self;}implDummyAstNode for +Option{fn dummy()->Self{((Default ::default()))}}impl +DummyAstNode for P{fn dummy()->Self {(((P(((DummyAstNode::dummy()))))))}}impl +DummyAstNode for Item{fn dummy()->Self{Item{attrs:((((Default::default())))),id: +DUMMY_NODE_ID,span:(((Default::default()))),vis:Visibility{kind:VisibilityKind:: +Public,span:Default::default(),tokens:Default:: default(),},ident:Ident::empty() +,kind:(((ItemKind::ExternCrate(None)))),tokens :(((Default::default()))),}}}impl +DummyAstNode for Expr{fn dummy()->Self{Expr{id:DUMMY_NODE_ID,kind:ExprKind:://3; +Dummy,span:Default::default(),attrs: Default::default(),tokens:Default::default( +),}}}impl DummyAstNode for Ty{fn dummy()->Self{Ty{id:DUMMY_NODE_ID,kind:TyKind// +::Dummy,span:(Default::default()),tokens:Default::default(),}}}impl DummyAstNode +for Pat{fn dummy()->Self{Pat{ id:DUMMY_NODE_ID,kind:PatKind::Wild,span:Default:: +default(),tokens:(Default::default()),}}}impl DummyAstNode for Stmt{fn dummy()-> +Self{(Stmt{id:DUMMY_NODE_ID,kind:StmtKind::Empty,span:Default::default()})}}impl +DummyAstNode for Crate{fn dummy()->Self{ Crate{attrs:(Default::default()),items: +Default::default(),spans:((Default::default())),id:DUMMY_NODE_ID,is_placeholder: +Default::default(),}}}impl< N:DummyAstNode,T:DummyAstNode>DummyAstNode for crate +::ast_traits::AstNodeWrapper{fn dummy()->Self{crate::ast_traits:://((),()); +AstNodeWrapper::new((((((((((N::dummy()))))))))),(((((((((T::dummy()))))))))))}} diff --git a/compiler/rustc_ast/src/node_id.rs b/compiler/rustc_ast/src/node_id.rs index 1cd2449530901..583340ec3cb75 100644 --- a/compiler/rustc_ast/src/node_id.rs +++ b/compiler/rustc_ast/src/node_id.rs @@ -1,41 +1,8 @@ -use rustc_span::LocalExpnId; -use std::fmt; - -rustc_index::newtype_index! { - /// Identifies an AST node. - /// - /// This identifies top-level definitions, expressions, and everything in between. - /// This is later turned into [`DefId`] and `HirId` for the HIR. - /// - /// [`DefId`]: rustc_span::def_id::DefId - #[encodable] - #[orderable] - #[debug_format = "NodeId({})"] - pub struct NodeId { - /// The [`NodeId`] used to represent the root of the crate. - const CRATE_NODE_ID = 0; - } -} - -rustc_data_structures::define_id_collections!(NodeMap, NodeSet, NodeMapEntry, NodeId); - -/// When parsing and at the beginning of doing expansions, we initially give all AST nodes -/// this dummy AST [`NodeId`]. Then, during a later phase of expansion, we renumber them -/// to have small, positive IDs. -pub const DUMMY_NODE_ID: NodeId = NodeId::MAX; - -impl NodeId { - pub fn placeholder_from_expn_id(expn_id: LocalExpnId) -> Self { - NodeId::from_u32(expn_id.as_u32()) - } - - pub fn placeholder_to_expn_id(self) -> LocalExpnId { - LocalExpnId::from_u32(self.as_u32()) - } -} - -impl fmt::Display for NodeId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&self.as_u32(), f) - } -} +use rustc_span::LocalExpnId;use std::fmt;rustc_index::newtype_index!{#[//*&*&(); +encodable]#[orderable]#[debug_format="NodeId({})"]pub struct NodeId{const//({}); +CRATE_NODE_ID=0;}}rustc_data_structures ::define_id_collections!(NodeMap,NodeSet +,NodeMapEntry,NodeId);pub const DUMMY_NODE_ID:NodeId=NodeId::MAX;impl NodeId{//; +pub fn placeholder_from_expn_id(expn_id:LocalExpnId)->Self{NodeId::from_u32(//3; +expn_id.as_u32())}pub fn placeholder_to_expn_id(self)->LocalExpnId{LocalExpnId// +::from_u32(self.as_u32())}}impl fmt:: Display for NodeId{fn fmt(&self,f:&mut fmt +::Formatter<'_>)->fmt::Result{((fmt::Display::fmt (((&((self.as_u32())))),f)))}} diff --git a/compiler/rustc_ast/src/ptr.rs b/compiler/rustc_ast/src/ptr.rs index 0140fb752bf92..59340923d5710 100644 --- a/compiler/rustc_ast/src/ptr.rs +++ b/compiler/rustc_ast/src/ptr.rs @@ -1,212 +1,35 @@ -//! The AST pointer. -//! -//! Provides `P`, a frozen owned smart pointer. -//! -//! # Motivations and benefits -//! -//! * **Identity**: sharing AST nodes is problematic for the various analysis -//! passes (e.g., one may be able to bypass the borrow checker with a shared -//! `ExprKind::AddrOf` node taking a mutable borrow). -//! -//! * **Immutability**: `P` disallows mutating its inner `T`, unlike `Box` -//! (unless it contains an `Unsafe` interior, but that may be denied later). -//! This mainly prevents mistakes, but also enforces a kind of "purity". -//! -//! * **Efficiency**: folding can reuse allocation space for `P` and `Vec`, -//! the latter even when the input and output types differ (as it would be the -//! case with arenas or a GADT AST using type parameters to toggle features). -//! -//! * **Maintainability**: `P` provides a fixed interface - `Deref`, -//! `and_then` and `map` - which can remain fully functional even if the -//! implementation changes (using a special thread-local heap, for example). -//! Moreover, a switch to, e.g., `P<'a, T>` would be easy and mostly automated. - -use std::fmt::{self, Debug, Display}; -use std::ops::{Deref, DerefMut}; -use std::{slice, vec}; - -use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; - -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -/// An owned smart pointer. -pub struct P { - ptr: Box, -} - -/// Construct a `P` from a `T` value. -#[allow(non_snake_case)] -pub fn P(value: T) -> P { - P { ptr: Box::new(value) } -} - -impl P { - /// Move out of the pointer. - /// Intended for chaining transformations not covered by `map`. - pub fn and_then(self, f: F) -> U - where - F: FnOnce(T) -> U, - { - f(*self.ptr) - } - - /// Equivalent to `and_then(|x| x)`. - pub fn into_inner(self) -> T { - *self.ptr - } - - /// Produce a new `P` from `self` without reallocating. - pub fn map(mut self, f: F) -> P - where - F: FnOnce(T) -> T, - { - let x = f(*self.ptr); - *self.ptr = x; - - self - } - - /// Optionally produce a new `P` from `self` without reallocating. - pub fn filter_map(mut self, f: F) -> Option> - where - F: FnOnce(T) -> Option, - { - *self.ptr = f(*self.ptr)?; - Some(self) - } -} - -impl Deref for P { - type Target = T; - - fn deref(&self) -> &T { - &self.ptr - } -} - -impl DerefMut for P { - fn deref_mut(&mut self) -> &mut T { - &mut self.ptr - } -} - -impl Clone for P { - fn clone(&self) -> P { - P((**self).clone()) - } -} - -impl Debug for P { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - Debug::fmt(&self.ptr, f) - } -} - -impl Display for P { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - Display::fmt(&**self, f) - } -} - -impl fmt::Pointer for P { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Pointer::fmt(&self.ptr, f) - } -} - -impl> Decodable for P { - fn decode(d: &mut D) -> P { - P(Decodable::decode(d)) - } -} - -impl> Encodable for P { - fn encode(&self, s: &mut S) { - (**self).encode(s); - } -} - -impl P<[T]> { - // FIXME(const-hack) make this const again - pub fn new() -> P<[T]> { - P { ptr: Box::default() } - } - - #[inline(never)] - pub fn from_vec(v: Vec) -> P<[T]> { - P { ptr: v.into_boxed_slice() } - } - - #[inline(never)] - pub fn into_vec(self) -> Vec { - self.ptr.into_vec() - } -} - -impl Default for P<[T]> { - /// Creates an empty `P<[T]>`. - fn default() -> P<[T]> { - P::new() - } -} - -impl Clone for P<[T]> { - fn clone(&self) -> P<[T]> { - P::from_vec(self.to_vec()) - } -} - -impl From> for P<[T]> { - fn from(v: Vec) -> Self { - P::from_vec(v) - } -} - -impl Into> for P<[T]> { - fn into(self) -> Vec { - self.into_vec() - } -} - -impl FromIterator for P<[T]> { - fn from_iter>(iter: I) -> P<[T]> { - P::from_vec(iter.into_iter().collect()) - } -} - -impl IntoIterator for P<[T]> { - type Item = T; - type IntoIter = vec::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.into_vec().into_iter() - } -} - -impl<'a, T> IntoIterator for &'a P<[T]> { - type Item = &'a T; - type IntoIter = slice::Iter<'a, T>; - fn into_iter(self) -> Self::IntoIter { - self.ptr.into_iter() - } -} - -impl> Encodable for P<[T]> { - fn encode(&self, s: &mut S) { - Encodable::encode(&**self, s); - } -} - -impl> Decodable for P<[T]> { - fn decode(d: &mut D) -> P<[T]> { - P::from_vec(Decodable::decode(d)) - } -} - -impl HashStable for P -where - T: ?Sized + HashStable, -{ - fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { - (**self).hash_stable(hcx, hasher); - } -} +use std::fmt::{self,Debug,Display};use std::ops::{Deref,DerefMut};use std::{//3; +slice,vec};use rustc_serialize::{Decodable,Decoder,Encodable,Encoder};use//({}); +rustc_data_structures::stable_hasher::{HashStable,StableHasher} ;pub struct P{ptr:Box,}#[allow(non_snake_case)]pub fn P(value:T)->P{ +P{ptr:((Box::new(value)))}}implP{pub fn and_then(self,f:F)->U +where F:FnOnce(T)->U,{(f(*self.ptr))}pub fn into_inner(self)->T{*self.ptr}pub fn +map(mut self,f:F)->Pwhere F:FnOnce(T)->T,{;let x=f(*self.ptr);*self.ptr=x; +self}pub fn filter_map(mut self,f:F )->Option>where F:FnOnce(T)->Option< +T>,{{;};*self.ptr=f(*self.ptr)?;();Some(self)}}implDeref for P{type +Target=T;fn deref(&self)->&T{(((&self.ptr)))}}implDerefMut for P{fn +deref_mut(&mut self)->&mut T{&mut self. ptr}}implClone for P +{fn clone(&self)->P{P((**self) .clone())}}implDebug for P{ +fn fmt(&self,f:&mut fmt::Formatter<'_>)->fmt::Result{(Debug::fmt(&self.ptr,f))}} +implDisplay for P{fn fmt(&self,f:&mut fmt::Formatter<'_>)->fmt::// +Result{(Display::fmt(&**self,f))}}impl fmt::Pointer for P{fn fmt(&self,f:& +mut fmt::Formatter<'_>)->fmt::Result{(fmt::Pointer::fmt((&self.ptr),f))}}impl>Decodablefor P {fn decode(d:&mut D)->P{P +((Decodable::decode(d)))}}impl>Encodablefor P{fn +encode(&self,s:&mut S){;(**self).encode(s);}}implP<[T]>{pub fn new()->P<[T]>{ +P{ptr:Box::default()}}#[inline(never)]pub fn from_vec(v:Vec)->P<[T]>{P{ptr:v +.into_boxed_slice()}}#[inline(never)]pub fn into_vec(self)->Vec{self.ptr.//3; +into_vec()}}implDefault for P<[T]>{fn default()->P<[T]>{((P::new()))}}implClone for P<[T]>{fn clone(&self)->P <[T]>{P::from_vec(self.to_vec())}}impl +From>for P<[T]>{fn from(v:Vec)->Self{(P::from_vec(v))}}implInto< +Vec>for P<[T]>{fn into(self)->Vec {self.into_vec()}}implFromIterator +for P<[T]>{fn from_iter>(iter:I)->P<[T]>{P::from_vec(//3; +iter.into_iter().collect())}}implIntoIterator for P<[T]>{type Item=T;type//3; +IntoIter=vec::IntoIter;fn into_iter(self )->Self::IntoIter{(self.into_vec()). +into_iter()}}impl<'a,T>IntoIterator for&'a P<[T]>{type Item=&'a T;type IntoIter +=slice::Iter<'a,T>;fn into_iter(self)->Self::IntoIter{((self.ptr.into_iter()))}} +impl>Encodablefor P<[T]>{fn encode(&self,s:&mut S){; +Encodable::encode(&**self,s);;}}impl>Decodablefor P< +[T]>{fn decode(d:&mut D)->P<[T]> {P::from_vec(Decodable::decode(d))}}impl +HashStablefor Pwhere T:? Sized+HashStable,{fn hash_stable(&self,hcx +:&mut CTX,hasher:&mut StableHasher){({});(**self).hash_stable(hcx,hasher);{;};}} diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index f49eb2f22c50b..bb9696e559df0 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -1,1035 +1,219 @@ -pub use BinOpToken::*; -pub use LitKind::*; -pub use Nonterminal::*; -pub use TokenKind::*; - -use crate::ast; -use crate::ptr::P; -use crate::util::case::Case; - -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::Lrc; -use rustc_macros::HashStable_Generic; -use rustc_span::symbol::{kw, sym}; -#[allow(clippy::useless_attribute)] // FIXME: following use of `hidden_glob_reexports` incorrectly triggers `useless_attribute` lint. -#[allow(hidden_glob_reexports)] -use rustc_span::symbol::{Ident, Symbol}; -use rustc_span::{edition::Edition, ErrorGuaranteed, Span, DUMMY_SP}; -use std::borrow::Cow; -use std::fmt; - -#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] -pub enum CommentKind { - Line, - Block, -} - -#[derive(Clone, PartialEq, Encodable, Decodable, Hash, Debug, Copy)] -#[derive(HashStable_Generic)] -pub enum BinOpToken { - Plus, - Minus, - Star, - Slash, - Percent, - Caret, - And, - Or, - Shl, - Shr, -} - -/// Describes how a sequence of token trees is delimited. -/// Cannot use `proc_macro::Delimiter` directly because this -/// structure should implement some additional traits. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -#[derive(Encodable, Decodable, Hash, HashStable_Generic)] -pub enum Delimiter { - /// `( ... )` - Parenthesis, - /// `{ ... }` - Brace, - /// `[ ... ]` - Bracket, - /// `Ø ... Ø` - /// An invisible delimiter, that may, for example, appear around tokens coming from a - /// "macro variable" `$var`. It is important to preserve operator priorities in cases like - /// `$var * 3` where `$var` is `1 + 2`. - /// Invisible delimiters might not survive roundtrip of a token stream through a string. - Invisible, -} - -// Note that the suffix is *not* considered when deciding the `LitKind` in this -// type. This means that float literals like `1f32` are classified by this type -// as `Int`. Only upon conversion to `ast::LitKind` will such a literal be -// given the `Float` kind. -#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] -pub enum LitKind { - Bool, // AST only, must never appear in a `Token` - Byte, - Char, - Integer, // e.g. `1`, `1u8`, `1f32` - Float, // e.g. `1.`, `1.0`, `1e3f32` - Str, - StrRaw(u8), // raw string delimited by `n` hash symbols - ByteStr, - ByteStrRaw(u8), // raw byte string delimited by `n` hash symbols - CStr, - CStrRaw(u8), - Err(ErrorGuaranteed), -} - -/// A literal token. -#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] -pub struct Lit { - pub kind: LitKind, - pub symbol: Symbol, - pub suffix: Option, -} - -impl Lit { - pub fn new(kind: LitKind, symbol: Symbol, suffix: Option) -> Lit { - Lit { kind, symbol, suffix } - } - - /// Returns `true` if this is semantically a float literal. This includes - /// ones like `1f32` that have an `Integer` kind but a float suffix. - pub fn is_semantic_float(&self) -> bool { - match self.kind { - LitKind::Float => true, - LitKind::Integer => match self.suffix { - Some(sym) => sym == sym::f32 || sym == sym::f64, - None => false, - }, - _ => false, - } - } - - /// Keep this in sync with `Token::can_begin_literal_maybe_minus` excluding unary negation. - pub fn from_token(token: &Token) -> Option { - match token.uninterpolate().kind { - Ident(name, IdentIsRaw::No) if name.is_bool_lit() => Some(Lit::new(Bool, name, None)), - Literal(token_lit) => Some(token_lit), - Interpolated(ref nt) - if let NtExpr(expr) | NtLiteral(expr) = &nt.0 - && let ast::ExprKind::Lit(token_lit) = expr.kind => - { - Some(token_lit) - } - _ => None, - } - } -} - -impl fmt::Display for Lit { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Lit { kind, symbol, suffix } = *self; - match kind { - Byte => write!(f, "b'{symbol}'")?, - Char => write!(f, "'{symbol}'")?, - Str => write!(f, "\"{symbol}\"")?, - StrRaw(n) => write!( - f, - "r{delim}\"{string}\"{delim}", - delim = "#".repeat(n as usize), - string = symbol - )?, - ByteStr => write!(f, "b\"{symbol}\"")?, - ByteStrRaw(n) => write!( - f, - "br{delim}\"{string}\"{delim}", - delim = "#".repeat(n as usize), - string = symbol - )?, - CStr => write!(f, "c\"{symbol}\"")?, - CStrRaw(n) => { - write!(f, "cr{delim}\"{symbol}\"{delim}", delim = "#".repeat(n as usize))? - } - Integer | Float | Bool | Err(_) => write!(f, "{symbol}")?, - } - - if let Some(suffix) = suffix { - write!(f, "{suffix}")?; - } - - Ok(()) - } -} - -impl LitKind { - /// An English article for the literal token kind. - pub fn article(self) -> &'static str { - match self { - Integer | Err(_) => "an", - _ => "a", - } - } - - pub fn descr(self) -> &'static str { - match self { - Bool => panic!("literal token contains `Lit::Bool`"), - Byte => "byte", - Char => "char", - Integer => "integer", - Float => "float", - Str | StrRaw(..) => "string", - ByteStr | ByteStrRaw(..) => "byte string", - CStr | CStrRaw(..) => "C string", - Err(_) => "error", - } - } - - pub(crate) fn may_have_suffix(self) -> bool { - matches!(self, Integer | Float | Err(_)) - } -} - -pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: IdentIsRaw) -> bool { - let ident_token = Token::new(Ident(name, is_raw), span); - - !ident_token.is_reserved_ident() - || ident_token.is_path_segment_keyword() - || [ - kw::Async, - kw::Do, - kw::Box, - kw::Break, - kw::Const, - kw::Continue, - kw::False, - kw::For, - kw::Gen, - kw::If, - kw::Let, - kw::Loop, - kw::Match, - kw::Move, - kw::Return, - kw::True, - kw::Try, - kw::Unsafe, - kw::While, - kw::Yield, - kw::Static, - ] - .contains(&name) -} - -fn ident_can_begin_type(name: Symbol, span: Span, is_raw: IdentIsRaw) -> bool { - let ident_token = Token::new(Ident(name, is_raw), span); - - !ident_token.is_reserved_ident() - || ident_token.is_path_segment_keyword() - || [kw::Underscore, kw::For, kw::Impl, kw::Fn, kw::Unsafe, kw::Extern, kw::Typeof, kw::Dyn] - .contains(&name) -} - -#[derive(PartialEq, Encodable, Decodable, Debug, Copy, Clone, HashStable_Generic)] -pub enum IdentIsRaw { - No, - Yes, -} - -impl From for IdentIsRaw { - fn from(b: bool) -> Self { - if b { Self::Yes } else { Self::No } - } -} - -impl From for bool { - fn from(is_raw: IdentIsRaw) -> bool { - matches!(is_raw, IdentIsRaw::Yes) - } -} - -// SAFETY: due to the `Clone` impl below, all fields of all variants other than -// `Interpolated` must impl `Copy`. -#[derive(PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] -pub enum TokenKind { - /* Expression-operator symbols. */ - /// `=` - Eq, - /// `<` - Lt, - /// `<=` - Le, - /// `==` - EqEq, - /// `!=` - Ne, - /// `>=` - Ge, - /// `>` - Gt, - /// `&&` - AndAnd, - /// `||` - OrOr, - /// `!` - Not, - /// `~` - Tilde, - BinOp(BinOpToken), - BinOpEq(BinOpToken), - - /* Structural symbols */ - /// `@` - At, - /// `.` - Dot, - /// `..` - DotDot, - /// `...` - DotDotDot, - /// `..=` - DotDotEq, - /// `,` - Comma, - /// `;` - Semi, - /// `:` - Colon, - /// `::` - ModSep, - /// `->` - RArrow, - /// `<-` - LArrow, - /// `=>` - FatArrow, - /// `#` - Pound, - /// `$` - Dollar, - /// `?` - Question, - /// Used by proc macros for representing lifetimes, not generated by lexer right now. - SingleQuote, - /// An opening delimiter (e.g., `{`). - OpenDelim(Delimiter), - /// A closing delimiter (e.g., `}`). - CloseDelim(Delimiter), - - /* Literals */ - Literal(Lit), - - /// Identifier token. - /// Do not forget about `NtIdent` when you want to match on identifiers. - /// It's recommended to use `Token::(ident,uninterpolate,uninterpolated_span)` to - /// treat regular and interpolated identifiers in the same way. - Ident(Symbol, IdentIsRaw), - /// Lifetime identifier token. - /// Do not forget about `NtLifetime` when you want to match on lifetime identifiers. - /// It's recommended to use `Token::(lifetime,uninterpolate,uninterpolated_span)` to - /// treat regular and interpolated lifetime identifiers in the same way. - Lifetime(Symbol), - - /// An embedded AST node, as produced by a macro. This only exists for - /// historical reasons. We'd like to get rid of it, for multiple reasons. - /// - It's conceptually very strange. Saying a token can contain an AST - /// node is like saying, in natural language, that a word can contain a - /// sentence. - /// - It requires special handling in a bunch of places in the parser. - /// - It prevents `Token` from implementing `Copy`. - /// It adds complexity and likely slows things down. Please don't add new - /// occurrences of this token kind! - Interpolated(Lrc<(Nonterminal, Span)>), - - /// A doc comment token. - /// `Symbol` is the doc comment's data excluding its "quotes" (`///`, `/**`, etc) - /// similarly to symbols in string literal tokens. - DocComment(CommentKind, ast::AttrStyle, Symbol), - - /// End Of File - Eof, -} - -impl Clone for TokenKind { - fn clone(&self) -> Self { - // `TokenKind` would impl `Copy` if it weren't for `Interpolated`. So - // for all other variants, this implementation of `clone` is just like - // a copy. This is faster than the `derive(Clone)` version which has a - // separate path for every variant. - match self { - Interpolated(nt) => Interpolated(nt.clone()), - _ => unsafe { std::ptr::read(self) }, - } - } -} - -#[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] -pub struct Token { - pub kind: TokenKind, - pub span: Span, -} - -impl TokenKind { - pub fn lit(kind: LitKind, symbol: Symbol, suffix: Option) -> TokenKind { - Literal(Lit::new(kind, symbol, suffix)) - } - - /// An approximation to proc-macro-style single-character operators used by rustc parser. - /// If the operator token can be broken into two tokens, the first of which is single-character, - /// then this function performs that operation, otherwise it returns `None`. - pub fn break_two_token_op(&self) -> Option<(TokenKind, TokenKind)> { - Some(match *self { - Le => (Lt, Eq), - EqEq => (Eq, Eq), - Ne => (Not, Eq), - Ge => (Gt, Eq), - AndAnd => (BinOp(And), BinOp(And)), - OrOr => (BinOp(Or), BinOp(Or)), - BinOp(Shl) => (Lt, Lt), - BinOp(Shr) => (Gt, Gt), - BinOpEq(Plus) => (BinOp(Plus), Eq), - BinOpEq(Minus) => (BinOp(Minus), Eq), - BinOpEq(Star) => (BinOp(Star), Eq), - BinOpEq(Slash) => (BinOp(Slash), Eq), - BinOpEq(Percent) => (BinOp(Percent), Eq), - BinOpEq(Caret) => (BinOp(Caret), Eq), - BinOpEq(And) => (BinOp(And), Eq), - BinOpEq(Or) => (BinOp(Or), Eq), - BinOpEq(Shl) => (Lt, Le), - BinOpEq(Shr) => (Gt, Ge), - DotDot => (Dot, Dot), - DotDotDot => (Dot, DotDot), - ModSep => (Colon, Colon), - RArrow => (BinOp(Minus), Gt), - LArrow => (Lt, BinOp(Minus)), - FatArrow => (Eq, Gt), - _ => return None, - }) - } - - /// Returns tokens that are likely to be typed accidentally instead of the current token. - /// Enables better error recovery when the wrong token is found. - pub fn similar_tokens(&self) -> Option> { - match *self { - Comma => Some(vec![Dot, Lt, Semi]), - Semi => Some(vec![Colon, Comma]), - Colon => Some(vec![Semi]), - FatArrow => Some(vec![Eq, RArrow, Ge, Gt]), - _ => None, - } - } - - pub fn should_end_const_arg(&self) -> bool { - matches!(self, Gt | Ge | BinOp(Shr) | BinOpEq(Shr)) - } -} - -impl Token { - pub fn new(kind: TokenKind, span: Span) -> Self { - Token { kind, span } - } - - /// Some token that will be thrown away later. - pub fn dummy() -> Self { - Token::new(TokenKind::Question, DUMMY_SP) - } - - /// Recovers a `Token` from an `Ident`. This creates a raw identifier if necessary. - pub fn from_ast_ident(ident: Ident) -> Self { - Token::new(Ident(ident.name, ident.is_raw_guess().into()), ident.span) - } - - /// 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 - /// for which spans affect name resolution and edition checks. - /// Note that keywords are also identifiers, so they should use this - /// if they keep spans or perform edition checks. - pub fn uninterpolated_span(&self) -> Span { - match &self.kind { - Interpolated(nt) => nt.0.use_span(), - _ => self.span, - } - } - - pub fn is_range_separator(&self) -> bool { - [DotDot, DotDotDot, DotDotEq].contains(&self.kind) - } - - pub fn is_punct(&self) -> bool { - 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 { - matches!(self.kind, BinOp(Plus) | BinOpEq(Plus)) - } - - /// Returns `true` if the token can appear at the start of an expression. - pub fn can_begin_expr(&self) -> bool { - match self.uninterpolate().kind { - Ident(name, is_raw) => - ident_can_begin_expr(name, self.span, is_raw), // value name or keyword - OpenDelim(..) | // tuple, array or block - Literal(..) | // literal - Not | // operator not - BinOp(Minus) | // unary minus - BinOp(Star) | // dereference - BinOp(Or) | OrOr | // closure - BinOp(And) | // reference - AndAnd | // double reference - // DotDotDot is no longer supported, but we need some way to display the error - DotDot | DotDotDot | DotDotEq | // range notation - Lt | BinOp(Shl) | // associated path - ModSep | // global path - Lifetime(..) | // labeled loop - Pound => true, // expression attributes - Interpolated(ref nt) => matches!(&nt.0, NtLiteral(..) | - NtExpr(..) | - NtBlock(..) | - NtPath(..)), - _ => false, - } - } - - /// Returns `true` if the token can appear at the start of a pattern. - /// - /// Shamelessly borrowed from `can_begin_expr`, only used for diagnostics right now. - pub fn can_begin_pattern(&self) -> bool { - match self.uninterpolate().kind { - Ident(name, is_raw) => - ident_can_begin_expr(name, self.span, is_raw), // value name or keyword - | OpenDelim(Delimiter::Bracket | Delimiter::Parenthesis) // tuple or array - | Literal(..) // literal - | BinOp(Minus) // unary minus - | BinOp(And) // reference - | AndAnd // double reference - // DotDotDot is no longer supported - | DotDot | DotDotDot | DotDotEq // ranges - | Lt | BinOp(Shl) // associated path - | ModSep => true, // global path - Interpolated(ref nt) => matches!(&nt.0, NtLiteral(..) | - NtPat(..) | - NtBlock(..) | - NtPath(..)), - _ => false, - } - } - - /// Returns `true` if the token can appear at the start of a type. - pub fn can_begin_type(&self) -> bool { - match self.uninterpolate().kind { - Ident(name, is_raw) => - ident_can_begin_type(name, self.span, is_raw), // type name or keyword - OpenDelim(Delimiter::Parenthesis) | // tuple - OpenDelim(Delimiter::Bracket) | // array - Not | // never - BinOp(Star) | // raw pointer - BinOp(And) | // reference - AndAnd | // double reference - Question | // maybe bound in trait object - Lifetime(..) | // lifetime bound in trait object - Lt | BinOp(Shl) | // associated path - ModSep => true, // global path - Interpolated(ref nt) => matches!(&nt.0, NtTy(..) | NtPath(..)), - // For anonymous structs or unions, which only appear in specific positions - // (type of struct fields or union fields), we don't consider them as regular types - _ => false, - } - } - - /// Returns `true` if the token can appear at the start of a const param. - pub fn can_begin_const_arg(&self) -> bool { - match self.kind { - OpenDelim(Delimiter::Brace) => true, - Interpolated(ref nt) => matches!(&nt.0, NtExpr(..) | NtBlock(..) | NtLiteral(..)), - _ => self.can_begin_literal_maybe_minus(), - } - } - - /// Returns `true` if the token can appear at the start of an item. - pub fn can_begin_item(&self) -> bool { - match self.kind { - Ident(name, _) => [ - kw::Fn, - kw::Use, - kw::Struct, - kw::Enum, - kw::Pub, - kw::Trait, - kw::Extern, - kw::Impl, - kw::Unsafe, - kw::Const, - kw::Static, - kw::Union, - kw::Macro, - kw::Mod, - kw::Type, - ] - .contains(&name), - _ => false, - } - } - - /// Returns `true` if the token is any literal. - pub fn is_lit(&self) -> bool { - matches!(self.kind, Literal(..)) - } - - /// Returns `true` if the token is any literal, a minus (which can prefix a literal, - /// for example a '-42', or one of the boolean idents). - /// - /// In other words, would this token be a valid start of `parse_literal_maybe_minus`? - /// - /// Keep this in sync with and `Lit::from_token`, excluding unary negation. - pub fn can_begin_literal_maybe_minus(&self) -> bool { - match self.uninterpolate().kind { - Literal(..) | BinOp(Minus) => true, - Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true, - Interpolated(ref nt) => match &nt.0 { - NtLiteral(_) => true, - NtExpr(e) => match &e.kind { - ast::ExprKind::Lit(_) => true, - ast::ExprKind::Unary(ast::UnOp::Neg, e) => { - matches!(&e.kind, ast::ExprKind::Lit(_)) - } - _ => false, - }, - _ => false, - }, - _ => false, - } - } - - /// A convenience function for matching on identifiers during parsing. - /// Turns interpolated identifier (`$i: ident`) or lifetime (`$l: lifetime`) token - /// into the regular identifier or lifetime token it refers to, - /// otherwise returns the original token. - pub fn uninterpolate(&self) -> Cow<'_, Token> { - match &self.kind { - Interpolated(nt) => match &nt.0 { - NtIdent(ident, is_raw) => { - Cow::Owned(Token::new(Ident(ident.name, *is_raw), ident.span)) - } - NtLifetime(ident) => Cow::Owned(Token::new(Lifetime(ident.name), ident.span)), - _ => Cow::Borrowed(self), - }, - _ => Cow::Borrowed(self), - } - } - - /// Returns an identifier if this token is an identifier. - #[inline] - pub fn ident(&self) -> Option<(Ident, IdentIsRaw)> { - // We avoid using `Token::uninterpolate` here because it's slow. - match &self.kind { - &Ident(name, is_raw) => Some((Ident::new(name, self.span), is_raw)), - Interpolated(nt) => match &nt.0 { - NtIdent(ident, is_raw) => Some((*ident, *is_raw)), - _ => None, - }, - _ => None, - } - } - - /// Returns a lifetime identifier if this token is a lifetime. - #[inline] - pub fn lifetime(&self) -> Option { - // We avoid using `Token::uninterpolate` here because it's slow. - match &self.kind { - &Lifetime(name) => Some(Ident::new(name, self.span)), - Interpolated(nt) => match &nt.0 { - NtLifetime(ident) => Some(*ident), - _ => None, - }, - _ => None, - } - } - - /// Returns `true` if the token is an identifier. - pub fn is_ident(&self) -> bool { - self.ident().is_some() - } - - /// Returns `true` if the token is a lifetime. - pub fn is_lifetime(&self) -> bool { - self.lifetime().is_some() - } - - /// Returns `true` if the token is an identifier whose name is the given - /// string slice. - pub fn is_ident_named(&self, name: Symbol) -> bool { - self.ident().is_some_and(|(ident, _)| ident.name == name) - } - - /// Returns `true` if the token is an interpolated path. - fn is_whole_path(&self) -> bool { - if let Interpolated(nt) = &self.kind - && let NtPath(..) = &nt.0 - { - return true; - } - - false - } - - /// Would `maybe_whole_expr` in `parser.rs` return `Ok(..)`? - /// That is, is this a pre-parsed expression dropped into the token stream - /// (which happens while parsing the result of macro expansion)? - pub fn is_whole_expr(&self) -> bool { - if let Interpolated(nt) = &self.kind - && let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtBlock(_) = &nt.0 - { - return true; - } - - false - } - - /// Is the token an interpolated block (`$b:block`)? - pub fn is_whole_block(&self) -> bool { - if let Interpolated(nt) = &self.kind - && let NtBlock(..) = &nt.0 - { - return true; - } - - false - } - - /// Returns `true` if the token is either the `mut` or `const` keyword. - pub fn is_mutability(&self) -> bool { - self.is_keyword(kw::Mut) || self.is_keyword(kw::Const) - } - - pub fn is_qpath_start(&self) -> bool { - self == &Lt || self == &BinOp(Shl) - } - - pub fn is_path_start(&self) -> bool { - self == &ModSep - || self.is_qpath_start() - || self.is_whole_path() - || self.is_path_segment_keyword() - || self.is_ident() && !self.is_reserved_ident() - } - - /// Returns `true` if the token is a given keyword, `kw`. - pub fn is_keyword(&self, kw: Symbol) -> bool { - self.is_non_raw_ident_where(|id| id.name == kw) - } - - /// Returns `true` if the token is a given keyword, `kw` or if `case` is `Insensitive` and this token is an identifier equal to `kw` ignoring the case. - pub fn is_keyword_case(&self, kw: Symbol, case: Case) -> bool { - self.is_keyword(kw) - || (case == Case::Insensitive - && self.is_non_raw_ident_where(|id| { - id.name.as_str().to_lowercase() == kw.as_str().to_lowercase() - })) - } - - pub fn is_path_segment_keyword(&self) -> bool { - self.is_non_raw_ident_where(Ident::is_path_segment_keyword) - } - - /// Returns true for reserved identifiers used internally for elided lifetimes, - /// unnamed method parameters, crate root module, error recovery etc. - pub fn is_special_ident(&self) -> bool { - self.is_non_raw_ident_where(Ident::is_special) - } - - /// Returns `true` if the token is a keyword used in the language. - pub fn is_used_keyword(&self) -> bool { - self.is_non_raw_ident_where(Ident::is_used_keyword) - } - - /// Returns `true` if the token is a keyword reserved for possible future use. - pub fn is_unused_keyword(&self) -> bool { - self.is_non_raw_ident_where(Ident::is_unused_keyword) - } - - /// Returns `true` if the token is either a special identifier or a keyword. - pub fn is_reserved_ident(&self) -> bool { - self.is_non_raw_ident_where(Ident::is_reserved) - } - - /// Returns `true` if the token is the identifier `true` or `false`. - pub fn is_bool_lit(&self) -> bool { - self.is_non_raw_ident_where(|id| id.name.is_bool_lit()) - } - - pub fn is_numeric_lit(&self) -> bool { - matches!( - self.kind, - Literal(Lit { kind: LitKind::Integer, .. }) | Literal(Lit { kind: LitKind::Float, .. }) - ) - } - - /// Returns `true` if the token is the integer literal. - pub fn is_integer_lit(&self) -> bool { - matches!(self.kind, Literal(Lit { kind: LitKind::Integer, .. })) - } - - /// Returns `true` if the token is a non-raw identifier for which `pred` holds. - pub fn is_non_raw_ident_where(&self, pred: impl FnOnce(Ident) -> bool) -> bool { - match self.ident() { - Some((id, IdentIsRaw::No)) => pred(id), - _ => false, - } - } - - pub fn glue(&self, joint: &Token) -> Option { - let kind = match self.kind { - Eq => match joint.kind { - Eq => EqEq, - Gt => FatArrow, - _ => return None, - }, - Lt => match joint.kind { - Eq => Le, - Lt => BinOp(Shl), - Le => BinOpEq(Shl), - BinOp(Minus) => LArrow, - _ => return None, - }, - Gt => match joint.kind { - Eq => Ge, - Gt => BinOp(Shr), - Ge => BinOpEq(Shr), - _ => return None, - }, - Not => match joint.kind { - Eq => Ne, - _ => return None, - }, - BinOp(op) => match joint.kind { - Eq => BinOpEq(op), - BinOp(And) if op == And => AndAnd, - BinOp(Or) if op == Or => OrOr, - Gt if op == Minus => RArrow, - _ => return None, - }, - Dot => match joint.kind { - Dot => DotDot, - DotDot => DotDotDot, - _ => return None, - }, - DotDot => match joint.kind { - Dot => DotDotDot, - Eq => DotDotEq, - _ => return None, - }, - Colon => match joint.kind { - Colon => ModSep, - _ => return None, - }, - SingleQuote => match joint.kind { - Ident(name, IdentIsRaw::No) => Lifetime(Symbol::intern(&format!("'{name}"))), - _ => return None, - }, - - Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot - | DotDotEq | Comma | Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar - | Question | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..) - | Lifetime(..) | Interpolated(..) | DocComment(..) | Eof => return None, - }; - - Some(Token::new(kind, self.span.to(joint.span))) - } -} - -impl PartialEq for Token { - #[inline] - fn eq(&self, rhs: &TokenKind) -> bool { - self.kind == *rhs - } -} - -#[derive(Clone, Encodable, Decodable)] -/// For interpolation during macro expansion. -pub enum Nonterminal { - NtItem(P), - NtBlock(P), - NtStmt(P), - NtPat(P), - NtExpr(P), - NtTy(P), - NtIdent(Ident, IdentIsRaw), - NtLifetime(Ident), - NtLiteral(P), - /// Stuff inside brackets for attributes - NtMeta(P), - NtPath(P), - NtVis(P), -} - -#[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable)] -pub enum NonterminalKind { - Item, - Block, - Stmt, - PatParam { - /// Keep track of whether the user used `:pat_param` or `:pat` and we inferred it from the - /// edition of the span. This is used for diagnostics. - inferred: bool, - }, - PatWithOr, - Expr, - Ty, - Ident, - Lifetime, - Literal, - Meta, - Path, - Vis, - TT, -} - -impl NonterminalKind { - /// The `edition` closure is used to get the edition for the given symbol. Doing - /// `span.edition()` is expensive, so we do it lazily. - pub fn from_symbol( - symbol: Symbol, - edition: impl FnOnce() -> Edition, - ) -> Option { - Some(match symbol { - sym::item => NonterminalKind::Item, - sym::block => NonterminalKind::Block, - sym::stmt => NonterminalKind::Stmt, - sym::pat => match edition() { - Edition::Edition2015 | Edition::Edition2018 => { - NonterminalKind::PatParam { inferred: true } - } - Edition::Edition2021 | Edition::Edition2024 => NonterminalKind::PatWithOr, - }, - sym::pat_param => NonterminalKind::PatParam { inferred: false }, - sym::expr => NonterminalKind::Expr, - sym::ty => NonterminalKind::Ty, - sym::ident => NonterminalKind::Ident, - sym::lifetime => NonterminalKind::Lifetime, - sym::literal => NonterminalKind::Literal, - sym::meta => NonterminalKind::Meta, - sym::path => NonterminalKind::Path, - sym::vis => NonterminalKind::Vis, - sym::tt => NonterminalKind::TT, - _ => return None, - }) - } - fn symbol(self) -> Symbol { - match self { - NonterminalKind::Item => sym::item, - NonterminalKind::Block => sym::block, - NonterminalKind::Stmt => sym::stmt, - NonterminalKind::PatParam { inferred: false } => sym::pat_param, - NonterminalKind::PatParam { inferred: true } | NonterminalKind::PatWithOr => sym::pat, - NonterminalKind::Expr => sym::expr, - NonterminalKind::Ty => sym::ty, - NonterminalKind::Ident => sym::ident, - NonterminalKind::Lifetime => sym::lifetime, - NonterminalKind::Literal => sym::literal, - NonterminalKind::Meta => sym::meta, - NonterminalKind::Path => sym::path, - NonterminalKind::Vis => sym::vis, - NonterminalKind::TT => sym::tt, - } - } -} - -impl fmt::Display for NonterminalKind { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.symbol()) - } -} - -impl Nonterminal { - pub fn use_span(&self) -> Span { - match self { - NtItem(item) => item.span, - NtBlock(block) => block.span, - NtStmt(stmt) => stmt.span, - NtPat(pat) => pat.span, - NtExpr(expr) | NtLiteral(expr) => expr.span, - NtTy(ty) => ty.span, - NtIdent(ident, _) | NtLifetime(ident) => ident.span, - NtMeta(attr_item) => attr_item.span(), - NtPath(path) => path.span, - NtVis(vis) => vis.span, - } - } - - pub fn descr(&self) -> &'static str { - match self { - NtItem(..) => "item", - NtBlock(..) => "block", - NtStmt(..) => "statement", - NtPat(..) => "pattern", - NtExpr(..) => "expression", - NtLiteral(..) => "literal", - NtTy(..) => "type", - NtIdent(..) => "identifier", - NtLifetime(..) => "lifetime", - NtMeta(..) => "attribute", - NtPath(..) => "path", - NtVis(..) => "visibility", - } - } -} - -impl PartialEq for Nonterminal { - fn eq(&self, rhs: &Self) -> bool { - match (self, rhs) { - (NtIdent(ident_lhs, is_raw_lhs), NtIdent(ident_rhs, is_raw_rhs)) => { - ident_lhs == ident_rhs && is_raw_lhs == is_raw_rhs - } - (NtLifetime(ident_lhs), NtLifetime(ident_rhs)) => ident_lhs == ident_rhs, - // FIXME: Assume that all "complex" nonterminal are not equal, we can't compare them - // correctly based on data from AST. This will prevent them from matching each other - // in macros. The comparison will become possible only when each nonterminal has an - // attached token stream from which it was parsed. - _ => false, - } - } -} - -impl fmt::Debug for Nonterminal { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - NtItem(..) => f.pad("NtItem(..)"), - NtBlock(..) => f.pad("NtBlock(..)"), - NtStmt(..) => f.pad("NtStmt(..)"), - NtPat(..) => f.pad("NtPat(..)"), - NtExpr(..) => f.pad("NtExpr(..)"), - NtTy(..) => f.pad("NtTy(..)"), - NtIdent(..) => f.pad("NtIdent(..)"), - NtLiteral(..) => f.pad("NtLiteral(..)"), - NtMeta(..) => f.pad("NtMeta(..)"), - NtPath(..) => f.pad("NtPath(..)"), - NtVis(..) => f.pad("NtVis(..)"), - NtLifetime(..) => f.pad("NtLifetime(..)"), - } - } -} - -impl HashStable for Nonterminal -where - CTX: crate::HashStableContext, -{ - fn hash_stable(&self, _hcx: &mut CTX, _hasher: &mut StableHasher) { - 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 -} +pub use BinOpToken::*;pub use LitKind::*;pub use Nonterminal::*;pub use//*&*&(); +TokenKind::*;use crate::ast;use crate::ptr::P;use crate::util::case::Case;use//; +rustc_data_structures::stable_hasher::{HashStable,StableHasher};use//let _=||(); +rustc_data_structures::sync::Lrc;use rustc_macros::HashStable_Generic;use//({}); +rustc_span::symbol::{kw,sym};#[allow(clippy::useless_attribute)]#[allow(//{();}; +hidden_glob_reexports)]use rustc_span::symbol::{ Ident,Symbol};use rustc_span::{ +edition::Edition,ErrorGuaranteed,Span,DUMMY_SP};use std::borrow::Cow;use std::// +fmt;#[derive(Clone,Copy, PartialEq,Encodable,Decodable,Debug,HashStable_Generic) +]pub enum CommentKind{Line,Block,} #[derive(Clone,PartialEq,Encodable,Decodable, +Hash,Debug,Copy)]#[derive(HashStable_Generic)]pub enum BinOpToken{Plus,Minus,//; +Star,Slash,Percent,Caret,And,Or,Shl,Shr ,}#[derive(Copy,Clone,Debug,PartialEq,Eq +)]#[derive(Encodable,Decodable,Hash,HashStable_Generic)]pub enum Delimiter{//(); +Parenthesis,Brace,Bracket,Invisible,}#[derive(Clone,Copy,PartialEq,Encodable,//; +Decodable,Debug,HashStable_Generic)]pub enum LitKind{Bool,Byte,Char,Integer,//3; +Float,Str,StrRaw(u8),ByteStr,ByteStrRaw(u8),CStr,CStrRaw(u8),Err(//loop{break;}; +ErrorGuaranteed),}#[derive(Clone,Copy,PartialEq,Encodable,Decodable,Debug,//{;}; +HashStable_Generic)]pub struct Lit{pub kind:LitKind,pub symbol:Symbol,pub//({}); +suffix:Option,}impl Lit{pub fn new(kind:LitKind,symbol:Symbol,suffix://; +Option)->Lit{(Lit{kind,symbol,suffix})}pub fn is_semantic_float(&self)-> +bool{match self.kind{LitKind::Float=>(true),LitKind::Integer=>match self.suffix{ +Some(sym)=>((sym==sym::f32)||(sym==sym::f64) ),None=>(false),},_=>false,}}pub fn +from_token(token:&Token)->Option{ match (token.uninterpolate()).kind{Ident( +name,IdentIsRaw::No)if (name.is_bool_lit())=>(Some((Lit::new(Bool,name,None)))), +Literal(token_lit)=>((Some(token_lit))),Interpolated(ref nt)if let NtExpr(expr)| +NtLiteral(expr)=(((&nt.0)))&&let ast::ExprKind::Lit(token_lit)=expr.kind=>{Some( +token_lit)}_=>None,}}}impl fmt::Display for Lit{fn fmt(&self,f:&mut fmt:://({}); +Formatter<'_>)->fmt::Result{;let Lit{kind,symbol,suffix}=*self;match kind{Byte=> +write!(f,"b'{symbol}'")?,Char=>(((((write! (f,"'{symbol}'")))?))),Str=>write!(f, +"\"{symbol}\"")?,StrRaw(n)=>write!(f,"r{delim}\"{string}\"{delim}",delim="#".//; +repeat(n as usize),string=symbol)? ,ByteStr=>((((write!(f,"b\"{symbol}\"")))?)), +ByteStrRaw(n)=>write!(f,"br{delim}\"{string}\"{delim}",delim="#".repeat(n as//3; +usize),string=symbol)?,CStr=>(write!(f,"c\"{symbol}\"")?),CStrRaw(n)=>{write!(f, +"cr{delim}\"{symbol}\"{delim}",delim="#".repeat(n as usize))?}Integer|Float|//3; +Bool|Err(_)=>write!(f,"{symbol}")?,}if let Some(suffix)=suffix{((),());write!(f, +"{suffix}")?;({});}Ok(())}}impl LitKind{pub fn article(self)->&'static str{match +self{Integer|Err(_)=>"an",_=>"a", }}pub fn descr(self)->&'static str{match self{ +Bool=>(panic!("literal token contains `Lit::Bool`")),Byte =>"byte",Char=>"char", +Integer=>("integer"),Float=>"float",Str|StrRaw(..)=>"string",ByteStr|ByteStrRaw( +..)=>("byte string"),CStr|CStrRaw(..)=>"C string",Err(_)=>"error",}}pub(crate)fn +may_have_suffix(self)->bool{((((matches!(self,Integer |Float|Err(_))))))}}pub fn +ident_can_begin_expr(name:Symbol,span:Span,is_raw:IdentIsRaw)->bool{let _=();let +ident_token=Token::new(Ident(name,is_raw),span);;!ident_token.is_reserved_ident( +)||(ident_token.is_path_segment_keyword())||[kw::Async,kw::Do,kw::Box,kw::Break, +kw::Const,kw::Continue,kw::False,kw::For,kw::Gen,kw::If,kw::Let,kw::Loop,kw:://; +Match,kw::Move,kw::Return,kw::True,kw::Try,kw::Unsafe,kw::While,kw::Yield,kw::// +Static,].contains((&name))}fn ident_can_begin_type(name:Symbol,span:Span,is_raw: +IdentIsRaw)->bool{({});let ident_token=Token::new(Ident(name,is_raw),span);{;};! +ident_token.is_reserved_ident()||(ident_token. is_path_segment_keyword())||[kw:: +Underscore,kw::For,kw::Impl,kw::Fn,kw::Unsafe,kw::Extern,kw::Typeof,kw::Dyn].//; +contains(((((&name)))))}#[derive(PartialEq,Encodable,Decodable,Debug,Copy,Clone, +HashStable_Generic)]pub enum IdentIsRaw{No,Yes,}impl Fromfor IdentIsRaw{// +fn from(b:bool)->Self{if b{Self::Yes}else{Self::No}}}impl Fromfor//; +bool{fn from(is_raw:IdentIsRaw)->bool{(((matches!(is_raw,IdentIsRaw::Yes))))}}#[ +derive(PartialEq,Encodable,Decodable,Debug,HashStable_Generic)]pub enum//*&*&(); +TokenKind{Eq,Lt,Le,EqEq,Ne,Ge,Gt,AndAnd,OrOr,Not,Tilde,BinOp(BinOpToken),//({}); +BinOpEq(BinOpToken),At,Dot,DotDot,DotDotDot,DotDotEq,Comma,Semi,Colon,ModSep,//; +RArrow,LArrow,FatArrow,Pound,Dollar,Question,SingleQuote,OpenDelim(Delimiter),// +CloseDelim(Delimiter),Literal(Lit),Ident(Symbol,IdentIsRaw),Lifetime(Symbol),//; +Interpolated(Lrc<(Nonterminal,Span)>),DocComment(CommentKind,ast::AttrStyle,//3; +Symbol),Eof,}impl Clone for TokenKind{fn clone(&self)->Self{match self{//*&*&(); +Interpolated(nt)=>Interpolated(nt.clone()),_ =>unsafe{std::ptr::read(self)},}}}# +[derive(Clone,PartialEq,Encodable,Decodable,Debug,HashStable_Generic)]pub//({}); +struct Token{pub kind:TokenKind,pub span:Span,}impl TokenKind{pub fn lit(kind:// +LitKind,symbol:Symbol,suffix:Option)->TokenKind{Literal(Lit::new(kind,// +symbol,suffix))}pub fn break_two_token_op (&self)->Option<(TokenKind,TokenKind)> +{Some(match(*self){Le=>(Lt,Eq),EqEq=>(Eq,Eq ),Ne=>(Not,Eq),Ge=>(Gt,Eq),AndAnd=>( +BinOp(And),(BinOp(And))),OrOr=>(BinOp(Or) ,BinOp(Or)),BinOp(Shl)=>(Lt,Lt),BinOp( +Shr)=>(Gt,Gt),BinOpEq(Plus)=>(BinOp(Plus) ,Eq),BinOpEq(Minus)=>(BinOp(Minus),Eq) +,BinOpEq(Star)=>(((BinOp(Star)),Eq)), BinOpEq(Slash)=>(BinOp(Slash),Eq),BinOpEq( +Percent)=>(BinOp(Percent),Eq),BinOpEq(Caret)=> (BinOp(Caret),Eq),BinOpEq(And)=>( +BinOp(And),Eq),BinOpEq(Or)=>(BinOp(Or) ,Eq),BinOpEq(Shl)=>(Lt,Le),BinOpEq(Shr)=> +(Gt,Ge),DotDot=>((Dot,Dot)),DotDotDot=>(Dot,DotDot),ModSep=>(Colon,Colon),RArrow +=>(BinOp(Minus),Gt),LArrow=>(Lt,BinOp( Minus)),FatArrow=>(Eq,Gt),_=>return None, +})}pub fn similar_tokens(&self)->Option< Vec>{match*self{Comma=>Some( +vec![Dot,Lt,Semi]),Semi=>(Some((vec![ Colon,Comma]))),Colon=>(Some(vec![Semi])), +FatArrow=>(Some(vec![Eq,RArrow,Ge,Gt] )),_=>None,}}pub fn should_end_const_arg(& +self)->bool{matches!(self,Gt|Ge|BinOp(Shr )|BinOpEq(Shr))}}impl Token{pub fn new +(kind:TokenKind,span:Span)->Self{(Token{kind,span})}pub fn dummy()->Self{Token:: +new(TokenKind::Question,DUMMY_SP)}pub fn from_ast_ident(ident:Ident)->Self{//(); +Token::new((Ident(ident.name,(ident.is_raw_guess() .into()))),ident.span)}pub fn +uninterpolated_span(&self)->Span{match((((&self.kind)))){Interpolated(nt)=>nt.0. +use_span(),_=>self.span,}}pub fn is_range_separator(&self)->bool{[DotDot,//({}); +DotDotDot,DotDotEq].contains(((&self.kind))) }pub fn is_punct(&self)->bool{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{(matches!(self.kind,BinOp(Plus)|BinOpEq(Plus)))}pub fn +can_begin_expr(&self)->bool{match (self.uninterpolate()).kind{Ident(name,is_raw) +=>((ident_can_begin_expr(name,self.span,is_raw))),OpenDelim(..)|Literal(..)|Not| +BinOp(Minus)|BinOp(Star)|BinOp(Or)|OrOr|BinOp(And)|AndAnd|DotDot|DotDotDot|//(); +DotDotEq|Lt|BinOp(Shl)|ModSep|Lifetime(..) |Pound=>(true),Interpolated(ref nt)=> +matches!(&nt.0,NtLiteral(..)|NtExpr(..)|NtBlock(..)|NtPath(..)),_=>(false),}}pub +fn can_begin_pattern(&self)->bool{match ( self.uninterpolate()).kind{Ident(name, +is_raw)=>((ident_can_begin_expr(name,self. span,is_raw))),|OpenDelim(Delimiter:: +Bracket|Delimiter::Parenthesis)|Literal(..)|BinOp(Minus)|BinOp(And)|AndAnd|//(); +DotDot|DotDotDot|DotDotEq|Lt|BinOp(Shl)| ModSep=>((true)),Interpolated(ref nt)=> +matches!(&nt.0,NtLiteral(..)|NtPat(..)|NtBlock (..)|NtPath(..)),_=>(false),}}pub +fn can_begin_type(&self)->bool{match (((self.uninterpolate()))).kind{Ident(name, +is_raw)=>(((ident_can_begin_type(name,self.span,is_raw)))),OpenDelim(Delimiter:: +Parenthesis)|OpenDelim(Delimiter::Bracket)|Not|BinOp(Star)|BinOp(And)|AndAnd|//; +Question|Lifetime(..)|Lt|BinOp(Shl)|ModSep =>true,Interpolated(ref nt)=>matches! +(&nt.0,NtTy(..)|NtPath(..)),_ =>false,}}pub fn can_begin_const_arg(&self)->bool{ +match self.kind{OpenDelim(Delimiter::Brace)=> true,Interpolated(ref nt)=>matches +!(&nt.0,NtExpr(..)|NtBlock(..)|NtLiteral(..)),_=>self.//loop{break};loop{break}; +can_begin_literal_maybe_minus(),}}pub fn can_begin_item(&self)->bool{match self +.kind{Ident(name,_)=>[kw::Fn,kw:: Use,kw::Struct,kw::Enum,kw::Pub,kw::Trait,kw:: +Extern,kw::Impl,kw::Unsafe,kw::Const,kw::Static,kw::Union,kw::Macro,kw::Mod,kw// +::Type,].contains((&name)),_=>false ,}}pub fn is_lit(&self)->bool{matches!(self. +kind,Literal(..))}pub fn can_begin_literal_maybe_minus(&self)->bool{match self. +uninterpolate().kind{Literal(..)|BinOp(Minus)=>(true),Ident(name,IdentIsRaw::No) +if name.is_bool_lit()=>true,Interpolated(ref nt)=>match&nt.0{NtLiteral(_)=>true +,NtExpr(e)=>match&e.kind{ast::ExprKind ::Lit(_)=>true,ast::ExprKind::Unary(ast:: +UnOp::Neg,e)=>{(matches!(&e.kind,ast::ExprKind::Lit(_)))}_=>false,},_=>false,},_ +=>(((false))),}}pub fn uninterpolate(&self) ->Cow<'_,Token>{match((&self.kind)){ +Interpolated(nt)=>match((&nt.0)){NtIdent(ident ,is_raw)=>{Cow::Owned(Token::new( +Ident(ident.name,*is_raw),ident.span) )}NtLifetime(ident)=>Cow::Owned(Token::new +((Lifetime(ident.name)),ident.span)),_ =>Cow::Borrowed(self),},_=>Cow::Borrowed( +self),}}#[inline]pub fn ident(&self)->Option<(Ident,IdentIsRaw)>{match&self.//3; +kind{&Ident(name,is_raw)=>((Some((((((Ident::new(name,self.span))),is_raw)))))), +Interpolated(nt)=>match(&nt.0){NtIdent(ident,is_raw)=>Some((*ident,*is_raw)),_=> +None,},_=>None,}}#[inline]pub fn lifetime(&self)->Option{match&self.kind +{&Lifetime(name)=>Some(Ident::new(name,self .span)),Interpolated(nt)=>match&nt.0 +{NtLifetime(ident)=>(Some(*ident)),_=>None ,},_=>None,}}pub fn is_ident(&self)-> +bool{((self.ident()).is_some())}pub fn is_lifetime(&self)->bool{self.lifetime(). +is_some()}pub fn is_ident_named(&self,name:Symbol)->bool{(((((self.ident()))))). +is_some_and((|(ident,_)|ident.name==name ))}fn is_whole_path(&self)->bool{if let +Interpolated(nt)=&self.kind&&let NtPath(..)=&nt.0{();return true;3;}false}pub fn +is_whole_expr(&self)->bool{if let Interpolated(nt )=(&self.kind)&&let NtExpr(_)| +NtLiteral(_)|NtPath(_)|NtBlock(_)=&nt.0{((),());return true;*&*&();}false}pub fn +is_whole_block(&self)->bool{if let Interpolated( nt)=&self.kind&&let NtBlock(..) +=&nt.0{;return true;;}false}pub fn is_mutability(&self)->bool{self.is_keyword(kw +::Mut)||self.is_keyword(kw::Const)}pub fn is_qpath_start(&self)->bool{self==&Lt +||(self==(&(BinOp(Shl))))}pub fn is_path_start(&self)->bool{self==&ModSep||self. +is_qpath_start()||(self.is_whole_path()) ||self.is_path_segment_keyword()||self. +is_ident()&&!self.is_reserved_ident() }pub fn is_keyword(&self,kw:Symbol)->bool{ +self.is_non_raw_ident_where((|id|id.name==kw ))}pub fn is_keyword_case(&self,kw: +Symbol,case:Case)->bool{(self.is_keyword(kw))||((case==Case::Insensitive)&&self. +is_non_raw_ident_where(|id|{((id.name.as_str( )).to_lowercase())==(kw.as_str()). +to_lowercase()}))}pub fn is_path_segment_keyword(&self)->bool{self.//let _=||(); +is_non_raw_ident_where(Ident::is_path_segment_keyword) }pub fn is_special_ident( +&self)->bool{(((((((self.is_non_raw_ident_where(Ident::is_special))))))))}pub fn +is_used_keyword(&self)->bool{ self.is_non_raw_ident_where(Ident::is_used_keyword +)}pub fn is_unused_keyword(&self)->bool{self.is_non_raw_ident_where(Ident:://(); +is_unused_keyword)}pub fn is_reserved_ident(&self)->bool{self.//((),());((),()); +is_non_raw_ident_where(Ident::is_reserved)}pub fn is_bool_lit(&self)->bool{self +.is_non_raw_ident_where(|id|id.name.is_bool_lit( ))}pub fn is_numeric_lit(&self) +->bool{matches!(self.kind,Literal(Lit{kind:LitKind::Integer,..})|Literal(Lit{//; +kind:LitKind::Float,..}))}pub fn is_integer_lit(&self)->bool{matches!(self.kind +,Literal(Lit{kind:LitKind::Integer,..}))}pub fn is_non_raw_ident_where(&self,//; +pred:impl FnOnce(Ident)->bool)->bool{match self.ident(){Some((id,IdentIsRaw::No +))=>pred(id),_=>false,}}pub fn glue(&self,joint:&Token)->Option{;let kind +=match self.kind{Eq=>match joint.kind{Eq=> EqEq,Gt=>FatArrow,_=>return None,},Lt +=>match joint.kind{Eq=>Le,Lt=>BinOp(Shl) ,Le=>BinOpEq(Shl),BinOp(Minus)=>LArrow, +_=>(return None),},Gt=>match joint.kind{Eq=>Ge,Gt=>BinOp(Shr),Ge=>BinOpEq(Shr),_ +=>(return None),},Not=>match joint.kind{Eq=>Ne,_=>return None,},BinOp(op)=>match +joint.kind{Eq=>(BinOpEq(op)),BinOp(And)if (op==And)=>AndAnd,BinOp(Or)if op==Or=> +OrOr,Gt if op==Minus=>RArrow,_=> return None,},Dot=>match joint.kind{Dot=>DotDot +,DotDot=>DotDotDot,_=>(return None),},DotDot=>match joint.kind{Dot=>DotDotDot,Eq +=>DotDotEq,_=>((return None)),},Colon =>match joint.kind{Colon=>ModSep,_=>return +None,},SingleQuote=>match joint.kind{Ident(name,IdentIsRaw::No)=>Lifetime(//{;}; +Symbol::intern(&format!("'{name}"))),_ =>return None,},Le|EqEq|Ne|Ge|AndAnd|OrOr +|Tilde|BinOpEq(..)|At|DotDotDot|DotDotEq|Comma|Semi|ModSep|RArrow|LArrow|//({}); +FatArrow|Pound|Dollar|Question|OpenDelim(..)|CloseDelim(..)|Literal(..)|Ident(// +..)|Lifetime(..)|Interpolated(..)|DocComment(..)|Eof=>return None,};3;Some(Token +::new(kind,((self.span.to(joint.span)))))}}impl PartialEqfor Token{#[ +inline]fn eq(&self,rhs:&TokenKind)->bool{ ((self.kind==(*rhs)))}}#[derive(Clone, +Encodable,Decodable)]pub enum Nonterminal{NtItem(P),NtBlock(P),NtStmt(P),NtPat(P),NtExpr(P),NtTy(P),NtIdent(Ident,IdentIsRaw),NtLifetime(Ident),NtLiteral(P),//(); +NtMeta(P),NtPath(P),NtVis(P),}#[//(); +derive(Debug,Copy,Clone,PartialEq, Encodable,Decodable)]pub enum NonterminalKind +{Item,Block,Stmt,PatParam{inferred:bool,},PatWithOr,Expr,Ty,Ident,Lifetime,//(); +Literal,Meta,Path,Vis,TT,}impl NonterminalKind{pub fn from_symbol(symbol:Symbol +,edition:impl FnOnce()->Edition,)->Option{Some(match symbol{//; +sym::item=>NonterminalKind::Item,sym:: block=>NonterminalKind::Block,sym::stmt=> +NonterminalKind::Stmt,sym::pat=>match (edition()){Edition::Edition2015|Edition:: +Edition2018=>{(NonterminalKind::PatParam{inferred:(true)})}Edition::Edition2021| +Edition::Edition2024=>NonterminalKind::PatWithOr,},sym::pat_param=>//let _=||(); +NonterminalKind::PatParam{inferred:(false)},sym::expr=>NonterminalKind::Expr,sym +::ty=>NonterminalKind::Ty,sym::ident=>NonterminalKind::Ident,sym::lifetime=>//3; +NonterminalKind::Lifetime,sym::literal=>NonterminalKind::Literal,sym::meta=>//3; +NonterminalKind::Meta,sym::path=>NonterminalKind::Path,sym::vis=>//loop{break;}; +NonterminalKind::Vis,sym::tt=>NonterminalKind::TT,_=>(return None),})}fn symbol( +self)->Symbol{match self{NonterminalKind::Item=>sym::item,NonterminalKind:://(); +Block=>sym::block,NonterminalKind::Stmt=>sym::stmt,NonterminalKind::PatParam{//; +inferred:false}=>sym::pat_param,NonterminalKind::PatParam{inferred:true}|//({}); +NonterminalKind::PatWithOr=>sym::pat,NonterminalKind::Expr=>sym::expr,//((),()); +NonterminalKind::Ty=>sym::ty, NonterminalKind::Ident=>sym::ident,NonterminalKind +::Lifetime=>sym::lifetime,NonterminalKind::Literal=>sym::literal,//loop{break;}; +NonterminalKind::Meta=>sym::meta,NonterminalKind::Path=>sym::path,//loop{break}; +NonterminalKind::Vis=>sym::vis,NonterminalKind::TT=>sym::tt,}}}impl fmt:://({}); +Display for NonterminalKind{fn fmt(&self,f:&mut fmt::Formatter<'_>)->fmt:://{;}; +Result{(write!(f,"{}",self.symbol()))}}impl Nonterminal{pub fn use_span(&self)-> +Span{match self{NtItem(item)=>item.span ,NtBlock(block)=>block.span,NtStmt(stmt) +=>stmt.span,NtPat(pat)=>pat.span,NtExpr(expr)|NtLiteral(expr)=>expr.span,NtTy(// +ty)=>ty.span,NtIdent(ident,_)| NtLifetime(ident)=>ident.span,NtMeta(attr_item)=> +attr_item.span(),NtPath(path)=>path.span,NtVis(vis)=>vis.span,}}pub fn descr(&// +self)->&'static str{match self{NtItem(..)=>("item"),NtBlock(..)=>"block",NtStmt( +..)=>("statement"),NtPat(..)=>"pattern",NtExpr(..)=>"expression",NtLiteral(..)=> +"literal",NtTy(..)=>"type",NtIdent( ..)=>"identifier",NtLifetime(..)=>"lifetime" +,NtMeta(..)=>("attribute"),NtPath(..)=>( "path"),NtVis(..)=>"visibility",}}}impl +PartialEq for Nonterminal{fn eq(&self,rhs:& Self)->bool{match(self,rhs){(NtIdent +(ident_lhs,is_raw_lhs),NtIdent(ident_rhs,is_raw_rhs))=>{(ident_lhs==ident_rhs)&& +is_raw_lhs==is_raw_rhs}(NtLifetime(ident_lhs ),NtLifetime(ident_rhs))=>ident_lhs +==ident_rhs,_=>false,}}}impl fmt::Debug for Nonterminal{fn fmt(&self,f:&mut fmt +::Formatter<'_>)->fmt::Result{match(*self) {NtItem(..)=>(f.pad(("NtItem(..)"))), +NtBlock(..)=>f.pad("NtBlock(..)"),NtStmt(..) =>f.pad("NtStmt(..)"),NtPat(..)=>f. +pad(("NtPat(..)")),NtExpr(..)=>f.pad("NtExpr(..)" ),NtTy(..)=>f.pad("NtTy(..)"), +NtIdent(..)=>f.pad("NtIdent(..)"),NtLiteral (..)=>f.pad("NtLiteral(..)"),NtMeta( +..)=>(f.pad(("NtMeta(..)"))),NtPath(..)=>(f.pad("NtPath(..)")),NtVis(..)=>f.pad( +"NtVis(..)"),NtLifetime(..)=>f.pad( "NtLifetime(..)"),}}}implHashStablefor Nonterminal where CTX:crate:: HashStableContext,{fn hash_stable(&self,_hcx: +&mut CTX,_hasher:&mut StableHasher){panic!(//((),());let _=();let _=();let _=(); +"interpolated tokens should not be present in the HIR")}}# [cfg(all(target_arch= +"x86_64",target_pointer_width="64"))]mod size_asserts{use super::*;use//((),()); +rustc_data_structures::static_assert_size;static_assert_size!(Lit,12);//((),()); +static_assert_size!(LitKind,2);static_assert_size!(Nonterminal,16);//let _=||(); +static_assert_size!(Token,24);static_assert_size!(TokenKind,16);}//loop{break;}; diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 239735456ad53..54f12d7c90ba9 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -1,782 +1,185 @@ -//! # Token Streams -//! -//! `TokenStream`s represent syntactic objects before they are converted into ASTs. -//! A `TokenStream` is, roughly speaking, a sequence of [`TokenTree`]s, -//! which are themselves a single [`Token`] or a `Delimited` subsequence of tokens. -//! -//! ## Ownership -//! -//! `TokenStream`s are persistent data structures constructed as ropes with reference -//! counted-children. In general, this means that calling an operation on a `TokenStream` -//! (such as `slice`) produces an entirely new `TokenStream` from the borrowed reference to -//! the original. This essentially coerces `TokenStream`s into "views" of their subparts, -//! and a borrowed `TokenStream` is sufficient to build an owned `TokenStream` without taking -//! ownership of the original. - -use crate::ast::{AttrStyle, StmtKind}; -use crate::ast_traits::{HasAttrs, HasSpan, HasTokens}; -use crate::token::{self, Delimiter, Nonterminal, Token, TokenKind}; -use crate::AttrVec; - -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::{self, Lrc}; -use rustc_macros::HashStable_Generic; -use rustc_serialize::{Decodable, Encodable}; -use rustc_span::{sym, Span, SpanDecoder, SpanEncoder, Symbol, DUMMY_SP}; -use smallvec::{smallvec, SmallVec}; - -use std::borrow::Cow; -use std::{cmp, fmt, iter}; - -/// Part of a `TokenStream`. -#[derive(Debug, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)] -pub enum TokenTree { - /// A single token. Should never be `OpenDelim` or `CloseDelim`, because - /// delimiters are implicitly represented by `Delimited`. - Token(Token, Spacing), - /// A delimited sequence of token trees. - Delimited(DelimSpan, DelimSpacing, Delimiter, TokenStream), -} - -// Ensure all fields of `TokenTree` are `DynSend` and `DynSync`. -#[cfg(parallel_compiler)] -fn _dummy() -where - Token: sync::DynSend + sync::DynSync, - Spacing: sync::DynSend + sync::DynSync, - DelimSpan: sync::DynSend + sync::DynSync, - Delimiter: sync::DynSend + sync::DynSync, - TokenStream: sync::DynSend + sync::DynSync, -{ -} - -impl TokenTree { - /// Checks if this `TokenTree` is equal to the other, regardless of span/spacing information. - pub fn eq_unspanned(&self, other: &TokenTree) -> bool { - match (self, other) { - (TokenTree::Token(token, _), TokenTree::Token(token2, _)) => token.kind == token2.kind, - (TokenTree::Delimited(.., delim, tts), TokenTree::Delimited(.., delim2, tts2)) => { - delim == delim2 && tts.eq_unspanned(tts2) - } - _ => false, - } - } - - /// Retrieves the `TokenTree`'s span. - pub fn span(&self) -> Span { - match self { - TokenTree::Token(token, _) => token.span, - TokenTree::Delimited(sp, ..) => sp.entire(), - } - } - - /// Create a `TokenTree::Token` with alone spacing. - pub fn token_alone(kind: TokenKind, span: Span) -> TokenTree { - TokenTree::Token(Token::new(kind, span), Spacing::Alone) - } - - /// Create a `TokenTree::Token` with joint spacing. - pub fn token_joint(kind: TokenKind, span: Span) -> TokenTree { - TokenTree::Token(Token::new(kind, span), Spacing::Joint) - } - - /// Create a `TokenTree::Token` with joint-hidden spacing. - pub fn token_joint_hidden(kind: TokenKind, span: Span) -> TokenTree { - TokenTree::Token(Token::new(kind, span), Spacing::JointHidden) - } - - pub fn uninterpolate(&self) -> Cow<'_, TokenTree> { - match self { - TokenTree::Token(token, spacing) => match token.uninterpolate() { - Cow::Owned(token) => Cow::Owned(TokenTree::Token(token, *spacing)), - Cow::Borrowed(_) => Cow::Borrowed(self), - }, - _ => Cow::Borrowed(self), - } - } -} - -impl HashStable for TokenStream -where - CTX: crate::HashStableContext, -{ - fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { - for sub_tt in self.trees() { - sub_tt.hash_stable(hcx, hasher); - } - } -} - -pub trait ToAttrTokenStream: sync::DynSend + sync::DynSync { - fn to_attr_token_stream(&self) -> AttrTokenStream; -} - -impl ToAttrTokenStream for AttrTokenStream { - fn to_attr_token_stream(&self) -> AttrTokenStream { - self.clone() - } -} - -/// A lazy version of [`TokenStream`], which defers creation -/// of an actual `TokenStream` until it is needed. -/// `Box` is here only to reduce the structure size. -#[derive(Clone)] -pub struct LazyAttrTokenStream(Lrc>); - -impl LazyAttrTokenStream { - pub fn new(inner: impl ToAttrTokenStream + 'static) -> LazyAttrTokenStream { - LazyAttrTokenStream(Lrc::new(Box::new(inner))) - } - - pub fn to_attr_token_stream(&self) -> AttrTokenStream { - self.0.to_attr_token_stream() - } -} - -impl fmt::Debug for LazyAttrTokenStream { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "LazyAttrTokenStream({:?})", self.to_attr_token_stream()) - } -} - -impl Encodable for LazyAttrTokenStream { - fn encode(&self, s: &mut S) { - // Used by AST json printing. - Encodable::encode(&self.to_attr_token_stream(), s); - } -} - -impl Decodable for LazyAttrTokenStream { - fn decode(_d: &mut D) -> Self { - panic!("Attempted to decode LazyAttrTokenStream"); - } -} - -impl HashStable for LazyAttrTokenStream { - fn hash_stable(&self, _hcx: &mut CTX, _hasher: &mut StableHasher) { - panic!("Attempted to compute stable hash for LazyAttrTokenStream"); - } -} - -/// An `AttrTokenStream` is similar to a `TokenStream`, but with extra -/// information about the tokens for attribute targets. This is used -/// during expansion to perform early cfg-expansion, and to process attributes -/// during proc-macro invocations. -#[derive(Clone, Debug, Default, Encodable, Decodable)] -pub struct AttrTokenStream(pub Lrc>); - -/// Like `TokenTree`, but for `AttrTokenStream`. -#[derive(Clone, Debug, Encodable, Decodable)] -pub enum AttrTokenTree { - Token(Token, Spacing), - Delimited(DelimSpan, DelimSpacing, Delimiter, AttrTokenStream), - /// Stores the attributes for an attribute target, - /// along with the tokens for that attribute target. - /// See `AttributesData` for more information - Attributes(AttributesData), -} - -impl AttrTokenStream { - pub fn new(tokens: Vec) -> AttrTokenStream { - AttrTokenStream(Lrc::new(tokens)) - } - - /// Converts this `AttrTokenStream` to a plain `TokenStream`. - /// During conversion, `AttrTokenTree::Attributes` get 'flattened' - /// back to a `TokenStream` of the form `outer_attr attr_target`. - /// If there are inner attributes, they are inserted into the proper - /// place in the attribute target tokens. - pub fn to_tokenstream(&self) -> TokenStream { - let trees: Vec<_> = self - .0 - .iter() - .flat_map(|tree| match &tree { - AttrTokenTree::Token(inner, spacing) => { - smallvec![TokenTree::Token(inner.clone(), *spacing)].into_iter() - } - AttrTokenTree::Delimited(span, spacing, delim, stream) => { - smallvec![TokenTree::Delimited( - *span, - *spacing, - *delim, - stream.to_tokenstream() - ),] - .into_iter() - } - AttrTokenTree::Attributes(data) => { - let idx = data - .attrs - .partition_point(|attr| matches!(attr.style, crate::AttrStyle::Outer)); - let (outer_attrs, inner_attrs) = data.attrs.split_at(idx); - - let mut target_tokens: Vec<_> = data - .tokens - .to_attr_token_stream() - .to_tokenstream() - .0 - .iter() - .cloned() - .collect(); - if !inner_attrs.is_empty() { - let mut found = false; - // Check the last two trees (to account for a trailing semi) - for tree in target_tokens.iter_mut().rev().take(2) { - if let TokenTree::Delimited(span, spacing, delim, delim_tokens) = tree { - // Inner attributes are only supported on extern blocks, functions, - // impls, and modules. All of these have their inner attributes - // placed at the beginning of the rightmost outermost braced group: - // e.g. fn foo() { #![my_attr} } - // - // Therefore, we can insert them back into the right location - // without needing to do any extra position tracking. - // - // Note: Outline modules are an exception - they can - // have attributes like `#![my_attr]` at the start of a file. - // Support for custom attributes in this position is not - // properly implemented - we always synthesize fake tokens, - // so we never reach this code. - - let mut stream = TokenStream::default(); - for inner_attr in inner_attrs { - stream.push_stream(inner_attr.tokens()); - } - stream.push_stream(delim_tokens.clone()); - *tree = TokenTree::Delimited(*span, *spacing, *delim, stream); - found = true; - break; - } - } - - assert!( - found, - "Failed to find trailing delimited group in: {target_tokens:?}" - ); - } - let mut flat: SmallVec<[_; 1]> = - SmallVec::with_capacity(target_tokens.len() + outer_attrs.len()); - for attr in outer_attrs { - flat.extend(attr.tokens().0.iter().cloned()); - } - flat.extend(target_tokens); - flat.into_iter() - } - }) - .collect(); - TokenStream::new(trees) - } -} - -/// Stores the tokens for an attribute target, along -/// with its attributes. -/// -/// This is constructed during parsing when we need to capture -/// tokens. -/// -/// For example, `#[cfg(FALSE)] struct Foo {}` would -/// have an `attrs` field containing the `#[cfg(FALSE)]` attr, -/// and a `tokens` field storing the (unparsed) tokens `struct Foo {}` -#[derive(Clone, Debug, Encodable, Decodable)] -pub struct AttributesData { - /// Attributes, both outer and inner. - /// These are stored in the original order that they were parsed in. - pub attrs: AttrVec, - /// The underlying tokens for the attribute target that `attrs` - /// are applied to - pub tokens: LazyAttrTokenStream, -} - -/// A `TokenStream` is an abstract sequence of tokens, organized into [`TokenTree`]s. -/// -/// The goal is for procedural macros to work with `TokenStream`s and `TokenTree`s -/// instead of a representation of the abstract syntax tree. -/// Today's `TokenTree`s can still contain AST via `token::Interpolated` for -/// backwards compatibility. -#[derive(Clone, Debug, Default, Encodable, Decodable)] -pub struct TokenStream(pub(crate) Lrc>); - -/// Indicates whether a token can join with the following token to form a -/// compound token. Used for conversions to `proc_macro::Spacing`. Also used to -/// guide pretty-printing, which is where the `JointHidden` value (which isn't -/// part of `proc_macro::Spacing`) comes in useful. -#[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)] -pub enum Spacing { - /// The token cannot join with the following token to form a compound - /// token. - /// - /// In token streams parsed from source code, the compiler will use `Alone` - /// for any token immediately followed by whitespace, a non-doc comment, or - /// EOF. - /// - /// When constructing token streams within the compiler, use this for each - /// token that (a) should be pretty-printed with a space after it, or (b) - /// is the last token in the stream. (In the latter case the choice of - /// spacing doesn't matter because it is never used for the last token. We - /// arbitrarily use `Alone`.) - /// - /// Converts to `proc_macro::Spacing::Alone`, and - /// `proc_macro::Spacing::Alone` converts back to this. - Alone, - - /// The token can join with the following token to form a compound token. - /// - /// In token streams parsed from source code, the compiler will use `Joint` - /// for any token immediately followed by punctuation (as determined by - /// `Token::is_punct`). - /// - /// When constructing token streams within the compiler, use this for each - /// token that (a) should be pretty-printed without a space after it, and - /// (b) is followed by a punctuation token. - /// - /// Converts to `proc_macro::Spacing::Joint`, and - /// `proc_macro::Spacing::Joint` converts back to this. - Joint, - - /// The token can join with the following token to form a compound token, - /// but this will not be visible at the proc macro level. (This is what the - /// `Hidden` means; see below.) - /// - /// In token streams parsed from source code, the compiler will use - /// `JointHidden` for any token immediately followed by anything not - /// covered by the `Alone` and `Joint` cases: an identifier, lifetime, - /// literal, delimiter, doc comment. - /// - /// When constructing token streams, use this for each token that (a) - /// should be pretty-printed without a space after it, and (b) is followed - /// by a non-punctuation token. - /// - /// Converts to `proc_macro::Spacing::Alone`, but - /// `proc_macro::Spacing::Alone` converts back to `token::Spacing::Alone`. - /// Because of that, pretty-printing of `TokenStream`s produced by proc - /// macros is unavoidably uglier (with more whitespace between tokens) than - /// pretty-printing of `TokenStream`'s produced by other means (i.e. parsed - /// source code, internally constructed token streams, and token streams - /// produced by declarative macros). - JointHidden, -} - -impl TokenStream { - /// Given a `TokenStream` with a `Stream` of only two arguments, return a new `TokenStream` - /// separating the two arguments with a comma for diagnostic suggestions. - pub fn add_comma(&self) -> Option<(TokenStream, Span)> { - // Used to suggest if a user writes `foo!(a b);` - let mut suggestion = None; - let mut iter = self.0.iter().enumerate().peekable(); - while let Some((pos, ts)) = iter.next() { - if let Some((_, next)) = iter.peek() { - let sp = match (&ts, &next) { - (_, TokenTree::Token(Token { kind: token::Comma, .. }, _)) => continue, - ( - TokenTree::Token(token_left, Spacing::Alone), - TokenTree::Token(token_right, _), - ) if ((token_left.is_ident() && !token_left.is_reserved_ident()) - || token_left.is_lit()) - && ((token_right.is_ident() && !token_right.is_reserved_ident()) - || token_right.is_lit()) => - { - token_left.span - } - (TokenTree::Delimited(sp, ..), _) => sp.entire(), - _ => continue, - }; - let sp = sp.shrink_to_hi(); - let comma = TokenTree::token_alone(token::Comma, sp); - suggestion = Some((pos, comma, sp)); - } - } - if let Some((pos, comma, sp)) = suggestion { - let mut new_stream = Vec::with_capacity(self.0.len() + 1); - let parts = self.0.split_at(pos + 1); - new_stream.extend_from_slice(parts.0); - new_stream.push(comma); - new_stream.extend_from_slice(parts.1); - return Some((TokenStream::new(new_stream), sp)); - } - None - } -} - -impl FromIterator for TokenStream { - fn from_iter>(iter: I) -> Self { - TokenStream::new(iter.into_iter().collect::>()) - } -} - -impl Eq for TokenStream {} - -impl PartialEq for TokenStream { - fn eq(&self, other: &TokenStream) -> bool { - self.trees().eq(other.trees()) - } -} - -impl TokenStream { - pub fn new(streams: Vec) -> TokenStream { - TokenStream(Lrc::new(streams)) - } - - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } - - pub fn len(&self) -> usize { - self.0.len() - } - - pub fn trees(&self) -> RefTokenTreeCursor<'_> { - RefTokenTreeCursor::new(self) - } - - pub fn into_trees(self) -> TokenTreeCursor { - TokenTreeCursor::new(self) - } - - /// Compares two `TokenStream`s, checking equality without regarding span information. - pub fn eq_unspanned(&self, other: &TokenStream) -> bool { - let mut t1 = self.trees(); - let mut t2 = other.trees(); - for (t1, t2) in iter::zip(&mut t1, &mut t2) { - if !t1.eq_unspanned(t2) { - return false; - } - } - t1.next().is_none() && t2.next().is_none() - } - - /// Create a token stream containing a single token with alone spacing. The - /// spacing used for the final token in a constructed stream doesn't matter - /// because it's never used. In practice we arbitrarily use - /// `Spacing::Alone`. - pub fn token_alone(kind: TokenKind, span: Span) -> TokenStream { - TokenStream::new(vec![TokenTree::token_alone(kind, span)]) - } - - pub fn from_ast(node: &(impl HasAttrs + HasSpan + HasTokens + fmt::Debug)) -> TokenStream { - let Some(tokens) = node.tokens() else { - panic!("missing tokens for node at {:?}: {:?}", node.span(), node); - }; - let attrs = node.attrs(); - let attr_stream = if attrs.is_empty() { - tokens.to_attr_token_stream() - } else { - let attr_data = - AttributesData { attrs: attrs.iter().cloned().collect(), tokens: tokens.clone() }; - AttrTokenStream::new(vec![AttrTokenTree::Attributes(attr_data)]) - }; - attr_stream.to_tokenstream() - } - - pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream { - match nt { - Nonterminal::NtIdent(ident, is_raw) => { - TokenStream::token_alone(token::Ident(ident.name, *is_raw), ident.span) - } - Nonterminal::NtLifetime(ident) => { - TokenStream::token_alone(token::Lifetime(ident.name), ident.span) - } - Nonterminal::NtItem(item) => TokenStream::from_ast(item), - Nonterminal::NtBlock(block) => TokenStream::from_ast(block), - Nonterminal::NtStmt(stmt) if let StmtKind::Empty = stmt.kind => { - // FIXME: Properly collect tokens for empty statements. - TokenStream::token_alone(token::Semi, stmt.span) - } - Nonterminal::NtStmt(stmt) => TokenStream::from_ast(stmt), - Nonterminal::NtPat(pat) => TokenStream::from_ast(pat), - Nonterminal::NtTy(ty) => TokenStream::from_ast(ty), - Nonterminal::NtMeta(attr) => TokenStream::from_ast(attr), - Nonterminal::NtPath(path) => TokenStream::from_ast(path), - Nonterminal::NtVis(vis) => TokenStream::from_ast(vis), - Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => TokenStream::from_ast(expr), - } - } - - fn flatten_token(token: &Token, spacing: Spacing) -> TokenTree { - match &token.kind { - token::Interpolated(nt) if let token::NtIdent(ident, is_raw) = nt.0 => { - TokenTree::Token(Token::new(token::Ident(ident.name, is_raw), ident.span), spacing) - } - token::Interpolated(nt) => TokenTree::Delimited( - DelimSpan::from_single(token.span), - DelimSpacing::new(Spacing::JointHidden, spacing), - Delimiter::Invisible, - TokenStream::from_nonterminal_ast(&nt.0).flattened(), - ), - _ => TokenTree::Token(token.clone(), spacing), - } - } - - fn flatten_token_tree(tree: &TokenTree) -> TokenTree { - match tree { - TokenTree::Token(token, spacing) => TokenStream::flatten_token(token, *spacing), - TokenTree::Delimited(span, spacing, delim, tts) => { - TokenTree::Delimited(*span, *spacing, *delim, tts.flattened()) - } - } - } - - #[must_use] - pub fn flattened(&self) -> TokenStream { - fn can_skip(stream: &TokenStream) -> bool { - stream.trees().all(|tree| match tree { - TokenTree::Token(token, _) => !matches!(token.kind, token::Interpolated(_)), - TokenTree::Delimited(.., inner) => can_skip(inner), - }) - } - - if can_skip(self) { - return self.clone(); - } - - self.trees().map(|tree| TokenStream::flatten_token_tree(tree)).collect() - } - - // 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, tt: &TokenTree) -> bool { - if let Some(TokenTree::Token(last_tok, Spacing::Joint | Spacing::JointHidden)) = 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 - } - } - - /// 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); - } - } - - pub fn chunks(&self, chunk_size: usize) -> core::slice::Chunks<'_, TokenTree> { - self.0.chunks(chunk_size) - } - - /// Desugar doc comments like `/// foo` in the stream into `#[doc = - /// r"foo"]`. Modifies the `TokenStream` via `Lrc::make_mut`, but as little - /// as possible. - pub fn desugar_doc_comments(&mut self) { - if let Some(desugared_stream) = desugar_inner(self.clone()) { - *self = desugared_stream; - } - - // The return value is `None` if nothing in `stream` changed. - fn desugar_inner(mut stream: TokenStream) -> Option { - let mut i = 0; - let mut modified = false; - while let Some(tt) = stream.0.get(i) { - match tt { - &TokenTree::Token( - Token { kind: token::DocComment(_, attr_style, data), span }, - _spacing, - ) => { - let desugared = desugared_tts(attr_style, data, span); - let desugared_len = desugared.len(); - Lrc::make_mut(&mut stream.0).splice(i..i + 1, desugared); - modified = true; - i += desugared_len; - } - - &TokenTree::Token(..) => i += 1, - - &TokenTree::Delimited(sp, spacing, delim, ref delim_stream) => { - if let Some(desugared_delim_stream) = desugar_inner(delim_stream.clone()) { - let new_tt = - TokenTree::Delimited(sp, spacing, delim, desugared_delim_stream); - Lrc::make_mut(&mut stream.0)[i] = new_tt; - modified = true; - } - i += 1; - } - } - } - if modified { Some(stream) } else { None } - } - - fn desugared_tts(attr_style: AttrStyle, data: Symbol, span: Span) -> Vec { - // Searches for the occurrences of `"#*` and returns the minimum number of `#`s - // 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() { - count = match ch { - '"' => 1, - '#' if count > 0 => count + 1, - _ => 0, - }; - 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, - DelimSpacing::new(Spacing::JointHidden, Spacing::Alone), - Delimiter::Bracket, - [ - TokenTree::token_alone(token::Ident(sym::doc, token::IdentIsRaw::No), span), - TokenTree::token_alone(token::Eq, span), - TokenTree::token_alone( - TokenKind::lit(token::StrRaw(num_of_hashes), data, None), - span, - ), - ] - .into_iter() - .collect::(), - ); - - if attr_style == AttrStyle::Inner { - vec![ - TokenTree::token_joint(token::Pound, span), - TokenTree::token_alone(token::Not, span), - body, - ] - } else { - vec![TokenTree::token_alone(token::Pound, span), body] - } - } - } -} - -/// By-reference iterator over a [`TokenStream`], that produces `&TokenTree` -/// items. -#[derive(Clone)] -pub struct RefTokenTreeCursor<'t> { - stream: &'t TokenStream, - index: usize, -} - -impl<'t> RefTokenTreeCursor<'t> { - fn new(stream: &'t TokenStream) -> Self { - RefTokenTreeCursor { stream, index: 0 } - } - - pub fn look_ahead(&self, n: usize) -> Option<&TokenTree> { - self.stream.0.get(self.index + n) - } -} - -impl<'t> Iterator for RefTokenTreeCursor<'t> { - type Item = &'t TokenTree; - - fn next(&mut self) -> Option<&'t TokenTree> { - self.stream.0.get(self.index).map(|tree| { - self.index += 1; - tree - }) - } -} - -/// Owning by-value iterator over a [`TokenStream`], that produces `&TokenTree` -/// items. -/// -/// Doesn't impl `Iterator` because Rust doesn't permit an owning iterator to -/// return `&T` from `next`; the need for an explicit lifetime in the `Item` -/// associated type gets in the way. Instead, use `next_ref` (which doesn't -/// involve associated types) for getting individual elements, or -/// `RefTokenTreeCursor` if you really want an `Iterator`, e.g. in a `for` -/// loop. -#[derive(Clone)] -pub struct TokenTreeCursor { - pub stream: TokenStream, - index: usize, -} - -impl TokenTreeCursor { - fn new(stream: TokenStream) -> Self { - TokenTreeCursor { stream, index: 0 } - } - - #[inline] - pub fn next_ref(&mut self) -> Option<&TokenTree> { - self.stream.0.get(self.index).map(|tree| { - self.index += 1; - tree - }) - } - - pub fn look_ahead(&self, n: usize) -> Option<&TokenTree> { - self.stream.0.get(self.index + n) - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)] -pub struct DelimSpan { - pub open: Span, - pub close: Span, -} - -impl DelimSpan { - pub fn from_single(sp: Span) -> Self { - DelimSpan { open: sp, close: sp } - } - - pub fn from_pair(open: Span, close: Span) -> Self { - DelimSpan { open, close } - } - - pub fn dummy() -> Self { - Self::from_single(DUMMY_SP) - } - - pub fn entire(self) -> Span { - self.open.with_hi(self.close.hi()) - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)] -pub struct DelimSpacing { - pub open: Spacing, - pub close: Spacing, -} - -impl DelimSpacing { - pub fn new(open: Spacing, close: Spacing) -> DelimSpacing { - DelimSpacing { open, close } - } -} - -// 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 -} +use crate::ast::{AttrStyle,StmtKind};use crate::ast_traits::{HasAttrs,HasSpan,// +HasTokens};use crate::token::{self,Delimiter,Nonterminal,Token,TokenKind};use//; +crate::AttrVec;use rustc_data_structures::stable_hasher::{HashStable,//let _=(); +StableHasher};use rustc_data_structures::sync::{self,Lrc};use rustc_macros:://3; +HashStable_Generic;use rustc_serialize::{Decodable ,Encodable};use rustc_span::{ +sym,Span,SpanDecoder,SpanEncoder,Symbol,DUMMY_SP};use smallvec::{smallvec,//{;}; +SmallVec};use std::borrow::Cow;use std::{cmp,fmt,iter};#[derive(Debug,Clone,//3; +PartialEq,Encodable,Decodable,HashStable_Generic)]pub enum TokenTree{Token(//(); +Token,Spacing),Delimited(DelimSpan,DelimSpacing,Delimiter,TokenStream),}#[cfg(// +parallel_compiler)]fn _dummy()where Token:sync::DynSend+sync::DynSync,Spacing:// +sync::DynSend+sync::DynSync,DelimSpan:sync::DynSend+sync::DynSync,Delimiter://3; +sync::DynSend+sync::DynSync,TokenStream:sync::DynSend+sync::DynSync,{}impl//{;}; +TokenTree{pub fn eq_unspanned(&self,other:& TokenTree)->bool{match(self,other){( +TokenTree::Token(token,_),TokenTree::Token(token2 ,_))=>token.kind==token2.kind, +(TokenTree::Delimited(..,delim,tts),TokenTree::Delimited(..,delim2,tts2))=>{//3; +delim==delim2&&tts.eq_unspanned(tts2)}_=> false,}}pub fn span(&self)->Span{match +self{TokenTree::Token(token,_)=>token.span,TokenTree::Delimited(sp,..)=>sp.//(); +entire(),}}pub fn token_alone(kind:TokenKind,span:Span)->TokenTree{TokenTree::// +Token((Token::new(kind,span)),Spacing::Alone)}pub fn token_joint(kind:TokenKind, +span:Span)->TokenTree{(TokenTree::Token(Token ::new(kind,span),Spacing::Joint))} +pub fn token_joint_hidden(kind:TokenKind, span:Span)->TokenTree{TokenTree::Token +((Token::new(kind,span)),Spacing::JointHidden)}pub fn uninterpolate(&self)->Cow< +'_,TokenTree>{match self{TokenTree::Token(token,spacing)=>match token.//((),()); +uninterpolate(){Cow::Owned(token)=>Cow::Owned (TokenTree::Token(token,*spacing)) +,Cow::Borrowed(_)=>(Cow::Borrowed(self)),},_=>(Cow::Borrowed(self)),}}}impl +HashStablefor TokenStream where CTX:crate::HashStableContext,{fn//let _=(); +hash_stable(&self,hcx:&mut CTX,hasher:&mut StableHasher){for sub_tt in self.//3; +trees(){3;sub_tt.hash_stable(hcx,hasher);3;}}}pub trait ToAttrTokenStream:sync:: +DynSend+sync::DynSync{fn to_attr_token_stream(&self)->AttrTokenStream;}impl//(); +ToAttrTokenStream for AttrTokenStream{fn to_attr_token_stream(&self)->//((),()); +AttrTokenStream{(self.clone())}}# [derive(Clone)]pub struct LazyAttrTokenStream( +Lrc>);impl LazyAttrTokenStream{pub fn new(inner:impl +ToAttrTokenStream+'static)->LazyAttrTokenStream{LazyAttrTokenStream(Lrc::new(//; +Box::new(inner)))}pub fn to_attr_token_stream(&self)->AttrTokenStream{self.0.//; +to_attr_token_stream()}}impl fmt::Debug for LazyAttrTokenStream{fn fmt(&self,f: +&mut fmt::Formatter<'_>)->fmt ::Result{write!(f,"LazyAttrTokenStream({:?})",self +.to_attr_token_stream())}}implEncodablefor//let _=();let _=(); +LazyAttrTokenStream{fn encode(&self,s:&mut S){if true{};Encodable::encode(&self. +to_attr_token_stream(),s);let _=();let _=();}}implDecodablefor +LazyAttrTokenStream{fn decode(_d:&mut D)->Self{loop{break;};loop{break;};panic!( +"Attempted to decode LazyAttrTokenStream");((),());}}implHashStablefor +LazyAttrTokenStream{fn hash_stable(&self,_hcx:&mut CTX,_hasher:&mut//let _=||(); +StableHasher){;panic!("Attempted to compute stable hash for LazyAttrTokenStream" +);((),());((),());}}#[derive(Clone,Debug,Default,Encodable,Decodable)]pub struct +AttrTokenStream(pub Lrc>);#[derive(Clone,Debug,Encodable,//3; +Decodable)]pub enum AttrTokenTree{Token(Token,Spacing),Delimited(DelimSpan,//(); +DelimSpacing,Delimiter,AttrTokenStream),Attributes(AttributesData),}impl//{();}; +AttrTokenStream{pub fn new(tokens:Vec)->AttrTokenStream{//*&*&(); +AttrTokenStream(Lrc::new(tokens))}pub fn to_tokenstream(&self)->TokenStream{;let +trees:Vec<_>=((self.0.iter())).flat_map(|tree|match(&tree){AttrTokenTree::Token( +inner,spacing)=>{smallvec![TokenTree::Token (inner.clone(),*spacing)].into_iter( +)}AttrTokenTree::Delimited(span,spacing,delim,stream)=>{smallvec![TokenTree:://; +Delimited(*span,*spacing,*delim,stream.to_tokenstream()),].into_iter()}//*&*&(); +AttrTokenTree::Attributes(data)=>{({});let idx=data.attrs.partition_point(|attr| +matches!(attr.style,crate::AttrStyle::Outer));;let(outer_attrs,inner_attrs)=data +.attrs.split_at(idx);let _=();let _=();let mut target_tokens:Vec<_>=data.tokens. +to_attr_token_stream().to_tokenstream().0.iter().cloned().collect();let _=();if! +inner_attrs.is_empty(){;let mut found=false;for tree in target_tokens.iter_mut() +.rev().take(((2))){if let TokenTree::Delimited(span,spacing,delim,delim_tokens)= +tree{;let mut stream=TokenStream::default();for inner_attr in inner_attrs{stream +.push_stream(inner_attr.tokens());;};stream.push_stream(delim_tokens.clone());;* +tree=TokenTree::Delimited(*span,*spacing,*delim,stream);;;found=true;;;break;;}} +assert!(found,"Failed to find trailing delimited group in: {target_tokens:?}");; +}{();};let mut flat:SmallVec<[_;1]>=SmallVec::with_capacity(target_tokens.len()+ +outer_attrs.len());;for attr in outer_attrs{;flat.extend(attr.tokens().0.iter(). +cloned());;}flat.extend(target_tokens);flat.into_iter()}}).collect();TokenStream +::new(trees)}}#[derive(Clone,Debug,Encodable,Decodable)]pub struct//loop{break}; +AttributesData{pub attrs:AttrVec,pub tokens:LazyAttrTokenStream,}#[derive(Clone +,Debug,Default,Encodable,Decodable)]pub struct TokenStream(pub(crate)Lrc>);#[derive(Clone,Copy,Debug,PartialEq,Encodable,Decodable,//let _=(); +HashStable_Generic)]pub enum Spacing{Alone ,Joint,JointHidden,}impl TokenStream{ +pub fn add_comma(&self)->Option<(TokenStream,Span)>{;let mut suggestion=None;let +mut iter=self.0.iter().enumerate().peekable();{;};while let Some((pos,ts))=iter. +next(){if let Some((_,next))=iter.peek(){;let sp=match(&ts,&next){(_,TokenTree:: +Token(Token{kind:token::Comma,..},_ ))=>(continue),(TokenTree::Token(token_left, +Spacing::Alone),TokenTree::Token(token_right,_),)if (((token_left.is_ident())&&! +token_left.is_reserved_ident())||token_left.is_lit() )&&((token_right.is_ident() +&&(!token_right.is_reserved_ident()))||token_right.is_lit())=>{token_left.span}( +TokenTree::Delimited(sp,..),_)=>sp.entire(),_=>continue,};{();};{();};let sp=sp. +shrink_to_hi();;;let comma=TokenTree::token_alone(token::Comma,sp);;;suggestion= +Some((pos,comma,sp));{();};}}if let Some((pos,comma,sp))=suggestion{({});let mut +new_stream=Vec::with_capacity(self.0.len()+1);;let parts=self.0.split_at(pos+1); +new_stream.extend_from_slice(parts.0);3;3;new_stream.push(comma);3;3;new_stream. +extend_from_slice(parts.1);;return Some((TokenStream::new(new_stream),sp));}None +}}impl FromIteratorfor TokenStream {fn from_iter>(iter:I)->Self{TokenStream::new((((iter.into_iter()))).collect::>())}}impl Eq for TokenStream{}impl PartialEqfor//*&*&(); +TokenStream{fn eq(&self,other:&TokenStream)->bool{ self.trees().eq(other.trees() +)}}impl TokenStream{pub fn new (streams:Vec)->TokenStream{TokenStream +(Lrc::new(streams))}pub fn is_empty(&self )->bool{self.0.is_empty()}pub fn len(& +self)->usize{(((((self.0.len())))))}pub fn trees(&self)->RefTokenTreeCursor<'_>{ +RefTokenTreeCursor::new(self)}pub fn into_trees(self)->TokenTreeCursor{//*&*&(); +TokenTreeCursor::new(self)}pub fn eq_unspanned(&self,other:&TokenStream)->bool{; +let mut t1=self.trees();;let mut t2=other.trees();for(t1,t2)in iter::zip(&mut t1 +,&mut t2){if!t1.eq_unspanned(t2){;return false;}}t1.next().is_none()&&t2.next(). +is_none()}pub fn token_alone( kind:TokenKind,span:Span)->TokenStream{TokenStream +::new((((vec![TokenTree::token_alone(kind,span)]))))}pub fn from_ast(node:&(impl +HasAttrs+HasSpan+HasTokens+fmt::Debug))->TokenStream{({});let Some(tokens)=node. +tokens()else{;panic!("missing tokens for node at {:?}: {:?}",node.span(),node);} +;{;};();let attrs=node.attrs();();();let attr_stream=if attrs.is_empty(){tokens. +to_attr_token_stream()}else{{;};let attr_data=AttributesData{attrs:attrs.iter(). +cloned().collect(),tokens:tokens.clone()};loop{break};AttrTokenStream::new(vec![ +AttrTokenTree::Attributes(attr_data)])};({});attr_stream.to_tokenstream()}pub fn +from_nonterminal_ast(nt:&Nonterminal)->TokenStream{match nt{Nonterminal:://({}); +NtIdent(ident,is_raw)=>{TokenStream::token_alone(token::Ident(ident.name,*//{;}; +is_raw),ident.span)}Nonterminal::NtLifetime(ident)=>{TokenStream::token_alone(// +token::Lifetime(ident.name),ident.span)}Nonterminal::NtItem(item)=>TokenStream// +::from_ast(item),Nonterminal::NtBlock( block)=>((TokenStream::from_ast(block))), +Nonterminal::NtStmt(stmt)if let StmtKind::Empty=stmt.kind=>{TokenStream:://({}); +token_alone(token::Semi,stmt.span)}Nonterminal::NtStmt(stmt)=>TokenStream:://(); +from_ast(stmt),Nonterminal::NtPat(pat)=>(TokenStream::from_ast(pat)),Nonterminal +::NtTy(ty)=>(TokenStream::from_ast(ty)),Nonterminal::NtMeta(attr)=>TokenStream:: +from_ast(attr),Nonterminal::NtPath(path)=>(((((TokenStream::from_ast(path)))))), +Nonterminal::NtVis(vis)=>(TokenStream::from_ast(vis)),Nonterminal::NtExpr(expr)| +Nonterminal::NtLiteral(expr)=>(TokenStream::from_ast (expr)),}}fn flatten_token( +token:&Token,spacing:Spacing)->TokenTree{match(&token.kind){token::Interpolated( +nt)if let token::NtIdent(ident,is_raw)=nt .0=>{TokenTree::Token(Token::new(token +::Ident(ident.name,is_raw),ident.span),spacing)}token::Interpolated(nt)=>//({}); +TokenTree::Delimited((((DelimSpan::from_single(token.span)))),DelimSpacing::new( +Spacing::JointHidden,spacing),Delimiter::Invisible,TokenStream:://if let _=(){}; +from_nonterminal_ast((&nt.0)).flattened(),),_=>TokenTree::Token((token.clone()), +spacing),}}fn flatten_token_tree(tree:&TokenTree)->TokenTree{match tree{//{();}; +TokenTree::Token(token,spacing)=>(TokenStream::flatten_token(token,(*spacing))), +TokenTree::Delimited(span,spacing,delim,tts)=> {TokenTree::Delimited(((*span)),* +spacing,(((*delim))),((tts.flattened())))}}}#[must_use]pub fn flattened(&self)-> +TokenStream{{;};fn can_skip(stream:&TokenStream)->bool{stream.trees().all(|tree| +match tree{TokenTree::Token(token,_)=> !matches!(token.kind,token::Interpolated( +_)),TokenTree::Delimited(..,inner)=>can_skip(inner),})};if can_skip(self){return +self.clone();{;};}self.trees().map(|tree|TokenStream::flatten_token_tree(tree)). +collect()}fn try_glue_to_last(vec:&mut Vec,tt:&TokenTree)->bool{if // +let Some(TokenTree::Token(last_tok,Spacing::Joint|Spacing::JointHidden))=vec.//; +last()&&let TokenTree::Token(tok,spacing) =tt&&let Some(glued_tok)=last_tok.glue +(tok){;*vec.last_mut().unwrap()=TokenTree::Token(glued_tok,*spacing);;true}else{ +false}}pub fn push_tree(&mut self,tt:TokenTree){3;let vec_mut=Lrc::make_mut(&mut +self.0);;if Self::try_glue_to_last(vec_mut,&tt){}else{;vec_mut.push(tt);}}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){3;vec_mut.extend(stream_iter.skip(1));;} +else{;vec_mut.extend(stream_iter);;}}pub fn chunks(&self,chunk_size:usize)->core +::slice::Chunks<'_,TokenTree>{(((((((((self.0.chunks(chunk_size))))))))))}pub fn +desugar_doc_comments(&mut self){if let Some(desugared_stream)=desugar_inner(//3; +self.clone()){;*self=desugared_stream;;}fn desugar_inner(mut stream:TokenStream) +->Option{;let mut i=0;;;let mut modified=false;;while let Some(tt)= +stream.0.get(i){match tt{&TokenTree::Token(Token{kind:token::DocComment(_,//{;}; +attr_style,data),span},_spacing,)=>{;let desugared=desugared_tts(attr_style,data +,span);;;let desugared_len=desugared.len();Lrc::make_mut(&mut stream.0).splice(i +..i+1,desugared);;;modified=true;i+=desugared_len;}&TokenTree::Token(..)=>i+=1,& +TokenTree::Delimited(sp,spacing,delim,ref delim_stream)=>{if let Some(//((),()); +desugared_delim_stream)=desugar_inner(delim_stream.clone()){let _=();let new_tt= +TokenTree::Delimited(sp,spacing,delim,desugared_delim_stream);3;;Lrc::make_mut(& +mut stream.0)[i]=new_tt;;;modified=true;;}i+=1;}}}if modified{Some(stream)}else{ +None}}{;};{;};fn desugared_tts(attr_style:AttrStyle,data:Symbol,span:Span)->Vec< +TokenTree>{3;let mut num_of_hashes=0;;;let mut count=0;;for ch in data.as_str(). +chars(){;count=match ch{'"'=>1,'#' if count>0=>count+1,_=>0,};;num_of_hashes=cmp +::max(num_of_hashes,count);3;};let delim_span=DelimSpan::from_single(span);;;let +body=TokenTree::Delimited(delim_span,DelimSpacing::new(Spacing::JointHidden,//3; +Spacing::Alone),Delimiter::Bracket,[TokenTree::token_alone(token::Ident(sym:://; +doc,token::IdentIsRaw::No),span),((((TokenTree::token_alone(token::Eq,span))))), +TokenTree::token_alone((TokenKind::lit(token::StrRaw(num_of_hashes),data,None)), +span,),].into_iter().collect::(),);;if attr_style==AttrStyle::Inner +{vec![TokenTree::token_joint(token::Pound,span),TokenTree::token_alone(token::// +Not,span),body,]}else{vec![TokenTree::token_alone(token::Pound,span),body]}};}}# +[derive(Clone)]pub struct RefTokenTreeCursor<'t>{stream:&'t TokenStream,index:// +usize,}impl<'t>RefTokenTreeCursor<'t>{fn new(stream:&'t TokenStream)->Self{//(); +RefTokenTreeCursor{stream,index:(0)}}pub fn look_ahead(&self,n:usize)->Option<& +TokenTree>{((((self.stream.0.get(((((self.index+n)))))))))}}impl<'t>Iterator for +RefTokenTreeCursor<'t>{type Item=&'t TokenTree;fn next(&mut self)->Option<&'t//; +TokenTree>{self.stream.0.get(self.index).map(|tree|{3;self.index+=1;3;tree})}}#[ +derive(Clone)]pub struct TokenTreeCursor{pub stream:TokenStream,index:usize,}//; +impl TokenTreeCursor{fn new(stream:TokenStream)->Self{TokenTreeCursor{stream,//; +index:0}}#[inline]pub fn next_ref(& mut self)->Option<&TokenTree>{self.stream.0. +get(self.index).map(|tree|{;self.index+=1;tree})}pub fn look_ahead(&self,n:usize +)->Option<&TokenTree>{(self.stream.0.get(( self.index+n)))}}#[derive(Debug,Copy, +Clone,PartialEq,Encodable,Decodable,HashStable_Generic)]pub struct DelimSpan{//; +pub open:Span,pub close:Span,}impl DelimSpan{pub fn from_single(sp:Span)->Self{ +DelimSpan{open:sp,close:sp}}pub fn from_pair(open:Span,close:Span)->Self{//({}); +DelimSpan{open,close}}pub fn dummy() ->Self{(Self::from_single(DUMMY_SP))}pub fn +entire(self)->Span{(self.open.with_hi((self. close.hi())))}}#[derive(Copy,Clone, +Debug,PartialEq,Encodable,Decodable, HashStable_Generic)]pub struct DelimSpacing +{pub open:Spacing,pub close:Spacing,} impl DelimSpacing{pub fn new(open:Spacing, +close:Spacing)->DelimSpacing{(DelimSpacing{open, close})}}#[cfg(all(target_arch= +"x86_64",target_pointer_width="64"))]mod size_asserts{use super::*;use//((),()); +rustc_data_structures::static_assert_size;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);}//{;}; diff --git a/compiler/rustc_ast/src/util/case.rs b/compiler/rustc_ast/src/util/case.rs index 1afd7dea7408e..86feeb2ac524d 100644 --- a/compiler/rustc_ast/src/util/case.rs +++ b/compiler/rustc_ast/src/util/case.rs @@ -1,6 +1 @@ -/// Whatever to ignore case (`fn` vs `Fn` vs `FN`) or not. Used for recovering. -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum Case { - Sensitive, - Insensitive, -} +#[derive(Copy,Clone,Debug,Eq,PartialEq)]pub enum Case{Sensitive,Insensitive,}//; diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs index f21a9cabb81be..72fd87084e21d 100644 --- a/compiler/rustc_ast/src/util/classify.rs +++ b/compiler/rustc_ast/src/util/classify.rs @@ -1,96 +1,15 @@ -//! Routines the parser uses to classify AST nodes - -// Predicates on exprs and stmts that the pretty-printer and parser use - -use crate::{ast, token::Delimiter}; - -/// Does this expression require a semicolon to be treated -/// as a statement? The negation of this: 'can this expression -/// be used as a statement without a semicolon' -- is used -/// as an early-bail-out in the parser so that, for instance, -/// if true {...} else {...} -/// |x| 5 -/// isn't parsed as (if true {...} else {...} | x) | 5 -pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool { - !matches!( - e.kind, - ast::ExprKind::If(..) - | ast::ExprKind::Match(..) - | ast::ExprKind::Block(..) - | ast::ExprKind::While(..) - | ast::ExprKind::Loop(..) - | ast::ExprKind::ForLoop { .. } - | ast::ExprKind::TryBlock(..) - | ast::ExprKind::ConstBlock(..) - ) -} - -/// If an expression ends with `}`, returns the innermost expression ending in the `}` -pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> { - use ast::ExprKind::*; - - loop { - match &expr.kind { - AddrOf(_, _, e) - | Assign(_, e, _) - | AssignOp(_, _, e) - | Binary(_, _, e) - | Break(_, Some(e)) - | Let(_, e, _, _) - | Range(_, Some(e), _) - | Ret(Some(e)) - | Unary(_, e) - | Yield(Some(e)) - | Yeet(Some(e)) - | Become(e) => { - expr = e; - } - Closure(closure) => { - expr = &closure.body; - } - Gen(..) - | Block(..) - | ForLoop { .. } - | If(..) - | Loop(..) - | Match(..) - | Struct(..) - | TryBlock(..) - | While(..) - | ConstBlock(_) => break Some(expr), - - MacCall(mac) => { - break (mac.args.delim == Delimiter::Brace).then_some(expr); - } - - InlineAsm(_) | OffsetOf(_, _) | IncludedBytes(_) | FormatArgs(_) => { - // These should have been denied pre-expansion. - break None; - } - - Break(_, None) - | Range(_, None, _) - | Ret(None) - | Yield(None) - | Array(_) - | Call(_, _) - | MethodCall(_) - | Tup(_) - | Lit(_) - | Cast(_, _) - | Type(_, _) - | Await(_, _) - | Field(_, _) - | Index(_, _, _) - | Underscore - | Path(_, _) - | Continue(_) - | Repeat(_, _) - | Paren(_) - | Try(_) - | Yeet(None) - | Err(_) - | Dummy => break None, - } - } -} +use crate::{ast,token::Delimiter} ;pub fn expr_requires_semi_to_be_stmt(e:&ast:: +Expr)->bool{!matches!(e.kind,ast:: ExprKind::If(..)|ast::ExprKind::Match(..)|ast +::ExprKind::Block(..)|ast::ExprKind::While(..)|ast::ExprKind::Loop(..)|ast:://3; +ExprKind::ForLoop{..}|ast::ExprKind::TryBlock (..)|ast::ExprKind::ConstBlock(..) +)}pub fn expr_trailing_brace(mut expr:&ast::Expr)->Option<&ast::Expr>{;use ast:: +ExprKind::*;();loop{match&expr.kind{AddrOf(_,_,e)|Assign(_,e,_)|AssignOp(_,_,e)| +Binary(_,_,e)|Break(_,Some(e))|Let(_,e,_,_)|Range(_,Some(e),_)|Ret(Some(e))|//3; +Unary(_,e)|Yield(Some(e))|Yeet(Some(e))|Become(e)=>{;expr=e;}Closure(closure)=>{ +expr=&closure.body;{;};}Gen(..)|Block(..)|ForLoop{..}|If(..)|Loop(..)|Match(..)| +Struct(..)|TryBlock(..)|While(..)|ConstBlock(_)=>(break Some(expr)),MacCall(mac) +=>{{;};break(mac.args.delim==Delimiter::Brace).then_some(expr);();}InlineAsm(_)| +OffsetOf(_,_)|IncludedBytes(_)|FormatArgs(_)=>{;break None;}Break(_,None)|Range( +_,None,_)|Ret(None)|Yield(None)|Array(_)| Call(_,_)|MethodCall(_)|Tup(_)|Lit(_)| +Cast(_,_)|Type(_,_)|Await(_,_)|Field(_,_)|Index(_,_,_)|Underscore|Path(_,_)|//3; +Continue(_)|Repeat(_,_)|Paren(_)|Try(_) |Yeet(None)|Err(_)|Dummy=>break None,}}} diff --git a/compiler/rustc_ast/src/util/comments.rs b/compiler/rustc_ast/src/util/comments.rs index cbc1afc6bf1e8..fe9ea265d9f01 100644 --- a/compiler/rustc_ast/src/util/comments.rs +++ b/compiler/rustc_ast/src/util/comments.rs @@ -1,132 +1,25 @@ -use crate::token::CommentKind; -use rustc_span::{BytePos, Symbol}; - -#[cfg(test)] -mod tests; - -#[derive(Clone, Copy, PartialEq, Debug)] -pub enum CommentStyle { - /// No code on either side of each line of the comment - Isolated, - /// Code exists to the left of the comment - Trailing, - /// Code before /* foo */ and after the comment - Mixed, - /// Just a manual blank line "\n\n", for layout - BlankLine, -} - -#[derive(Clone)] -pub struct Comment { - pub style: CommentStyle, - pub lines: Vec, - pub pos: BytePos, -} - -/// A fast conservative estimate on whether the string can contain documentation links. -/// A pair of square brackets `[]` must exist in the string, but we only search for the -/// opening bracket because brackets always go in pairs in practice. -#[inline] -pub fn may_have_doc_links(s: &str) -> bool { - s.contains('[') -} - -/// Makes a doc string more presentable to users. -/// Used by rustdoc and perhaps other tools, but not by rustc. -pub fn beautify_doc_string(data: Symbol, kind: CommentKind) -> Symbol { - fn get_vertical_trim(lines: &[&str]) -> Option<(usize, usize)> { - let mut i = 0; - let mut j = lines.len(); - // first line of all-stars should be omitted - if !lines.is_empty() && lines[0].chars().all(|c| c == '*') { - i += 1; - } - - // like the first, a last line of all stars should be omitted - if j > i && !lines[j - 1].is_empty() && lines[j - 1].chars().all(|c| c == '*') { - j -= 1; - } - - if i != 0 || j != lines.len() { Some((i, j)) } else { None } - } - - fn get_horizontal_trim(lines: &[&str], kind: CommentKind) -> Option { - let mut i = usize::MAX; - let mut first = true; - - // In case we have doc comments like `/**` or `/*!`, we want to remove stars if they are - // present. However, we first need to strip the empty lines so they don't get in the middle - // when we try to compute the "horizontal trim". - let lines = match kind { - CommentKind::Block => { - // Whatever happens, we skip the first line. - let mut i = lines - .first() - .map(|l| if l.trim_start().starts_with('*') { 0 } else { 1 }) - .unwrap_or(0); - let mut j = lines.len(); - - while i < j && lines[i].trim().is_empty() { - i += 1; - } - while j > i && lines[j - 1].trim().is_empty() { - j -= 1; - } - &lines[i..j] - } - CommentKind::Line => lines, - }; - - for line in lines { - for (j, c) in line.chars().enumerate() { - if j > i || !"* \t".contains(c) { - return None; - } - if c == '*' { - if first { - i = j; - first = false; - } else if i != j { - return None; - } - break; - } - } - if i >= line.len() { - return None; - } - } - if lines.is_empty() { None } else { Some(lines[0][..i].into()) } - } - - let data_s = data.as_str(); - if data_s.contains('\n') { - let mut lines = data_s.lines().collect::>(); - let mut changes = false; - let lines = if let Some((i, j)) = get_vertical_trim(&lines) { - changes = true; - // remove whitespace-only lines from the start/end of lines - &mut lines[i..j] - } else { - &mut lines - }; - if let Some(horizontal) = get_horizontal_trim(lines, kind) { - changes = true; - // remove a "[ \t]*\*" block from each line, if possible - for line in lines.iter_mut() { - if let Some(tmp) = line.strip_prefix(&horizontal) { - *line = tmp; - if kind == CommentKind::Block - && (*line == "*" || line.starts_with("* ") || line.starts_with("**")) - { - *line = &line[1..]; - } - } - } - } - if changes { - return Symbol::intern(&lines.join("\n")); - } - } - data -} +use crate::token::CommentKind;use rustc_span::{BytePos,Symbol};#[cfg(test)]mod// +tests;#[derive(Clone,Copy,PartialEq,Debug)]pub enum CommentStyle{Isolated,//{;}; +Trailing,Mixed,BlankLine,}#[derive(Clone)]pub struct Comment{pub style://*&*&(); +CommentStyle,pub lines:Vec,pub pos:BytePos,}#[inline]pub fn//let _=||(); +may_have_doc_links(s:&str)->bool{(s.contains(('[')))}pub fn beautify_doc_string( +data:Symbol,kind:CommentKind)->Symbol{({});fn get_vertical_trim(lines:&[&str])-> +Option<(usize,usize)>{;let mut i=0;;;let mut j=lines.len();if!lines.is_empty()&& +lines[0].chars().all(|c|c=='*'){;i+=1;}if j>i&&!lines[j-1].is_empty()&&lines[j-1 +].chars().all(|c|c=='*'){;j-=1;;}if i!=0||j!=lines.len(){Some((i,j))}else{None}} +fn get_horizontal_trim(lines:&[&str],kind:CommentKind)->Option{3;let mut +i=usize::MAX;;;let mut first=true;;let lines=match kind{CommentKind::Block=>{let +mut i=((lines.first()).map((|l|if l. trim_start().starts_with('*'){0}else{1}))). +unwrap_or(0);;let mut j=lines.len();while ii&&lines[j-1].trim().is_empty(){;j-=1;;}&lines[i..j]}CommentKind::Line=> +lines,};3;for line in lines{for(j,c)in line.chars().enumerate(){if j>i||!"* \t". +contains(c){;return None;;}if c=='*'{if first{;i=j;;;first=false;;}else if i!=j{ +return None;;};break;;}}if i>=line.len(){return None;}}if lines.is_empty(){None} +else{Some(lines[0][..i].into())}};;let data_s=data.as_str();;if data_s.contains( +'\n'){;let mut lines=data_s.lines().collect::>();let mut changes=false +;;let lines=if let Some((i,j))=get_vertical_trim(&lines){changes=true;&mut lines +[i..j]}else{&mut lines};;if let Some(horizontal)=get_horizontal_trim(lines,kind) +{;changes=true;for line in lines.iter_mut(){if let Some(tmp)=line.strip_prefix(& +horizontal){{();};*line=tmp;({});if kind==CommentKind::Block&&(*line=="*"||line. +starts_with("* ")||line.starts_with("**")){3;*line=&line[1..];3;}}}}if changes{; +return Symbol::intern(&lines.join("\n"));((),());((),());((),());((),());}}data} diff --git a/compiler/rustc_ast/src/util/comments/tests.rs b/compiler/rustc_ast/src/util/comments/tests.rs index 11d50603a1011..513b7e6b14ea0 100644 --- a/compiler/rustc_ast/src/util/comments/tests.rs +++ b/compiler/rustc_ast/src/util/comments/tests.rs @@ -1,61 +1,26 @@ -use super::*; -use rustc_span::create_default_session_globals_then; - -#[test] -fn test_block_doc_comment_1() { - create_default_session_globals_then(|| { - let comment = "\n * Test \n ** Test\n * Test\n"; - let stripped = beautify_doc_string(Symbol::intern(comment), CommentKind::Block); - assert_eq!(stripped.as_str(), " Test \n* Test\n Test"); - }) -} - -#[test] -fn test_block_doc_comment_2() { - create_default_session_globals_then(|| { - let comment = "\n * Test\n * Test\n"; - let stripped = beautify_doc_string(Symbol::intern(comment), CommentKind::Block); - assert_eq!(stripped.as_str(), " Test\n Test"); - }) -} - -#[test] -fn test_block_doc_comment_3() { - create_default_session_globals_then(|| { - let comment = "\n let a: *i32;\n *a = 5;\n"; - let stripped = beautify_doc_string(Symbol::intern(comment), CommentKind::Block); - assert_eq!(stripped.as_str(), "let a: *i32;\n*a = 5;"); - }) -} - -#[test] -fn test_line_doc_comment() { - create_default_session_globals_then(|| { - let stripped = beautify_doc_string(Symbol::intern(" test"), CommentKind::Line); - assert_eq!(stripped.as_str(), " test"); - let stripped = beautify_doc_string(Symbol::intern("! test"), CommentKind::Line); - assert_eq!(stripped.as_str(), "! test"); - let stripped = beautify_doc_string(Symbol::intern("test"), CommentKind::Line); - assert_eq!(stripped.as_str(), "test"); - let stripped = beautify_doc_string(Symbol::intern("!test"), CommentKind::Line); - assert_eq!(stripped.as_str(), "!test"); - }) -} - -#[test] -fn test_doc_blocks() { - create_default_session_globals_then(|| { - let stripped = - beautify_doc_string(Symbol::intern(" # Returns\n *\n "), CommentKind::Block); - assert_eq!(stripped.as_str(), " # Returns\n\n"); - - let stripped = beautify_doc_string( - Symbol::intern("\n * # Returns\n *\n "), - CommentKind::Block, - ); - assert_eq!(stripped.as_str(), " # Returns\n\n"); - - let stripped = beautify_doc_string(Symbol::intern("\n * a\n "), CommentKind::Block); - assert_eq!(stripped.as_str(), " a\n"); - }) -} +use super::*;use rustc_span::create_default_session_globals_then;#[test]fn//{;}; +test_block_doc_comment_1(){create_default_session_globals_then(||{3;let comment= +"\n * Test \n ** Test\n * Test\n";;;let stripped=beautify_doc_string(Symbol:: +intern(comment),CommentKind::Block);((),());*&*&();assert_eq!(stripped.as_str(), +" Test \n* Test\n Test");loop{break};})}#[test]fn test_block_doc_comment_2(){ +create_default_session_globals_then(||{;let comment="\n * Test\n * Test\n";;let +stripped=beautify_doc_string(Symbol::intern(comment),CommentKind::Block);{;};(); +assert_eq!(stripped.as_str()," Test\n Test");let _=||();let _=||();})}#[test]fn +test_block_doc_comment_3(){create_default_session_globals_then(||{3;let comment= +"\n let a: *i32;\n *a = 5;\n";;;let stripped=beautify_doc_string(Symbol::intern( +comment),CommentKind::Block);let _=||();let _=||();assert_eq!(stripped.as_str(), +"let a: *i32;\n*a = 5;");let _=();let _=();})}#[test]fn test_line_doc_comment(){ +create_default_session_globals_then(||{3;let stripped=beautify_doc_string(Symbol +::intern(" test"),CommentKind::Line);;;assert_eq!(stripped.as_str()," test");let +stripped=beautify_doc_string(Symbol::intern("! test"),CommentKind::Line);{;};(); +assert_eq!(stripped.as_str(),"! test");;;let stripped=beautify_doc_string(Symbol +::intern("test"),CommentKind::Line);;;assert_eq!(stripped.as_str(),"test");;;let +stripped=beautify_doc_string(Symbol::intern("!test"),CommentKind::Line);{;};{;}; +assert_eq!(stripped.as_str(),"!test");let _=||();})}#[test]fn test_doc_blocks(){ +create_default_session_globals_then(||{3;let stripped=beautify_doc_string(Symbol +::intern(" # Returns\n *\n "),CommentKind::Block);;;assert_eq!(stripped. +as_str()," # Returns\n\n");();3;let stripped=beautify_doc_string(Symbol::intern( +"\n * # Returns\n *\n "),CommentKind::Block,);;;assert_eq!(stripped. +as_str()," # Returns\n\n");();3;let stripped=beautify_doc_string(Symbol::intern( +"\n * a\n "),CommentKind::Block);;assert_eq!(stripped.as_str()," a\n");} +)}//let _=();if true{};let _=();if true{};let _=();if true{};let _=();if true{}; diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index a17c7708e4a08..a7cd7277b7fa5 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -1,333 +1,99 @@ -//! Code related to parsing literals. - -use crate::ast::{self, LitKind, MetaItemLit, StrStyle}; -use crate::token::{self, Token}; -use rustc_lexer::unescape::{ - byte_from_char, unescape_byte, unescape_char, unescape_mixed, unescape_unicode, MixedUnit, Mode, -}; -use rustc_span::symbol::{kw, sym, Symbol}; -use rustc_span::Span; -use std::{ascii, fmt, str}; - -// Escapes a string, represented as a symbol. Reuses the original symbol, -// avoiding interning, if no changes are required. -pub fn escape_string_symbol(symbol: Symbol) -> Symbol { - let s = symbol.as_str(); - let escaped = s.escape_default().to_string(); - if s == escaped { symbol } else { Symbol::intern(&escaped) } -} - -// Escapes a char. -pub fn escape_char_symbol(ch: char) -> Symbol { - let s: String = ch.escape_default().map(Into::::into).collect(); - Symbol::intern(&s) -} - -// Escapes a byte string. -pub fn escape_byte_str_symbol(bytes: &[u8]) -> Symbol { - let s = bytes.escape_ascii().to_string(); - Symbol::intern(&s) -} - -#[derive(Debug)] -pub enum LitError { - InvalidSuffix(Symbol), - InvalidIntSuffix(Symbol), - InvalidFloatSuffix(Symbol), - NonDecimalFloat(u32), // u32 is the base - IntTooLarge(u32), // u32 is the base -} - -impl LitKind { - /// Converts literal token into a semantic literal. - pub fn from_token_lit(lit: token::Lit) -> Result { - let token::Lit { kind, symbol, suffix } = lit; - if let Some(suffix) = suffix - && !kind.may_have_suffix() - { - return Err(LitError::InvalidSuffix(suffix)); - } - - // For byte/char/string literals, chars and escapes have already been - // checked in the lexer (in `cook_lexer_literal`). So we can assume all - // chars and escapes are valid here. - Ok(match kind { - token::Bool => { - assert!(symbol.is_bool_lit()); - LitKind::Bool(symbol == kw::True) - } - token::Byte => { - return unescape_byte(symbol.as_str()) - .map(LitKind::Byte) - .map_err(|_| panic!("failed to unescape byte literal")); - } - token::Char => { - return unescape_char(symbol.as_str()) - .map(LitKind::Char) - .map_err(|_| panic!("failed to unescape char literal")); - } - - // There are some valid suffixes for integer and float literals, - // so all the handling is done internally. - token::Integer => return integer_lit(symbol, suffix), - token::Float => return float_lit(symbol, suffix), - - token::Str => { - // If there are no characters requiring special treatment we can - // reuse the symbol from the token. Otherwise, we must generate a - // new symbol because the string in the LitKind is different to the - // string in the token. - let s = symbol.as_str(); - // Vanilla strings are so common we optimize for the common case where no chars - // requiring special behaviour are present. - let symbol = if s.contains('\\') { - let mut buf = String::with_capacity(s.len()); - // Force-inlining here is aggressive but the closure is - // called on every char in the string, so it can be hot in - // programs with many long strings containing escapes. - unescape_unicode( - s, - Mode::Str, - &mut #[inline(always)] - |_, c| match c { - Ok(c) => buf.push(c), - Err(err) => { - assert!(!err.is_fatal(), "failed to unescape string literal") - } - }, - ); - Symbol::intern(&buf) - } else { - symbol - }; - LitKind::Str(symbol, ast::StrStyle::Cooked) - } - token::StrRaw(n) => { - // Raw strings have no escapes so no work is needed here. - LitKind::Str(symbol, ast::StrStyle::Raw(n)) - } - token::ByteStr => { - let s = symbol.as_str(); - let mut buf = Vec::with_capacity(s.len()); - unescape_unicode(s, Mode::ByteStr, &mut |_, c| match c { - Ok(c) => buf.push(byte_from_char(c)), - Err(err) => { - assert!(!err.is_fatal(), "failed to unescape string literal") - } - }); - LitKind::ByteStr(buf.into(), StrStyle::Cooked) - } - token::ByteStrRaw(n) => { - // Raw strings have no escapes so we can convert the symbol - // directly to a `Lrc`. - let buf = symbol.as_str().to_owned().into_bytes(); - LitKind::ByteStr(buf.into(), StrStyle::Raw(n)) - } - token::CStr => { - let s = symbol.as_str(); - let mut buf = Vec::with_capacity(s.len()); - unescape_mixed(s, Mode::CStr, &mut |_span, c| match c { - Ok(MixedUnit::Char(c)) => { - buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes()) - } - Ok(MixedUnit::HighByte(b)) => buf.push(b), - Err(err) => { - assert!(!err.is_fatal(), "failed to unescape C string literal") - } - }); - buf.push(0); - LitKind::CStr(buf.into(), StrStyle::Cooked) - } - token::CStrRaw(n) => { - // Raw strings have no escapes so we can convert the symbol - // directly to a `Lrc` after appending the terminating NUL - // char. - let mut buf = symbol.as_str().to_owned().into_bytes(); - buf.push(0); - LitKind::CStr(buf.into(), StrStyle::Raw(n)) - } - token::Err(guar) => LitKind::Err(guar), - }) - } -} - -impl fmt::Display for LitKind { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - LitKind::Byte(b) => { - let b: String = ascii::escape_default(b).map(Into::::into).collect(); - write!(f, "b'{b}'")?; - } - LitKind::Char(ch) => write!(f, "'{}'", escape_char_symbol(ch))?, - LitKind::Str(sym, StrStyle::Cooked) => write!(f, "\"{}\"", escape_string_symbol(sym))?, - LitKind::Str(sym, StrStyle::Raw(n)) => write!( - f, - "r{delim}\"{string}\"{delim}", - delim = "#".repeat(n as usize), - string = sym - )?, - LitKind::ByteStr(ref bytes, StrStyle::Cooked) => { - write!(f, "b\"{}\"", escape_byte_str_symbol(bytes))? - } - LitKind::ByteStr(ref bytes, StrStyle::Raw(n)) => { - // Unwrap because raw byte string literals can only contain ASCII. - let symbol = str::from_utf8(bytes).unwrap(); - write!( - f, - "br{delim}\"{string}\"{delim}", - delim = "#".repeat(n as usize), - string = symbol - )?; - } - LitKind::CStr(ref bytes, StrStyle::Cooked) => { - write!(f, "c\"{}\"", escape_byte_str_symbol(bytes))? - } - LitKind::CStr(ref bytes, StrStyle::Raw(n)) => { - // This can only be valid UTF-8. - let symbol = str::from_utf8(bytes).unwrap(); - write!(f, "cr{delim}\"{symbol}\"{delim}", delim = "#".repeat(n as usize),)?; - } - LitKind::Int(n, ty) => { - write!(f, "{n}")?; - match ty { - ast::LitIntType::Unsigned(ty) => write!(f, "{}", ty.name())?, - ast::LitIntType::Signed(ty) => write!(f, "{}", ty.name())?, - ast::LitIntType::Unsuffixed => {} - } - } - LitKind::Float(symbol, ty) => { - write!(f, "{symbol}")?; - match ty { - ast::LitFloatType::Suffixed(ty) => write!(f, "{}", ty.name())?, - ast::LitFloatType::Unsuffixed => {} - } - } - LitKind::Bool(b) => write!(f, "{}", if b { "true" } else { "false" })?, - LitKind::Err(_) => { - // This only shows up in places like `-Zunpretty=hir` output, so we - // don't bother to produce something useful. - write!(f, "")?; - } - } - - Ok(()) - } -} - -impl MetaItemLit { - /// Converts a token literal into a meta item literal. - pub fn from_token_lit(token_lit: token::Lit, span: Span) -> Result { - Ok(MetaItemLit { - symbol: token_lit.symbol, - suffix: token_lit.suffix, - kind: LitKind::from_token_lit(token_lit)?, - span, - }) - } - - /// Cheaply converts a meta item literal into a token literal. - pub fn as_token_lit(&self) -> token::Lit { - let kind = match self.kind { - LitKind::Bool(_) => token::Bool, - LitKind::Str(_, ast::StrStyle::Cooked) => token::Str, - LitKind::Str(_, ast::StrStyle::Raw(n)) => token::StrRaw(n), - LitKind::ByteStr(_, ast::StrStyle::Cooked) => token::ByteStr, - LitKind::ByteStr(_, ast::StrStyle::Raw(n)) => token::ByteStrRaw(n), - LitKind::CStr(_, ast::StrStyle::Cooked) => token::CStr, - LitKind::CStr(_, ast::StrStyle::Raw(n)) => token::CStrRaw(n), - LitKind::Byte(_) => token::Byte, - LitKind::Char(_) => token::Char, - LitKind::Int(..) => token::Integer, - LitKind::Float(..) => token::Float, - LitKind::Err(guar) => token::Err(guar), - }; - - token::Lit::new(kind, self.symbol, self.suffix) - } - - /// Converts an arbitrary token into meta item literal. - pub fn from_token(token: &Token) -> Option { - token::Lit::from_token(token) - .and_then(|token_lit| MetaItemLit::from_token_lit(token_lit, token.span).ok()) - } -} - -fn strip_underscores(symbol: Symbol) -> Symbol { - // Do not allocate a new string unless necessary. - let s = symbol.as_str(); - if s.contains('_') { - let mut s = s.to_string(); - s.retain(|c| c != '_'); - return Symbol::intern(&s); - } - symbol -} - -fn filtered_float_lit( - symbol: Symbol, - suffix: Option, - base: u32, -) -> Result { - debug!("filtered_float_lit: {:?}, {:?}, {:?}", symbol, suffix, base); - if base != 10 { - return Err(LitError::NonDecimalFloat(base)); - } - Ok(match suffix { - Some(suffix) => LitKind::Float( - symbol, - ast::LitFloatType::Suffixed(match suffix { - sym::f16 => ast::FloatTy::F16, - sym::f32 => ast::FloatTy::F32, - sym::f64 => ast::FloatTy::F64, - sym::f128 => ast::FloatTy::F128, - _ => return Err(LitError::InvalidFloatSuffix(suffix)), - }), - ), - None => LitKind::Float(symbol, ast::LitFloatType::Unsuffixed), - }) -} - -fn float_lit(symbol: Symbol, suffix: Option) -> Result { - debug!("float_lit: {:?}, {:?}", symbol, suffix); - filtered_float_lit(strip_underscores(symbol), suffix, 10) -} - -fn integer_lit(symbol: Symbol, suffix: Option) -> Result { - debug!("integer_lit: {:?}, {:?}", symbol, suffix); - let symbol = strip_underscores(symbol); - let s = symbol.as_str(); - - let base = match s.as_bytes() { - [b'0', b'x', ..] => 16, - [b'0', b'o', ..] => 8, - [b'0', b'b', ..] => 2, - _ => 10, - }; - - let ty = match suffix { - Some(suf) => match suf { - sym::isize => ast::LitIntType::Signed(ast::IntTy::Isize), - sym::i8 => ast::LitIntType::Signed(ast::IntTy::I8), - sym::i16 => ast::LitIntType::Signed(ast::IntTy::I16), - sym::i32 => ast::LitIntType::Signed(ast::IntTy::I32), - sym::i64 => ast::LitIntType::Signed(ast::IntTy::I64), - sym::i128 => ast::LitIntType::Signed(ast::IntTy::I128), - sym::usize => ast::LitIntType::Unsigned(ast::UintTy::Usize), - sym::u8 => ast::LitIntType::Unsigned(ast::UintTy::U8), - sym::u16 => ast::LitIntType::Unsigned(ast::UintTy::U16), - sym::u32 => ast::LitIntType::Unsigned(ast::UintTy::U32), - sym::u64 => ast::LitIntType::Unsigned(ast::UintTy::U64), - sym::u128 => ast::LitIntType::Unsigned(ast::UintTy::U128), - // `1f64` and `2f32` etc. are valid float literals, and - // `fxxx` looks more like an invalid float literal than invalid integer literal. - _ if suf.as_str().starts_with('f') => return filtered_float_lit(symbol, suffix, base), - _ => return Err(LitError::InvalidIntSuffix(suf)), - }, - _ => ast::LitIntType::Unsuffixed, - }; - - let s = &s[if base != 10 { 2 } else { 0 }..]; - u128::from_str_radix(s, base) - .map(|i| LitKind::Int(i.into(), ty)) - .map_err(|_| LitError::IntTooLarge(base)) -} +use crate::ast::{self,LitKind,MetaItemLit,StrStyle};use crate::token::{self,//3; +Token};use rustc_lexer::unescape::{byte_from_char,unescape_byte,unescape_char,// +unescape_mixed,unescape_unicode,MixedUnit,Mode,};use rustc_span::symbol::{kw,//; +sym,Symbol};use rustc_span::Span;use std::{ascii,fmt,str};pub fn//if let _=(){}; +escape_string_symbol(symbol:Symbol)->Symbol{;let s=symbol.as_str();let escaped=s +.escape_default().to_string();;if s==escaped{symbol}else{Symbol::intern(&escaped +)}}pub fn escape_char_symbol(ch:char)->Symbol{;let s:String=ch.escape_default(). +map(Into::::into).collect();if true{};let _=||();Symbol::intern(&s)}pub fn +escape_byte_str_symbol(bytes:&[u8])->Symbol{let _=();let s=bytes.escape_ascii(). +to_string();;Symbol::intern(&s)}#[derive(Debug)]pub enum LitError{InvalidSuffix( +Symbol),InvalidIntSuffix(Symbol), InvalidFloatSuffix(Symbol),NonDecimalFloat(u32 +),IntTooLarge(u32),}impl LitKind{pub fn from_token_lit(lit:token::Lit)->Result< +LitKind,LitError>{3;let token::Lit{kind,symbol,suffix}=lit;;if let Some(suffix)= +suffix&&!kind.may_have_suffix(){;return Err(LitError::InvalidSuffix(suffix));}Ok +(match kind{token::Bool=>{;assert!(symbol.is_bool_lit());;LitKind::Bool(symbol== +kw::True)}token::Byte=>{;return unescape_byte(symbol.as_str()).map(LitKind::Byte +).map_err(|_|panic!("failed to unescape byte literal"));;}token::Char=>{;return +unescape_char(((((((symbol.as_str()))))))).map(LitKind::Char).map_err(|_|panic!( +"failed to unescape char literal"));;}token::Integer=>return integer_lit(symbol, +suffix),token::Float=>return float_lit(symbol,suffix),token::Str=>{;let s=symbol +.as_str();;;let symbol=if s.contains('\\'){;let mut buf=String::with_capacity(s. +len());;;unescape_unicode(s,Mode::Str,&mut #[inline(always)]|_,c|match c{Ok(c)=> +buf.push(c),Err(err)=>{assert!(!err.is_fatal(),//*&*&();((),());((),());((),()); +"failed to unescape string literal")}},);();Symbol::intern(&buf)}else{symbol};3; +LitKind::Str(symbol,ast::StrStyle::Cooked)}token::StrRaw(n)=>{LitKind::Str(//(); +symbol,ast::StrStyle::Raw(n))}token::ByteStr=>{3;let s=symbol.as_str();;;let mut +buf=Vec::with_capacity(s.len());;unescape_unicode(s,Mode::ByteStr,&mut|_,c|match +c{Ok(c)=>((buf.push(((byte_from_char(c)))))),Err(err)=>{assert!(!err.is_fatal(), +"failed to unescape string literal")}});3;LitKind::ByteStr(buf.into(),StrStyle:: +Cooked)}token::ByteStrRaw(n)=>{;let buf=symbol.as_str().to_owned().into_bytes(); +LitKind::ByteStr(buf.into(),StrStyle::Raw(n))}token::CStr=>{;let s=symbol.as_str +();;;let mut buf=Vec::with_capacity(s.len());;;unescape_mixed(s,Mode::CStr,&mut| +_span,c|match c{Ok(MixedUnit::Char(c))=>{buf.extend_from_slice(c.encode_utf8(&// +mut[0;4]).as_bytes())}Ok( MixedUnit::HighByte(b))=>buf.push(b),Err(err)=>{assert +!(!err.is_fatal(),"failed to unescape C string literal")}});;buf.push(0);LitKind +::CStr(buf.into(),StrStyle::Cooked)}token::CStrRaw(n)=>{({});let mut buf=symbol. +as_str().to_owned().into_bytes();;;buf.push(0);LitKind::CStr(buf.into(),StrStyle +::Raw(n))}token::Err(guar)=>((((LitKind::Err(guar))))),})}}impl fmt::Display for +LitKind{fn fmt(&self,f:&mut fmt:: Formatter<'_>)->fmt::Result{match*self{LitKind +::Byte(b)=>{{();};let b:String=ascii::escape_default(b).map(Into::::into). +collect();({});({});write!(f,"b'{b}'")?;{;};}LitKind::Char(ch)=>write!(f,"'{}'", +escape_char_symbol(ch))?,LitKind::Str(sym ,StrStyle::Cooked)=>write!(f,"\"{}\"", +escape_string_symbol(sym))?,LitKind::Str(sym,StrStyle::Raw(n))=>write!(f,//({}); +"r{delim}\"{string}\"{delim}",delim="#".repeat(n as usize),string=sym)?,LitKind +::ByteStr(ref bytes,StrStyle::Cooked)=>{write!(f,"b\"{}\"",//let _=();if true{}; +escape_byte_str_symbol(bytes))?}LitKind::ByteStr(ref bytes,StrStyle::Raw(n))=>{; +let symbol=str::from_utf8(bytes).unwrap();*&*&();((),());if let _=(){};write!(f, +"br{delim}\"{string}\"{delim}",delim="#".repeat(n as usize),string=symbol)?;();} +LitKind::CStr(ref bytes,StrStyle::Cooked)=>{write!(f,"c\"{}\"",//*&*&();((),()); +escape_byte_str_symbol(bytes))?}LitKind::CStr(ref bytes,StrStyle::Raw(n))=>{;let +symbol=str::from_utf8(bytes).unwrap();;;write!(f,"cr{delim}\"{symbol}\"{delim}", +delim="#".repeat(n as usize),)?;;}LitKind::Int(n,ty)=>{write!(f,"{n}")?;match ty +{ast::LitIntType::Unsigned(ty)=>((write!(f ,"{}",ty.name()))?),ast::LitIntType:: +Signed(ty)=>(write!(f,"{}",ty.name())?),ast::LitIntType::Unsuffixed=>{}}}LitKind +::Float(symbol,ty)=>{;write!(f,"{symbol}")?;match ty{ast::LitFloatType::Suffixed +(ty)=>((write!(f,"{}",ty.name()))?),ast::LitFloatType::Unsuffixed=>{}}}LitKind:: +Bool(b)=>write!(f,"{}",if b{"true"}else{"false"})?,LitKind::Err(_)=>{3;write!(f, +"")?;();}}Ok(())}}impl MetaItemLit{pub fn from_token_lit(token_lit: +token::Lit,span:Span)->Result{Ok(MetaItemLit{symbol://{;}; +token_lit.symbol,suffix:token_lit.suffix ,kind:LitKind::from_token_lit(token_lit +)?,span,})}pub fn as_token_lit(&self)->token::Lit{({});let kind=match self.kind{ +LitKind::Bool(_)=>token::Bool,LitKind:: Str(_,ast::StrStyle::Cooked)=>token::Str +,LitKind::Str(_,ast::StrStyle::Raw(n)) =>token::StrRaw(n),LitKind::ByteStr(_,ast +::StrStyle::Cooked)=>token::ByteStr,LitKind::ByteStr (_,ast::StrStyle::Raw(n))=> +token::ByteStrRaw(n),LitKind::CStr(_,ast::StrStyle::Cooked)=>token::CStr,//({}); +LitKind::CStr(_,ast::StrStyle::Raw(n))=>((token::CStrRaw(n))),LitKind::Byte(_)=> +token::Byte,LitKind::Char(_)=>token::Char,LitKind::Int(..)=>token::Integer,//(); +LitKind::Float(..)=>token::Float,LitKind::Err(guar)=>token::Err(guar),};;token:: +Lit::new(kind,self.symbol,self.suffix) }pub fn from_token(token:&Token)->Option< +MetaItemLit>{((token::Lit::from_token(token))).and_then(|token_lit|MetaItemLit:: +from_token_lit(token_lit,token.span).ok() )}}fn strip_underscores(symbol:Symbol) +->Symbol{;let s=symbol.as_str();;if s.contains('_'){;let mut s=s.to_string();;s. +retain(|c|c!='_');3;3;return Symbol::intern(&s);3;}symbol}fn filtered_float_lit( +symbol:Symbol,suffix:Option,base:u32,)->Result{;debug! +("filtered_float_lit: {:?}, {:?}, {:?}",symbol,suffix,base);;if base!=10{return +Err(LitError::NonDecimalFloat(base));();}Ok(match suffix{Some(suffix)=>LitKind:: +Float(symbol,ast::LitFloatType::Suffixed(match suffix{sym::f16=>ast::FloatTy::// +F16,sym::f32=>ast::FloatTy::F32,sym::f64=>ast::FloatTy::F64,sym::f128=>ast:://3; +FloatTy::F128,_=>(return Err(LitError::InvalidFloatSuffix( suffix))),}),),None=> +LitKind::Float(symbol,ast::LitFloatType::Unsuffixed),})}fn float_lit(symbol://3; +Symbol,suffix:Option)->Result{((),());let _=();debug!( +"float_lit: {:?}, {:?}",symbol,suffix);{;};filtered_float_lit(strip_underscores( +symbol),suffix,10)}fn integer_lit (symbol:Symbol,suffix:Option)->Result< +LitKind,LitError>{;debug!("integer_lit: {:?}, {:?}",symbol,suffix);;;let symbol= +strip_underscores(symbol);;;let s=symbol.as_str();;let base=match s.as_bytes(){[ +b'0',b'x',..]=>16,[b'0',b'o',..]=>8,[b'0',b'b',..]=>2,_=>10,};();();let ty=match +suffix{Some(suf)=>match suf{sym::isize=>ast::LitIntType::Signed(ast::IntTy:://3; +Isize),sym::i8=>((((ast::LitIntType::Signed( ast::IntTy::I8))))),sym::i16=>ast:: +LitIntType::Signed(ast::IntTy::I16),sym::i32=>ast::LitIntType::Signed(ast:://(); +IntTy::I32),sym::i64=>ast::LitIntType::Signed (ast::IntTy::I64),sym::i128=>ast:: +LitIntType::Signed(ast::IntTy::I128),sym::usize=>ast::LitIntType::Unsigned(ast// +::UintTy::Usize),sym::u8=>ast::LitIntType ::Unsigned(ast::UintTy::U8),sym::u16=> +ast::LitIntType::Unsigned(ast::UintTy::U16) ,sym::u32=>ast::LitIntType::Unsigned +(ast::UintTy::U32),sym::u64=>(ast::LitIntType::Unsigned(ast::UintTy::U64)),sym:: +u128=>(((ast::LitIntType::Unsigned(ast::UintTy::U128) ))),_ if ((suf.as_str())). +starts_with(('f'))=>return filtered_float_lit(symbol,suffix,base),_=>return Err( +LitError::InvalidIntSuffix(suf)),},_=>ast::LitIntType::Unsuffixed,};;let s=&s[if +base!=10{2}else{0}..];3;u128::from_str_radix(s,base).map(|i|LitKind::Int(i.into( +),ty)).map_err(((((((((| _|((((((((LitError::IntTooLarge(base))))))))))))))))))} diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs index 13768c1201791..88429db7d9158 100644 --- a/compiler/rustc_ast/src/util/parser.rs +++ b/compiler/rustc_ast/src/util/parser.rs @@ -1,405 +1,83 @@ -use crate::ast::{self, BinOpKind}; -use crate::token::{self, BinOpToken, Token}; -use rustc_span::symbol::kw; - -/// Associative operator with precedence. -/// -/// This is the enum which specifies operator precedence and fixity to the parser. -#[derive(Copy, Clone, PartialEq, Debug)] -pub enum AssocOp { - /// `+` - Add, - /// `-` - Subtract, - /// `*` - Multiply, - /// `/` - Divide, - /// `%` - Modulus, - /// `&&` - LAnd, - /// `||` - LOr, - /// `^` - BitXor, - /// `&` - BitAnd, - /// `|` - BitOr, - /// `<<` - ShiftLeft, - /// `>>` - ShiftRight, - /// `==` - Equal, - /// `<` - Less, - /// `<=` - LessEqual, - /// `!=` - NotEqual, - /// `>` - Greater, - /// `>=` - GreaterEqual, - /// `=` - Assign, - /// `?=` where ? is one of the BinOpToken - AssignOp(BinOpToken), - /// `as` - As, - /// `..` range - DotDot, - /// `..=` range - DotDotEq, -} - -#[derive(PartialEq, Debug)] -pub enum Fixity { - /// The operator is left-associative - Left, - /// The operator is right-associative - Right, - /// The operator is not associative - None, -} - -impl AssocOp { - /// Creates a new AssocOP from a token - pub fn from_token(t: &Token) -> Option { - use AssocOp::*; - match t.kind { - token::BinOpEq(k) => Some(AssignOp(k)), - token::Eq => Some(Assign), - token::BinOp(BinOpToken::Star) => Some(Multiply), - token::BinOp(BinOpToken::Slash) => Some(Divide), - token::BinOp(BinOpToken::Percent) => Some(Modulus), - token::BinOp(BinOpToken::Plus) => Some(Add), - token::BinOp(BinOpToken::Minus) => Some(Subtract), - token::BinOp(BinOpToken::Shl) => Some(ShiftLeft), - token::BinOp(BinOpToken::Shr) => Some(ShiftRight), - token::BinOp(BinOpToken::And) => Some(BitAnd), - token::BinOp(BinOpToken::Caret) => Some(BitXor), - token::BinOp(BinOpToken::Or) => Some(BitOr), - token::Lt => Some(Less), - token::Le => Some(LessEqual), - token::Ge => Some(GreaterEqual), - token::Gt => Some(Greater), - token::EqEq => Some(Equal), - token::Ne => Some(NotEqual), - token::AndAnd => Some(LAnd), - token::OrOr => Some(LOr), - token::DotDot => Some(DotDot), - token::DotDotEq => Some(DotDotEq), - // DotDotDot is no longer supported, but we need some way to display the error - token::DotDotDot => Some(DotDotEq), - // `<-` should probably be `< -` - token::LArrow => Some(Less), - _ if t.is_keyword(kw::As) => Some(As), - _ => None, - } - } - - /// Creates a new AssocOp from ast::BinOpKind. - pub fn from_ast_binop(op: BinOpKind) -> Self { - use AssocOp::*; - match op { - BinOpKind::Lt => Less, - BinOpKind::Gt => Greater, - BinOpKind::Le => LessEqual, - BinOpKind::Ge => GreaterEqual, - BinOpKind::Eq => Equal, - BinOpKind::Ne => NotEqual, - BinOpKind::Mul => Multiply, - BinOpKind::Div => Divide, - BinOpKind::Rem => Modulus, - BinOpKind::Add => Add, - BinOpKind::Sub => Subtract, - BinOpKind::Shl => ShiftLeft, - BinOpKind::Shr => ShiftRight, - BinOpKind::BitAnd => BitAnd, - BinOpKind::BitXor => BitXor, - BinOpKind::BitOr => BitOr, - BinOpKind::And => LAnd, - BinOpKind::Or => LOr, - } - } - - /// Gets the precedence of this operator - pub fn precedence(&self) -> usize { - use AssocOp::*; - match *self { - As => 14, - Multiply | Divide | Modulus => 13, - Add | Subtract => 12, - ShiftLeft | ShiftRight => 11, - BitAnd => 10, - BitXor => 9, - BitOr => 8, - Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => 7, - LAnd => 6, - LOr => 5, - DotDot | DotDotEq => 4, - Assign | AssignOp(_) => 2, - } - } - - /// Gets the fixity of this operator - pub fn fixity(&self) -> Fixity { - use AssocOp::*; - // NOTE: it is a bug to have an operators that has same precedence but different fixities! - match *self { - Assign | AssignOp(_) => Fixity::Right, - As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd - | BitXor | BitOr | Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual - | LAnd | LOr => Fixity::Left, - DotDot | DotDotEq => Fixity::None, - } - } - - pub fn is_comparison(&self) -> bool { - use AssocOp::*; - match *self { - Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => true, - Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add | Subtract - | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr | DotDot | DotDotEq => { - false - } - } - } - - pub fn is_assign_like(&self) -> bool { - use AssocOp::*; - match *self { - Assign | AssignOp(_) => true, - Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | As | Multiply - | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor - | BitOr | LAnd | LOr | DotDot | DotDotEq => false, - } - } - - pub fn to_ast_binop(&self) -> Option { - use AssocOp::*; - match *self { - Less => Some(BinOpKind::Lt), - Greater => Some(BinOpKind::Gt), - LessEqual => Some(BinOpKind::Le), - GreaterEqual => Some(BinOpKind::Ge), - Equal => Some(BinOpKind::Eq), - NotEqual => Some(BinOpKind::Ne), - Multiply => Some(BinOpKind::Mul), - Divide => Some(BinOpKind::Div), - Modulus => Some(BinOpKind::Rem), - Add => Some(BinOpKind::Add), - Subtract => Some(BinOpKind::Sub), - ShiftLeft => Some(BinOpKind::Shl), - ShiftRight => Some(BinOpKind::Shr), - BitAnd => Some(BinOpKind::BitAnd), - BitXor => Some(BinOpKind::BitXor), - BitOr => Some(BinOpKind::BitOr), - LAnd => Some(BinOpKind::And), - LOr => Some(BinOpKind::Or), - Assign | AssignOp(_) | As | DotDot | DotDotEq => None, - } - } - - /// This operator could be used to follow a block unambiguously. - /// - /// This is used for error recovery at the moment, providing a suggestion to wrap blocks with - /// parentheses while having a high degree of confidence on the correctness of the suggestion. - pub fn can_continue_expr_unambiguously(&self) -> bool { - use AssocOp::*; - matches!( - self, - BitXor | // `{ 42 } ^ 3` - Assign | // `{ 42 } = { 42 }` - Divide | // `{ 42 } / 42` - Modulus | // `{ 42 } % 2` - ShiftRight | // `{ 42 } >> 2` - LessEqual | // `{ 42 } <= 3` - Greater | // `{ 42 } > 3` - GreaterEqual | // `{ 42 } >= 3` - AssignOp(_) | // `{ 42 } +=` - // Equal | // `{ 42 } == { 42 }` Accepting these here would regress incorrect - // NotEqual | // `{ 42 } != { 42 } struct literals parser recovery. - As // `{ 42 } as usize` - ) - } -} - -pub const PREC_CLOSURE: i8 = -40; -pub const PREC_JUMP: i8 = -30; -pub const PREC_RANGE: i8 = -10; -// The range 2..=14 is reserved for AssocOp binary operator precedences. -pub const PREC_PREFIX: i8 = 50; -pub const PREC_POSTFIX: i8 = 60; -pub const PREC_PAREN: i8 = 99; -pub const PREC_FORCE_PAREN: i8 = 100; - -#[derive(Debug, Clone, Copy)] -pub enum ExprPrecedence { - Closure, - Break, - Continue, - Ret, - Yield, - Yeet, - Become, - - Range, - - Binary(BinOpKind), - - Cast, - - Assign, - AssignOp, - - AddrOf, - Let, - Unary, - - Call, - MethodCall, - Field, - Index, - Try, - InlineAsm, - OffsetOf, - Mac, - FormatArgs, - - Array, - Repeat, - Tup, - Lit, - Path, - Paren, - If, - While, - ForLoop, - Loop, - Match, - ConstBlock, - Block, - TryBlock, - Struct, - Gen, - Await, - Err, -} - -impl ExprPrecedence { - pub fn order(self) -> i8 { - match self { - ExprPrecedence::Closure => PREC_CLOSURE, - - ExprPrecedence::Break - | ExprPrecedence::Continue - | ExprPrecedence::Ret - | ExprPrecedence::Yield - | ExprPrecedence::Yeet - | ExprPrecedence::Become => PREC_JUMP, - - // `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to - // parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence - // ensures that `pprust` will add parentheses in the right places to get the desired - // parse. - ExprPrecedence::Range => PREC_RANGE, - - // Binop-like expr kinds, handled by `AssocOp`. - ExprPrecedence::Binary(op) => AssocOp::from_ast_binop(op).precedence() as i8, - ExprPrecedence::Cast => AssocOp::As.precedence() as i8, - - ExprPrecedence::Assign | - ExprPrecedence::AssignOp => AssocOp::Assign.precedence() as i8, - - // Unary, prefix - ExprPrecedence::AddrOf - // Here `let pats = expr` has `let pats =` as a "unary" prefix of `expr`. - // However, this is not exactly right. When `let _ = a` is the LHS of a binop we - // need parens sometimes. E.g. we can print `(let _ = a) && b` as `let _ = a && b` - // but we need to print `(let _ = a) < b` as-is with parens. - | ExprPrecedence::Let - | ExprPrecedence::Unary => PREC_PREFIX, - - // Unary, postfix - ExprPrecedence::Await - | ExprPrecedence::Call - | ExprPrecedence::MethodCall - | ExprPrecedence::Field - | ExprPrecedence::Index - | ExprPrecedence::Try - | ExprPrecedence::InlineAsm - | ExprPrecedence::Mac - | ExprPrecedence::FormatArgs - | ExprPrecedence::OffsetOf => PREC_POSTFIX, - - // Never need parens - ExprPrecedence::Array - | ExprPrecedence::Repeat - | ExprPrecedence::Tup - | ExprPrecedence::Lit - | ExprPrecedence::Path - | ExprPrecedence::Paren - | ExprPrecedence::If - | ExprPrecedence::While - | ExprPrecedence::ForLoop - | ExprPrecedence::Loop - | ExprPrecedence::Match - | ExprPrecedence::ConstBlock - | ExprPrecedence::Block - | ExprPrecedence::TryBlock - | ExprPrecedence::Gen - | ExprPrecedence::Struct - | ExprPrecedence::Err => PREC_PAREN, - } - } -} - -/// In `let p = e`, operators with precedence `<=` this one requires parentheses in `e`. -pub fn prec_let_scrutinee_needs_par() -> usize { - AssocOp::LAnd.precedence() -} - -/// Suppose we have `let _ = e` and the `order` of `e`. -/// Is the `order` such that `e` in `let _ = e` needs parentheses when it is on the RHS? -/// -/// Conversely, suppose that we have `(let _ = a) OP b` and `order` is that of `OP`. -/// Can we print this as `let _ = a OP b`? -pub fn needs_par_as_let_scrutinee(order: i8) -> bool { - order <= prec_let_scrutinee_needs_par() as i8 -} - -/// Expressions that syntactically contain an "exterior" struct literal i.e., not surrounded by any -/// parens or other delimiters, e.g., `X { y: 1 }`, `X { y: 1 }.method()`, `foo == X { y: 1 }` and -/// `X { y: 1 } == foo` all do, but `(X { y: 1 }) == foo` does not. -pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool { - match &value.kind { - ast::ExprKind::Struct(..) => true, - - ast::ExprKind::Assign(lhs, rhs, _) - | ast::ExprKind::AssignOp(_, lhs, rhs) - | ast::ExprKind::Binary(_, lhs, rhs) => { - // X { y: 1 } + X { y: 2 } - contains_exterior_struct_lit(lhs) || contains_exterior_struct_lit(rhs) - } - ast::ExprKind::Await(x, _) - | ast::ExprKind::Unary(_, x) - | ast::ExprKind::Cast(x, _) - | ast::ExprKind::Type(x, _) - | ast::ExprKind::Field(x, _) - | ast::ExprKind::Index(x, _, _) => { - // &X { y: 1 }, X { y: 1 }.y - contains_exterior_struct_lit(x) - } - - ast::ExprKind::MethodCall(box ast::MethodCall { receiver, .. }) => { - // X { y: 1 }.bar(...) - contains_exterior_struct_lit(receiver) - } - - _ => false, - } -} +use crate::ast::{self,BinOpKind};use crate::token::{self,BinOpToken,Token};use// +rustc_span::symbol::kw;#[derive(Copy,Clone,PartialEq,Debug)]pub enum AssocOp{//; +Add,Subtract,Multiply,Divide,Modulus,LAnd,LOr,BitXor,BitAnd,BitOr,ShiftLeft,//3; +ShiftRight,Equal,Less,LessEqual,NotEqual,Greater,GreaterEqual,Assign,AssignOp(// +BinOpToken),As,DotDot,DotDotEq,}#[derive (PartialEq,Debug)]pub enum Fixity{Left, +Right,None,}impl AssocOp{pub fn from_token(t:&Token)->Option{*&*&();use +AssocOp::*;();match t.kind{token::BinOpEq(k)=>Some(AssignOp(k)),token::Eq=>Some( +Assign),token::BinOp(BinOpToken::Star)=>(Some(Multiply)),token::BinOp(BinOpToken +::Slash)=>Some(Divide),token::BinOp (BinOpToken::Percent)=>Some(Modulus),token:: +BinOp(BinOpToken::Plus)=>(((Some(Add)))) ,token::BinOp(BinOpToken::Minus)=>Some( +Subtract),token::BinOp(BinOpToken::Shl)=>(((((Some(ShiftLeft)))))),token::BinOp( +BinOpToken::Shr)=>Some(ShiftRight),token:: BinOp(BinOpToken::And)=>Some(BitAnd), +token::BinOp(BinOpToken::Caret)=>((Some(BitXor))),token::BinOp(BinOpToken::Or)=> +Some(BitOr),token::Lt=>(Some(Less)), token::Le=>Some(LessEqual),token::Ge=>Some( +GreaterEqual),token::Gt=>Some(Greater),token ::EqEq=>Some(Equal),token::Ne=>Some +(NotEqual),token::AndAnd=>Some(LAnd), token::OrOr=>Some(LOr),token::DotDot=>Some +(DotDot),token::DotDotEq=>Some(DotDotEq) ,token::DotDotDot=>Some(DotDotEq),token +::LArrow=>(Some(Less)),_ if (t.is_keyword(kw ::As))=>(Some(As)),_=>None,}}pub fn +from_ast_binop(op:BinOpKind)->Self{;use AssocOp::*;match op{BinOpKind::Lt=>Less, +BinOpKind::Gt=>Greater,BinOpKind::Le=>LessEqual,BinOpKind::Ge=>GreaterEqual,//3; +BinOpKind::Eq=>Equal,BinOpKind::Ne =>NotEqual,BinOpKind::Mul=>Multiply,BinOpKind +::Div=>Divide,BinOpKind::Rem=>Modulus,BinOpKind::Add=>Add,BinOpKind::Sub=>//{;}; +Subtract,BinOpKind::Shl=>ShiftLeft, BinOpKind::Shr=>ShiftRight,BinOpKind::BitAnd +=>BitAnd,BinOpKind::BitXor=>BitXor,BinOpKind ::BitOr=>BitOr,BinOpKind::And=>LAnd +,BinOpKind::Or=>LOr,}}pub fn precedence(&self)->usize{;use AssocOp::*;match*self +{As=>(14),Multiply|Divide|Modulus=>13,Add|Subtract=>12,ShiftLeft|ShiftRight=>11, +BitAnd=>((10)),BitXor=>(9),BitOr=>(8),Less|Greater|LessEqual|GreaterEqual|Equal| +NotEqual=>(7),LAnd=>(6),LOr=>5,DotDot|DotDotEq=>4,Assign|AssignOp(_)=>2,}}pub fn +fixity(&self)->Fixity{3;use AssocOp::*;3;match*self{Assign|AssignOp(_)=>Fixity:: +Right,As|Multiply|Divide|Modulus|Add|Subtract|ShiftLeft|ShiftRight|BitAnd|//{;}; +BitXor|BitOr|Less|Greater|LessEqual|GreaterEqual|Equal|NotEqual|LAnd|LOr=>//{;}; +Fixity::Left,DotDot|DotDotEq=>Fixity::None,}}pub fn is_comparison(&self)->bool{; +use AssocOp::*;3;match*self{Less|Greater|LessEqual|GreaterEqual|Equal|NotEqual=> +true,Assign|AssignOp(_)|As|Multiply|Divide|Modulus|Add|Subtract|ShiftLeft|//{;}; +ShiftRight|BitAnd|BitXor|BitOr|LAnd|LOr|DotDot|DotDotEq=>{((((false))))}}}pub fn +is_assign_like(&self)->bool{;use AssocOp::*;match*self{Assign|AssignOp(_)=>true, +Less|Greater|LessEqual|GreaterEqual|Equal|NotEqual|As|Multiply|Divide|Modulus|// +Add|Subtract|ShiftLeft|ShiftRight|BitAnd|BitXor|BitOr|LAnd|LOr|DotDot|DotDotEq// +=>false,}}pub fn to_ast_binop(&self)->Option{3;use AssocOp::*;;match* +self{Less=>(Some(BinOpKind::Lt)),Greater=>(Some(BinOpKind::Gt)),LessEqual=>Some( +BinOpKind::Le),GreaterEqual=>(Some(BinOpKind::Ge)),Equal=>(Some(BinOpKind::Eq)), +NotEqual=>((Some(BinOpKind::Ne))),Multiply=>(Some(BinOpKind::Mul)),Divide=>Some( +BinOpKind::Div),Modulus=>((Some(BinOpKind::Rem))),Add=>((Some(BinOpKind::Add))), +Subtract=>Some(BinOpKind::Sub),ShiftLeft=> Some(BinOpKind::Shl),ShiftRight=>Some +(BinOpKind::Shr),BitAnd=>Some(BinOpKind ::BitAnd),BitXor=>Some(BinOpKind::BitXor +),BitOr=>(Some(BinOpKind::BitOr)),LAnd=>Some(BinOpKind::And),LOr=>Some(BinOpKind +::Or),Assign|AssignOp(_)|As|DotDot|DotDotEq=>None,}}pub fn//if true{};if true{}; +can_continue_expr_unambiguously(&self)->bool{();use AssocOp::*;();matches!(self, +BitXor|Assign|Divide|Modulus| ShiftRight|LessEqual|Greater|GreaterEqual|AssignOp +(_)|As)}}pub const PREC_CLOSURE:i8=(-(40 ));pub const PREC_JUMP:i8=-30;pub const +PREC_RANGE:i8=(-10);pub const PREC_PREFIX:i8=50;pub const PREC_POSTFIX:i8=60;pub +const PREC_PAREN:i8=(99);pub const PREC_FORCE_PAREN:i8=100;#[derive(Debug,Clone, +Copy)]pub enum ExprPrecedence{Closure,Break,Continue,Ret,Yield,Yeet,Become,//(); +Range,Binary(BinOpKind),Cast,Assign,AssignOp,AddrOf,Let,Unary,Call,MethodCall,// +Field,Index,Try,InlineAsm,OffsetOf,Mac,FormatArgs,Array,Repeat,Tup,Lit,Path,//3; +Paren,If,While,ForLoop,Loop,Match,ConstBlock,Block,TryBlock,Struct,Gen,Await,//; +Err,}impl ExprPrecedence{pub fn order(self)->i8{match self{ExprPrecedence:://(); +Closure=>PREC_CLOSURE,ExprPrecedence::Break|ExprPrecedence::Continue|//let _=(); +ExprPrecedence::Ret|ExprPrecedence::Yield |ExprPrecedence::Yeet|ExprPrecedence:: +Become=>PREC_JUMP,ExprPrecedence::Range=>PREC_RANGE,ExprPrecedence::Binary(op)// +=>AssocOp::from_ast_binop(op).precedence( )as i8,ExprPrecedence::Cast=>AssocOp:: +As.precedence()as i8, ExprPrecedence::Assign|ExprPrecedence::AssignOp=>AssocOp:: +Assign.precedence()as i8,ExprPrecedence::AddrOf|ExprPrecedence::Let|//if true{}; +ExprPrecedence::Unary=>PREC_PREFIX,ExprPrecedence::Await|ExprPrecedence::Call|// +ExprPrecedence::MethodCall|ExprPrecedence::Field|ExprPrecedence::Index|//*&*&(); +ExprPrecedence::Try|ExprPrecedence::InlineAsm|ExprPrecedence::Mac|//loop{break}; +ExprPrecedence::FormatArgs|ExprPrecedence::OffsetOf=>PREC_POSTFIX,//loop{break}; +ExprPrecedence::Array|ExprPrecedence:: Repeat|ExprPrecedence::Tup|ExprPrecedence +::Lit|ExprPrecedence::Path|ExprPrecedence::Paren|ExprPrecedence::If|//if true{}; +ExprPrecedence::While|ExprPrecedence::ForLoop|ExprPrecedence::Loop|//let _=||(); +ExprPrecedence::Match|ExprPrecedence::ConstBlock|ExprPrecedence::Block|//*&*&(); +ExprPrecedence::TryBlock|ExprPrecedence::Gen|ExprPrecedence::Struct|//if true{}; +ExprPrecedence::Err=>PREC_PAREN,}}} pub fn prec_let_scrutinee_needs_par()->usize +{(AssocOp::LAnd.precedence())}pub fn needs_par_as_let_scrutinee(order:i8)->bool{ +order<=prec_let_scrutinee_needs_par()as i8}pub fn contains_exterior_struct_lit( +value:&ast::Expr)->bool{match(&value.kind){ast::ExprKind::Struct(..)=>true,ast:: +ExprKind::Assign(lhs,rhs,_)|ast::ExprKind::AssignOp(_,lhs,rhs)|ast::ExprKind::// +Binary(_,lhs,rhs)=> {((((((((((((contains_exterior_struct_lit(lhs)))))))))))))|| +contains_exterior_struct_lit(rhs)}ast::ExprKind::Await(x,_)|ast::ExprKind:://(); +Unary(_,x)|ast::ExprKind::Cast(x,_)|ast::ExprKind::Type(x,_)|ast::ExprKind:://3; +Field(x,_)|ast::ExprKind::Index(x,_,_)=>{(contains_exterior_struct_lit(x))}ast:: +ExprKind::MethodCall(box ast::MethodCall{receiver,..})=>{//if true{};let _=||(); +contains_exterior_struct_lit(receiver)}_=>(((((((((((((((false))))))))))))))),}} diff --git a/compiler/rustc_ast/src/util/unicode.rs b/compiler/rustc_ast/src/util/unicode.rs index 6f57d66b2273a..78dc9d61734a5 100644 --- a/compiler/rustc_ast/src/util/unicode.rs +++ b/compiler/rustc_ast/src/util/unicode.rs @@ -1,35 +1,6 @@ -pub const TEXT_FLOW_CONTROL_CHARS: &[char] = &[ - '\u{202A}', '\u{202B}', '\u{202D}', '\u{202E}', '\u{2066}', '\u{2067}', '\u{2068}', '\u{202C}', - '\u{2069}', -]; - -#[inline] -pub fn contains_text_flow_control_chars(s: &str) -> bool { - // Char - UTF-8 - // U+202A - E2 80 AA - // U+202B - E2 80 AB - // U+202C - E2 80 AC - // U+202D - E2 80 AD - // U+202E - E2 80 AE - // U+2066 - E2 81 A6 - // U+2067 - E2 81 A7 - // U+2068 - E2 81 A8 - // U+2069 - E2 81 A9 - let mut bytes = s.as_bytes(); - loop { - match memchr::memchr(0xE2, bytes) { - Some(idx) => { - // bytes are valid UTF-8 -> E2 must be followed by two bytes - let ch = &bytes[idx..idx + 3]; - match ch { - [_, 0x80, 0xAA..=0xAE] | [_, 0x81, 0xA6..=0xA9] => break true, - _ => {} - } - bytes = &bytes[idx + 3..]; - } - None => { - break false; - } - } - } -} +pub const TEXT_FLOW_CONTROL_CHARS:&[char]=& [('\u{202A}'),'\u{202B}','\u{202D}', +'\u{202E}',('\u{2066}'),'\u{2067}','\u{2068}', '\u{202C}','\u{2069}',];#[inline] +pub fn contains_text_flow_control_chars(s:&str)->bool{;let mut bytes=s.as_bytes( +);;loop{match memchr::memchr(0xE2,bytes){Some(idx)=>{;let ch=&bytes[idx..idx+3]; +match ch{[_,0x80,0xAA..=0xAE]|[_,0x81,0xA6..=0xA9]=>break true,_=>{}}{;};bytes=& +bytes[idx+3..];if let _=(){};}None=>{if let _=(){};break false;loop{break;};}}}} diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 18986fb7504cc..fb25abffcd401 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -1,1054 +1,387 @@ -//! AST walker. Each overridden visit method has full control over what -//! happens with its node, it can do its own traversal of the node's children, -//! call `visit::walk_*` to apply the default traversal algorithm, or prevent -//! deeper traversal by doing nothing. -//! -//! Note: it is an important invariant that the default visitor walks the body -//! of a function in "execution order" (more concretely, reverse post-order -//! with respect to the CFG implied by the AST), meaning that if AST node A may -//! execute before AST node B, then A is visited first. The borrow checker in -//! particular relies on this property. -//! -//! Note: walking an AST before macro expansion is probably a bad idea. For -//! instance, a walker looking for item names in a module will miss all of -//! those that are created by the expansion of a macro. - -use crate::ast::*; - -use rustc_span::symbol::Ident; -use rustc_span::Span; - -pub use rustc_ast_ir::visit::VisitorResult; -pub use rustc_ast_ir::{try_visit, visit_opt, walk_list, walk_visitable_list}; - -#[derive(Copy, Clone, Debug, PartialEq)] -pub enum AssocCtxt { - Trait, - Impl, -} - -#[derive(Copy, Clone, Debug, PartialEq)] -pub enum FnCtxt { - Free, - Foreign, - Assoc(AssocCtxt), -} - -#[derive(Copy, Clone, Debug)] -pub enum BoundKind { - /// Trait bounds in generics bounds and type/trait alias. - /// E.g., ``, `type A: Bound`, or `where T: Bound`. - Bound, - - /// Trait bounds in `impl` type. - /// E.g., `type Foo = impl Bound1 + Bound2 + Bound3`. - Impl, - - /// Trait bounds in trait object type. - /// E.g., `dyn Bound1 + Bound2 + Bound3`. - TraitObject, - - /// Super traits of a trait. - /// E.g., `trait A: B` - SuperTraits, -} - -#[derive(Copy, Clone, Debug)] -pub enum FnKind<'a> { - /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`. - Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, &'a Generics, Option<&'a Block>), - - /// E.g., `|x, y| body`. - Closure(&'a ClosureBinder, &'a FnDecl, &'a Expr), -} - -impl<'a> FnKind<'a> { - pub fn header(&self) -> Option<&'a FnHeader> { - match *self { - FnKind::Fn(_, _, sig, _, _, _) => Some(&sig.header), - FnKind::Closure(_, _, _) => None, - } - } - - pub fn ident(&self) -> Option<&Ident> { - match self { - FnKind::Fn(_, ident, ..) => Some(ident), - _ => None, - } - } - - pub fn decl(&self) -> &'a FnDecl { - match self { - FnKind::Fn(_, _, sig, _, _, _) => &sig.decl, - FnKind::Closure(_, decl, _) => decl, - } - } - - pub fn ctxt(&self) -> Option { - match self { - FnKind::Fn(ctxt, ..) => Some(*ctxt), - FnKind::Closure(..) => None, - } - } -} - -#[derive(Copy, Clone, Debug)] -pub enum LifetimeCtxt { - /// Appears in a reference type. - Ref, - /// Appears as a bound on a type or another lifetime. - Bound, - /// Appears as a generic argument. - GenericArg, -} - -/// Each method of the `Visitor` trait is a hook to be potentially -/// overridden. Each method's default implementation recursively visits -/// the substructure of the input via the corresponding `walk` method; -/// e.g., the `visit_item` method by default calls `visit::walk_item`. -/// -/// If you want to ensure that your code handles every variant -/// explicitly, you need to override each method. (And you also need -/// to monitor future changes to `Visitor` in case a new method with a -/// new default implementation gets introduced.) -pub trait Visitor<'ast>: Sized { - /// The result type of the `visit_*` methods. Can be either `()`, - /// or `ControlFlow`. - type Result: VisitorResult = (); - - fn visit_ident(&mut self, _ident: Ident) -> Self::Result { - Self::Result::output() - } - fn visit_foreign_item(&mut self, i: &'ast ForeignItem) -> Self::Result { - walk_foreign_item(self, i) - } - fn visit_item(&mut self, i: &'ast Item) -> Self::Result { - walk_item(self, i) - } - fn visit_local(&mut self, l: &'ast Local) -> Self::Result { - walk_local(self, l) - } - fn visit_block(&mut self, b: &'ast Block) -> Self::Result { - walk_block(self, b) - } - fn visit_stmt(&mut self, s: &'ast Stmt) -> Self::Result { - walk_stmt(self, s) - } - fn visit_param(&mut self, param: &'ast Param) -> Self::Result { - walk_param(self, param) - } - fn visit_arm(&mut self, a: &'ast Arm) -> Self::Result { - walk_arm(self, a) - } - fn visit_pat(&mut self, p: &'ast Pat) -> Self::Result { - walk_pat(self, p) - } - fn visit_anon_const(&mut self, c: &'ast AnonConst) -> Self::Result { - walk_anon_const(self, c) - } - fn visit_expr(&mut self, ex: &'ast Expr) -> Self::Result { - 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::Result { - self.visit_expr(ex) - } - fn visit_expr_post(&mut self, _ex: &'ast Expr) -> Self::Result { - Self::Result::output() - } - fn visit_ty(&mut self, t: &'ast Ty) -> Self::Result { - walk_ty(self, t) - } - fn visit_generic_param(&mut self, param: &'ast GenericParam) -> Self::Result { - walk_generic_param(self, param) - } - fn visit_generics(&mut self, g: &'ast Generics) -> Self::Result { - walk_generics(self, g) - } - fn visit_closure_binder(&mut self, b: &'ast ClosureBinder) -> Self::Result { - walk_closure_binder(self, b) - } - fn visit_where_predicate(&mut self, p: &'ast WherePredicate) -> Self::Result { - walk_where_predicate(self, p) - } - fn visit_fn(&mut self, fk: FnKind<'ast>, _: Span, _: NodeId) -> Self::Result { - walk_fn(self, fk) - } - fn visit_assoc_item(&mut self, i: &'ast AssocItem, ctxt: AssocCtxt) -> Self::Result { - walk_assoc_item(self, i, ctxt) - } - fn visit_trait_ref(&mut self, t: &'ast TraitRef) -> Self::Result { - walk_trait_ref(self, t) - } - fn visit_param_bound(&mut self, bounds: &'ast GenericBound, _ctxt: BoundKind) -> Self::Result { - walk_param_bound(self, bounds) - } - fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef) -> Self::Result { - walk_poly_trait_ref(self, t) - } - fn visit_variant_data(&mut self, s: &'ast VariantData) -> Self::Result { - walk_struct_def(self, s) - } - fn visit_field_def(&mut self, s: &'ast FieldDef) -> Self::Result { - walk_field_def(self, s) - } - fn visit_enum_def(&mut self, enum_definition: &'ast EnumDef) -> Self::Result { - walk_enum_def(self, enum_definition) - } - fn visit_variant(&mut self, v: &'ast Variant) -> Self::Result { - walk_variant(self, v) - } - fn visit_variant_discr(&mut self, discr: &'ast AnonConst) -> Self::Result { - self.visit_anon_const(discr) - } - fn visit_label(&mut self, label: &'ast Label) -> Self::Result { - walk_label(self, label) - } - fn visit_lifetime(&mut self, lifetime: &'ast Lifetime, _: LifetimeCtxt) -> Self::Result { - walk_lifetime(self, lifetime) - } - fn visit_mac_call(&mut self, mac: &'ast MacCall) -> Self::Result { - walk_mac(self, mac) - } - fn visit_mac_def(&mut self, _mac: &'ast MacroDef, _id: NodeId) -> Self::Result { - Self::Result::output() - } - fn visit_path(&mut self, path: &'ast Path, _id: NodeId) -> Self::Result { - walk_path(self, path) - } - fn visit_use_tree( - &mut self, - use_tree: &'ast UseTree, - id: NodeId, - _nested: bool, - ) -> Self::Result { - walk_use_tree(self, use_tree, id) - } - fn visit_path_segment(&mut self, path_segment: &'ast PathSegment) -> Self::Result { - walk_path_segment(self, path_segment) - } - fn visit_generic_args(&mut self, generic_args: &'ast GenericArgs) -> Self::Result { - walk_generic_args(self, generic_args) - } - fn visit_generic_arg(&mut self, generic_arg: &'ast GenericArg) -> Self::Result { - walk_generic_arg(self, generic_arg) - } - fn visit_assoc_constraint(&mut self, constraint: &'ast AssocConstraint) -> Self::Result { - walk_assoc_constraint(self, constraint) - } - fn visit_attribute(&mut self, attr: &'ast Attribute) -> Self::Result { - walk_attribute(self, attr) - } - fn visit_vis(&mut self, vis: &'ast Visibility) -> Self::Result { - walk_vis(self, vis) - } - fn visit_fn_ret_ty(&mut self, ret_ty: &'ast FnRetTy) -> Self::Result { - walk_fn_ret_ty(self, ret_ty) - } - fn visit_fn_header(&mut self, _header: &'ast FnHeader) -> Self::Result { - Self::Result::output() - } - fn visit_expr_field(&mut self, f: &'ast ExprField) -> Self::Result { - walk_expr_field(self, f) - } - fn visit_pat_field(&mut self, fp: &'ast PatField) -> Self::Result { - walk_pat_field(self, fp) - } - fn visit_crate(&mut self, krate: &'ast Crate) -> Self::Result { - walk_crate(self, krate) - } - fn visit_inline_asm(&mut self, asm: &'ast InlineAsm) -> Self::Result { - walk_inline_asm(self, asm) - } - fn visit_format_args(&mut self, fmt: &'ast FormatArgs) -> Self::Result { - walk_format_args(self, fmt) - } - fn visit_inline_asm_sym(&mut self, sym: &'ast InlineAsmSym) -> Self::Result { - walk_inline_asm_sym(self, sym) - } - fn visit_capture_by(&mut self, _capture_by: &'ast CaptureBy) -> Self::Result { - Self::Result::output() - } -} - -pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) -> V::Result { - walk_list!(visitor, visit_item, &krate.items); - walk_list!(visitor, visit_attribute, &krate.attrs); - V::Result::output() -} - -pub fn walk_local<'a, V: Visitor<'a>>(visitor: &mut V, local: &'a Local) -> V::Result { - walk_list!(visitor, visit_attribute, &local.attrs); - try_visit!(visitor.visit_pat(&local.pat)); - visit_opt!(visitor, visit_ty, &local.ty); - if let Some((init, els)) = local.kind.init_else_opt() { - try_visit!(visitor.visit_expr(init)); - visit_opt!(visitor, visit_block, els); - } - V::Result::output() -} - -pub fn walk_label<'a, V: Visitor<'a>>(visitor: &mut V, label: &'a Label) -> V::Result { - visitor.visit_ident(label.ident) -} - -pub fn walk_lifetime<'a, V: Visitor<'a>>(visitor: &mut V, lifetime: &'a Lifetime) -> V::Result { - visitor.visit_ident(lifetime.ident) -} - -pub fn walk_poly_trait_ref<'a, V>(visitor: &mut V, trait_ref: &'a PolyTraitRef) -> V::Result -where - V: Visitor<'a>, -{ - walk_list!(visitor, visit_generic_param, &trait_ref.bound_generic_params); - visitor.visit_trait_ref(&trait_ref.trait_ref) -} - -pub fn walk_trait_ref<'a, V: Visitor<'a>>(visitor: &mut V, trait_ref: &'a TraitRef) -> V::Result { - visitor.visit_path(&trait_ref.path, trait_ref.ref_id) -} - -pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) -> V::Result { - try_visit!(visitor.visit_vis(&item.vis)); - try_visit!(visitor.visit_ident(item.ident)); - match &item.kind { - ItemKind::ExternCrate(_) => {} - ItemKind::Use(use_tree) => try_visit!(visitor.visit_use_tree(use_tree, item.id, false)), - ItemKind::Static(box StaticItem { ty, mutability: _, expr }) => { - try_visit!(visitor.visit_ty(ty)); - visit_opt!(visitor, visit_expr, expr); - } - ItemKind::Const(box ConstItem { defaultness: _, generics, ty, expr }) => { - try_visit!(visitor.visit_generics(generics)); - try_visit!(visitor.visit_ty(ty)); - visit_opt!(visitor, visit_expr, expr); - } - ItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => { - let kind = - FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref()); - try_visit!(visitor.visit_fn(kind, item.span, item.id)); - } - ItemKind::Mod(_unsafety, mod_kind) => match mod_kind { - ModKind::Loaded(items, _inline, _inner_span) => { - walk_list!(visitor, visit_item, items); - } - ModKind::Unloaded => {} - }, - ItemKind::ForeignMod(foreign_module) => { - walk_list!(visitor, visit_foreign_item, &foreign_module.items); - } - ItemKind::GlobalAsm(asm) => try_visit!(visitor.visit_inline_asm(asm)), - ItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => { - try_visit!(visitor.visit_generics(generics)); - walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); - visit_opt!(visitor, visit_ty, ty); - } - ItemKind::Enum(enum_definition, generics) => { - try_visit!(visitor.visit_generics(generics)); - try_visit!(visitor.visit_enum_def(enum_definition)); - } - ItemKind::Impl(box Impl { - defaultness: _, - unsafety: _, - generics, - constness: _, - polarity: _, - of_trait, - self_ty, - items, - }) => { - try_visit!(visitor.visit_generics(generics)); - visit_opt!(visitor, visit_trait_ref, of_trait); - try_visit!(visitor.visit_ty(self_ty)); - walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Impl); - } - ItemKind::Struct(struct_definition, generics) - | ItemKind::Union(struct_definition, generics) => { - try_visit!(visitor.visit_generics(generics)); - try_visit!(visitor.visit_variant_data(struct_definition)); - } - ItemKind::Trait(box Trait { unsafety: _, is_auto: _, generics, bounds, items }) => { - try_visit!(visitor.visit_generics(generics)); - walk_list!(visitor, visit_param_bound, bounds, BoundKind::SuperTraits); - walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Trait); - } - ItemKind::TraitAlias(generics, bounds) => { - try_visit!(visitor.visit_generics(generics)); - walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); - } - ItemKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)), - ItemKind::MacroDef(ts) => try_visit!(visitor.visit_mac_def(ts, item.id)), - ItemKind::Delegation(box Delegation { id, qself, path, body }) => { - if let Some(qself) = qself { - try_visit!(visitor.visit_ty(&qself.ty)); - } - try_visit!(visitor.visit_path(path, *id)); - visit_opt!(visitor, visit_block, body); - } - } - walk_list!(visitor, visit_attribute, &item.attrs); - V::Result::output() -} - -pub fn walk_enum_def<'a, V: Visitor<'a>>( - visitor: &mut V, - enum_definition: &'a EnumDef, -) -> V::Result { - walk_list!(visitor, visit_variant, &enum_definition.variants); - V::Result::output() -} - -pub fn walk_variant<'a, V: Visitor<'a>>(visitor: &mut V, variant: &'a Variant) -> V::Result -where - V: Visitor<'a>, -{ - try_visit!(visitor.visit_ident(variant.ident)); - try_visit!(visitor.visit_vis(&variant.vis)); - try_visit!(visitor.visit_variant_data(&variant.data)); - visit_opt!(visitor, visit_variant_discr, &variant.disr_expr); - walk_list!(visitor, visit_attribute, &variant.attrs); - V::Result::output() -} - -pub fn walk_expr_field<'a, V: Visitor<'a>>(visitor: &mut V, f: &'a ExprField) -> V::Result { - try_visit!(visitor.visit_expr(&f.expr)); - try_visit!(visitor.visit_ident(f.ident)); - walk_list!(visitor, visit_attribute, &f.attrs); - V::Result::output() -} - -pub fn walk_pat_field<'a, V: Visitor<'a>>(visitor: &mut V, fp: &'a PatField) -> V::Result { - try_visit!(visitor.visit_ident(fp.ident)); - try_visit!(visitor.visit_pat(&fp.pat)); - walk_list!(visitor, visit_attribute, &fp.attrs); - V::Result::output() -} - -pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result { - match &typ.kind { - TyKind::Slice(ty) | TyKind::Paren(ty) => try_visit!(visitor.visit_ty(ty)), - TyKind::Ptr(mutable_type) => try_visit!(visitor.visit_ty(&mutable_type.ty)), - TyKind::Ref(opt_lifetime, mutable_type) => { - visit_opt!(visitor, visit_lifetime, opt_lifetime, LifetimeCtxt::Ref); - try_visit!(visitor.visit_ty(&mutable_type.ty)); - } - TyKind::Tup(tuple_element_types) => { - walk_list!(visitor, visit_ty, tuple_element_types); - } - TyKind::BareFn(function_declaration) => { - walk_list!(visitor, visit_generic_param, &function_declaration.generic_params); - try_visit!(walk_fn_decl(visitor, &function_declaration.decl)); - } - TyKind::Path(maybe_qself, path) => { - if let Some(qself) = maybe_qself { - try_visit!(visitor.visit_ty(&qself.ty)); - } - try_visit!(visitor.visit_path(path, typ.id)); - } - TyKind::Array(ty, length) => { - try_visit!(visitor.visit_ty(ty)); - try_visit!(visitor.visit_anon_const(length)); - } - TyKind::TraitObject(bounds, ..) => { - walk_list!(visitor, visit_param_bound, bounds, BoundKind::TraitObject); - } - TyKind::ImplTrait(_, bounds) => { - walk_list!(visitor, visit_param_bound, bounds, BoundKind::Impl); - } - TyKind::Typeof(expression) => try_visit!(visitor.visit_anon_const(expression)), - TyKind::Infer | TyKind::ImplicitSelf | TyKind::Dummy | TyKind::Err(_) => {} - TyKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)), - TyKind::Never | TyKind::CVarArgs => {} - TyKind::AnonStruct(_, ref fields) | TyKind::AnonUnion(_, ref fields) => { - walk_list!(visitor, visit_field_def, fields); - } - } - V::Result::output() -} - -pub fn walk_path<'a, V: Visitor<'a>>(visitor: &mut V, path: &'a Path) -> V::Result { - walk_list!(visitor, visit_path_segment, &path.segments); - V::Result::output() -} - -pub fn walk_use_tree<'a, V: Visitor<'a>>( - visitor: &mut V, - use_tree: &'a UseTree, - id: NodeId, -) -> V::Result { - try_visit!(visitor.visit_path(&use_tree.prefix, id)); - match use_tree.kind { - UseTreeKind::Simple(rename) => { - // The extra IDs are handled during AST lowering. - visit_opt!(visitor, visit_ident, rename); - } - UseTreeKind::Glob => {} - UseTreeKind::Nested(ref use_trees) => { - for &(ref nested_tree, nested_id) in use_trees { - try_visit!(visitor.visit_use_tree(nested_tree, nested_id, true)); - } - } - } - V::Result::output() -} - -pub fn walk_path_segment<'a, V: Visitor<'a>>( - visitor: &mut V, - segment: &'a PathSegment, -) -> V::Result { - try_visit!(visitor.visit_ident(segment.ident)); - visit_opt!(visitor, visit_generic_args, &segment.args); - V::Result::output() -} - -pub fn walk_generic_args<'a, V>(visitor: &mut V, generic_args: &'a GenericArgs) -> V::Result -where - V: Visitor<'a>, -{ - match generic_args { - GenericArgs::AngleBracketed(data) => { - for arg in &data.args { - match arg { - AngleBracketedArg::Arg(a) => try_visit!(visitor.visit_generic_arg(a)), - AngleBracketedArg::Constraint(c) => { - try_visit!(visitor.visit_assoc_constraint(c)) - } - } - } - } - GenericArgs::Parenthesized(data) => { - walk_list!(visitor, visit_ty, &data.inputs); - try_visit!(visitor.visit_fn_ret_ty(&data.output)); - } - } - V::Result::output() -} - -pub fn walk_generic_arg<'a, V>(visitor: &mut V, generic_arg: &'a GenericArg) -> V::Result -where - V: Visitor<'a>, -{ - match generic_arg { - GenericArg::Lifetime(lt) => visitor.visit_lifetime(lt, LifetimeCtxt::GenericArg), - GenericArg::Type(ty) => visitor.visit_ty(ty), - GenericArg::Const(ct) => visitor.visit_anon_const(ct), - } -} - -pub fn walk_assoc_constraint<'a, V: Visitor<'a>>( - visitor: &mut V, - constraint: &'a AssocConstraint, -) -> V::Result { - try_visit!(visitor.visit_ident(constraint.ident)); - visit_opt!(visitor, visit_generic_args, &constraint.gen_args); - match &constraint.kind { - AssocConstraintKind::Equality { term } => match term { - Term::Ty(ty) => try_visit!(visitor.visit_ty(ty)), - Term::Const(c) => try_visit!(visitor.visit_anon_const(c)), - }, - AssocConstraintKind::Bound { bounds } => { - walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); - } - } - V::Result::output() -} - -pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Result { - match &pattern.kind { - PatKind::TupleStruct(opt_qself, path, elems) => { - if let Some(qself) = opt_qself { - try_visit!(visitor.visit_ty(&qself.ty)); - } - try_visit!(visitor.visit_path(path, pattern.id)); - walk_list!(visitor, visit_pat, elems); - } - PatKind::Path(opt_qself, path) => { - if let Some(qself) = opt_qself { - try_visit!(visitor.visit_ty(&qself.ty)); - } - try_visit!(visitor.visit_path(path, pattern.id)) - } - PatKind::Struct(opt_qself, path, fields, _) => { - if let Some(qself) = opt_qself { - try_visit!(visitor.visit_ty(&qself.ty)); - } - try_visit!(visitor.visit_path(path, pattern.id)); - walk_list!(visitor, visit_pat_field, fields); - } - PatKind::Box(subpattern) - | PatKind::Deref(subpattern) - | PatKind::Ref(subpattern, _) - | PatKind::Paren(subpattern) => { - try_visit!(visitor.visit_pat(subpattern)); - } - PatKind::Ident(_, ident, optional_subpattern) => { - try_visit!(visitor.visit_ident(*ident)); - visit_opt!(visitor, visit_pat, optional_subpattern); - } - PatKind::Lit(expression) => try_visit!(visitor.visit_expr(expression)), - PatKind::Range(lower_bound, upper_bound, _) => { - visit_opt!(visitor, visit_expr, lower_bound); - visit_opt!(visitor, visit_expr, upper_bound); - } - PatKind::Wild | PatKind::Rest | PatKind::Never | PatKind::Err(_) => {} - PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => { - walk_list!(visitor, visit_pat, elems); - } - PatKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)), - } - V::Result::output() -} - -pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignItem) -> V::Result { - let &Item { id, span, ident, ref vis, ref attrs, ref kind, tokens: _ } = item; - try_visit!(visitor.visit_vis(vis)); - try_visit!(visitor.visit_ident(ident)); - walk_list!(visitor, visit_attribute, attrs); - match kind { - ForeignItemKind::Static(ty, _, expr) => { - try_visit!(visitor.visit_ty(ty)); - visit_opt!(visitor, visit_expr, expr); - } - ForeignItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => { - let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, generics, body.as_deref()); - try_visit!(visitor.visit_fn(kind, span, id)); - } - ForeignItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => { - try_visit!(visitor.visit_generics(generics)); - walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); - visit_opt!(visitor, visit_ty, ty); - } - ForeignItemKind::MacCall(mac) => { - try_visit!(visitor.visit_mac_call(mac)); - } - } - V::Result::output() -} - -pub fn walk_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a GenericBound) -> V::Result { - match bound { - GenericBound::Trait(typ, _modifier) => visitor.visit_poly_trait_ref(typ), - GenericBound::Outlives(lifetime) => visitor.visit_lifetime(lifetime, LifetimeCtxt::Bound), - } -} - -pub fn walk_generic_param<'a, V: Visitor<'a>>( - visitor: &mut V, - param: &'a GenericParam, -) -> V::Result { - try_visit!(visitor.visit_ident(param.ident)); - walk_list!(visitor, visit_attribute, ¶m.attrs); - walk_list!(visitor, visit_param_bound, ¶m.bounds, BoundKind::Bound); - match ¶m.kind { - GenericParamKind::Lifetime => (), - GenericParamKind::Type { default } => visit_opt!(visitor, visit_ty, default), - GenericParamKind::Const { ty, default, .. } => { - try_visit!(visitor.visit_ty(ty)); - visit_opt!(visitor, visit_anon_const, default); - } - } - V::Result::output() -} - -pub fn walk_generics<'a, V: Visitor<'a>>(visitor: &mut V, generics: &'a Generics) -> V::Result { - walk_list!(visitor, visit_generic_param, &generics.params); - walk_list!(visitor, visit_where_predicate, &generics.where_clause.predicates); - V::Result::output() -} - -pub fn walk_closure_binder<'a, V: Visitor<'a>>( - visitor: &mut V, - binder: &'a ClosureBinder, -) -> V::Result { - match binder { - ClosureBinder::NotPresent => {} - ClosureBinder::For { generic_params, span: _ } => { - walk_list!(visitor, visit_generic_param, generic_params) - } - } - V::Result::output() -} - -pub fn walk_where_predicate<'a, V: Visitor<'a>>( - visitor: &mut V, - predicate: &'a WherePredicate, -) -> V::Result { - match predicate { - WherePredicate::BoundPredicate(WhereBoundPredicate { - bounded_ty, - bounds, - bound_generic_params, - .. - }) => { - try_visit!(visitor.visit_ty(bounded_ty)); - walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); - walk_list!(visitor, visit_generic_param, bound_generic_params); - } - WherePredicate::RegionPredicate(WhereRegionPredicate { lifetime, bounds, .. }) => { - try_visit!(visitor.visit_lifetime(lifetime, LifetimeCtxt::Bound)); - walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); - } - WherePredicate::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty, .. }) => { - try_visit!(visitor.visit_ty(lhs_ty)); - try_visit!(visitor.visit_ty(rhs_ty)); - } - } - V::Result::output() -} - -pub fn walk_fn_ret_ty<'a, V: Visitor<'a>>(visitor: &mut V, ret_ty: &'a FnRetTy) -> V::Result { - if let FnRetTy::Ty(output_ty) = ret_ty { - try_visit!(visitor.visit_ty(output_ty)); - } - V::Result::output() -} - -pub fn walk_fn_decl<'a, V: Visitor<'a>>( - visitor: &mut V, - function_declaration: &'a FnDecl, -) -> V::Result { - walk_list!(visitor, visit_param, &function_declaration.inputs); - visitor.visit_fn_ret_ty(&function_declaration.output) -} - -pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Result { - match kind { - FnKind::Fn(_, _, sig, _, generics, body) => { - try_visit!(visitor.visit_generics(generics)); - try_visit!(visitor.visit_fn_header(&sig.header)); - try_visit!(walk_fn_decl(visitor, &sig.decl)); - visit_opt!(visitor, visit_block, body); - } - FnKind::Closure(binder, decl, body) => { - try_visit!(visitor.visit_closure_binder(binder)); - try_visit!(walk_fn_decl(visitor, decl)); - try_visit!(visitor.visit_expr(body)); - } - } - V::Result::output() -} - -pub fn walk_assoc_item<'a, V: Visitor<'a>>( - visitor: &mut V, - item: &'a AssocItem, - ctxt: AssocCtxt, -) -> V::Result { - let &Item { id, span, ident, ref vis, ref attrs, ref kind, tokens: _ } = item; - try_visit!(visitor.visit_vis(vis)); - try_visit!(visitor.visit_ident(ident)); - walk_list!(visitor, visit_attribute, attrs); - match kind { - AssocItemKind::Const(box ConstItem { defaultness: _, generics, ty, expr }) => { - try_visit!(visitor.visit_generics(generics)); - try_visit!(visitor.visit_ty(ty)); - visit_opt!(visitor, visit_expr, expr); - } - AssocItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => { - let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, generics, body.as_deref()); - try_visit!(visitor.visit_fn(kind, span, id)); - } - AssocItemKind::Type(box TyAlias { generics, bounds, ty, .. }) => { - try_visit!(visitor.visit_generics(generics)); - walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); - visit_opt!(visitor, visit_ty, ty); - } - AssocItemKind::MacCall(mac) => { - try_visit!(visitor.visit_mac_call(mac)); - } - AssocItemKind::Delegation(box Delegation { id, qself, path, body }) => { - if let Some(qself) = qself { - try_visit!(visitor.visit_ty(&qself.ty)); - } - try_visit!(visitor.visit_path(path, *id)); - visit_opt!(visitor, visit_block, body); - } - } - V::Result::output() -} - -pub fn walk_struct_def<'a, V: Visitor<'a>>( - visitor: &mut V, - struct_definition: &'a VariantData, -) -> V::Result { - walk_list!(visitor, visit_field_def, struct_definition.fields()); - V::Result::output() -} - -pub fn walk_field_def<'a, V: Visitor<'a>>(visitor: &mut V, field: &'a FieldDef) -> V::Result { - try_visit!(visitor.visit_vis(&field.vis)); - visit_opt!(visitor, visit_ident, field.ident); - try_visit!(visitor.visit_ty(&field.ty)); - walk_list!(visitor, visit_attribute, &field.attrs); - V::Result::output() -} - -pub fn walk_block<'a, V: Visitor<'a>>(visitor: &mut V, block: &'a Block) -> V::Result { - walk_list!(visitor, visit_stmt, &block.stmts); - V::Result::output() -} - -pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) -> V::Result { - match &statement.kind { - StmtKind::Let(local) => try_visit!(visitor.visit_local(local)), - StmtKind::Item(item) => try_visit!(visitor.visit_item(item)), - StmtKind::Expr(expr) | StmtKind::Semi(expr) => try_visit!(visitor.visit_expr(expr)), - StmtKind::Empty => {} - StmtKind::MacCall(mac) => { - let MacCallStmt { mac, attrs, style: _, tokens: _ } = &**mac; - try_visit!(visitor.visit_mac_call(mac)); - walk_list!(visitor, visit_attribute, attrs); - } - } - V::Result::output() -} - -pub fn walk_mac<'a, V: Visitor<'a>>(visitor: &mut V, mac: &'a MacCall) -> V::Result { - visitor.visit_path(&mac.path, DUMMY_NODE_ID) -} - -pub fn walk_anon_const<'a, V: Visitor<'a>>(visitor: &mut V, constant: &'a AnonConst) -> V::Result { - visitor.visit_expr(&constant.value) -} - -pub fn walk_inline_asm<'a, V: Visitor<'a>>(visitor: &mut V, asm: &'a InlineAsm) -> V::Result { - for (op, _) in &asm.operands { - match op { - InlineAsmOperand::In { expr, .. } - | InlineAsmOperand::Out { expr: Some(expr), .. } - | InlineAsmOperand::InOut { expr, .. } => try_visit!(visitor.visit_expr(expr)), - InlineAsmOperand::Out { expr: None, .. } => {} - InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => { - try_visit!(visitor.visit_expr(in_expr)); - visit_opt!(visitor, visit_expr, out_expr); - } - InlineAsmOperand::Const { anon_const, .. } => { - try_visit!(visitor.visit_anon_const(anon_const)) - } - InlineAsmOperand::Sym { sym } => try_visit!(visitor.visit_inline_asm_sym(sym)), - InlineAsmOperand::Label { block } => try_visit!(visitor.visit_block(block)), - } - } - V::Result::output() -} - -pub fn walk_inline_asm_sym<'a, V: Visitor<'a>>( - visitor: &mut V, - sym: &'a InlineAsmSym, -) -> V::Result { - if let Some(qself) = &sym.qself { - try_visit!(visitor.visit_ty(&qself.ty)); - } - visitor.visit_path(&sym.path, sym.id) -} - -pub fn walk_format_args<'a, V: Visitor<'a>>(visitor: &mut V, fmt: &'a FormatArgs) -> V::Result { - for arg in fmt.arguments.all_args() { - if let FormatArgumentKind::Named(name) = arg.kind { - try_visit!(visitor.visit_ident(name)); - } - try_visit!(visitor.visit_expr(&arg.expr)); - } - V::Result::output() -} - -pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V::Result { - walk_list!(visitor, visit_attribute, &expression.attrs); - - match &expression.kind { - ExprKind::Array(subexpressions) => { - walk_list!(visitor, visit_expr, subexpressions); - } - ExprKind::ConstBlock(anon_const) => try_visit!(visitor.visit_anon_const(anon_const)), - ExprKind::Repeat(element, count) => { - try_visit!(visitor.visit_expr(element)); - try_visit!(visitor.visit_anon_const(count)); - } - ExprKind::Struct(se) => { - if let Some(qself) = &se.qself { - try_visit!(visitor.visit_ty(&qself.ty)); - } - try_visit!(visitor.visit_path(&se.path, expression.id)); - walk_list!(visitor, visit_expr_field, &se.fields); - match &se.rest { - StructRest::Base(expr) => try_visit!(visitor.visit_expr(expr)), - StructRest::Rest(_span) => {} - StructRest::None => {} - } - } - ExprKind::Tup(subexpressions) => { - walk_list!(visitor, visit_expr, subexpressions); - } - ExprKind::Call(callee_expression, arguments) => { - try_visit!(visitor.visit_expr(callee_expression)); - walk_list!(visitor, visit_expr, arguments); - } - ExprKind::MethodCall(box MethodCall { seg, receiver, args, span: _ }) => { - try_visit!(visitor.visit_path_segment(seg)); - try_visit!(visitor.visit_expr(receiver)); - walk_list!(visitor, visit_expr, args); - } - ExprKind::Binary(_, left_expression, right_expression) => { - try_visit!(visitor.visit_expr(left_expression)); - try_visit!(visitor.visit_expr(right_expression)); - } - ExprKind::AddrOf(_, _, subexpression) | ExprKind::Unary(_, subexpression) => { - try_visit!(visitor.visit_expr(subexpression)); - } - ExprKind::Cast(subexpression, typ) | ExprKind::Type(subexpression, typ) => { - try_visit!(visitor.visit_expr(subexpression)); - try_visit!(visitor.visit_ty(typ)); - } - ExprKind::Let(pat, expr, _, _) => { - try_visit!(visitor.visit_pat(pat)); - try_visit!(visitor.visit_expr(expr)); - } - ExprKind::If(head_expression, if_block, optional_else) => { - try_visit!(visitor.visit_expr(head_expression)); - try_visit!(visitor.visit_block(if_block)); - visit_opt!(visitor, visit_expr, optional_else); - } - ExprKind::While(subexpression, block, opt_label) => { - visit_opt!(visitor, visit_label, opt_label); - try_visit!(visitor.visit_expr(subexpression)); - try_visit!(visitor.visit_block(block)); - } - ExprKind::ForLoop { pat, iter, body, label, kind: _ } => { - visit_opt!(visitor, visit_label, label); - try_visit!(visitor.visit_pat(pat)); - try_visit!(visitor.visit_expr(iter)); - try_visit!(visitor.visit_block(body)); - } - ExprKind::Loop(block, opt_label, _) => { - visit_opt!(visitor, visit_label, opt_label); - try_visit!(visitor.visit_block(block)); - } - ExprKind::Match(subexpression, arms, _kind) => { - try_visit!(visitor.visit_expr(subexpression)); - walk_list!(visitor, visit_arm, arms); - } - ExprKind::Closure(box Closure { - binder, - capture_clause, - coroutine_kind: _, - constness: _, - movability: _, - fn_decl, - body, - fn_decl_span: _, - fn_arg_span: _, - }) => { - try_visit!(visitor.visit_capture_by(capture_clause)); - try_visit!(visitor.visit_fn( - FnKind::Closure(binder, fn_decl, body), - expression.span, - expression.id - )) - } - ExprKind::Block(block, opt_label) => { - visit_opt!(visitor, visit_label, opt_label); - try_visit!(visitor.visit_block(block)); - } - ExprKind::Gen(_, body, _) => try_visit!(visitor.visit_block(body)), - ExprKind::Await(expr, _) => try_visit!(visitor.visit_expr(expr)), - ExprKind::Assign(lhs, rhs, _) => { - try_visit!(visitor.visit_expr(lhs)); - try_visit!(visitor.visit_expr(rhs)); - } - ExprKind::AssignOp(_, left_expression, right_expression) => { - try_visit!(visitor.visit_expr(left_expression)); - try_visit!(visitor.visit_expr(right_expression)); - } - ExprKind::Field(subexpression, ident) => { - try_visit!(visitor.visit_expr(subexpression)); - try_visit!(visitor.visit_ident(*ident)); - } - ExprKind::Index(main_expression, index_expression, _) => { - try_visit!(visitor.visit_expr(main_expression)); - try_visit!(visitor.visit_expr(index_expression)); - } - ExprKind::Range(start, end, _) => { - visit_opt!(visitor, visit_expr, start); - visit_opt!(visitor, visit_expr, end); - } - ExprKind::Underscore => {} - ExprKind::Path(maybe_qself, path) => { - if let Some(qself) = maybe_qself { - try_visit!(visitor.visit_ty(&qself.ty)); - } - try_visit!(visitor.visit_path(path, expression.id)); - } - ExprKind::Break(opt_label, opt_expr) => { - visit_opt!(visitor, visit_label, opt_label); - visit_opt!(visitor, visit_expr, opt_expr); - } - ExprKind::Continue(opt_label) => { - visit_opt!(visitor, visit_label, opt_label); - } - ExprKind::Ret(optional_expression) => { - visit_opt!(visitor, visit_expr, optional_expression); - } - ExprKind::Yeet(optional_expression) => { - visit_opt!(visitor, visit_expr, optional_expression); - } - ExprKind::Become(expr) => try_visit!(visitor.visit_expr(expr)), - ExprKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)), - ExprKind::Paren(subexpression) => try_visit!(visitor.visit_expr(subexpression)), - ExprKind::InlineAsm(asm) => try_visit!(visitor.visit_inline_asm(asm)), - ExprKind::FormatArgs(f) => try_visit!(visitor.visit_format_args(f)), - ExprKind::OffsetOf(container, fields) => { - try_visit!(visitor.visit_ty(container)); - walk_list!(visitor, visit_ident, fields.iter().copied()); - } - ExprKind::Yield(optional_expression) => { - visit_opt!(visitor, visit_expr, optional_expression); - } - ExprKind::Try(subexpression) => try_visit!(visitor.visit_expr(subexpression)), - ExprKind::TryBlock(body) => try_visit!(visitor.visit_block(body)), - ExprKind::Lit(_) | ExprKind::IncludedBytes(..) | ExprKind::Err(_) | ExprKind::Dummy => {} - } - - visitor.visit_expr_post(expression) -} - -pub fn walk_param<'a, V: Visitor<'a>>(visitor: &mut V, param: &'a Param) -> V::Result { - walk_list!(visitor, visit_attribute, ¶m.attrs); - try_visit!(visitor.visit_pat(¶m.pat)); - try_visit!(visitor.visit_ty(¶m.ty)); - V::Result::output() -} - -pub fn walk_arm<'a, V: Visitor<'a>>(visitor: &mut V, arm: &'a Arm) -> V::Result { - try_visit!(visitor.visit_pat(&arm.pat)); - visit_opt!(visitor, visit_expr, &arm.guard); - visit_opt!(visitor, visit_expr, &arm.body); - walk_list!(visitor, visit_attribute, &arm.attrs); - V::Result::output() -} - -pub fn walk_vis<'a, V: Visitor<'a>>(visitor: &mut V, vis: &'a Visibility) -> V::Result { - if let VisibilityKind::Restricted { ref path, id, shorthand: _ } = vis.kind { - try_visit!(visitor.visit_path(path, id)); - } - V::Result::output() -} - -pub fn walk_attribute<'a, V: Visitor<'a>>(visitor: &mut V, attr: &'a Attribute) -> V::Result { - match &attr.kind { - AttrKind::Normal(normal) => try_visit!(walk_attr_args(visitor, &normal.item.args)), - AttrKind::DocComment(..) => {} - } - V::Result::output() -} - -pub fn walk_attr_args<'a, V: Visitor<'a>>(visitor: &mut V, args: &'a AttrArgs) -> V::Result { - match args { - AttrArgs::Empty => {} - AttrArgs::Delimited(_) => {} - AttrArgs::Eq(_eq_span, AttrArgsEq::Ast(expr)) => try_visit!(visitor.visit_expr(expr)), - AttrArgs::Eq(_, AttrArgsEq::Hir(lit)) => { - unreachable!("in literal form when walking mac args eq: {:?}", lit) - } - } - V::Result::output() -} +use crate::ast::*;use rustc_span::symbol::Ident;use rustc_span::Span;pub use//3; +rustc_ast_ir::visit::VisitorResult;pub use rustc_ast_ir::{try_visit,visit_opt,// +walk_list,walk_visitable_list};#[derive(Copy,Clone,Debug,PartialEq)]pub enum//3; +AssocCtxt{Trait,Impl,}#[derive(Copy, Clone,Debug,PartialEq)]pub enum FnCtxt{Free +,Foreign,Assoc(AssocCtxt),}#[derive(Copy ,Clone,Debug)]pub enum BoundKind{Bound, +Impl,TraitObject,SuperTraits,}#[derive(Copy,Clone ,Debug)]pub enum FnKind<'a>{Fn +(FnCtxt,Ident,&'a FnSig,&'a Visibility, &'a Generics,Option<&'a Block>),Closure( +&'a ClosureBinder,&'a FnDecl,&'a Expr),} impl<'a>FnKind<'a>{pub fn header(&self) +->Option<&'a FnHeader>{match*self{FnKind::Fn(_,_ ,sig,_,_,_)=>Some(&sig.header), +FnKind::Closure(_,_,_)=>None,}}pub fn ident(&self)->Option<&Ident>{match self{// +FnKind::Fn(_,ident,..)=>(Some(ident)),_ =>None,}}pub fn decl(&self)->&'a FnDecl{ +match self{FnKind::Fn(_,_,sig,_,_,_) =>&sig.decl,FnKind::Closure(_,decl,_)=>decl +,}}pub fn ctxt(&self)->Option{match self{FnKind::Fn(ctxt,..)=>Some(*//3; +ctxt),FnKind::Closure(..)=>None,}}}#[derive(Copy,Clone,Debug)]pub enum//((),()); +LifetimeCtxt{Ref,Bound,GenericArg,}pub trait Visitor<'ast>:Sized{type Result://; +VisitorResult=();fn visit_ident(&mut self,_ident:Ident)->Self::Result{Self:://3; +Result::output()}fn visit_foreign_item(&mut self,i:&'ast ForeignItem)->Self:://; +Result{(walk_foreign_item(self,i))}fn visit_item(&mut self,i:&'ast Item)->Self:: +Result{walk_item(self,i)}fn visit_local(& mut self,l:&'ast Local)->Self::Result{ +walk_local(self,l)}fn visit_block(&mut self,b:&'ast Block)->Self::Result{//({}); +walk_block(self,b)}fn visit_stmt(&mut self,s:&'ast Stmt)->Self::Result{//*&*&(); +walk_stmt(self,s)}fn visit_param(&mut self,param:&'ast Param)->Self::Result{//3; +walk_param(self,param)}fn visit_arm(&mut self,a:&'ast Arm)->Self::Result{//({}); +walk_arm(self,a)}fn visit_pat(&mut self,p:&'ast Pat)->Self::Result{walk_pat(//3; +self,p)}fn visit_anon_const(&mut self,c:&'ast AnonConst)->Self::Result{//*&*&(); +walk_anon_const(self,c)}fn visit_expr(&mut self,ex:&'ast Expr)->Self::Result{//; +walk_expr(self,ex)}fn visit_method_receiver_expr(& mut self,ex:&'ast Expr)->Self +::Result{self.visit_expr(ex)}fn visit_expr_post (&mut self,_ex:&'ast Expr)->Self +::Result{Self::Result::output()}fn visit_ty (&mut self,t:&'ast Ty)->Self::Result +{(walk_ty(self,t))}fn visit_generic_param (&mut self,param:&'ast GenericParam)-> +Self::Result{walk_generic_param(self,param)} fn visit_generics(&mut self,g:&'ast +Generics)->Self::Result{(((walk_generics(self,g))))}fn visit_closure_binder(&mut +self,b:&'ast ClosureBinder)->Self::Result{((((walk_closure_binder(self,b)))))}fn +visit_where_predicate(&mut self,p:&'ast WherePredicate)->Self::Result{//((),()); +walk_where_predicate(self,p)}fn visit_fn(&mut self,fk:FnKind<'ast>,_:Span,_://3; +NodeId)->Self::Result{((walk_fn(self,fk)))}fn visit_assoc_item(&mut self,i:&'ast +AssocItem,ctxt:AssocCtxt)->Self::Result{ ((((walk_assoc_item(self,i,ctxt)))))}fn +visit_trait_ref(&mut self,t:&'ast TraitRef)->Self::Result{walk_trait_ref(self,t +)}fn visit_param_bound(&mut self,bounds:&'ast GenericBound,_ctxt:BoundKind)->//; +Self::Result{walk_param_bound(self,bounds) }fn visit_poly_trait_ref(&mut self,t: +&'ast PolyTraitRef)->Self::Result{((((((((walk_poly_trait_ref(self,t)))))))))}fn +visit_variant_data(&mut self,s:& 'ast VariantData)->Self::Result{walk_struct_def +(self,s)}fn visit_field_def(&mut self,s:&'ast FieldDef)->Self::Result{//((),()); +walk_field_def(self,s)}fn visit_enum_def(&mut self,enum_definition:&'ast//{();}; +EnumDef)->Self::Result{(walk_enum_def( self,enum_definition))}fn visit_variant(& +mut self,v:&'ast Variant)->Self ::Result{((((((((walk_variant(self,v)))))))))}fn +visit_variant_discr(&mut self,discr:&'ast AnonConst)->Self::Result{self.//{();}; +visit_anon_const(discr)}fn visit_label(&mut self,label:&'ast Label)->Self:://(); +Result{((((walk_label(self,label)))))}fn visit_lifetime(&mut self,lifetime:&'ast +Lifetime,_:LifetimeCtxt)->Self::Result{(((((walk_lifetime(self,lifetime))))))}fn +visit_mac_call(&mut self,mac:&'ast MacCall) ->Self::Result{walk_mac(self,mac)}fn +visit_mac_def(&mut self,_mac:&'ast MacroDef,_id:NodeId)->Self::Result{Self:://3; +Result::output()}fn visit_path(&mut self,path:&'ast Path,_id:NodeId)->Self:://3; +Result{walk_path(self,path)}fn visit_use_tree(&mut self,use_tree:&'ast UseTree, +id:NodeId,_nested:bool,)->Self::Result {(((walk_use_tree(self,use_tree,id))))}fn +visit_path_segment(&mut self,path_segment:&'ast PathSegment)->Self::Result{//(); +walk_path_segment(self,path_segment)}fn visit_generic_args(&mut self,//let _=(); +generic_args:&'ast GenericArgs)->Self::Result{walk_generic_args(self,//let _=(); +generic_args)}fn visit_generic_arg(&mut self,generic_arg:&'ast GenericArg)->//3; +Self::Result{(walk_generic_arg(self,generic_arg))}fn visit_assoc_constraint(&mut +self,constraint:&'ast AssocConstraint) ->Self::Result{walk_assoc_constraint(self +,constraint)}fn visit_attribute(&mut self,attr:&'ast Attribute)->Self::Result{// +walk_attribute(self,attr)}fn visit_vis(&mut self,vis:&'ast Visibility)->Self::// +Result{(walk_vis(self,vis))}fn visit_fn_ret_ty(&mut self,ret_ty:&'ast FnRetTy)-> +Self::Result{walk_fn_ret_ty(self,ret_ty) }fn visit_fn_header(&mut self,_header:& +'ast FnHeader)->Self::Result{((Self::Result::output()))}fn visit_expr_field(&mut +self,f:&'ast ExprField)->Self::Result{((((((((walk_expr_field(self,f)))))))))}fn +visit_pat_field(&mut self,fp:&'ast PatField)->Self::Result{walk_pat_field(self, +fp)}fn visit_crate(&mut self,krate:&'ast Crate)->Self::Result{walk_crate(self,// +krate)}fn visit_inline_asm(&mut self,asm:&'ast InlineAsm)->Self::Result{//{();}; +walk_inline_asm(self,asm)}fn visit_format_args(&mut self,fmt:&'ast FormatArgs)// +->Self::Result{walk_format_args(self,fmt) }fn visit_inline_asm_sym(&mut self,sym +:&'ast InlineAsmSym)->Self::Result {((((((walk_inline_asm_sym(self,sym)))))))}fn +visit_capture_by(&mut self,_capture_by:&'ast CaptureBy)->Self::Result{Self:://3; +Result::output()}}pub fn walk_crate<'a,V:Visitor<'a>>(visitor:&mut V,krate:&'a// +Crate)->V::Result{();walk_list!(visitor,visit_item,&krate.items);3;3;walk_list!( +visitor,visit_attribute,&krate.attrs);;V::Result::output()}pub fn walk_local<'a, +V:Visitor<'a>>(visitor:&mut V,local:&'a Local)->V::Result{();walk_list!(visitor, +visit_attribute,&local.attrs);3;3;try_visit!(visitor.visit_pat(&local.pat));3;3; +visit_opt!(visitor,visit_ty,&local.ty);{();};if let Some((init,els))=local.kind. +init_else_opt(){();try_visit!(visitor.visit_expr(init));();3;visit_opt!(visitor, +visit_block,els);{();};}V::Result::output()}pub fn walk_label<'a,V:Visitor<'a>>( +visitor:&mut V,label:&'a Label)-> V::Result{visitor.visit_ident(label.ident)}pub +fn walk_lifetime<'a,V:Visitor<'a>>(visitor:&mut V,lifetime:&'a Lifetime)->V:://; +Result{((visitor.visit_ident(lifetime.ident)))}pub fn walk_poly_trait_ref<'a,V>( +visitor:&mut V,trait_ref:&'a PolyTraitRef)->V::Result where V:Visitor<'a>,{({}); +walk_list!(visitor,visit_generic_param,&trait_ref.bound_generic_params);;visitor +.visit_trait_ref(&trait_ref.trait_ref)}pub fn walk_trait_ref<'a,V:Visitor<'a>>( +visitor:&mut V,trait_ref:&'a TraitRef )->V::Result{visitor.visit_path(&trait_ref +.path,trait_ref.ref_id)}pub fn walk_item<'a ,V:Visitor<'a>>(visitor:&mut V,item: +&'a Item)->V::Result{();try_visit!(visitor.visit_vis(&item.vis));3;3;try_visit!( +visitor.visit_ident(item.ident));();match&item.kind{ItemKind::ExternCrate(_)=>{} +ItemKind::Use(use_tree)=>try_visit!(visitor.visit_use_tree(use_tree,item.id,//3; +false)),ItemKind::Static(box StaticItem{ty,mutability:_,expr})=>{{;};try_visit!( +visitor.visit_ty(ty));;;visit_opt!(visitor,visit_expr,expr);}ItemKind::Const(box +ConstItem{defaultness:_,generics,ty,expr})=>{;try_visit!(visitor.visit_generics( +generics));;try_visit!(visitor.visit_ty(ty));visit_opt!(visitor,visit_expr,expr) +;;}ItemKind::Fn(box Fn{defaultness:_,generics,sig,body})=>{;let kind=FnKind::Fn( +FnCtxt::Free,item.ident,sig,&item.vis,generics,body.as_deref());();3;try_visit!( +visitor.visit_fn(kind,item.span,item.id));3;}ItemKind::Mod(_unsafety,mod_kind)=> +match mod_kind{ModKind::Loaded(items,_inline,_inner_span)=>{;walk_list!(visitor, +visit_item,items);3;}ModKind::Unloaded=>{}},ItemKind::ForeignMod(foreign_module) +=>{();walk_list!(visitor,visit_foreign_item,&foreign_module.items);3;}ItemKind:: +GlobalAsm(asm)=>try_visit!(visitor. visit_inline_asm(asm)),ItemKind::TyAlias(box +TyAlias{generics,bounds,ty,..})=>{3;try_visit!(visitor.visit_generics(generics)) +;3;3;walk_list!(visitor,visit_param_bound,bounds,BoundKind::Bound);;;visit_opt!( +visitor,visit_ty,ty);3;}ItemKind::Enum(enum_definition,generics)=>{3;try_visit!( +visitor.visit_generics(generics));{();};{();};try_visit!(visitor.visit_enum_def( +enum_definition));();}ItemKind::Impl(box Impl{defaultness:_,unsafety:_,generics, +constness:_,polarity:_,of_trait,self_ty,items,})=>{if true{};try_visit!(visitor. +visit_generics(generics));();3;visit_opt!(visitor,visit_trait_ref,of_trait);3;3; +try_visit!(visitor.visit_ty(self_ty));;walk_list!(visitor,visit_assoc_item,items +,AssocCtxt::Impl);;}ItemKind::Struct(struct_definition,generics)|ItemKind::Union +(struct_definition,generics)=>{3;try_visit!(visitor.visit_generics(generics));;; +try_visit!(visitor.visit_variant_data(struct_definition));3;}ItemKind::Trait(box +Trait{unsafety:_,is_auto:_,generics,bounds,items})=>{((),());try_visit!(visitor. +visit_generics(generics));;walk_list!(visitor,visit_param_bound,bounds,BoundKind +::SuperTraits);3;;walk_list!(visitor,visit_assoc_item,items,AssocCtxt::Trait);;} +ItemKind::TraitAlias(generics,bounds)=>{{();};try_visit!(visitor.visit_generics( +generics));3;3;walk_list!(visitor,visit_param_bound,bounds,BoundKind::Bound);3;} +ItemKind::MacCall(mac)=>(((try_visit!(visitor.visit_mac_call(mac))))),ItemKind:: +MacroDef(ts)=>(((((try_visit!(visitor.visit_mac_def(ts,item.id))))))),ItemKind:: +Delegation(box Delegation{id,qself,path,body})=>{if let Some(qself)=qself{{();}; +try_visit!(visitor.visit_ty(&qself.ty));;}try_visit!(visitor.visit_path(path,*id +));;;visit_opt!(visitor,visit_block,body);}}walk_list!(visitor,visit_attribute,& +item.attrs);;V::Result::output()}pub fn walk_enum_def<'a,V:Visitor<'a>>(visitor: +&mut V,enum_definition:&'a EnumDef,)->V::Result{loop{break;};walk_list!(visitor, +visit_variant,&enum_definition.variants);loop{break;};V::Result::output()}pub fn +walk_variant<'a,V:Visitor<'a>>(visitor:&mut V,variant:&'a Variant)->V::Result//; +where V:Visitor<'a>,{;try_visit!(visitor.visit_ident(variant.ident));try_visit!( +visitor.visit_vis(&variant.vis));;try_visit!(visitor.visit_variant_data(&variant +.data));;;visit_opt!(visitor,visit_variant_discr,&variant.disr_expr);walk_list!( +visitor,visit_attribute,&variant.attrs);if let _=(){};V::Result::output()}pub fn +walk_expr_field<'a,V:Visitor<'a>>(visitor:&mut V,f:&'a ExprField)->V::Result{(); +try_visit!(visitor.visit_expr(&f.expr));;try_visit!(visitor.visit_ident(f.ident) +);();3;walk_list!(visitor,visit_attribute,&f.attrs);3;V::Result::output()}pub fn +walk_pat_field<'a,V:Visitor<'a>>(visitor:&mut V,fp:&'a PatField)->V::Result{{;}; +try_visit!(visitor.visit_ident(fp.ident));;try_visit!(visitor.visit_pat(&fp.pat) +);3;3;walk_list!(visitor,visit_attribute,&fp.attrs);3;V::Result::output()}pub fn +walk_ty<'a,V:Visitor<'a>>(visitor:&mut V,typ :&'a Ty)->V::Result{match&typ.kind{ +TyKind::Slice(ty)|TyKind::Paren(ty)=>(try_visit!(visitor.visit_ty(ty))),TyKind:: +Ptr(mutable_type)=>(try_visit!(visitor.visit_ty(&mutable_type.ty))),TyKind::Ref( +opt_lifetime,mutable_type)=>{{;};visit_opt!(visitor,visit_lifetime,opt_lifetime, +LifetimeCtxt::Ref);;try_visit!(visitor.visit_ty(&mutable_type.ty));}TyKind::Tup( +tuple_element_types)=>{;walk_list!(visitor,visit_ty,tuple_element_types);}TyKind +::BareFn(function_declaration)=>{*&*&();walk_list!(visitor,visit_generic_param,& +function_declaration.generic_params);({});({});try_visit!(walk_fn_decl(visitor,& +function_declaration.decl));;}TyKind::Path(maybe_qself,path)=>{if let Some(qself +)=maybe_qself{3;try_visit!(visitor.visit_ty(&qself.ty));3;}3;try_visit!(visitor. +visit_path(path,typ.id));{;};}TyKind::Array(ty,length)=>{{;};try_visit!(visitor. +visit_ty(ty));;try_visit!(visitor.visit_anon_const(length));}TyKind::TraitObject +(bounds,..)=>{let _=||();walk_list!(visitor,visit_param_bound,bounds,BoundKind:: +TraitObject);let _=();}TyKind::ImplTrait(_,bounds)=>{((),());walk_list!(visitor, +visit_param_bound,bounds,BoundKind::Impl);let _=();}TyKind::Typeof(expression)=> +try_visit!(visitor.visit_anon_const(expression)),TyKind::Infer|TyKind:://*&*&(); +ImplicitSelf|TyKind::Dummy|TyKind::Err(_)=>{}TyKind::MacCall(mac)=>try_visit!(// +visitor.visit_mac_call(mac)),TyKind::Never|TyKind::CVarArgs=>{}TyKind:://*&*&(); +AnonStruct(_,ref fields)|TyKind::AnonUnion(_,ref fields)=>{3;walk_list!(visitor, +visit_field_def,fields);3;}}V::Result::output()}pub fn walk_path<'a,V:Visitor<'a +>>(visitor:&mut V,path:&'a Path)->V::Result{((),());let _=();walk_list!(visitor, +visit_path_segment,&path.segments);;V::Result::output()}pub fn walk_use_tree<'a, +V:Visitor<'a>>(visitor:&mut V,use_tree:&'a UseTree,id:NodeId,)->V::Result{{();}; +try_visit!(visitor.visit_path(&use_tree.prefix,id));((),());match use_tree.kind{ +UseTreeKind::Simple(rename)=>{({});visit_opt!(visitor,visit_ident,rename);({});} +UseTreeKind::Glob=>{}UseTreeKind::Nested(ref use_trees)=>{for&(ref nested_tree, +nested_id)in use_trees{;try_visit!(visitor.visit_use_tree(nested_tree,nested_id, +true));*&*&();}}}V::Result::output()}pub fn walk_path_segment<'a,V:Visitor<'a>>( +visitor:&mut V,segment:&'a PathSegment,)->V::Result{let _=();try_visit!(visitor. +visit_ident(segment.ident));;visit_opt!(visitor,visit_generic_args,&segment.args +);loop{break};V::Result::output()}pub fn walk_generic_args<'a,V>(visitor:&mut V, +generic_args:&'a GenericArgs)->V::Result where V:Visitor<'a>,{match//let _=||(); +generic_args{GenericArgs::AngleBracketed(data)=>{for arg in&data.args{match arg +{AngleBracketedArg::Arg(a)=>(((((try_visit !(visitor.visit_generic_arg(a))))))), +AngleBracketedArg::Constraint(c)=>{ try_visit!(visitor.visit_assoc_constraint(c) +)}}}}GenericArgs::Parenthesized(data)=>{{();};walk_list!(visitor,visit_ty,&data. +inputs);;try_visit!(visitor.visit_fn_ret_ty(&data.output));}}V::Result::output() +}pub fn walk_generic_arg<'a,V>(visitor:&mut V,generic_arg:&'a GenericArg)->V::// +Result where V:Visitor<'a>,{ match generic_arg{GenericArg::Lifetime(lt)=>visitor +.visit_lifetime(lt,LifetimeCtxt::GenericArg),GenericArg::Type(ty)=>visitor.//(); +visit_ty(ty),GenericArg::Const(ct)=> (((visitor.visit_anon_const(ct)))),}}pub fn +walk_assoc_constraint<'a,V:Visitor<'a>>(visitor:&mut V,constraint:&'a//let _=(); +AssocConstraint,)->V::Result{;try_visit!(visitor.visit_ident(constraint.ident)); +visit_opt!(visitor,visit_generic_args,&constraint.gen_args);();match&constraint. +kind{AssocConstraintKind::Equality{term}=>match term{Term::Ty(ty)=>try_visit!(// +visitor.visit_ty(ty)),Term::Const(c) =>try_visit!(visitor.visit_anon_const(c)),} +,AssocConstraintKind::Bound{bounds}=>{({});walk_list!(visitor,visit_param_bound, +bounds,BoundKind::Bound);3;}}V::Result::output()}pub fn walk_pat<'a,V:Visitor<'a +>>(visitor:&mut V,pattern:&'a Pat)->V::Result{match(((&pattern.kind))){PatKind:: +TupleStruct(opt_qself,path,elems)=>{if let Some(qself)=opt_qself{{;};try_visit!( +visitor.visit_ty(&qself.ty));;};try_visit!(visitor.visit_path(path,pattern.id)); +walk_list!(visitor,visit_pat,elems);({});}PatKind::Path(opt_qself,path)=>{if let +Some(qself)=opt_qself{();try_visit!(visitor.visit_ty(&qself.ty));();}try_visit!( +visitor.visit_path(path,pattern.id))} PatKind::Struct(opt_qself,path,fields,_)=> +{if let Some(qself)=opt_qself{();try_visit!(visitor.visit_ty(&qself.ty));();}(); +try_visit!(visitor.visit_path(path,pattern.id));*&*&();{();};walk_list!(visitor, +visit_pat_field,fields);();}PatKind::Box(subpattern)|PatKind::Deref(subpattern)| +PatKind::Ref(subpattern,_)|PatKind::Paren(subpattern)=>{({});try_visit!(visitor. +visit_pat(subpattern));;}PatKind::Ident(_,ident,optional_subpattern)=>{try_visit +!(visitor.visit_ident(*ident));;visit_opt!(visitor,visit_pat,optional_subpattern +);;}PatKind::Lit(expression)=>try_visit!(visitor.visit_expr(expression)),PatKind +::Range(lower_bound,upper_bound,_)=>{;visit_opt!(visitor,visit_expr,lower_bound) +;();3;visit_opt!(visitor,visit_expr,upper_bound);3;}PatKind::Wild|PatKind::Rest| +PatKind::Never|PatKind::Err(_)=>{}PatKind::Tuple(elems)|PatKind::Slice(elems)|// +PatKind::Or(elems)=>{;walk_list!(visitor,visit_pat,elems);}PatKind::MacCall(mac) +=>(((try_visit!(visitor.visit_mac_call(mac))))), }((V::Result::output()))}pub fn +walk_foreign_item<'a,V:Visitor<'a>>(visitor:&mut V,item:&'a ForeignItem)->V:://; +Result{();let&Item{id,span,ident,ref vis,ref attrs,ref kind,tokens:_}=item;();3; +try_visit!(visitor.visit_vis(vis));3;3;try_visit!(visitor.visit_ident(ident));;; +walk_list!(visitor,visit_attribute,attrs);;match kind{ForeignItemKind::Static(ty +,_,expr)=>{;try_visit!(visitor.visit_ty(ty));visit_opt!(visitor,visit_expr,expr) +;();}ForeignItemKind::Fn(box Fn{defaultness:_,generics,sig,body})=>{();let kind= +FnKind::Fn(FnCtxt::Foreign,ident,sig,vis,generics,body.as_deref());;;try_visit!( +visitor.visit_fn(kind,span,id));;}ForeignItemKind::TyAlias(box TyAlias{generics, +bounds,ty,..})=>{();try_visit!(visitor.visit_generics(generics));3;3;walk_list!( +visitor,visit_param_bound,bounds,BoundKind::Bound);;visit_opt!(visitor,visit_ty, +ty);;}ForeignItemKind::MacCall(mac)=>{try_visit!(visitor.visit_mac_call(mac));}} +V::Result::output()}pub fn walk_param_bound<'a,V:Visitor<'a>>(visitor:&mut V,//; +bound:&'a GenericBound)->V::Result{match bound{GenericBound::Trait(typ,//*&*&(); +_modifier)=>(visitor.visit_poly_trait_ref(typ)),GenericBound::Outlives(lifetime) +=>((((((((visitor.visit_lifetime(lifetime,LifetimeCtxt ::Bound))))))))),}}pub fn +walk_generic_param<'a,V:Visitor<'a>>(visitor:& mut V,param:&'a GenericParam,)->V +::Result{();try_visit!(visitor.visit_ident(param.ident));3;3;walk_list!(visitor, +visit_attribute,¶m.attrs);();();walk_list!(visitor,visit_param_bound,¶m. +bounds,BoundKind::Bound);*&*&();match¶m.kind{GenericParamKind::Lifetime=>(), +GenericParamKind::Type{default}=>(((((visit_opt!(visitor,visit_ty,default)))))), +GenericParamKind::Const{ty,default,..}=>{3;try_visit!(visitor.visit_ty(ty));3;3; +visit_opt!(visitor,visit_anon_const,default);*&*&();}}V::Result::output()}pub fn +walk_generics<'a,V:Visitor<'a>>(visitor:&mut V,generics:&'a Generics)->V:://{;}; +Result{3;walk_list!(visitor,visit_generic_param,&generics.params);3;;walk_list!( +visitor,visit_where_predicate,&generics.where_clause.predicates);{;};V::Result:: +output()}pub fn walk_closure_binder<'a,V: Visitor<'a>>(visitor:&mut V,binder:&'a +ClosureBinder,)->V::Result{match binder{ClosureBinder::NotPresent=>{}//let _=(); +ClosureBinder::For{generic_params,span:_}=>{walk_list!(visitor,//*&*&();((),()); +visit_generic_param,generic_params)}}((((((((V:: Result::output()))))))))}pub fn +walk_where_predicate<'a,V:Visitor<'a>>(visitor:&mut V,predicate:&'a//let _=||(); +WherePredicate,)->V::Result{match predicate{WherePredicate::BoundPredicate(//(); +WhereBoundPredicate{bounded_ty,bounds,bound_generic_params,..})=>{();try_visit!( +visitor.visit_ty(bounded_ty));();();walk_list!(visitor,visit_param_bound,bounds, +BoundKind::Bound);;walk_list!(visitor,visit_generic_param,bound_generic_params); +}WherePredicate::RegionPredicate(WhereRegionPredicate{lifetime,bounds,..})=>{(); +try_visit!(visitor.visit_lifetime(lifetime,LifetimeCtxt::Bound));3;3;walk_list!( +visitor,visit_param_bound,bounds,BoundKind::Bound);;}WherePredicate::EqPredicate +(WhereEqPredicate{lhs_ty,rhs_ty,..})=>{3;try_visit!(visitor.visit_ty(lhs_ty));;; +try_visit!(visitor.visit_ty(rhs_ty));*&*&();((),());}}V::Result::output()}pub fn +walk_fn_ret_ty<'a,V:Visitor<'a>>(visitor:&mut V,ret_ty:&'a FnRetTy)->V::Result{ +if let FnRetTy::Ty(output_ty)=ret_ty{;try_visit!(visitor.visit_ty(output_ty));}V +::Result::output()}pub fn walk_fn_decl<'a,V:Visitor<'a>>(visitor:&mut V,//{();}; +function_declaration:&'a FnDecl,)->V::Result{();walk_list!(visitor,visit_param,& +function_declaration.inputs);({});visitor.visit_fn_ret_ty(&function_declaration. +output)}pub fn walk_fn<'a,V:Visitor<'a>>(visitor:&mut V,kind:FnKind<'a>)->V:://; +Result{match kind{FnKind::Fn(_,_,sig,_,generics,body)=>{({});try_visit!(visitor. +visit_generics(generics));3;;try_visit!(visitor.visit_fn_header(&sig.header));;; +try_visit!(walk_fn_decl(visitor,&sig.decl));;visit_opt!(visitor,visit_block,body +);;}FnKind::Closure(binder,decl,body)=>{try_visit!(visitor.visit_closure_binder( +binder));;;try_visit!(walk_fn_decl(visitor,decl));try_visit!(visitor.visit_expr( +body));;}}V::Result::output()}pub fn walk_assoc_item<'a,V:Visitor<'a>>(visitor:& +mut V,item:&'a AssocItem,ctxt:AssocCtxt,)->V::Result{;let&Item{id,span,ident,ref +vis,ref attrs,ref kind,tokens:_}=item;3;3;try_visit!(visitor.visit_vis(vis));3;; +try_visit!(visitor.visit_ident(ident));;walk_list!(visitor,visit_attribute,attrs +);;match kind{AssocItemKind::Const(box ConstItem{defaultness:_,generics,ty,expr} +)=>{;try_visit!(visitor.visit_generics(generics));try_visit!(visitor.visit_ty(ty +));;visit_opt!(visitor,visit_expr,expr);}AssocItemKind::Fn(box Fn{defaultness:_, +generics,sig,body})=>{{;};let kind=FnKind::Fn(FnCtxt::Assoc(ctxt),ident,sig,vis, +generics,body.as_deref());{;};();try_visit!(visitor.visit_fn(kind,span,id));();} +AssocItemKind::Type(box TyAlias{generics,bounds,ty,..})=>{();try_visit!(visitor. +visit_generics(generics));;walk_list!(visitor,visit_param_bound,bounds,BoundKind +::Bound);3;3;visit_opt!(visitor,visit_ty,ty);3;}AssocItemKind::MacCall(mac)=>{3; +try_visit!(visitor.visit_mac_call(mac));if true{};}AssocItemKind::Delegation(box +Delegation{id,qself,path,body})=>{if let Some(qself)=qself{3;try_visit!(visitor. +visit_ty(&qself.ty));3;}3;try_visit!(visitor.visit_path(path,*id));;;visit_opt!( +visitor,visit_block,body);{;};}}V::Result::output()}pub fn walk_struct_def<'a,V: +Visitor<'a>>(visitor:&mut V,struct_definition:&'a VariantData,)->V::Result{({}); +walk_list!(visitor,visit_field_def,struct_definition.fields());{();};V::Result:: +output()}pub fn walk_field_def<'a,V:Visitor<'a>>(visitor:&mut V,field:&'a//({}); +FieldDef)->V::Result{3;try_visit!(visitor.visit_vis(&field.vis));3;3;visit_opt!( +visitor,visit_ident,field.ident);3;3;try_visit!(visitor.visit_ty(&field.ty));3;; +walk_list!(visitor,visit_attribute,&field.attrs);({});V::Result::output()}pub fn +walk_block<'a,V:Visitor<'a>>(visitor:&mut V,block:&'a Block)->V::Result{((),()); +walk_list!(visitor,visit_stmt,&block.stmts);if true{};V::Result::output()}pub fn +walk_stmt<'a,V:Visitor<'a>>(visitor:&mut V,statement:&'a Stmt)->V::Result{match +&statement.kind{StmtKind::Let(local)=> (try_visit!(visitor.visit_local(local))), +StmtKind::Item(item)=>try_visit!(visitor. visit_item(item)),StmtKind::Expr(expr) +|StmtKind::Semi(expr)=>try_visit!(visitor .visit_expr(expr)),StmtKind::Empty=>{} +StmtKind::MacCall(mac)=>{3;let MacCallStmt{mac,attrs,style:_,tokens:_}=&**mac;;; +try_visit!(visitor.visit_mac_call(mac));();3;walk_list!(visitor,visit_attribute, +attrs);3;}}V::Result::output()}pub fn walk_mac<'a,V:Visitor<'a>>(visitor:&mut V, +mac:&'a MacCall)->V::Result{(visitor.visit_path(&mac.path,DUMMY_NODE_ID))}pub fn +walk_anon_const<'a,V:Visitor<'a>>(visitor:&mut V,constant:&'a AnonConst)->V:://; +Result{visitor.visit_expr(&constant.value) }pub fn walk_inline_asm<'a,V:Visitor< +'a>>(visitor:&mut V,asm:&'a InlineAsm)-> V::Result{for(op,_)in((&asm.operands)){ +match op{InlineAsmOperand::In{expr,..} |InlineAsmOperand::Out{expr:Some(expr),.. +}|InlineAsmOperand::InOut{expr,..}=>((( try_visit!(visitor.visit_expr(expr))))), +InlineAsmOperand::Out{expr:None,..}=>{}InlineAsmOperand::SplitInOut{in_expr,//3; +out_expr,..}=>{3;try_visit!(visitor.visit_expr(in_expr));3;3;visit_opt!(visitor, +visit_expr,out_expr);{();};}InlineAsmOperand::Const{anon_const,..}=>{try_visit!( +visitor.visit_anon_const(anon_const))}InlineAsmOperand::Sym{sym}=>try_visit!(//; +visitor.visit_inline_asm_sym(sym)),InlineAsmOperand::Label{block}=>try_visit!(// +visitor.visit_block(block)),}}V:: Result::output()}pub fn walk_inline_asm_sym<'a +,V:Visitor<'a>>(visitor:&mut V,sym:&'a InlineAsmSym,)->V::Result{if let Some(//; +qself)=&sym.qself{;try_visit!(visitor.visit_ty(&qself.ty));}visitor.visit_path(& +sym.path,sym.id)}pub fn walk_format_args<'a ,V:Visitor<'a>>(visitor:&mut V,fmt:& +'a FormatArgs)->V::Result{for arg in ((((((fmt.arguments.all_args())))))){if let +FormatArgumentKind::Named(name)=arg.kind{;try_visit!(visitor.visit_ident(name)); +}({});try_visit!(visitor.visit_expr(&arg.expr));({});}V::Result::output()}pub fn +walk_expr<'a,V:Visitor<'a>>(visitor:&mut V,expression:&'a Expr)->V::Result{({}); +walk_list!(visitor,visit_attribute,&expression.attrs);{;};match&expression.kind{ +ExprKind::Array(subexpressions)=>{;walk_list!(visitor,visit_expr,subexpressions) +;((),());}ExprKind::ConstBlock(anon_const)=>try_visit!(visitor.visit_anon_const( +anon_const)),ExprKind::Repeat(element,count)=>{();try_visit!(visitor.visit_expr( +element));;;try_visit!(visitor.visit_anon_const(count));}ExprKind::Struct(se)=>{ +if let Some(qself)=&se.qself{;try_visit!(visitor.visit_ty(&qself.ty));}try_visit +!(visitor.visit_path(&se.path,expression.id));((),());*&*&();walk_list!(visitor, +visit_expr_field,&se.fields);3;match&se.rest{StructRest::Base(expr)=>try_visit!( +visitor.visit_expr(expr)),StructRest::Rest(_span)=>{}StructRest::None=>{}}}//(); +ExprKind::Tup(subexpressions)=>{;walk_list!(visitor,visit_expr,subexpressions);} +ExprKind::Call(callee_expression,arguments)=>{{;};try_visit!(visitor.visit_expr( +callee_expression));();();walk_list!(visitor,visit_expr,arguments);3;}ExprKind:: +MethodCall(box MethodCall{seg,receiver,args,span:_})=>{{();};try_visit!(visitor. +visit_path_segment(seg));;;try_visit!(visitor.visit_expr(receiver));;walk_list!( +visitor,visit_expr,args);3;}ExprKind::Binary(_,left_expression,right_expression) +=>{{;};try_visit!(visitor.visit_expr(left_expression));();();try_visit!(visitor. +visit_expr(right_expression));();}ExprKind::AddrOf(_,_,subexpression)|ExprKind:: +Unary(_,subexpression)=>{{;};try_visit!(visitor.visit_expr(subexpression));{;};} +ExprKind::Cast(subexpression,typ)|ExprKind::Type(subexpression,typ)=>{;try_visit +!(visitor.visit_expr(subexpression));();();try_visit!(visitor.visit_ty(typ));3;} +ExprKind::Let(pat,expr,_,_)=>{3;try_visit!(visitor.visit_pat(pat));;;try_visit!( +visitor.visit_expr(expr));;}ExprKind::If(head_expression,if_block,optional_else) +=>{{;};try_visit!(visitor.visit_expr(head_expression));();();try_visit!(visitor. +visit_block(if_block));;visit_opt!(visitor,visit_expr,optional_else);}ExprKind:: +While(subexpression,block,opt_label)=>{;visit_opt!(visitor,visit_label,opt_label +);;try_visit!(visitor.visit_expr(subexpression));try_visit!(visitor.visit_block( +block));3;}ExprKind::ForLoop{pat,iter,body,label,kind:_}=>{3;visit_opt!(visitor, +visit_label,label);3;3;try_visit!(visitor.visit_pat(pat));3;;try_visit!(visitor. +visit_expr(iter));;;try_visit!(visitor.visit_block(body));}ExprKind::Loop(block, +opt_label,_)=>{3;visit_opt!(visitor,visit_label,opt_label);;;try_visit!(visitor. +visit_block(block));3;}ExprKind::Match(subexpression,arms,_kind)=>{3;try_visit!( +visitor.visit_expr(subexpression));;walk_list!(visitor,visit_arm,arms);}ExprKind +::Closure(box Closure{binder,capture_clause,coroutine_kind:_,constness:_,//({}); +movability:_,fn_decl,body,fn_decl_span:_,fn_arg_span:_,})=>{;try_visit!(visitor. +visit_capture_by(capture_clause));3;try_visit!(visitor.visit_fn(FnKind::Closure( +binder,fn_decl,body),expression.span,expression.id))}ExprKind::Block(block,//(); +opt_label)=>{3;visit_opt!(visitor,visit_label,opt_label);3;3;try_visit!(visitor. +visit_block(block));();}ExprKind::Gen(_,body,_)=>try_visit!(visitor.visit_block( +body)),ExprKind::Await(expr,_)=> try_visit!(visitor.visit_expr(expr)),ExprKind:: +Assign(lhs,rhs,_)=>{3;try_visit!(visitor.visit_expr(lhs));3;;try_visit!(visitor. +visit_expr(rhs));();}ExprKind::AssignOp(_,left_expression,right_expression)=>{3; +try_visit!(visitor.visit_expr(left_expression));;;try_visit!(visitor.visit_expr( +right_expression));;}ExprKind::Field(subexpression,ident)=>{;try_visit!(visitor. +visit_expr(subexpression));;;try_visit!(visitor.visit_ident(*ident));}ExprKind:: +Index(main_expression,index_expression,_)=>{{();};try_visit!(visitor.visit_expr( +main_expression));;;try_visit!(visitor.visit_expr(index_expression));}ExprKind:: +Range(start,end,_)=>{;visit_opt!(visitor,visit_expr,start);;;visit_opt!(visitor, +visit_expr,end);3;}ExprKind::Underscore=>{}ExprKind::Path(maybe_qself,path)=>{if +let Some(qself)=maybe_qself{;try_visit!(visitor.visit_ty(&qself.ty));}try_visit! +(visitor.visit_path(path,expression.id));;}ExprKind::Break(opt_label,opt_expr)=> +{();visit_opt!(visitor,visit_label,opt_label);3;3;visit_opt!(visitor,visit_expr, +opt_expr);();}ExprKind::Continue(opt_label)=>{();visit_opt!(visitor,visit_label, +opt_label);;}ExprKind::Ret(optional_expression)=>{visit_opt!(visitor,visit_expr, +optional_expression);;}ExprKind::Yeet(optional_expression)=>{visit_opt!(visitor, +visit_expr,optional_expression);{;};}ExprKind::Become(expr)=>try_visit!(visitor. +visit_expr(expr)),ExprKind::MacCall( mac)=>try_visit!(visitor.visit_mac_call(mac +)),ExprKind::Paren(subexpression) =>try_visit!(visitor.visit_expr(subexpression) +),ExprKind::InlineAsm(asm)=>(try_visit!(visitor.visit_inline_asm(asm))),ExprKind +::FormatArgs(f)=>(try_visit!(visitor .visit_format_args(f))),ExprKind::OffsetOf( +container,fields)=>{;try_visit!(visitor.visit_ty(container));walk_list!(visitor, +visit_ident,fields.iter().copied());3;}ExprKind::Yield(optional_expression)=>{3; +visit_opt!(visitor,visit_expr,optional_expression);;}ExprKind::Try(subexpression +)=>((try_visit!(visitor.visit_expr(subexpression )))),ExprKind::TryBlock(body)=> +try_visit!(visitor.visit_block(body)) ,ExprKind::Lit(_)|ExprKind::IncludedBytes( +..)|ExprKind::Err(_)|ExprKind::Dummy =>{}}(visitor.visit_expr_post(expression))} +pub fn walk_param<'a,V:Visitor<'a>>(visitor:&mut V,param:&'a Param)->V::Result{; +walk_list!(visitor,visit_attribute,¶m.attrs);;try_visit!(visitor.visit_pat(& +param.pat));;;try_visit!(visitor.visit_ty(¶m.ty));V::Result::output()}pub fn +walk_arm<'a,V:Visitor<'a>>(visitor:&mut V,arm:&'a Arm)->V::Result{();try_visit!( +visitor.visit_pat(&arm.pat));();3;visit_opt!(visitor,visit_expr,&arm.guard);3;3; +visit_opt!(visitor,visit_expr,&arm.body);3;;walk_list!(visitor,visit_attribute,& +arm.attrs);;V::Result::output()}pub fn walk_vis<'a,V:Visitor<'a>>(visitor:&mut V +,vis:&'a Visibility)->V::Result{if let VisibilityKind::Restricted{ref path,id,// +shorthand:_}=vis.kind{();try_visit!(visitor.visit_path(path,id));();}V::Result:: +output()}pub fn walk_attribute<'a,V:Visitor<'a>>(visitor:&mut V,attr:&'a//{();}; +Attribute)->V::Result{match((&attr.kind )){AttrKind::Normal(normal)=>try_visit!( +walk_attr_args(visitor,&normal.item.args)),AttrKind::DocComment(..)=>{}}V:://(); +Result::output()}pub fn walk_attr_args<'a,V:Visitor<'a>>(visitor:&mut V,args:&// +'a AttrArgs)->V::Result{match args{ AttrArgs::Empty=>{}AttrArgs::Delimited(_)=>{ +}AttrArgs::Eq(_eq_span,AttrArgsEq::Ast(expr))=>try_visit!(visitor.visit_expr(//; +expr)),AttrArgs::Eq(_,AttrArgsEq::Hir(lit))=>{unreachable!(//let _=();if true{}; +"in literal form when walking mac args eq: {:?}",lit)}}(( V::Result::output()))} diff --git a/compiler/rustc_ast_ir/src/lib.rs b/compiler/rustc_ast_ir/src/lib.rs index ff7a155204716..c8541377ef526 100644 --- a/compiler/rustc_ast_ir/src/lib.rs +++ b/compiler/rustc_ast_ir/src/lib.rs @@ -1,71 +1,15 @@ -#![cfg_attr(feature = "nightly", feature(never_type))] -#![cfg_attr(feature = "nightly", feature(rustc_attrs))] -#![cfg_attr(feature = "nightly", allow(internal_features))] - -#[cfg(feature = "nightly")] -#[macro_use] -extern crate rustc_macros; - -pub mod visit; - -/// The movability of a coroutine / closure literal: -/// whether a coroutine contains self-references, causing it to be `!Unpin`. -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)] -#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))] -pub enum Movability { - /// May contain self-references, `!Unpin`. - Static, - /// Must not contain self-references, `Unpin`. - Movable, -} - -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)] -#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))] -pub enum Mutability { - // N.B. Order is deliberate, so that Not < Mut - Not, - Mut, -} - -impl Mutability { - pub fn invert(self) -> Self { - match self { - Mutability::Mut => Mutability::Not, - Mutability::Not => Mutability::Mut, - } - } - - /// Returns `""` (empty string) or `"mut "` depending on the mutability. - pub fn prefix_str(self) -> &'static str { - match self { - Mutability::Mut => "mut ", - Mutability::Not => "", - } - } - - /// Returns `"&"` or `"&mut "` depending on the mutability. - pub fn ref_prefix_str(self) -> &'static str { - match self { - Mutability::Not => "&", - Mutability::Mut => "&mut ", - } - } - - /// Returns `""` (empty string) or `"mutably "` depending on the mutability. - pub fn mutably_str(self) -> &'static str { - match self { - Mutability::Not => "", - Mutability::Mut => "mutably ", - } - } - - /// Return `true` if self is mutable - pub fn is_mut(self) -> bool { - matches!(self, Self::Mut) - } - - /// Return `true` if self is **not** mutable - pub fn is_not(self) -> bool { - matches!(self, Self::Not) - } -} +#![cfg_attr(feature="nightly",feature(never_type))]#![cfg_attr(feature=//*&*&(); +"nightly",feature(rustc_attrs))]#![cfg_attr(feature="nightly",allow(//if true{}; +internal_features))]#[cfg(feature="nightly")]#[macro_use]extern crate//let _=(); +rustc_macros;pub mod visit;#[derive(Clone,PartialEq,Eq,PartialOrd,Ord,Hash,//(); +Debug,Copy)]#[cfg_attr(feature="nightly",derive(Encodable,Decodable,//if true{}; +HashStable_NoContext))]pub enum Movability{Static,Movable,}#[derive(Clone,//{;}; +PartialEq,Eq,PartialOrd,Ord,Hash,Debug,Copy)]#[cfg_attr(feature="nightly",//{;}; +derive(Encodable,Decodable,HashStable_NoContext))] pub enum Mutability{Not,Mut,} +impl Mutability{pub fn invert(self)->Self{match self{Mutability::Mut=>//((),()); +Mutability::Not,Mutability::Not=>Mutability::Mut,}}pub fn prefix_str(self)->&//; +'static str{match self{Mutability::Mut=>("mut " ),Mutability::Not=>(""),}}pub fn +ref_prefix_str(self)->&'static str{match self{Mutability::Not=>"&",Mutability:: +Mut=>("&mut "),}}pub fn mutably_str( self)->&'static str{match self{Mutability:: +Not=>(""),Mutability::Mut=>"mutably ",}}pub fn is_mut(self)->bool{matches!(self, +Self::Mut)}pub fn is_not(self)-> bool{((((((((matches!(self,Self::Not)))))))))}} diff --git a/compiler/rustc_ast_ir/src/visit.rs b/compiler/rustc_ast_ir/src/visit.rs index f6d6bf3a3e309..477d8aff027b7 100644 --- a/compiler/rustc_ast_ir/src/visit.rs +++ b/compiler/rustc_ast_ir/src/visit.rs @@ -1,82 +1,21 @@ -use core::ops::ControlFlow; - -/// Similar to the `Try` trait, but also implemented for `()`. -pub trait VisitorResult { - type Residual; - fn output() -> Self; - fn from_residual(residual: Self::Residual) -> Self; - fn from_branch(b: ControlFlow) -> Self; - fn branch(self) -> ControlFlow; -} - -impl VisitorResult for () { - #[cfg(feature = "nightly")] - type Residual = !; - - #[cfg(not(feature = "nightly"))] - type Residual = core::convert::Infallible; - - fn output() -> Self {} - fn from_residual(_: Self::Residual) -> Self {} - fn from_branch(_: ControlFlow) -> Self {} - fn branch(self) -> ControlFlow { - ControlFlow::Continue(()) - } -} - -impl VisitorResult for ControlFlow { - type Residual = T; - - fn output() -> Self { - ControlFlow::Continue(()) - } - fn from_residual(residual: Self::Residual) -> Self { - ControlFlow::Break(residual) - } - fn from_branch(b: Self) -> Self { - b - } - fn branch(self) -> Self { - self - } -} - -#[macro_export] -macro_rules! try_visit { - ($e:expr) => { - match $crate::visit::VisitorResult::branch($e) { - core::ops::ControlFlow::Continue(()) => (), - #[allow(unreachable_code)] - core::ops::ControlFlow::Break(r) => { - return $crate::visit::VisitorResult::from_residual(r); - } - } - }; -} - -#[macro_export] -macro_rules! visit_opt { - ($visitor: expr, $method: ident, $opt: expr $(, $($extra_args: expr),* )?) => { - if let Some(x) = $opt { - $crate::try_visit!($visitor.$method(x $(, $($extra_args,)* )?)); - } - } -} - -#[macro_export] -macro_rules! walk_list { - ($visitor: expr, $method: ident, $list: expr $(, $($extra_args: expr),* )?) => { - for elem in $list { - $crate::try_visit!($visitor.$method(elem $(, $($extra_args,)* )?)); - } - } -} - -#[macro_export] -macro_rules! walk_visitable_list { - ($visitor: expr, $list: expr $(, $($extra_args: expr),* )?) => { - for elem in $list { - $crate::try_visit!(elem.visit_with($visitor $(, $($extra_args,)* )?)); - } - } -} +use core::ops::ControlFlow;pub trait VisitorResult{type Residual;fn output()->// +Self;fn from_residual(residual:Self::Residual)->Self;fn from_branch(b://((),()); +ControlFlow)->Self;fn branch(self)->ControlFlow +;}impl VisitorResult for(){#[cfg(feature="nightly")]type Residual=!;#[cfg(not(// +feature="nightly"))]type Residual=core:: convert::Infallible;fn output()->Self{} +fn from_residual(_:Self::Residual)->Self{}fn from_branch(_:ControlFlow)->Self{}fn branch(self)->ControlFlow{ControlFlow:://3; +Continue(())}}implVisitorResult for ControlFlow{type Residual=T;fn output +()->Self{(ControlFlow::Continue(()))}fn from_residual(residual:Self::Residual)-> +Self{ControlFlow::Break(residual)}fn from_branch (b:Self)->Self{b}fn branch(self +)->Self{self}}#[macro_export]macro_rules!try_visit{($e:expr)=>{match$crate:://3; +visit::VisitorResult::branch($e){core::ops::ControlFlow::Continue(())=>(),#[//3; +allow(unreachable_code)]core::ops::ControlFlow::Break(r)=>{return$crate::visit// +::VisitorResult::from_residual(r);}}};}#[macro_export]macro_rules!visit_opt{($// +visitor:expr,$method:ident,$opt:expr$(,$( $extra_args:expr),*)?)=>{if let Some(x +)=$opt{$crate::try_visit!($visitor.$method(x$(,$($extra_args,)*)?));}}}#[//({}); +macro_export]macro_rules!walk_list{($visitor:expr,$ method:ident,$list:expr$(,$( +$extra_args:expr),*)?)=>{for elem in$list{$crate::try_visit!($visitor.$method(// +elem$(,$($extra_args,)*)?) );}}}#[macro_export]macro_rules!walk_visitable_list{( +$visitor:expr,$list:expr$(,$($extra_args:expr ),*)?)=>{for elem in$list{$crate:: +try_visit!(elem.visit_with($visitor$(,$($extra_args,)*)?));}}}//((),());((),()); diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 80c62d3fecf49..39a07a77db9ee 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1,1727 +1,525 @@ -// Validate AST before lowering it to HIR. -// -// This pass is supposed to catch things that fit into AST data structures, -// but not permitted by the language. It runs after expansion when AST is frozen, -// so it can check for erroneous constructions produced by syntax extensions. -// This pass is supposed to perform only simple checks not requiring name resolution -// or type checking or some other kind of complex analysis. - -use itertools::{Either, Itertools}; -use rustc_ast::ptr::P; -use rustc_ast::visit::{walk_list, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor}; -use rustc_ast::*; -use rustc_ast_pretty::pprust::{self, State}; -use rustc_data_structures::fx::FxIndexMap; -use rustc_feature::Features; -use rustc_parse::validate_attr; -use rustc_session::lint::builtin::{ - DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY, -}; -use rustc_session::lint::{BuiltinLintDiag, LintBuffer}; -use rustc_session::Session; -use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::Span; -use rustc_target::spec::abi; -use std::mem; -use std::ops::{Deref, DerefMut}; -use thin_vec::thin_vec; - -use crate::errors; -use crate::fluent_generated as fluent; - -/// Is `self` allowed semantically as the first parameter in an `FnDecl`? -enum SelfSemantic { - Yes, - No, -} - -/// What is the context that prevents using `~const`? -// FIXME(effects): Consider getting rid of this in favor of `errors::TildeConstReason`, they're -// almost identical. This gets rid of an abstraction layer which might be considered bad. -enum DisallowTildeConstContext<'a> { - TraitObject, - Fn(FnKind<'a>), - Trait(Span), - TraitImpl(Span), - Impl(Span), - TraitAssocTy(Span), - TraitImplAssocTy(Span), - InherentAssocTy(Span), - Item, -} - -enum TraitOrTraitImpl<'a> { - Trait { span: Span, constness: Option }, - TraitImpl { constness: Const, polarity: ImplPolarity, trait_ref: &'a TraitRef }, -} - -impl<'a> TraitOrTraitImpl<'a> { - fn constness(&self) -> Option { - match self { - Self::Trait { constness: Some(span), .. } - | Self::TraitImpl { constness: Const::Yes(span), .. } => Some(*span), - _ => None, - } - } -} - -struct AstValidator<'a> { - session: &'a Session, - features: &'a Features, - - /// The span of the `extern` in an `extern { ... }` block, if any. - extern_mod: Option<&'a Item>, - - outer_trait_or_trait_impl: Option>, - - has_proc_macro_decls: bool, - - /// Used to ban nested `impl Trait`, e.g., `impl Into`. - /// Nested `impl Trait` _is_ allowed in associated type position, - /// e.g., `impl Iterator`. - outer_impl_trait: Option, - - disallow_tilde_const: Option>, - - /// Used to ban `impl Trait` in path projections like `::Item` - /// or `Foo::Bar` - is_impl_trait_banned: bool, - - lint_buffer: &'a mut LintBuffer, -} - -impl<'a> AstValidator<'a> { - fn with_in_trait_impl( - &mut self, - trait_: Option<(Const, ImplPolarity, &'a TraitRef)>, - f: impl FnOnce(&mut Self), - ) { - let old = mem::replace( - &mut self.outer_trait_or_trait_impl, - trait_.map(|(constness, polarity, trait_ref)| TraitOrTraitImpl::TraitImpl { - constness, - polarity, - trait_ref, - }), - ); - f(self); - self.outer_trait_or_trait_impl = old; - } - - fn with_in_trait(&mut self, span: Span, constness: Option, f: impl FnOnce(&mut Self)) { - let old = mem::replace( - &mut self.outer_trait_or_trait_impl, - Some(TraitOrTraitImpl::Trait { span, constness }), - ); - f(self); - self.outer_trait_or_trait_impl = old; - } - - fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) { - let old = mem::replace(&mut self.is_impl_trait_banned, true); - f(self); - self.is_impl_trait_banned = old; - } - - fn with_tilde_const( - &mut self, - disallowed: Option>, - f: impl FnOnce(&mut Self), - ) { - let old = mem::replace(&mut self.disallow_tilde_const, disallowed); - f(self); - self.disallow_tilde_const = old; - } - - fn check_type_alias_where_clause_location( - &mut self, - ty_alias: &TyAlias, - ) -> Result<(), errors::WhereClauseBeforeTypeAlias> { - if ty_alias.ty.is_none() || !ty_alias.where_clauses.before.has_where_token { - return Ok(()); - } - - let (before_predicates, after_predicates) = - ty_alias.generics.where_clause.predicates.split_at(ty_alias.where_clauses.split); - let span = ty_alias.where_clauses.before.span; - - let sugg = if !before_predicates.is_empty() || !ty_alias.where_clauses.after.has_where_token - { - let mut state = State::new(); - - if !ty_alias.where_clauses.after.has_where_token { - state.space(); - state.word_space("where"); - } - - let mut first = after_predicates.is_empty(); - for p in before_predicates { - if !first { - state.word_space(","); - } - first = false; - state.print_where_predicate(p); - } - - errors::WhereClauseBeforeTypeAliasSugg::Move { - left: span, - snippet: state.s.eof(), - right: ty_alias.where_clauses.after.span.shrink_to_hi(), - } - } else { - errors::WhereClauseBeforeTypeAliasSugg::Remove { span } - }; - - Err(errors::WhereClauseBeforeTypeAlias { span, sugg }) - } - - fn with_impl_trait(&mut self, outer: Option, f: impl FnOnce(&mut Self)) { - let old = mem::replace(&mut self.outer_impl_trait, outer); - f(self); - self.outer_impl_trait = old; - } - - // Mirrors `visit::walk_ty`, but tracks relevant state. - fn walk_ty(&mut self, t: &'a Ty) { - match &t.kind { - TyKind::ImplTrait(..) => { - self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t)) - } - TyKind::TraitObject(..) => self - .with_tilde_const(Some(DisallowTildeConstContext::TraitObject), |this| { - visit::walk_ty(this, t) - }), - TyKind::Path(qself, path) => { - // We allow these: - // - `Option` - // - `option::Option` - // - `option::Option::Foo` - // - // But not these: - // - `::Foo` - // - `option::Option::Foo`. - // - // To implement this, we disallow `impl Trait` from `qself` - // (for cases like `::Foo>`) - // but we allow `impl Trait` in `GenericArgs` - // iff there are no more PathSegments. - if let Some(qself) = qself { - // `impl Trait` in `qself` is always illegal - self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty)); - } - - // Note that there should be a call to visit_path here, - // so if any logic is added to process `Path`s a call to it should be - // added both in visit_path and here. This code mirrors visit::walk_path. - for (i, segment) in path.segments.iter().enumerate() { - // Allow `impl Trait` iff we're on the final path segment - if i == path.segments.len() - 1 { - self.visit_path_segment(segment); - } else { - self.with_banned_impl_trait(|this| this.visit_path_segment(segment)); - } - } - } - TyKind::AnonStruct(_, ref fields) | TyKind::AnonUnion(_, ref fields) => { - walk_list!(self, visit_struct_field_def, fields) - } - _ => visit::walk_ty(self, t), - } - } - - fn visit_struct_field_def(&mut self, field: &'a FieldDef) { - if let Some(ident) = field.ident - && ident.name == kw::Underscore - { - self.check_unnamed_field_ty(&field.ty, ident.span); - 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); - } else { - self.visit_field_def(field); - } - } - - fn dcx(&self) -> &rustc_errors::DiagCtxt { - self.session.dcx() - } - - fn check_lifetime(&self, ident: Ident) { - let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty]; - if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() { - self.dcx().emit_err(errors::KeywordLifetime { span: ident.span }); - } - } - - fn check_label(&self, ident: Ident) { - if ident.without_first_quote().is_reserved() { - self.dcx().emit_err(errors::InvalidLabel { span: ident.span, name: ident.name }); - } - } - - fn visibility_not_permitted(&self, vis: &Visibility, note: errors::VisibilityNotPermittedNote) { - if let VisibilityKind::Inherited = vis.kind { - return; - } - - self.dcx().emit_err(errors::VisibilityNotPermitted { span: vis.span, note }); - } - - fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option, bool)) { - for Param { pat, .. } in &decl.inputs { - match pat.kind { - PatKind::Ident(BindingAnnotation::NONE, _, None) | PatKind::Wild => {} - PatKind::Ident(BindingAnnotation::MUT, ident, None) => { - report_err(pat.span, Some(ident), true) - } - _ => report_err(pat.span, None, false), - } - } - } - - fn check_unnamed_field_ty(&self, ty: &Ty, span: Span) { - if matches!( - &ty.kind, - // We already checked for `kw::Underscore` before calling this function, - // so skip the check - TyKind::AnonStruct(..) | TyKind::AnonUnion(..) - // If the anonymous field contains a Path as type, we can't determine - // if the path is a valid struct or union, so skip the check - | TyKind::Path(..) - ) { - return; - } - self.dcx().emit_err(errors::InvalidUnnamedFieldTy { span, ty_span: ty.span }); - } - - fn deny_anon_struct_or_union(&self, ty: &Ty) { - let struct_or_union = match &ty.kind { - TyKind::AnonStruct(..) => "struct", - TyKind::AnonUnion(..) => "union", - _ => return, - }; - self.dcx().emit_err(errors::AnonStructOrUnionNotAllowed { struct_or_union, span: ty.span }); - } - - fn deny_unnamed_field(&self, field: &FieldDef) { - if let Some(ident) = field.ident - && ident.name == kw::Underscore - { - self.dcx() - .emit_err(errors::InvalidUnnamedField { span: field.span, ident_span: ident.span }); - } - } - - fn check_trait_fn_not_const(&self, constness: Const, parent: &TraitOrTraitImpl<'a>) { - let Const::Yes(span) = constness else { - return; - }; - - let make_impl_const_sugg = if self.features.const_trait_impl - && let TraitOrTraitImpl::TraitImpl { - constness: Const::No, - polarity: ImplPolarity::Positive, - trait_ref, - .. - } = parent - { - Some(trait_ref.path.span.shrink_to_lo()) - } else { - None - }; - - let make_trait_const_sugg = if self.features.const_trait_impl - && let TraitOrTraitImpl::Trait { span, constness: None } = parent - { - Some(span.shrink_to_lo()) - } else { - None - }; - - let parent_constness = parent.constness(); - self.dcx().emit_err(errors::TraitFnConst { - span, - in_impl: matches!(parent, TraitOrTraitImpl::TraitImpl { .. }), - const_context_label: parent_constness, - remove_const_sugg: ( - self.session.source_map().span_extend_while(span, |c| c == ' ').unwrap_or(span), - match parent_constness { - Some(_) => rustc_errors::Applicability::MachineApplicable, - None => rustc_errors::Applicability::MaybeIncorrect, - }, - ), - requires_multiple_changes: make_impl_const_sugg.is_some() - || make_trait_const_sugg.is_some(), - make_impl_const_sugg, - make_trait_const_sugg, - }); - } - - fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) { - self.check_decl_num_args(fn_decl); - self.check_decl_cvaradic_pos(fn_decl); - self.check_decl_attrs(fn_decl); - self.check_decl_self_param(fn_decl, self_semantic); - } - - /// Emits fatal error if function declaration has more than `u16::MAX` arguments - /// Error is fatal to prevent errors during typechecking - fn check_decl_num_args(&self, fn_decl: &FnDecl) { - let max_num_args: usize = u16::MAX.into(); - if fn_decl.inputs.len() > max_num_args { - let Param { span, .. } = fn_decl.inputs[0]; - self.dcx().emit_fatal(errors::FnParamTooMany { span, max_num_args }); - } - } - - fn check_decl_cvaradic_pos(&self, fn_decl: &FnDecl) { - match &*fn_decl.inputs { - [Param { ty, span, .. }] => { - if let TyKind::CVarArgs = ty.kind { - self.dcx().emit_err(errors::FnParamCVarArgsOnly { span: *span }); - } - } - [ps @ .., _] => { - for Param { ty, span, .. } in ps { - if let TyKind::CVarArgs = ty.kind { - self.dcx().emit_err(errors::FnParamCVarArgsNotLast { span: *span }); - } - } - } - _ => {} - } - } - - fn check_decl_attrs(&self, fn_decl: &FnDecl) { - fn_decl - .inputs - .iter() - .flat_map(|i| i.attrs.as_ref()) - .filter(|attr| { - let arr = [ - sym::allow, - sym::cfg, - sym::cfg_attr, - sym::deny, - sym::expect, - sym::forbid, - sym::warn, - ]; - !arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(attr) - }) - .for_each(|attr| { - if attr.is_doc_comment() { - self.dcx().emit_err(errors::FnParamDocComment { span: attr.span }); - } else { - self.dcx().emit_err(errors::FnParamForbiddenAttr { span: attr.span }); - } - }); - } - - fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) { - if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) { - if param.is_self() { - self.dcx().emit_err(errors::FnParamForbiddenSelf { span: param.span }); - } - } - } - - fn check_defaultness(&self, span: Span, defaultness: Defaultness) { - if let Defaultness::Default(def_span) = defaultness { - let span = self.session.source_map().guess_head_span(span); - self.dcx().emit_err(errors::ForbiddenDefault { span, def_span }); - } - } - - /// If `sp` ends with a semicolon, returns it as a `Span` - /// Otherwise, returns `sp.shrink_to_hi()` - fn ending_semi_or_hi(&self, sp: Span) -> Span { - let source_map = self.session.source_map(); - let end = source_map.end_point(sp); - - if source_map.span_to_snippet(end).is_ok_and(|s| s == ";") { - end - } else { - sp.shrink_to_hi() - } - } - - fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) { - let span = match bounds { - [] => return, - [b0] => b0.span(), - [b0, .., bl] => b0.span().to(bl.span()), - }; - self.dcx().emit_err(errors::BoundInContext { span, ctx }); - } - - fn check_foreign_ty_genericless( - &self, - generics: &Generics, - where_clauses: &TyAliasWhereClauses, - ) { - let cannot_have = |span, descr, remove_descr| { - self.dcx().emit_err(errors::ExternTypesCannotHave { - span, - descr, - remove_descr, - block_span: self.current_extern_span(), - }); - }; - - if !generics.params.is_empty() { - cannot_have(generics.span, "generic parameters", "generic parameters"); - } - - let check_where_clause = |where_clause: TyAliasWhereClause| { - if where_clause.has_where_token { - cannot_have(where_clause.span, "`where` clauses", "`where` clause"); - } - }; - - check_where_clause(where_clauses.before); - check_where_clause(where_clauses.after); - } - - fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option) { - let Some(body) = body else { - return; - }; - self.dcx().emit_err(errors::BodyInExtern { - span: ident.span, - body, - block: self.current_extern_span(), - kind, - }); - } - - /// An `fn` in `extern { ... }` cannot have a body `{ ... }`. - fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) { - let Some(body) = body else { - return; - }; - self.dcx().emit_err(errors::FnBodyInExtern { - span: ident.span, - body: body.span, - block: self.current_extern_span(), - }); - } - - fn current_extern_span(&self) -> Span { - self.session.source_map().guess_head_span(self.extern_mod.unwrap().span) - } - - /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`. - fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) { - if header.has_qualifiers() { - self.dcx().emit_err(errors::FnQualifierInExtern { - span: ident.span, - block: self.current_extern_span(), - sugg_span: span.until(ident.span.shrink_to_lo()), - }); - } - } - - /// An item in `extern { ... }` cannot use non-ascii identifier. - fn check_foreign_item_ascii_only(&self, ident: Ident) { - if !ident.as_str().is_ascii() { - self.dcx().emit_err(errors::ExternItemAscii { - span: ident.span, - block: self.current_extern_span(), - }); - } - } - - /// Reject invalid C-variadic types. - /// - /// C-variadics must be: - /// - Non-const - /// - Either foreign, or free and `unsafe extern "C"` semantically - fn check_c_variadic_type(&self, fk: FnKind<'a>) { - let variadic_spans: Vec<_> = fk - .decl() - .inputs - .iter() - .filter(|arg| matches!(arg.ty.kind, TyKind::CVarArgs)) - .map(|arg| arg.span) - .collect(); - - if variadic_spans.is_empty() { - return; - } - - if let Some(header) = fk.header() { - if let Const::Yes(const_span) = header.constness { - let mut spans = variadic_spans.clone(); - spans.push(const_span); - self.dcx().emit_err(errors::ConstAndCVariadic { - spans, - const_span, - variadic_spans: variadic_spans.clone(), - }); - } - } - - match (fk.ctxt(), fk.header()) { - (Some(FnCtxt::Foreign), _) => return, - (Some(FnCtxt::Free), Some(header)) => match header.ext { - Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }, _) - | Extern::Implicit(_) - if matches!(header.unsafety, Unsafe::Yes(_)) => - { - return; - } - _ => {} - }, - _ => {} - }; - - self.dcx().emit_err(errors::BadCVariadic { span: variadic_spans }); - } - - fn check_item_named(&self, ident: Ident, kind: &str) { - if ident.name != kw::Underscore { - return; - } - self.dcx().emit_err(errors::ItemUnderscore { span: ident.span, kind }); - } - - fn check_nomangle_item_asciionly(&self, ident: Ident, item_span: Span) { - if ident.name.as_str().is_ascii() { - return; - } - let span = self.session.source_map().guess_head_span(item_span); - self.dcx().emit_err(errors::NoMangleAscii { span }); - } - - fn check_mod_file_item_asciionly(&self, ident: Ident) { - if ident.name.as_str().is_ascii() { - return; - } - self.dcx().emit_err(errors::ModuleNonAscii { span: ident.span, name: ident.name }); - } - - fn deny_generic_params(&self, generics: &Generics, ident: Span) { - if !generics.params.is_empty() { - self.dcx().emit_err(errors::AutoTraitGeneric { span: generics.span, ident }); - } - } - - fn emit_e0568(&self, span: Span, ident: Span) { - self.dcx().emit_err(errors::AutoTraitBounds { span, ident }); - } - - fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) { - if let [.., last] = &bounds[..] { - let span = ident_span.shrink_to_hi().to(last.span()); - self.emit_e0568(span, ident_span); - } - } - - fn deny_where_clause(&self, where_clause: &WhereClause, ident_span: Span) { - if !where_clause.predicates.is_empty() { - self.emit_e0568(where_clause.span, ident_span); - } - } - - fn deny_items(&self, trait_items: &[P], ident: Span) { - if !trait_items.is_empty() { - let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect(); - let total = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span); - self.dcx().emit_err(errors::AutoTraitItems { spans, total, ident }); - } - } - - fn correct_generic_order_suggestion(&self, data: &AngleBracketedArgs) -> String { - // Lifetimes always come first. - let lt_sugg = data.args.iter().filter_map(|arg| match arg { - AngleBracketedArg::Arg(lt @ GenericArg::Lifetime(_)) => { - Some(pprust::to_string(|s| s.print_generic_arg(lt))) - } - _ => None, - }); - let args_sugg = data.args.iter().filter_map(|a| match a { - AngleBracketedArg::Arg(GenericArg::Lifetime(_)) | AngleBracketedArg::Constraint(_) => { - None - } - AngleBracketedArg::Arg(arg) => Some(pprust::to_string(|s| s.print_generic_arg(arg))), - }); - // Constraints always come last. - let constraint_sugg = data.args.iter().filter_map(|a| match a { - AngleBracketedArg::Arg(_) => None, - AngleBracketedArg::Constraint(c) => { - Some(pprust::to_string(|s| s.print_assoc_constraint(c))) - } - }); - format!( - "<{}>", - lt_sugg.chain(args_sugg).chain(constraint_sugg).collect::>().join(", ") - ) - } - - /// Enforce generic args coming before constraints in `<...>` of a path segment. - fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) { - // Early exit in case it's partitioned as it should be. - if data.args.iter().is_partitioned(|arg| matches!(arg, AngleBracketedArg::Arg(_))) { - return; - } - // Find all generic argument coming after the first constraint... - let (constraint_spans, arg_spans): (Vec, Vec) = - data.args.iter().partition_map(|arg| match arg { - AngleBracketedArg::Constraint(c) => Either::Left(c.span), - AngleBracketedArg::Arg(a) => Either::Right(a.span()), - }); - let args_len = arg_spans.len(); - let constraint_len = constraint_spans.len(); - // ...and then error: - self.dcx().emit_err(errors::ArgsBeforeConstraint { - arg_spans: arg_spans.clone(), - constraints: constraint_spans[0], - args: *arg_spans.iter().last().unwrap(), - data: data.span, - constraint_spans: errors::EmptyLabelManySpans(constraint_spans), - arg_spans2: errors::EmptyLabelManySpans(arg_spans), - suggestion: self.correct_generic_order_suggestion(data), - constraint_len, - args_len, - }); - } - - fn visit_ty_common(&mut self, ty: &'a Ty) { - match &ty.kind { - TyKind::BareFn(bfty) => { - self.check_fn_decl(&bfty.decl, SelfSemantic::No); - Self::check_decl_no_pat(&bfty.decl, |span, _, _| { - self.dcx().emit_err(errors::PatternFnPointer { span }); - }); - if let Extern::Implicit(_) = bfty.ext { - let sig_span = self.session.source_map().next_point(ty.span.shrink_to_lo()); - self.maybe_lint_missing_abi(sig_span, ty.id); - } - } - TyKind::TraitObject(bounds, ..) => { - let mut any_lifetime_bounds = false; - for bound in bounds { - if let GenericBound::Outlives(lifetime) = bound { - if any_lifetime_bounds { - self.dcx() - .emit_err(errors::TraitObjectBound { span: lifetime.ident.span }); - break; - } - any_lifetime_bounds = true; - } - } - } - TyKind::ImplTrait(_, bounds) => { - if self.is_impl_trait_banned { - self.dcx().emit_err(errors::ImplTraitPath { span: ty.span }); - } - - if let Some(outer_impl_trait_sp) = self.outer_impl_trait { - self.dcx().emit_err(errors::NestedImplTrait { - span: ty.span, - outer: outer_impl_trait_sp, - inner: ty.span, - }); - } - - if !bounds.iter().any(|b| matches!(b, GenericBound::Trait(..))) { - self.dcx().emit_err(errors::AtLeastOneTrait { span: ty.span }); - } - } - _ => {} - } - } - - fn maybe_lint_missing_abi(&mut self, span: Span, id: NodeId) { - // FIXME(davidtwco): This is a hack to detect macros which produce spans of the - // call site which do not have a macro backtrace. See #61963. - if self - .session - .source_map() - .span_to_snippet(span) - .is_ok_and(|snippet| !snippet.starts_with("#[")) - { - self.lint_buffer.buffer_lint_with_diagnostic( - MISSING_ABI, - id, - span, - fluent::ast_passes_extern_without_abi, - BuiltinLintDiag::MissingAbi(span, abi::Abi::FALLBACK), - ) - } - } -} - -/// Checks that generic parameters are in the correct order, -/// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`) -fn validate_generic_param_order( - dcx: &rustc_errors::DiagCtxt, - generics: &[GenericParam], - span: Span, -) { - let mut max_param: Option = None; - let mut out_of_order = FxIndexMap::default(); - let mut param_idents = Vec::with_capacity(generics.len()); - - for (idx, param) in generics.iter().enumerate() { - let ident = param.ident; - let (kind, bounds, span) = (¶m.kind, ¶m.bounds, ident.span); - let (ord_kind, ident) = match ¶m.kind { - GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident.to_string()), - GenericParamKind::Type { .. } => (ParamKindOrd::TypeOrConst, ident.to_string()), - GenericParamKind::Const { ty, .. } => { - let ty = pprust::ty_to_string(ty); - (ParamKindOrd::TypeOrConst, format!("const {ident}: {ty}")) - } - }; - param_idents.push((kind, ord_kind, bounds, idx, ident)); - match max_param { - Some(max_param) if max_param > ord_kind => { - let entry = out_of_order.entry(ord_kind).or_insert((max_param, vec![])); - entry.1.push(span); - } - Some(_) | None => max_param = Some(ord_kind), - }; - } - - if !out_of_order.is_empty() { - let mut ordered_params = "<".to_string(); - param_idents.sort_by_key(|&(_, po, _, i, _)| (po, i)); - let mut first = true; - for (kind, _, bounds, _, ident) in param_idents { - if !first { - ordered_params += ", "; - } - ordered_params += &ident; - - if !bounds.is_empty() { - ordered_params += ": "; - ordered_params += &pprust::bounds_to_string(bounds); - } - - match kind { - GenericParamKind::Type { default: Some(default) } => { - ordered_params += " = "; - ordered_params += &pprust::ty_to_string(default); - } - GenericParamKind::Type { default: None } => (), - GenericParamKind::Lifetime => (), - GenericParamKind::Const { ty: _, kw_span: _, default: Some(default) } => { - ordered_params += " = "; - ordered_params += &pprust::expr_to_string(&default.value); - } - GenericParamKind::Const { ty: _, kw_span: _, default: None } => (), - } - first = false; - } - - ordered_params += ">"; - - for (param_ord, (max_param, spans)) in &out_of_order { - dcx.emit_err(errors::OutOfOrderParams { - spans: spans.clone(), - sugg_span: span, - param_ord, - max_param, - ordered_params: &ordered_params, - }); - } - } -} - -impl<'a> Visitor<'a> for AstValidator<'a> { - fn visit_attribute(&mut self, attr: &Attribute) { - validate_attr::check_attr(&self.session.psess, attr); - } - - fn visit_ty(&mut self, ty: &'a Ty) { - self.visit_ty_common(ty); - self.deny_anon_struct_or_union(ty); - self.walk_ty(ty) - } - - fn visit_label(&mut self, label: &'a Label) { - self.check_label(label.ident); - visit::walk_label(self, label); - } - - fn visit_lifetime(&mut self, lifetime: &'a Lifetime, _: visit::LifetimeCtxt) { - self.check_lifetime(lifetime.ident); - visit::walk_lifetime(self, lifetime); - } - - fn visit_field_def(&mut self, field: &'a FieldDef) { - self.deny_unnamed_field(field); - visit::walk_field_def(self, field) - } - - fn visit_item(&mut self, item: &'a Item) { - if item.attrs.iter().any(|attr| attr.is_proc_macro_attr()) { - self.has_proc_macro_decls = true; - } - - if attr::contains_name(&item.attrs, sym::no_mangle) { - self.check_nomangle_item_asciionly(item.ident, item.span); - } - - match &item.kind { - ItemKind::Impl(box Impl { - unsafety, - polarity, - defaultness: _, - constness, - generics, - of_trait: Some(t), - self_ty, - items, - }) => { - self.with_in_trait_impl(Some((*constness, *polarity, t)), |this| { - this.visibility_not_permitted( - &item.vis, - errors::VisibilityNotPermittedNote::TraitImpl, - ); - if let TyKind::Dummy = self_ty.kind { - // Abort immediately otherwise the `TyKind::Dummy` will reach HIR lowering, - // which isn't allowed. Not a problem for this obscure, obsolete syntax. - this.dcx().emit_fatal(errors::ObsoleteAuto { span: item.span }); - } - if let (&Unsafe::Yes(span), &ImplPolarity::Negative(sp)) = (unsafety, polarity) - { - this.dcx().emit_err(errors::UnsafeNegativeImpl { - span: sp.to(t.path.span), - negative: sp, - r#unsafe: span, - }); - } - - this.visit_vis(&item.vis); - this.visit_ident(item.ident); - let disallowed = matches!(constness, Const::No) - .then(|| DisallowTildeConstContext::TraitImpl(item.span)); - this.with_tilde_const(disallowed, |this| this.visit_generics(generics)); - this.visit_trait_ref(t); - this.visit_ty(self_ty); - - walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl); - }); - walk_list!(self, visit_attribute, &item.attrs); - return; // Avoid visiting again. - } - ItemKind::Impl(box Impl { - unsafety, - polarity, - defaultness, - constness, - generics, - of_trait: None, - self_ty, - items, - }) => { - let error = - |annotation_span, annotation, only_trait: bool| errors::InherentImplCannot { - span: self_ty.span, - annotation_span, - annotation, - self_ty: self_ty.span, - only_trait: only_trait.then_some(()), - }; - - self.with_in_trait_impl(None, |this| { - this.visibility_not_permitted( - &item.vis, - errors::VisibilityNotPermittedNote::IndividualImplItems, - ); - if let &Unsafe::Yes(span) = unsafety { - this.dcx().emit_err(errors::InherentImplCannotUnsafe { - span: self_ty.span, - annotation_span: span, - annotation: "unsafe", - self_ty: self_ty.span, - }); - } - if let &ImplPolarity::Negative(span) = polarity { - this.dcx().emit_err(error(span, "negative", false)); - } - if let &Defaultness::Default(def_span) = defaultness { - this.dcx().emit_err(error(def_span, "`default`", true)); - } - if let &Const::Yes(span) = constness { - this.dcx().emit_err(error(span, "`const`", true)); - } - - this.visit_vis(&item.vis); - this.visit_ident(item.ident); - this.with_tilde_const( - Some(DisallowTildeConstContext::Impl(item.span)), - |this| this.visit_generics(generics), - ); - this.visit_ty(self_ty); - walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl); - }); - walk_list!(self, visit_attribute, &item.attrs); - return; // Avoid visiting again. - } - ItemKind::Fn(box Fn { defaultness, sig, generics, body }) => { - self.check_defaultness(item.span, *defaultness); - - if body.is_none() { - self.dcx().emit_err(errors::FnWithoutBody { - span: item.span, - replace_span: self.ending_semi_or_hi(item.span), - extern_block_suggestion: match sig.header.ext { - Extern::None => None, - Extern::Implicit(start_span) => { - Some(errors::ExternBlockSuggestion::Implicit { - start_span, - end_span: item.span.shrink_to_hi(), - }) - } - Extern::Explicit(abi, start_span) => { - Some(errors::ExternBlockSuggestion::Explicit { - start_span, - end_span: item.span.shrink_to_hi(), - abi: abi.symbol_unescaped, - }) - } - }, - }); - } - - self.visit_vis(&item.vis); - self.visit_ident(item.ident); - let kind = - FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref()); - self.visit_fn(kind, item.span, item.id); - walk_list!(self, visit_attribute, &item.attrs); - return; // Avoid visiting again. - } - ItemKind::ForeignMod(ForeignMod { abi, unsafety, .. }) => { - let old_item = mem::replace(&mut self.extern_mod, Some(item)); - self.visibility_not_permitted( - &item.vis, - errors::VisibilityNotPermittedNote::IndividualForeignItems, - ); - if let &Unsafe::Yes(span) = unsafety { - self.dcx().emit_err(errors::UnsafeItem { span, kind: "extern block" }); - } - if abi.is_none() { - self.maybe_lint_missing_abi(item.span, item.id); - } - visit::walk_item(self, item); - self.extern_mod = old_item; - return; // Avoid visiting again. - } - ItemKind::Enum(def, _) => { - for variant in &def.variants { - self.visibility_not_permitted( - &variant.vis, - errors::VisibilityNotPermittedNote::EnumVariant, - ); - for field in variant.data.fields() { - self.visibility_not_permitted( - &field.vis, - errors::VisibilityNotPermittedNote::EnumVariant, - ); - } - } - } - ItemKind::Trait(box Trait { is_auto, generics, bounds, items, .. }) => { - let is_const_trait = - attr::find_by_name(&item.attrs, sym::const_trait).map(|attr| attr.span); - self.with_in_trait(item.span, is_const_trait, |this| { - if *is_auto == IsAuto::Yes { - // Auto traits cannot have generics, super traits nor contain items. - this.deny_generic_params(generics, item.ident.span); - this.deny_super_traits(bounds, item.ident.span); - this.deny_where_clause(&generics.where_clause, item.ident.span); - this.deny_items(items, item.ident.span); - } - - // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound - // context for the supertraits. - this.visit_vis(&item.vis); - this.visit_ident(item.ident); - let disallowed = is_const_trait - .is_none() - .then(|| DisallowTildeConstContext::Trait(item.span)); - this.with_tilde_const(disallowed, |this| { - this.visit_generics(generics); - walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits) - }); - walk_list!(this, visit_assoc_item, items, AssocCtxt::Trait); - }); - walk_list!(self, visit_attribute, &item.attrs); - return; // Avoid visiting again - } - ItemKind::Mod(unsafety, mod_kind) => { - if let &Unsafe::Yes(span) = unsafety { - self.dcx().emit_err(errors::UnsafeItem { span, kind: "module" }); - } - // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584). - if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _)) - && !attr::contains_name(&item.attrs, sym::path) - { - self.check_mod_file_item_asciionly(item.ident); - } - } - ItemKind::Struct(vdata, generics) => match vdata { - VariantData::Struct { fields, .. } => { - self.visit_vis(&item.vis); - self.visit_ident(item.ident); - self.visit_generics(generics); - // Permit `Anon{Struct,Union}` as field type. - walk_list!(self, visit_struct_field_def, fields); - walk_list!(self, visit_attribute, &item.attrs); - return; - } - _ => {} - }, - ItemKind::Union(vdata, generics) => { - if vdata.fields().is_empty() { - self.dcx().emit_err(errors::FieldlessUnion { span: item.span }); - } - match vdata { - VariantData::Struct { fields, .. } => { - self.visit_vis(&item.vis); - self.visit_ident(item.ident); - self.visit_generics(generics); - // Permit `Anon{Struct,Union}` as field type. - walk_list!(self, visit_struct_field_def, fields); - walk_list!(self, visit_attribute, &item.attrs); - return; - } - _ => {} - } - } - ItemKind::Const(box ConstItem { defaultness, expr, .. }) => { - self.check_defaultness(item.span, *defaultness); - if expr.is_none() { - self.dcx().emit_err(errors::ConstWithoutBody { - span: item.span, - replace_span: self.ending_semi_or_hi(item.span), - }); - } - } - ItemKind::Static(box StaticItem { expr: None, .. }) => { - self.dcx().emit_err(errors::StaticWithoutBody { - span: item.span, - replace_span: self.ending_semi_or_hi(item.span), - }); - } - ItemKind::TyAlias( - ty_alias @ box TyAlias { defaultness, bounds, where_clauses, ty, .. }, - ) => { - self.check_defaultness(item.span, *defaultness); - if ty.is_none() { - self.dcx().emit_err(errors::TyAliasWithoutBody { - span: item.span, - replace_span: self.ending_semi_or_hi(item.span), - }); - } - self.check_type_no_bounds(bounds, "this context"); - - if self.features.lazy_type_alias { - if let Err(err) = self.check_type_alias_where_clause_location(ty_alias) { - self.dcx().emit_err(err); - } - } else if where_clauses.after.has_where_token { - self.dcx().emit_err(errors::WhereClauseAfterTypeAlias { - span: where_clauses.after.span, - help: self.session.is_nightly_build().then_some(()), - }); - } - } - _ => {} - } - - visit::walk_item(self, item); - } - - fn visit_foreign_item(&mut self, fi: &'a ForeignItem) { - match &fi.kind { - ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => { - self.check_defaultness(fi.span, *defaultness); - self.check_foreign_fn_bodyless(fi.ident, body.as_deref()); - self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header); - self.check_foreign_item_ascii_only(fi.ident); - } - ForeignItemKind::TyAlias(box TyAlias { - defaultness, - generics, - where_clauses, - bounds, - ty, - .. - }) => { - self.check_defaultness(fi.span, *defaultness); - self.check_foreign_kind_bodyless(fi.ident, "type", ty.as_ref().map(|b| b.span)); - self.check_type_no_bounds(bounds, "`extern` blocks"); - self.check_foreign_ty_genericless(generics, where_clauses); - self.check_foreign_item_ascii_only(fi.ident); - } - ForeignItemKind::Static(_, _, body) => { - self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span)); - self.check_foreign_item_ascii_only(fi.ident); - } - ForeignItemKind::MacCall(..) => {} - } - - visit::walk_foreign_item(self, fi) - } - - // Mirrors `visit::walk_generic_args`, but tracks relevant state. - fn visit_generic_args(&mut self, generic_args: &'a GenericArgs) { - match generic_args { - GenericArgs::AngleBracketed(data) => { - self.check_generic_args_before_constraints(data); - - for arg in &data.args { - match arg { - AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg), - // Type bindings such as `Item = impl Debug` in `Iterator` - // are allowed to contain nested `impl Trait`. - AngleBracketedArg::Constraint(constraint) => { - self.with_impl_trait(None, |this| { - this.visit_assoc_constraint(constraint); - }); - } - } - } - } - GenericArgs::Parenthesized(data) => { - walk_list!(self, visit_ty, &data.inputs); - if let FnRetTy::Ty(ty) = &data.output { - // `-> Foo` syntax is essentially an associated type binding, - // so it is also allowed to contain nested `impl Trait`. - self.with_impl_trait(None, |this| this.visit_ty(ty)); - } - } - } - } - - fn visit_generics(&mut self, generics: &'a Generics) { - let mut prev_param_default = None; - for param in &generics.params { - match param.kind { - GenericParamKind::Lifetime => (), - GenericParamKind::Type { default: Some(_), .. } - | GenericParamKind::Const { default: Some(_), .. } => { - prev_param_default = Some(param.ident.span); - } - GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { - if let Some(span) = prev_param_default { - self.dcx().emit_err(errors::GenericDefaultTrailing { span }); - break; - } - } - } - } - - validate_generic_param_order(self.dcx(), &generics.params, generics.span); - - for predicate in &generics.where_clause.predicates { - if let WherePredicate::EqPredicate(predicate) = predicate { - deny_equality_constraints(self, predicate, generics); - } - } - walk_list!(self, visit_generic_param, &generics.params); - for predicate in &generics.where_clause.predicates { - match predicate { - WherePredicate::BoundPredicate(bound_pred) => { - // This is slightly complicated. Our representation for poly-trait-refs contains a single - // binder and thus we only allow a single level of quantification. However, - // the syntax of Rust permits quantification in two places in where clauses, - // e.g., `T: for <'a> Foo<'a>` and `for <'a, 'b> &'b T: Foo<'a>`. If both are - // defined, then error. - if !bound_pred.bound_generic_params.is_empty() { - for bound in &bound_pred.bounds { - match bound { - GenericBound::Trait(t, _) => { - if !t.bound_generic_params.is_empty() { - self.dcx() - .emit_err(errors::NestedLifetimes { span: t.span }); - } - } - GenericBound::Outlives(_) => {} - } - } - } - } - _ => {} - } - self.visit_where_predicate(predicate); - } - } - - fn visit_generic_param(&mut self, param: &'a GenericParam) { - if let GenericParamKind::Lifetime { .. } = param.kind { - self.check_lifetime(param.ident); - } - visit::walk_generic_param(self, param); - } - - fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) { - if let GenericBound::Trait(poly, modifiers) = bound { - match (ctxt, modifiers.constness, modifiers.polarity) { - (BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) => { - self.dcx().emit_err(errors::OptionalTraitSupertrait { - span: poly.span, - path_str: pprust::path_to_string(&poly.trait_ref.path), - }); - } - (BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) => { - self.dcx().emit_err(errors::OptionalTraitObject { span: poly.span }); - } - (BoundKind::TraitObject, BoundConstness::Always(_), BoundPolarity::Positive) => { - self.dcx().emit_err(errors::ConstBoundTraitObject { span: poly.span }); - } - (_, BoundConstness::Maybe(span), BoundPolarity::Positive) - if let Some(reason) = &self.disallow_tilde_const => - { - let reason = match reason { - DisallowTildeConstContext::Fn(FnKind::Closure(..)) => { - errors::TildeConstReason::Closure - } - DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => { - errors::TildeConstReason::Function { ident: ident.span } - } - &DisallowTildeConstContext::Trait(span) => { - errors::TildeConstReason::Trait { span } - } - &DisallowTildeConstContext::TraitImpl(span) => { - errors::TildeConstReason::TraitImpl { span } - } - &DisallowTildeConstContext::Impl(span) => { - // FIXME(effects): Consider providing a help message or even a structured - // suggestion for moving such bounds to the assoc const fns if available. - errors::TildeConstReason::Impl { span } - } - &DisallowTildeConstContext::TraitAssocTy(span) => { - errors::TildeConstReason::TraitAssocTy { span } - } - &DisallowTildeConstContext::TraitImplAssocTy(span) => { - errors::TildeConstReason::TraitImplAssocTy { span } - } - &DisallowTildeConstContext::InherentAssocTy(span) => { - errors::TildeConstReason::InherentAssocTy { span } - } - DisallowTildeConstContext::TraitObject => { - errors::TildeConstReason::TraitObject - } - DisallowTildeConstContext::Item => errors::TildeConstReason::Item, - }; - self.dcx().emit_err(errors::TildeConstDisallowed { span, reason }); - } - ( - _, - BoundConstness::Always(_) | BoundConstness::Maybe(_), - BoundPolarity::Negative(_) | BoundPolarity::Maybe(_), - ) => { - self.dcx().emit_err(errors::IncompatibleTraitBoundModifiers { - span: bound.span(), - left: modifiers.constness.as_str(), - right: modifiers.polarity.as_str(), - }); - } - _ => {} - } - } - - // Negative trait bounds are not allowed to have associated constraints - if let GenericBound::Trait(trait_ref, modifiers) = bound - && let BoundPolarity::Negative(_) = modifiers.polarity - && let Some(segment) = trait_ref.trait_ref.path.segments.last() - { - match segment.args.as_deref() { - Some(ast::GenericArgs::AngleBracketed(args)) => { - for arg in &args.args { - if let ast::AngleBracketedArg::Constraint(constraint) = arg { - self.dcx().emit_err(errors::ConstraintOnNegativeBound { - span: constraint.span, - }); - } - } - } - // The lowered form of parenthesized generic args contains a type binding. - Some(ast::GenericArgs::Parenthesized(args)) => { - self.dcx().emit_err(errors::NegativeBoundWithParentheticalNotation { - span: args.span, - }); - } - None => {} - } - } - - visit::walk_param_bound(self, bound) - } - - fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) { - // Only associated `fn`s can have `self` parameters. - let self_semantic = match fk.ctxt() { - Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes, - _ => SelfSemantic::No, - }; - self.check_fn_decl(fk.decl(), self_semantic); - - self.check_c_variadic_type(fk); - - // Functions cannot both be `const async` or `const gen` - if let Some(&FnHeader { - constness: Const::Yes(cspan), - coroutine_kind: Some(coroutine_kind), - .. - }) = fk.header() - { - let aspan = match coroutine_kind { - CoroutineKind::Async { span: aspan, .. } - | CoroutineKind::Gen { span: aspan, .. } - | CoroutineKind::AsyncGen { span: aspan, .. } => aspan, - }; - // FIXME(gen_blocks): Report a different error for `const gen` - self.dcx().emit_err(errors::ConstAndAsync { - spans: vec![cspan, aspan], - cspan, - aspan, - span, - }); - } - - if let FnKind::Fn( - _, - _, - FnSig { span: sig_span, header: FnHeader { ext: Extern::Implicit(_), .. }, .. }, - _, - _, - _, - ) = fk - { - self.maybe_lint_missing_abi(*sig_span, id); - } - - // Functions without bodies cannot have patterns. - if let FnKind::Fn(ctxt, _, sig, _, _, None) = fk { - Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| { - if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) { - if let Some(ident) = ident { - let msg = match ctxt { - FnCtxt::Foreign => fluent::ast_passes_pattern_in_foreign, - _ => fluent::ast_passes_pattern_in_bodiless, - }; - let diag = BuiltinLintDiag::PatternsInFnsWithoutBody(span, ident); - self.lint_buffer.buffer_lint_with_diagnostic( - PATTERNS_IN_FNS_WITHOUT_BODY, - id, - span, - msg, - diag, - ) - } - } else { - match ctxt { - FnCtxt::Foreign => self.dcx().emit_err(errors::PatternInForeign { span }), - _ => self.dcx().emit_err(errors::PatternInBodiless { span }), - }; - } - }); - } - - let tilde_const_allowed = - matches!(fk.header(), Some(FnHeader { constness: ast::Const::Yes(_), .. })) - || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_))) - && self - .outer_trait_or_trait_impl - .as_ref() - .and_then(TraitOrTraitImpl::constness) - .is_some(); - - 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) { - if attr::contains_name(&item.attrs, sym::no_mangle) { - self.check_nomangle_item_asciionly(item.ident, item.span); - } - - if ctxt == AssocCtxt::Trait || self.outer_trait_or_trait_impl.is_none() { - self.check_defaultness(item.span, item.kind.defaultness()); - } - - if ctxt == AssocCtxt::Impl { - match &item.kind { - AssocItemKind::Const(box ConstItem { expr: None, .. }) => { - self.dcx().emit_err(errors::AssocConstWithoutBody { - span: item.span, - replace_span: self.ending_semi_or_hi(item.span), - }); - } - AssocItemKind::Fn(box Fn { body, .. }) => { - if body.is_none() { - self.dcx().emit_err(errors::AssocFnWithoutBody { - span: item.span, - replace_span: self.ending_semi_or_hi(item.span), - }); - } - } - AssocItemKind::Type(box TyAlias { bounds, ty, .. }) => { - if ty.is_none() { - self.dcx().emit_err(errors::AssocTypeWithoutBody { - span: item.span, - replace_span: self.ending_semi_or_hi(item.span), - }); - } - self.check_type_no_bounds(bounds, "`impl`s"); - } - _ => {} - } - } - - if let AssocItemKind::Type(ty_alias) = &item.kind - && let Err(err) = self.check_type_alias_where_clause_location(ty_alias) - { - let sugg = match err.sugg { - errors::WhereClauseBeforeTypeAliasSugg::Remove { .. } => None, - errors::WhereClauseBeforeTypeAliasSugg::Move { snippet, right, .. } => { - Some((right, snippet)) - } - }; - self.lint_buffer.buffer_lint_with_diagnostic( - DEPRECATED_WHERE_CLAUSE_LOCATION, - item.id, - err.span, - fluent::ast_passes_deprecated_where_clause_location, - BuiltinLintDiag::DeprecatedWhereclauseLocation(sugg), - ); - } - - if let Some(parent) = &self.outer_trait_or_trait_impl { - self.visibility_not_permitted(&item.vis, errors::VisibilityNotPermittedNote::TraitImpl); - if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind { - self.check_trait_fn_not_const(sig.header.constness, parent); - } - } - - if let AssocItemKind::Const(..) = item.kind { - self.check_item_named(item.ident, "const"); - } - - let parent_is_const = - self.outer_trait_or_trait_impl.as_ref().and_then(TraitOrTraitImpl::constness).is_some(); - - match &item.kind { - AssocItemKind::Fn(box Fn { sig, generics, body, .. }) - if parent_is_const - || ctxt == AssocCtxt::Trait - || matches!(sig.header.constness, Const::Yes(_)) => - { - self.visit_vis(&item.vis); - self.visit_ident(item.ident); - let kind = FnKind::Fn( - FnCtxt::Assoc(ctxt), - item.ident, - sig, - &item.vis, - generics, - body.as_deref(), - ); - walk_list!(self, visit_attribute, &item.attrs); - self.visit_fn(kind, item.span, item.id); - } - AssocItemKind::Type(_) => { - let disallowed = (!parent_is_const).then(|| match self.outer_trait_or_trait_impl { - Some(TraitOrTraitImpl::Trait { .. }) => { - DisallowTildeConstContext::TraitAssocTy(item.span) - } - Some(TraitOrTraitImpl::TraitImpl { .. }) => { - DisallowTildeConstContext::TraitImplAssocTy(item.span) - } - None => DisallowTildeConstContext::InherentAssocTy(item.span), - }); - self.with_tilde_const(disallowed, |this| { - this.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt)) - }) - } - _ => self.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt)), - } - } -} - -/// When encountering an equality constraint in a `where` clause, emit an error. If the code seems -/// like it's setting an associated type, provide an appropriate suggestion. -fn deny_equality_constraints( - this: &AstValidator<'_>, - predicate: &WhereEqPredicate, - generics: &Generics, -) { - let mut err = errors::EqualityInWhere { span: predicate.span, assoc: None, assoc2: None }; - - // Given `::Bar = RhsTy`, suggest `A: Foo`. - if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind - && let TyKind::Path(None, path) = &qself.ty.kind - && let [PathSegment { ident, args: None, .. }] = &path.segments[..] - { - for param in &generics.params { - if param.ident == *ident - && let [PathSegment { ident, args, .. }] = &full_path.segments[qself.position..] - { - // Make a new `Path` from `foo::Bar` to `Foo`. - let mut assoc_path = full_path.clone(); - // Remove `Bar` from `Foo::Bar`. - assoc_path.segments.pop(); - let len = assoc_path.segments.len() - 1; - let gen_args = args.as_deref().cloned(); - // Build ``. - let arg = AngleBracketedArg::Constraint(AssocConstraint { - id: rustc_ast::node_id::DUMMY_NODE_ID, - ident: *ident, - gen_args, - kind: AssocConstraintKind::Equality { term: predicate.rhs_ty.clone().into() }, - span: ident.span, - }); - // Add `` to `Foo`. - match &mut assoc_path.segments[len].args { - Some(args) => match args.deref_mut() { - GenericArgs::Parenthesized(_) => continue, - GenericArgs::AngleBracketed(args) => { - args.args.push(arg); - } - }, - empty_args => { - *empty_args = Some( - AngleBracketedArgs { span: ident.span, args: thin_vec![arg] }.into(), - ); - } - } - err.assoc = Some(errors::AssociatedSuggestion { - span: predicate.span, - ident: *ident, - param: param.ident, - path: pprust::path_to_string(&assoc_path), - }) - } - } - } - - let mut suggest = - |poly: &PolyTraitRef, potential_assoc: &PathSegment, predicate: &WhereEqPredicate| { - if let [trait_segment] = &poly.trait_ref.path.segments[..] { - let assoc = pprust::path_to_string(&ast::Path::from_ident(potential_assoc.ident)); - let ty = pprust::ty_to_string(&predicate.rhs_ty); - let (args, span) = match &trait_segment.args { - Some(args) => match args.deref() { - ast::GenericArgs::AngleBracketed(args) => { - let Some(arg) = args.args.last() else { - return; - }; - (format!(", {assoc} = {ty}"), arg.span().shrink_to_hi()) - } - _ => return, - }, - None => (format!("<{assoc} = {ty}>"), trait_segment.span().shrink_to_hi()), - }; - let removal_span = if generics.where_clause.predicates.len() == 1 { - // We're removing th eonly where bound left, remove the whole thing. - generics.where_clause.span - } else { - let mut span = predicate.span; - let mut prev: Option = None; - let mut preds = generics.where_clause.predicates.iter().peekable(); - // Find the predicate that shouldn't have been in the where bound list. - while let Some(pred) = preds.next() { - if let WherePredicate::EqPredicate(pred) = pred - && pred.span == predicate.span - { - if let Some(next) = preds.peek() { - // This is the first predicate, remove the trailing comma as well. - span = span.with_hi(next.span().lo()); - } else if let Some(prev) = prev { - // Remove the previous comma as well. - span = span.with_lo(prev.hi()); - } - } - prev = Some(pred.span()); - } - span - }; - err.assoc2 = Some(errors::AssociatedSuggestion2 { - span, - args, - predicate: removal_span, - trait_segment: trait_segment.ident, - potential_assoc: potential_assoc.ident, - }); - } - }; - - if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind { - // Given `A: Foo, Foo::Bar = RhsTy`, suggest `A: Foo`. - for bounds in generics.params.iter().map(|p| &p.bounds).chain( - generics.where_clause.predicates.iter().filter_map(|pred| match pred { - WherePredicate::BoundPredicate(p) => Some(&p.bounds), - _ => None, - }), - ) { - for bound in bounds { - if let GenericBound::Trait(poly, TraitBoundModifiers::NONE) = bound { - if full_path.segments[..full_path.segments.len() - 1] - .iter() - .map(|segment| segment.ident.name) - .zip(poly.trait_ref.path.segments.iter().map(|segment| segment.ident.name)) - .all(|(a, b)| a == b) - && let Some(potential_assoc) = full_path.segments.iter().last() - { - suggest(poly, potential_assoc, predicate); - } - } - } - } - // Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo`. - if let [potential_param, potential_assoc] = &full_path.segments[..] { - for (ident, bounds) in generics.params.iter().map(|p| (p.ident, &p.bounds)).chain( - generics.where_clause.predicates.iter().filter_map(|pred| match pred { - WherePredicate::BoundPredicate(p) - if let ast::TyKind::Path(None, path) = &p.bounded_ty.kind - && let [segment] = &path.segments[..] => - { - Some((segment.ident, &p.bounds)) - } - _ => None, - }), - ) { - if ident == potential_param.ident { - for bound in bounds { - if let ast::GenericBound::Trait(poly, TraitBoundModifiers::NONE) = bound { - suggest(poly, potential_assoc, predicate); - } - } - } - } - } - } - this.dcx().emit_err(err); -} - -pub fn check_crate( - session: &Session, - features: &Features, - krate: &Crate, - lints: &mut LintBuffer, -) -> bool { - let mut validator = AstValidator { - session, - features, - extern_mod: None, - outer_trait_or_trait_impl: None, - has_proc_macro_decls: false, - outer_impl_trait: None, - disallow_tilde_const: Some(DisallowTildeConstContext::Item), - is_impl_trait_banned: false, - lint_buffer: lints, - }; - visit::walk_crate(&mut validator, krate); - - validator.has_proc_macro_decls -} +use itertools::{Either,Itertools};use rustc_ast::ptr::P;use rustc_ast::visit::{ +walk_list,AssocCtxt,BoundKind,FnCtxt,FnKind,Visitor};use rustc_ast::*;use//({}); +rustc_ast_pretty::pprust::{self,State};use rustc_data_structures::fx:://((),()); +FxIndexMap;use rustc_feature::Features;use rustc_parse::validate_attr;use//({}); +rustc_session::lint::builtin::{DEPRECATED_WHERE_CLAUSE_LOCATION,MISSING_ABI,//3; +PATTERNS_IN_FNS_WITHOUT_BODY,};use rustc_session::lint::{BuiltinLintDiag,//({}); +LintBuffer};use rustc_session::Session;use rustc_span::symbol::{kw,sym,Ident};// +use rustc_span::Span;use rustc_target::spec::abi;use std::mem;use std::ops::{//; +Deref,DerefMut};use thin_vec::thin_vec;use crate::errors;use crate:://if true{}; +fluent_generated as fluent;enum SelfSemantic{Yes,No,}enum//if true{};let _=||(); +DisallowTildeConstContext<'a>{TraitObject,Fn(FnKind< 'a>),Trait(Span),TraitImpl( +Span),Impl(Span),TraitAssocTy( Span),TraitImplAssocTy(Span),InherentAssocTy(Span +),Item,}enum TraitOrTraitImpl<'a>{Trait{span:Span,constness:Option},//{;}; +TraitImpl{constness:Const,polarity:ImplPolarity,trait_ref:&'a TraitRef},}implTraitOrTraitImpl<'a>{fn constness(&self)->Option{match self{Self:://(); +Trait{constness:Some(span),..}|Self:: TraitImpl{constness:Const::Yes(span),..}=> +Some(*span),_=>None,}}}struct AstValidator<'a>{session:&'a Session,features:&'a +Features,extern_mod:Option<&'a Item>,outer_trait_or_trait_impl:Option>,has_proc_macro_decls:bool,outer_impl_trait:Option,// +disallow_tilde_const:Option>,is_impl_trait_banned +:bool,lint_buffer:&'a mut LintBuffer,}impl<'a>AstValidator<'a>{fn//loop{break;}; +with_in_trait_impl(&mut self,trait_:Option<( Const,ImplPolarity,&'a TraitRef)>,f +:impl FnOnce(&mut Self),){let _=||();loop{break};let old=mem::replace(&mut self. +outer_trait_or_trait_impl,trait_.map(|(constness,polarity,trait_ref)|//let _=(); +TraitOrTraitImpl::TraitImpl{constness,polarity,trait_ref,}),);3;;f(self);;;self. +outer_trait_or_trait_impl=old;3;}fn with_in_trait(&mut self,span:Span,constness: +Option,f:impl FnOnce(&mut Self)){if true{};let old=mem::replace(&mut self. +outer_trait_or_trait_impl,Some(TraitOrTraitImpl::Trait{span,constness}),);3;3;f( +self);;self.outer_trait_or_trait_impl=old;}fn with_banned_impl_trait(&mut self,f +:impl FnOnce(&mut Self)){();let old=mem::replace(&mut self.is_impl_trait_banned, +true);;;f(self);;;self.is_impl_trait_banned=old;;}fn with_tilde_const(&mut self, +disallowed:Option>,f:impl FnOnce(&mut Self),){;let +old=mem::replace(&mut self.disallow_tilde_const,disallowed);3;3;f(self);3;;self. +disallow_tilde_const=old;3;}fn check_type_alias_where_clause_location(&mut self, +ty_alias:&TyAlias,)->Result<() ,errors::WhereClauseBeforeTypeAlias>{if ty_alias. +ty.is_none()||!ty_alias.where_clauses.before.has_where_token{;return Ok(());}let +(before_predicates,after_predicates)= ty_alias.generics.where_clause.predicates. +split_at(ty_alias.where_clauses.split);;;let span=ty_alias.where_clauses.before. +span;3;;let sugg=if!before_predicates.is_empty()||!ty_alias.where_clauses.after. +has_where_token{();let mut state=State::new();3;if!ty_alias.where_clauses.after. +has_where_token{3;state.space();3;3;state.word_space("where");3;};let mut first= +after_predicates.is_empty();({});for p in before_predicates{if!first{({});state. +word_space(",");();}3;first=false;3;3;state.print_where_predicate(p);3;}errors:: +WhereClauseBeforeTypeAliasSugg::Move{left:span,snippet:(( state.s.eof())),right: +ty_alias.where_clauses.after.span.shrink_to_hi(),}}else{errors:://if let _=(){}; +WhereClauseBeforeTypeAliasSugg::Remove{span}};let _=||();let _=||();Err(errors:: +WhereClauseBeforeTypeAlias{span,sugg})}fn with_impl_trait(&mut self,outer://{;}; +Option,f:impl FnOnce(&mut Self)){if true{};let old=mem::replace(&mut self. +outer_impl_trait,outer);;f(self);self.outer_impl_trait=old;}fn walk_ty(&mut self +,t:&'a Ty){match((&t.kind)){TyKind::ImplTrait(..)=>{self.with_impl_trait(Some(t. +span),((((|this|(((visit::walk_ty(this,t)))))))))}TyKind::TraitObject(..)=>self. +with_tilde_const(((Some(DisallowTildeConstContext::TraitObject))),|this|{visit:: +walk_ty(this,t)}),TyKind::Path(qself,path)=>{if let Some(qself)=qself{({});self. +with_banned_impl_trait(|this|this.visit_ty(&qself.ty));3;}for(i,segment)in path. +segments.iter().enumerate(){if i==path.segments.len()-1{;self.visit_path_segment +(segment);();}else{();self.with_banned_impl_trait(|this|this.visit_path_segment( +segment));;}}}TyKind::AnonStruct(_,ref fields)|TyKind::AnonUnion(_,ref fields)=> +{(walk_list!(self,visit_struct_field_def,fields))}_=>visit::walk_ty(self,t),}}fn +visit_struct_field_def(&mut self,field:&'a FieldDef){if let Some(ident)=field.// +ident&&ident.name==kw::Underscore{3;self.check_unnamed_field_ty(&field.ty,ident. +span);;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) +;3;}else{;self.visit_field_def(field);;}}fn dcx(&self)->&rustc_errors::DiagCtxt{ +self.session.dcx()}fn check_lifetime(&self,ident:Ident){();let valid_names=[kw:: +UnderscoreLifetime,kw::StaticLifetime,kw::Empty];;if!valid_names.contains(&ident +.name)&&ident.without_first_quote().is_reserved(){3;self.dcx().emit_err(errors:: +KeywordLifetime{span:ident.span});;}}fn check_label(&self,ident:Ident){if ident. +without_first_quote().is_reserved(){();self.dcx().emit_err(errors::InvalidLabel{ +span:ident.span,name:ident.name});({});}}fn visibility_not_permitted(&self,vis:& +Visibility,note:errors::VisibilityNotPermittedNote){if let VisibilityKind:://(); +Inherited=vis.kind{;return;;}self.dcx().emit_err(errors::VisibilityNotPermitted{ +span:vis.span,note});({});}fn check_decl_no_pat(decl:&FnDecl,mut report_err:impl +FnMut(Span,Option,bool)){for Param{ pat,..}in&decl.inputs{match pat.kind{ +PatKind::Ident(BindingAnnotation::NONE,_,None )|PatKind::Wild=>{}PatKind::Ident( +BindingAnnotation::MUT,ident,None)=>{(report_err(pat.span,Some(ident),true))}_=> +report_err(pat.span,None,false),} }}fn check_unnamed_field_ty(&self,ty:&Ty,span: +Span){if matches!(&ty.kind,TyKind::AnonStruct(..)|TyKind::AnonUnion(..)|TyKind// +::Path(..)){3;return;3;};self.dcx().emit_err(errors::InvalidUnnamedFieldTy{span, +ty_span:ty.span});((),());}fn deny_anon_struct_or_union(&self,ty:&Ty){*&*&();let +struct_or_union=match((&ty.kind)){TyKind ::AnonStruct(..)=>(("struct")),TyKind:: +AnonUnion(..)=>"union",_=>return,};let _=();((),());self.dcx().emit_err(errors:: +AnonStructOrUnionNotAllowed{struct_or_union,span:ty.span});let _=();let _=();}fn +deny_unnamed_field(&self,field:&FieldDef){if let Some(ident)=field.ident&&ident +.name==kw::Underscore{({});self.dcx().emit_err(errors::InvalidUnnamedField{span: +field.span,ident_span:ident.span});let _=();}}fn check_trait_fn_not_const(&self, +constness:Const,parent:&TraitOrTraitImpl<'a>){{;};let Const::Yes(span)=constness +else{;return;;};;let make_impl_const_sugg=if self.features.const_trait_impl&&let +TraitOrTraitImpl::TraitImpl{constness:Const ::No,polarity:ImplPolarity::Positive +,trait_ref,..}=parent{Some(trait_ref.path.span.shrink_to_lo())}else{None};3;;let +make_trait_const_sugg=if self. features.const_trait_impl&&let TraitOrTraitImpl:: +Trait{span,constness:None}=parent{Some(span.shrink_to_lo())}else{None};();();let +parent_constness=parent.constness();3;;self.dcx().emit_err(errors::TraitFnConst{ +span,in_impl:(((((((((matches!(parent,TraitOrTraitImpl::TraitImpl{..})))))))))), +const_context_label:parent_constness,remove_const_sugg:( self.session.source_map +().span_extend_while(span,(|c|(c==' '))).unwrap_or(span),match parent_constness{ +Some(_)=>rustc_errors::Applicability::MachineApplicable,None=>rustc_errors:://3; +Applicability::MaybeIncorrect,},),requires_multiple_changes://let _=();let _=(); +make_impl_const_sugg.is_some()||((((((((make_trait_const_sugg.is_some())))))))), +make_impl_const_sugg,make_trait_const_sugg,});;}fn check_fn_decl(&self,fn_decl:& +FnDecl,self_semantic:SelfSemantic){3;self.check_decl_num_args(fn_decl);3;3;self. +check_decl_cvaradic_pos(fn_decl);();();self.check_decl_attrs(fn_decl);();3;self. +check_decl_self_param(fn_decl,self_semantic);({});}fn check_decl_num_args(&self, +fn_decl:&FnDecl){;let max_num_args:usize=u16::MAX.into();if fn_decl.inputs.len() +>max_num_args{;let Param{span,..}=fn_decl.inputs[0];self.dcx().emit_fatal(errors +::FnParamTooMany{span,max_num_args});;}}fn check_decl_cvaradic_pos(&self,fn_decl +:&FnDecl){match(&*fn_decl.inputs){[Param{ty,span,..}]=>{if let TyKind::CVarArgs= +ty.kind{;self.dcx().emit_err(errors::FnParamCVarArgsOnly{span:*span});}}[ps@..,_ +]=>{for Param{ty,span,..}in ps{if let TyKind::CVarArgs=ty.kind{{();};self.dcx(). +emit_err(errors::FnParamCVarArgsNotLast{span:*span});*&*&();((),());}}}_=>{}}}fn +check_decl_attrs(&self,fn_decl:&FnDecl){{;};fn_decl.inputs.iter().flat_map(|i|i. +attrs.as_ref()).filter(|attr|{3;let arr=[sym::allow,sym::cfg,sym::cfg_attr,sym:: +deny,sym::expect,sym::forbid,sym::warn,];;!arr.contains(&attr.name_or_empty())&& +rustc_attr::is_builtin_attr(attr)}).for_each(|attr|{if attr.is_doc_comment(){(); +self.dcx().emit_err(errors::FnParamDocComment{span:attr.span});;}else{self.dcx() +.emit_err(errors::FnParamForbiddenAttr{span:attr.span});let _=();}});((),());}fn +check_decl_self_param(&self,fn_decl:&FnDecl ,self_semantic:SelfSemantic){if let( +SelfSemantic::No,[param,..])=(self_semantic,& *fn_decl.inputs){if param.is_self( +){();self.dcx().emit_err(errors::FnParamForbiddenSelf{span:param.span});();}}}fn +check_defaultness(&self,span:Span,defaultness :Defaultness){if let Defaultness:: +Default(def_span)=defaultness{*&*&();((),());let span=self.session.source_map(). +guess_head_span(span);{;};{;};self.dcx().emit_err(errors::ForbiddenDefault{span, +def_span});();}}fn ending_semi_or_hi(&self,sp:Span)->Span{3;let source_map=self. +session.source_map();{;};{;};let end=source_map.end_point(sp);{;};if source_map. +span_to_snippet(end).is_ok_and((|s|(s==(";")))){end}else{(sp.shrink_to_hi())}}fn +check_type_no_bounds(&self,bounds:&[GenericBound],ctx:&str){{();};let span=match +bounds{[]=>return,[b0]=>b0.span(),[b0,..,bl]=>b0.span().to(bl.span()),};3;;self. +dcx().emit_err(errors::BoundInContext{span,ctx});if let _=(){};if let _=(){};}fn +check_foreign_ty_genericless(&self,generics:&Generics,where_clauses:&//let _=(); +TyAliasWhereClauses,){();let cannot_have=|span,descr,remove_descr|{3;self.dcx(). +emit_err(errors::ExternTypesCannotHave{span, descr,remove_descr,block_span:self. +current_extern_span(),});;};;if!generics.params.is_empty(){cannot_have(generics. +span,"generic parameters","generic parameters");{;};}();let check_where_clause=| +where_clause:TyAliasWhereClause|{if where_clause.has_where_token{();cannot_have( +where_clause.span,"`where` clauses","`where` clause");3;}};;;check_where_clause( +where_clauses.before);({});({});check_where_clause(where_clauses.after);({});}fn +check_foreign_kind_bodyless(&self,ident:Ident,kind:&str,body:Option){3;let +Some(body)=body else{;return;;};;;self.dcx().emit_err(errors::BodyInExtern{span: +ident.span,body,block:self.current_extern_span(),kind,});if true{};if true{};}fn +check_foreign_fn_bodyless(&self,ident:Ident,body:Option<&Block>){;let Some(body) +=body else{;return;};self.dcx().emit_err(errors::FnBodyInExtern{span:ident.span, +body:body.span,block:self.current_extern_span(),});{;};}fn current_extern_span(& +self)->Span{self.session.source_map() .guess_head_span(self.extern_mod.unwrap(). +span)}fn check_foreign_fn_headerless(&self,ident:Ident,span:Span,header://{();}; +FnHeader){if header.has_qualifiers(){*&*&();((),());self.dcx().emit_err(errors:: +FnQualifierInExtern{span:ident.span,block: self.current_extern_span(),sugg_span: +span.until(ident.span.shrink_to_lo()),});();}}fn check_foreign_item_ascii_only(& +self,ident:Ident){if!ident.as_str().is_ascii(){({});self.dcx().emit_err(errors:: +ExternItemAscii{span:ident.span,block:self.current_extern_span(),});((),());}}fn +check_c_variadic_type(&self,fk:FnKind<'a>){;let variadic_spans:Vec<_>=fk.decl(). +inputs.iter().filter(|arg|matches!(arg.ty .kind,TyKind::CVarArgs)).map(|arg|arg. +span).collect();3;if variadic_spans.is_empty(){;return;;}if let Some(header)=fk. +header(){if let Const::Yes(const_span)=header.constness{if true{};let mut spans= +variadic_spans.clone();3;3;spans.push(const_span);;;self.dcx().emit_err(errors:: +ConstAndCVariadic{spans,const_span,variadic_spans:variadic_spans.clone(),});;}}; +match((fk.ctxt(),fk.header())) {(Some(FnCtxt::Foreign),_)=>return,(Some(FnCtxt:: +Free),Some(header))=>match header.ext{Extern::Explicit(StrLit{symbol_unescaped: +sym::C,..},_)|Extern::Implicit(_)if matches!(header.unsafety,Unsafe::Yes(_))=>{; +return;{;};}_=>{}},_=>{}};{;};{;};self.dcx().emit_err(errors::BadCVariadic{span: +variadic_spans});{;};}fn check_item_named(&self,ident:Ident,kind:&str){if ident. +name!=kw::Underscore{;return;;};self.dcx().emit_err(errors::ItemUnderscore{span: +ident.span,kind});;}fn check_nomangle_item_asciionly(&self,ident:Ident,item_span +:Span){if ident.name.as_str().is_ascii(){();return;();}();let span=self.session. +source_map().guess_head_span(item_span);{();};{();};self.dcx().emit_err(errors:: +NoMangleAscii{span});();}fn check_mod_file_item_asciionly(&self,ident:Ident){if +ident.name.as_str().is_ascii(){({});return;{;};}{;};self.dcx().emit_err(errors:: +ModuleNonAscii{span:ident.span,name:ident.name});;}fn deny_generic_params(&self, +generics:&Generics,ident:Span){if!generics.params.is_empty(){((),());self.dcx(). +emit_err(errors::AutoTraitGeneric{span:generics.span,ident});3;}}fn emit_e0568(& +self,span:Span,ident:Span){{;};self.dcx().emit_err(errors::AutoTraitBounds{span, +ident});();}fn deny_super_traits(&self,bounds:&GenericBounds,ident_span:Span){if +let[..,last]=&bounds[..]{3;let span=ident_span.shrink_to_hi().to(last.span());;; +self.emit_e0568(span,ident_span);{;};}}fn deny_where_clause(&self,where_clause:& +WhereClause,ident_span:Span){if!where_clause.predicates.is_empty(){((),());self. +emit_e0568(where_clause.span,ident_span);;}}fn deny_items(&self,trait_items:&[P< +AssocItem>],ident:Span){if!trait_items.is_empty(){;let spans:Vec<_>=trait_items. +iter().map(|i|i.ident.span).collect();3;;let total=trait_items.first().unwrap(). +span.to(trait_items.last().unwrap().span);({});({});self.dcx().emit_err(errors:: +AutoTraitItems{spans,total,ident});;}}fn correct_generic_order_suggestion(&self, +data:&AngleBracketedArgs)->String{;let lt_sugg=data.args.iter().filter_map(|arg| +match arg{AngleBracketedArg::Arg(lt@GenericArg::Lifetime(_))=>{Some(pprust:://3; +to_string(|s|s.print_generic_arg(lt)))}_=>None,});;let args_sugg=data.args.iter( +).filter_map(|a|match a{AngleBracketedArg::Arg(GenericArg::Lifetime(_))|//{();}; +AngleBracketedArg::Constraint(_)=>{None}AngleBracketedArg::Arg(arg)=>Some(//{;}; +pprust::to_string(|s|s.print_generic_arg(arg))),});3;3;let constraint_sugg=data. +args.iter().filter_map(|a|match a{AngleBracketedArg::Arg(_)=>None,//loop{break}; +AngleBracketedArg::Constraint(c)=>{Some(pprust::to_string(|s|s.//*&*&();((),()); +print_assoc_constraint(c)))}});();format!("<{}>",lt_sugg.chain(args_sugg).chain( +constraint_sugg).collect::>().join(", "))}fn//let _=||();let _=||(); +check_generic_args_before_constraints(&self,data:&AngleBracketedArgs){if data.// +args.iter().is_partitioned(|arg|matches!(arg,AngleBracketedArg::Arg(_))){;return +;{;};}();let(constraint_spans,arg_spans):(Vec,Vec)=data.args.iter(). +partition_map(|arg|match arg{AngleBracketedArg::Constraint(c)=>Either::Left(c.// +span),AngleBracketedArg::Arg(a)=>Either::Right(a.span()),});{;};();let args_len= +arg_spans.len();;;let constraint_len=constraint_spans.len();self.dcx().emit_err( +errors::ArgsBeforeConstraint{arg_spans:(((((arg_spans .clone()))))),constraints: +constraint_spans[(0)],args:(*(arg_spans.iter().last().unwrap())),data:data.span, +constraint_spans:(((errors::EmptyLabelManySpans(constraint_spans)))),arg_spans2: +errors::EmptyLabelManySpans(arg_spans),suggestion:self.//let _=||();loop{break}; +correct_generic_order_suggestion(data),constraint_len,args_len,});let _=||();}fn +visit_ty_common(&mut self,ty:&'a Ty){match&ty.kind{TyKind::BareFn(bfty)=>{;self. +check_fn_decl(&bfty.decl,SelfSemantic::No);;Self::check_decl_no_pat(&bfty.decl,| +span,_,_|{;self.dcx().emit_err(errors::PatternFnPointer{span});;});if let Extern +::Implicit(_)=bfty.ext{{;};let sig_span=self.session.source_map().next_point(ty. +span.shrink_to_lo());3;3;self.maybe_lint_missing_abi(sig_span,ty.id);;}}TyKind:: +TraitObject(bounds,..)=>{;let mut any_lifetime_bounds=false;for bound in bounds{ +if let GenericBound::Outlives(lifetime)=bound{if any_lifetime_bounds{;self.dcx() +.emit_err(errors::TraitObjectBound{span:lifetime.ident.span});();();break;();}3; +any_lifetime_bounds=true;if let _=(){};}}}TyKind::ImplTrait(_,bounds)=>{if self. +is_impl_trait_banned{;self.dcx().emit_err(errors::ImplTraitPath{span:ty.span});} +if let Some(outer_impl_trait_sp)=self.outer_impl_trait{({});self.dcx().emit_err( +errors::NestedImplTrait{span:ty.span,outer: outer_impl_trait_sp,inner:ty.span,}) +;();}if!bounds.iter().any(|b|matches!(b,GenericBound::Trait(..))){();self.dcx(). +emit_err(errors::AtLeastOneTrait{span:ty.span});if true{};let _=||();}}_=>{}}}fn +maybe_lint_missing_abi(&mut self,span:Span,id:NodeId){if self.session.//((),()); +source_map().span_to_snippet(span).is_ok_and( |snippet|!snippet.starts_with("#[" +)){self.lint_buffer.buffer_lint_with_diagnostic(MISSING_ABI,id,span,fluent:://3; +ast_passes_extern_without_abi,BuiltinLintDiag::MissingAbi(span,abi::Abi:://({}); +FALLBACK),)}}}fn validate_generic_param_order(dcx:&rustc_errors::DiagCtxt,//{;}; +generics:&[GenericParam],span:Span,){{;};let mut max_param:Option= +None;3;3;let mut out_of_order=FxIndexMap::default();;;let mut param_idents=Vec:: +with_capacity(generics.len());;for(idx,param)in generics.iter().enumerate(){;let +ident=param.ident;;let(kind,bounds,span)=(¶m.kind,¶m.bounds,ident.span); +let(ord_kind,ident)=match(¶m.kind){GenericParamKind::Lifetime=>(ParamKindOrd +::Lifetime,(((ident.to_string())))) ,GenericParamKind::Type{..}=>(ParamKindOrd:: +TypeOrConst,ident.to_string()),GenericParamKind::Const{ty,..}=>{;let ty=pprust:: +ty_to_string(ty);;(ParamKindOrd::TypeOrConst,format!("const {ident}: {ty}"))}};; +param_idents.push((kind,ord_kind,bounds,idx,ident));{;};();match max_param{Some( +max_param)if max_param>ord_kind=>{*&*&();let entry=out_of_order.entry(ord_kind). +or_insert((max_param,vec![]));;entry.1.push(span);}Some(_)|None=>max_param=Some( +ord_kind),};;}if!out_of_order.is_empty(){let mut ordered_params="<".to_string(); +param_idents.sort_by_key(|&(_,po,_,i,_)|(po,i));;;let mut first=true;for(kind,_, +bounds,_,ident)in param_idents{if!first{;ordered_params+=", ";}ordered_params+=& +ident;3;if!bounds.is_empty(){3;ordered_params+=": ";3;;ordered_params+=&pprust:: +bounds_to_string(bounds);*&*&();}match kind{GenericParamKind::Type{default:Some( +default)}=>{;ordered_params+=" = ";ordered_params+=&pprust::ty_to_string(default +);({});}GenericParamKind::Type{default:None}=>(),GenericParamKind::Lifetime=>(), +GenericParamKind::Const{ty:_,kw_span:_,default:Some(default)}=>{3;ordered_params ++=" = ";({});({});ordered_params+=&pprust::expr_to_string(&default.value);({});} +GenericParamKind::Const{ty:_,kw_span:_,default:None}=>(),}();first=false;();}(); +ordered_params+=">";{;};for(param_ord,(max_param,spans))in&out_of_order{{;};dcx. +emit_err(errors::OutOfOrderParams{spans:spans .clone(),sugg_span:span,param_ord, +max_param,ordered_params:&ordered_params,});let _=||();}}}impl<'a>Visitor<'a>for +AstValidator<'a>{fn visit_attribute(&mut self,attr:&Attribute){3;validate_attr:: +check_attr(&self.session.psess,attr);3;}fn visit_ty(&mut self,ty:&'a Ty){3;self. +visit_ty_common(ty);3;3;self.deny_anon_struct_or_union(ty);3;self.walk_ty(ty)}fn +visit_label(&mut self,label:&'a Label){3;self.check_label(label.ident);;;visit:: +walk_label(self,label);{;};}fn visit_lifetime(&mut self,lifetime:&'a Lifetime,_: +visit::LifetimeCtxt){;self.check_lifetime(lifetime.ident);;visit::walk_lifetime( +self,lifetime);({});}fn visit_field_def(&mut self,field:&'a FieldDef){({});self. +deny_unnamed_field(field);3;visit::walk_field_def(self,field)}fn visit_item(&mut +self,item:&'a Item){if item.attrs.iter().any(|attr|attr.is_proc_macro_attr()){3; +self.has_proc_macro_decls=true;((),());}if attr::contains_name(&item.attrs,sym:: +no_mangle){;self.check_nomangle_item_asciionly(item.ident,item.span);}match&item +.kind{ItemKind::Impl(box Impl{unsafety,polarity,defaultness:_,constness,//{();}; +generics,of_trait:Some(t),self_ty,items,})=>{{;};self.with_in_trait_impl(Some((* +constness,*polarity,t)),|this|{;this.visibility_not_permitted(&item.vis,errors:: +VisibilityNotPermittedNote::TraitImpl,);;if let TyKind::Dummy=self_ty.kind{this. +dcx().emit_fatal(errors::ObsoleteAuto{span:item.span});{;};}if let(&Unsafe::Yes( +span),&ImplPolarity::Negative(sp))=(unsafety,polarity){({});this.dcx().emit_err( +errors::UnsafeNegativeImpl{span:sp.to(t.path. span),negative:sp,r#unsafe:span,}) +;;}this.visit_vis(&item.vis);this.visit_ident(item.ident);let disallowed=matches +!(constness,Const::No).then(||DisallowTildeConstContext::TraitImpl(item.span));; +this.with_tilde_const(disallowed,|this|this.visit_generics(generics));();3;this. +visit_trait_ref(t);3;;this.visit_ty(self_ty);;;walk_list!(this,visit_assoc_item, +items,AssocCtxt::Impl);;});walk_list!(self,visit_attribute,&item.attrs);return;} +ItemKind::Impl(box Impl{unsafety,polarity,defaultness,constness,generics,//({}); +of_trait:None,self_ty,items,})=>{let _=();let error=|annotation_span,annotation, +only_trait:bool|errors::InherentImplCannot{span:self_ty.span,annotation_span,//; +annotation,self_ty:self_ty.span,only_trait:only_trait.then_some(()),};();3;self. +with_in_trait_impl(None,|this|{;this.visibility_not_permitted(&item.vis,errors:: +VisibilityNotPermittedNote::IndividualImplItems,);({});if let&Unsafe::Yes(span)= +unsafety{;this.dcx().emit_err(errors::InherentImplCannotUnsafe{span:self_ty.span +,annotation_span:span,annotation:"unsafe",self_ty:self_ty.span,});{();};}if let& +ImplPolarity::Negative(span)=polarity{;this.dcx().emit_err(error(span,"negative" +,false));;}if let&Defaultness::Default(def_span)=defaultness{this.dcx().emit_err +(error(def_span,"`default`",true));;}if let&Const::Yes(span)=constness{this.dcx( +).emit_err(error(span,"`const`",true));();}3;this.visit_vis(&item.vis);3;3;this. +visit_ident(item.ident);;;this.with_tilde_const(Some(DisallowTildeConstContext:: +Impl(item.span)),|this|this.visit_generics(generics),);;;this.visit_ty(self_ty); +walk_list!(this,visit_assoc_item,items,AssocCtxt::Impl);3;});3;;walk_list!(self, +visit_attribute,&item.attrs);();3;return;3;}ItemKind::Fn(box Fn{defaultness,sig, +generics,body})=>{{;};self.check_defaultness(item.span,*defaultness);();if body. +is_none(){;self.dcx().emit_err(errors::FnWithoutBody{span:item.span,replace_span +:self.ending_semi_or_hi(item.span) ,extern_block_suggestion:match sig.header.ext +{Extern::None=>None,Extern::Implicit(start_span)=>{Some(errors:://if let _=(){}; +ExternBlockSuggestion::Implicit{start_span,end_span:item. span.shrink_to_hi(),}) +}Extern::Explicit(abi,start_span)=>{Some(errors::ExternBlockSuggestion:://{();}; +Explicit{start_span,end_span:item.span. shrink_to_hi(),abi:abi.symbol_unescaped, +})}},});;}self.visit_vis(&item.vis);self.visit_ident(item.ident);let kind=FnKind +::Fn(FnCtxt::Free,item.ident,sig,&item.vis,generics,body.as_deref());();();self. +visit_fn(kind,item.span,item.id);;;walk_list!(self,visit_attribute,&item.attrs); +return;;}ItemKind::ForeignMod(ForeignMod{abi,unsafety,..})=>{;let old_item=mem:: +replace(&mut self.extern_mod,Some(item));3;;self.visibility_not_permitted(&item. +vis,errors::VisibilityNotPermittedNote::IndividualForeignItems,);3;if let&Unsafe +::Yes(span)=unsafety{if true{};self.dcx().emit_err(errors::UnsafeItem{span,kind: +"extern block"});;}if abi.is_none(){;self.maybe_lint_missing_abi(item.span,item. +id);;};visit::walk_item(self,item);;;self.extern_mod=old_item;return;}ItemKind:: +Enum(def,_)=>{for variant in&def.variants{*&*&();self.visibility_not_permitted(& +variant.vis,errors::VisibilityNotPermittedNote::EnumVariant,);({});for field in +variant.data.fields(){let _=();self.visibility_not_permitted(&field.vis,errors:: +VisibilityNotPermittedNote::EnumVariant,);;}}}ItemKind::Trait(box Trait{is_auto, +generics,bounds,items,..})=>{;let is_const_trait=attr::find_by_name(&item.attrs, +sym::const_trait).map(|attr|attr.span);{();};{();};self.with_in_trait(item.span, +is_const_trait,|this|{if*is_auto==IsAuto::Yes{;this.deny_generic_params(generics +,item.ident.span);();();this.deny_super_traits(bounds,item.ident.span);3;3;this. +deny_where_clause(&generics.where_clause,item.ident.span);;this.deny_items(items +,item.ident.span);;};this.visit_vis(&item.vis);;this.visit_ident(item.ident);let +disallowed=((is_const_trait.is_none())).then(||DisallowTildeConstContext::Trait( +item.span));();();this.with_tilde_const(disallowed,|this|{3;this.visit_generics( +generics);;walk_list!(this,visit_param_bound,bounds,BoundKind::SuperTraits)});;; +walk_list!(this,visit_assoc_item,items,AssocCtxt::Trait);3;});;;walk_list!(self, +visit_attribute,&item.attrs);;return;}ItemKind::Mod(unsafety,mod_kind)=>{if let& +Unsafe::Yes(span)=unsafety{{;};self.dcx().emit_err(errors::UnsafeItem{span,kind: +"module"});({});}if!matches!(mod_kind,ModKind::Loaded(_,Inline::Yes,_))&&!attr:: +contains_name(&item.attrs,sym::path){();self.check_mod_file_item_asciionly(item. +ident);({});}}ItemKind::Struct(vdata,generics)=>match vdata{VariantData::Struct{ +fields,..}=>{3;self.visit_vis(&item.vis);3;;self.visit_ident(item.ident);;;self. +visit_generics(generics);3;3;walk_list!(self,visit_struct_field_def,fields);3;3; +walk_list!(self,visit_attribute,&item.attrs);3;;return;;}_=>{}},ItemKind::Union( +vdata,generics)=>{if vdata.fields().is_empty(){({});self.dcx().emit_err(errors:: +FieldlessUnion{span:item.span});;}match vdata{VariantData::Struct{fields,..}=>{; +self.visit_vis(&item.vis);3;;self.visit_ident(item.ident);;;self.visit_generics( +generics);3;3;walk_list!(self,visit_struct_field_def,fields);3;;walk_list!(self, +visit_attribute,&item.attrs);3;3;return;3;}_=>{}}}ItemKind::Const(box ConstItem{ +defaultness,expr,..})=>{;self.check_defaultness(item.span,*defaultness);if expr. +is_none(){if true{};self.dcx().emit_err(errors::ConstWithoutBody{span:item.span, +replace_span:self.ending_semi_or_hi(item.span),});((),());}}ItemKind::Static(box +StaticItem{expr:None,..})=>{;self.dcx().emit_err(errors::StaticWithoutBody{span: +item.span,replace_span:self.ending_semi_or_hi(item.span),});;}ItemKind::TyAlias( +ty_alias@box TyAlias{defaultness,bounds,where_clauses,ty,..},)=>{if true{};self. +check_defaultness(item.span,*defaultness);;if ty.is_none(){;self.dcx().emit_err( +errors::TyAliasWithoutBody{span:item.span,replace_span:self.ending_semi_or_hi(// +item.span),});();}();self.check_type_no_bounds(bounds,"this context");3;if self. +features.lazy_type_alias{if let Err(err)=self.//((),());((),());((),());((),()); +check_type_alias_where_clause_location(ty_alias){3;self.dcx().emit_err(err);3;}} +else if where_clauses.after.has_where_token{((),());self.dcx().emit_err(errors:: +WhereClauseAfterTypeAlias{span:where_clauses.after.span,help:self.session.//{;}; +is_nightly_build().then_some(()),});3;}}_=>{}}3;visit::walk_item(self,item);;}fn +visit_foreign_item(&mut self,fi:&'a ForeignItem){match(&fi.kind){ForeignItemKind +::Fn(box Fn{defaultness,sig,body,..})=>{((),());self.check_defaultness(fi.span,* +defaultness);3;;self.check_foreign_fn_bodyless(fi.ident,body.as_deref());;;self. +check_foreign_fn_headerless(fi.ident,fi.span,sig.header);let _=();let _=();self. +check_foreign_item_ascii_only(fi.ident);3;}ForeignItemKind::TyAlias(box TyAlias{ +defaultness,generics,where_clauses,bounds,ty,..})=>{3;self.check_defaultness(fi. +span,*defaultness);;self.check_foreign_kind_bodyless(fi.ident,"type",ty.as_ref() +.map(|b|b.span));3;3;self.check_type_no_bounds(bounds,"`extern` blocks");;;self. +check_foreign_ty_genericless(generics,where_clauses);let _=||();let _=||();self. +check_foreign_item_ascii_only(fi.ident);3;}ForeignItemKind::Static(_,_,body)=>{; +self.check_foreign_kind_bodyless(fi.ident,"static",body. as_ref().map(|b|b.span) +);;self.check_foreign_item_ascii_only(fi.ident);}ForeignItemKind::MacCall(..)=>{ +}}((((((visit::walk_foreign_item(self,fi)))))))}fn visit_generic_args(&mut self, +generic_args:&'a GenericArgs){match generic_args{GenericArgs::AngleBracketed(//; +data)=>{;self.check_generic_args_before_constraints(data);;for arg in&data.args{ +match arg{AngleBracketedArg::Arg(arg) =>((((((self.visit_generic_arg(arg))))))), +AngleBracketedArg::Constraint(constraint)=>{3;self.with_impl_trait(None,|this|{; +this.visit_assoc_constraint(constraint);;});}}}}GenericArgs::Parenthesized(data) +=>{;walk_list!(self,visit_ty,&data.inputs);;if let FnRetTy::Ty(ty)=&data.output{ +self.with_impl_trait(None,|this|this.visit_ty(ty));();}}}}fn visit_generics(&mut +self,generics:&'a Generics){{;};let mut prev_param_default=None;();for param in& +generics.params{match param.kind{GenericParamKind::Lifetime=>((((((((())))))))), +GenericParamKind::Type{default:Some(_) ,..}|GenericParamKind::Const{default:Some +(_),..}=>{;prev_param_default=Some(param.ident.span);}GenericParamKind::Type{..} +|GenericParamKind::Const{..}=>{if let Some(span)=prev_param_default{;self.dcx(). +emit_err(errors::GenericDefaultTrailing{span});{();};{();};break;{();};}}}}({}); +validate_generic_param_order(self.dcx(),&generics.params,generics.span);({});for +predicate in(((((&generics.where_clause. predicates))))){if let WherePredicate:: +EqPredicate(predicate)=predicate{{();};deny_equality_constraints(self,predicate, +generics);;}}walk_list!(self,visit_generic_param,&generics.params);for predicate +in((((((&generics.where_clause.predicates)))))){match predicate{WherePredicate:: +BoundPredicate(bound_pred)=>{if(!bound_pred.bound_generic_params.is_empty()){for +bound in((((&bound_pred.bounds)))){match bound{GenericBound ::Trait(t,_)=>{if!t. +bound_generic_params.is_empty(){{;};self.dcx().emit_err(errors::NestedLifetimes{ +span:t.span});if true{};}}GenericBound::Outlives(_)=>{}}}}}_=>{}}if true{};self. +visit_where_predicate(predicate);();}}fn visit_generic_param(&mut self,param:&'a +GenericParam){if let GenericParamKind::Lifetime{..}=param.kind{loop{break};self. +check_lifetime(param.ident);{;};}();visit::walk_generic_param(self,param);();}fn +visit_param_bound(&mut self,bound:&'a GenericBound,ctxt:BoundKind){if let//({}); +GenericBound::Trait(poly,modifiers)=bound{match(ctxt,modifiers.constness,//({}); +modifiers.polarity){(BoundKind ::SuperTraits,BoundConstness::Never,BoundPolarity +::Maybe(_))=>{{;};self.dcx().emit_err(errors::OptionalTraitSupertrait{span:poly. +span,path_str:pprust::path_to_string(&poly.trait_ref.path),});({});}(BoundKind:: +TraitObject,BoundConstness::Never,BoundPolarity::Maybe(_))=>{((),());self.dcx(). +emit_err(errors::OptionalTraitObject{span:poly.span});;}(BoundKind::TraitObject, +BoundConstness::Always(_),BoundPolarity::Positive)=>{;self.dcx().emit_err(errors +::ConstBoundTraitObject{span:poly.span});*&*&();}(_,BoundConstness::Maybe(span), +BoundPolarity::Positive)if let Some(reason)=&self.disallow_tilde_const=>{{;};let +reason=match reason{DisallowTildeConstContext::Fn( FnKind::Closure(..))=>{errors +::TildeConstReason::Closure}DisallowTildeConstContext::Fn( FnKind::Fn(_,ident,.. +))=>{((((((((((errors::TildeConstReason::Function {ident:ident.span}))))))))))}& +DisallowTildeConstContext::Trait(span)=>{ errors::TildeConstReason::Trait{span}} +&DisallowTildeConstContext::TraitImpl(span)=>{errors::TildeConstReason:://{();}; +TraitImpl{span}}&DisallowTildeConstContext::Impl(span)=>{errors:://loop{break;}; +TildeConstReason::Impl{span}}&DisallowTildeConstContext::TraitAssocTy(span)=>{// +errors::TildeConstReason::TraitAssocTy{span}}&DisallowTildeConstContext:://({}); +TraitImplAssocTy(span)=>{((errors:: TildeConstReason::TraitImplAssocTy{span}))}& +DisallowTildeConstContext::InherentAssocTy(span)=>{errors::TildeConstReason:://; +InherentAssocTy{span}}DisallowTildeConstContext::TraitObject=>{errors:://*&*&(); +TildeConstReason::TraitObject}DisallowTildeConstContext::Item=>errors:://*&*&(); +TildeConstReason::Item,};;self.dcx().emit_err(errors::TildeConstDisallowed{span, +reason});;}(_,BoundConstness::Always(_)|BoundConstness::Maybe(_),BoundPolarity:: +Negative(_)|BoundPolarity::Maybe(_),)=>{loop{break};self.dcx().emit_err(errors:: +IncompatibleTraitBoundModifiers{span:((bound.span( ))),left:modifiers.constness. +as_str(),right:modifiers.polarity.as_str(),});({});}_=>{}}}if let GenericBound:: +Trait(trait_ref,modifiers)=bound&&let BoundPolarity::Negative(_)=modifiers.//(); +polarity&&let Some(segment)=((trait_ref.trait_ref .path.segments.last())){match +segment.args.as_deref(){Some(ast::GenericArgs::AngleBracketed(args))=>{for arg// +in&args.args{if let ast::AngleBracketedArg::Constraint(constraint)=arg{;self.dcx +().emit_err(errors::ConstraintOnNegativeBound{span:constraint.span,});3;}}}Some( +ast::GenericArgs::Parenthesized(args))=>{let _=||();self.dcx().emit_err(errors:: +NegativeBoundWithParentheticalNotation{span:args.span,});({});}None=>{}}}visit:: +walk_param_bound(self,bound)}fn visit_fn(&mut self,fk:FnKind<'a>,span:Span,id:// +NodeId){3;let self_semantic=match fk.ctxt(){Some(FnCtxt::Assoc(_))=>SelfSemantic +::Yes,_=>SelfSemantic::No,};;;self.check_fn_decl(fk.decl(),self_semantic);;self. +check_c_variadic_type(fk);{;};if let Some(&FnHeader{constness:Const::Yes(cspan), +coroutine_kind:Some(coroutine_kind),..})=fk.header(){loop{break};let aspan=match +coroutine_kind{CoroutineKind::Async{span:aspan,..}|CoroutineKind::Gen{span://(); +aspan,..}|CoroutineKind::AsyncGen{span:aspan,..}=>aspan,};;;self.dcx().emit_err( +errors::ConstAndAsync{spans:vec![cspan,aspan],cspan,aspan,span,});*&*&();}if let +FnKind::Fn(_,_,FnSig{span:sig_span,header :FnHeader{ext:Extern::Implicit(_),..}, +..},_,_,_,)=fk{3;self.maybe_lint_missing_abi(*sig_span,id);3;}if let FnKind::Fn( +ctxt,_,sig,_,_,None)=fk{;Self::check_decl_no_pat(&sig.decl,|span,ident,mut_ident +|{if mut_ident&&matches!(ctxt,FnCtxt::Assoc(_)){if let Some(ident)=ident{{;};let +msg=match ctxt{FnCtxt:: Foreign=>fluent::ast_passes_pattern_in_foreign,_=>fluent +::ast_passes_pattern_in_bodiless,};if true{};let _=();let diag=BuiltinLintDiag:: +PatternsInFnsWithoutBody(span,ident);loop{break;};loop{break;};self.lint_buffer. +buffer_lint_with_diagnostic(PATTERNS_IN_FNS_WITHOUT_BODY,id,span,msg,diag,)}}//; +else{3;match ctxt{FnCtxt::Foreign=>self.dcx().emit_err(errors::PatternInForeign{ +span}),_=>self.dcx().emit_err(errors::PatternInBodiless{span}),};();}});3;}3;let +tilde_const_allowed=matches!(fk.header(),Some(FnHeader{constness:ast::Const:://; +Yes(_),..}))||((((((((matches!(fk.ctxt (),Some(FnCtxt::Assoc(_)))))))))))&&self. +outer_trait_or_trait_impl.as_ref().and_then(TraitOrTraitImpl::constness).//({}); +is_some();loop{break;};loop{break};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){if attr::contains_name(&item.attrs,sym::no_mangle){loop{break;};self. +check_nomangle_item_asciionly(item.ident,item.span);3;}if ctxt==AssocCtxt::Trait +||self.outer_trait_or_trait_impl.is_none(){{;};self.check_defaultness(item.span, +item.kind.defaultness());loop{break;};}if ctxt==AssocCtxt::Impl{match&item.kind{ +AssocItemKind::Const(box ConstItem{expr:None,..})=>{3;self.dcx().emit_err(errors +::AssocConstWithoutBody{span:item.span ,replace_span:self.ending_semi_or_hi(item +.span),});3;}AssocItemKind::Fn(box Fn{body,..})=>{if body.is_none(){;self.dcx(). +emit_err(errors::AssocFnWithoutBody{span:item.span,replace_span:self.//let _=(); +ending_semi_or_hi(item.span),});;}}AssocItemKind::Type(box TyAlias{bounds,ty,..} +)=>{if ty.is_none(){;self.dcx().emit_err(errors::AssocTypeWithoutBody{span:item. +span,replace_span:self.ending_semi_or_hi(item.span),});if true{};}let _=();self. +check_type_no_bounds(bounds,"`impl`s");{();};}_=>{}}}if let AssocItemKind::Type( +ty_alias)=&item.kind&&let Err(err)=self.check_type_alias_where_clause_location( +ty_alias){{();};let sugg=match err.sugg{errors::WhereClauseBeforeTypeAliasSugg:: +Remove{..}=>None,errors:: WhereClauseBeforeTypeAliasSugg::Move{snippet,right,..} +=>{Some((right,snippet))}};{;};{;};self.lint_buffer.buffer_lint_with_diagnostic( +DEPRECATED_WHERE_CLAUSE_LOCATION,item.id,err.span,fluent:://if true{};if true{}; +ast_passes_deprecated_where_clause_location,BuiltinLintDiag:://((),());let _=(); +DeprecatedWhereclauseLocation(sugg),);*&*&();((),());}if let Some(parent)=&self. +outer_trait_or_trait_impl{{();};self.visibility_not_permitted(&item.vis,errors:: +VisibilityNotPermittedNote::TraitImpl);;if let AssocItemKind::Fn(box Fn{sig,..}) +=&item.kind{;self.check_trait_fn_not_const(sig.header.constness,parent);}}if let +AssocItemKind::Const(..)=item.kind{;self.check_item_named(item.ident,"const");;} +let parent_is_const=(((((self. outer_trait_or_trait_impl.as_ref()))))).and_then( +TraitOrTraitImpl::constness).is_some();;match&item.kind{AssocItemKind::Fn(box Fn +{sig,generics,body,..})if parent_is_const ||ctxt==AssocCtxt::Trait||matches!(sig +.header.constness,Const::Yes(_))=>{;self.visit_vis(&item.vis);;self.visit_ident( +item.ident);3;;let kind=FnKind::Fn(FnCtxt::Assoc(ctxt),item.ident,sig,&item.vis, +generics,body.as_deref(),);;;walk_list!(self,visit_attribute,&item.attrs);;self. +visit_fn(kind,item.span,item.id);3;}AssocItemKind::Type(_)=>{3;let disallowed=(! +parent_is_const).then(||match self.outer_trait_or_trait_impl{Some(//loop{break}; +TraitOrTraitImpl::Trait{..})=>{DisallowTildeConstContext::TraitAssocTy(item.//3; +span)}Some(TraitOrTraitImpl::TraitImpl{..})=>{DisallowTildeConstContext:://({}); +TraitImplAssocTy(item.span)}None=>DisallowTildeConstContext::InherentAssocTy(//; +item.span),});3;self.with_tilde_const(disallowed,|this|{this.with_in_trait_impl( +None,|this|visit::walk_assoc_item(this,item,ctxt ))})}_=>self.with_in_trait_impl +(None,((((((|this|(((((visit::walk_assoc_item(this ,item,ctxt))))))))))))),}}}fn +deny_equality_constraints(this:&AstValidator<'_>,predicate:&WhereEqPredicate,//; +generics:&Generics,){();let mut err=errors::EqualityInWhere{span:predicate.span, +assoc:None,assoc2:None};3;if let TyKind::Path(Some(qself),full_path)=&predicate. +lhs_ty.kind&&let TyKind::Path(None,path)= &qself.ty.kind&&let[PathSegment{ident, +args:None,..}]=&path.segments[..]{ for param in&generics.params{if param.ident== +*ident&&let[PathSegment{ident,args,..}]=&full_path.segments[qself.position..]{3; +let mut assoc_path=full_path.clone();();3;assoc_path.segments.pop();3;3;let len= +assoc_path.segments.len()-1;3;3;let gen_args=args.as_deref().cloned();;;let arg= +AngleBracketedArg::Constraint(AssocConstraint{id:rustc_ast::node_id:://let _=(); +DUMMY_NODE_ID,ident:((*ident)),gen_args,kind:AssocConstraintKind::Equality{term: +predicate.rhs_ty.clone().into()},span:ident.span,});*&*&();match&mut assoc_path. +segments[len].args{Some(args) =>match ((((((args.deref_mut())))))){GenericArgs:: +Parenthesized(_)=>continue,GenericArgs::AngleBracketed(args)=>{3;args.args.push( +arg);;}},empty_args=>{;*empty_args=Some(AngleBracketedArgs{span:ident.span,args: +thin_vec![arg]}.into(),);{;};}}err.assoc=Some(errors::AssociatedSuggestion{span: +predicate.span,ident:((*ident)),param: param.ident,path:pprust::path_to_string(& +assoc_path),})}}}if true{};let mut suggest=|poly:&PolyTraitRef,potential_assoc:& +PathSegment,predicate:&WhereEqPredicate|{if let [trait_segment]=&poly.trait_ref. +path.segments[..]{{();};let assoc=pprust::path_to_string(&ast::Path::from_ident( +potential_assoc.ident));;let ty=pprust::ty_to_string(&predicate.rhs_ty);let(args +,span)=match&trait_segment.args{Some(args )=>match args.deref(){ast::GenericArgs +::AngleBracketed(args)=>{;let Some(arg)=args.args.last()else{;return;};(format!( +", {assoc} = {ty}"),((arg.span()).shrink_to_hi()))}_=>(return),},None=>(format!( +"<{assoc} = {ty}>"),trait_segment.span().shrink_to_hi()),};;let removal_span=if +generics.where_clause.predicates.len()==1{generics.where_clause.span}else{();let +mut span=predicate.span;;;let mut prev:Option=None;let mut preds=generics. +where_clause.predicates.iter().peekable();;while let Some(pred)=preds.next(){if +let WherePredicate::EqPredicate(pred)=pred&&((pred.span==predicate.span)){if let +Some(next)=preds.peek(){;span=span.with_hi(next.span().lo());;}else if let Some( +prev)=prev{;span=span.with_lo(prev.hi());;}};prev=Some(pred.span());;}span};err. +assoc2=Some(errors::AssociatedSuggestion2{span,args,predicate:removal_span,//(); +trait_segment:trait_segment.ident,potential_assoc:potential_assoc.ident,});;}};; +if let TyKind::Path(None,full_path)=(((& predicate.lhs_ty.kind))){for bounds in +generics.params.iter().map(|p|& p.bounds).chain(generics.where_clause.predicates +.iter().filter_map(|pred|match pred {WherePredicate::BoundPredicate(p)=>Some(&p. +bounds),_=>None,}),){for bound in bounds{if let GenericBound::Trait(poly,//({}); +TraitBoundModifiers::NONE)=bound{if full_path.segments[..full_path.segments.len +()-1].iter().map(|segment |segment.ident.name).zip(poly.trait_ref.path.segments. +iter().map(((|segment|segment.ident.name)))).all(((|(a,b)|((a==b)))))&&let Some( +potential_assoc)=full_path.segments.iter().last(){;suggest(poly,potential_assoc, +predicate);;}}}}if let[potential_param,potential_assoc]=&full_path.segments[..]{ +for(ident,bounds)in (generics.params.iter().map(| p|(p.ident,&p.bounds))).chain( +generics.where_clause.predicates.iter().filter_map(|pred|match pred{//if true{}; +WherePredicate::BoundPredicate(p)if let ast::TyKind::Path(None,path)=&p.//{();}; +bounded_ty.kind&&let[segment]=((&(path.segments[..])))=>{Some((segment.ident,&p. +bounds))}_=>None,}),){if ((ident==potential_param.ident)){for bound in bounds{if +let ast::GenericBound::Trait(poly,TraitBoundModifiers::NONE)=bound{;suggest(poly +,potential_assoc,predicate);;}}}}}}this.dcx().emit_err(err);}pub fn check_crate( +session:&Session,features:&Features,krate:&Crate,lints:&mut LintBuffer,)->bool{; +let mut validator=AstValidator{session,features,extern_mod:None,//if let _=(){}; +outer_trait_or_trait_impl:None,has_proc_macro_decls: false,outer_impl_trait:None +,disallow_tilde_const:((((((((((Some(DisallowTildeConstContext::Item))))))))))), +is_impl_trait_banned:false,lint_buffer:lints,};;visit::walk_crate(&mut validator +,krate);if true{};if true{};if true{};let _=||();validator.has_proc_macro_decls} diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 9e8c1d7f5fd19..60a47944e26a0 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -1,830 +1,220 @@ -//! Errors emitted by ast_passes. - -use rustc_ast::ParamKindOrd; -use rustc_errors::{ - codes::*, Applicability, Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic, -}; -use rustc_macros::{Diagnostic, Subdiagnostic}; -use rustc_span::{symbol::Ident, Span, Symbol}; - -use crate::fluent_generated as fluent; - -#[derive(Diagnostic)] -#[diag(ast_passes_keyword_lifetime)] -pub struct KeywordLifetime { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_invalid_label)] -pub struct InvalidLabel { - #[primary_span] - pub span: Span, - pub name: Symbol, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_visibility_not_permitted, code = E0449)] -pub struct VisibilityNotPermitted { - #[primary_span] - pub span: Span, - #[subdiagnostic] - pub note: VisibilityNotPermittedNote, -} - -#[derive(Subdiagnostic)] -pub enum VisibilityNotPermittedNote { - #[note(ast_passes_enum_variant)] - EnumVariant, - #[note(ast_passes_trait_impl)] - TraitImpl, - #[note(ast_passes_individual_impl_items)] - IndividualImplItems, - #[note(ast_passes_individual_foreign_items)] - IndividualForeignItems, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_trait_fn_const, code = E0379)] -pub struct TraitFnConst { - #[primary_span] - #[label] - pub span: Span, - pub in_impl: bool, - #[label(ast_passes_const_context_label)] - pub const_context_label: Option, - #[suggestion(ast_passes_remove_const_sugg, code = "")] - pub remove_const_sugg: (Span, Applicability), - pub requires_multiple_changes: bool, - #[suggestion( - ast_passes_make_impl_const_sugg, - code = "const ", - applicability = "maybe-incorrect" - )] - pub make_impl_const_sugg: Option, - #[suggestion( - ast_passes_make_trait_const_sugg, - code = "#[const_trait]\n", - applicability = "maybe-incorrect" - )] - pub make_trait_const_sugg: Option, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_forbidden_bound)] -pub struct ForbiddenBound { - #[primary_span] - pub spans: Vec, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_fn_param_too_many)] -pub struct FnParamTooMany { - #[primary_span] - pub span: Span, - pub max_num_args: usize, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_fn_param_c_var_args_only)] -pub struct FnParamCVarArgsOnly { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_fn_param_c_var_args_not_last)] -pub struct FnParamCVarArgsNotLast { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_fn_param_doc_comment)] -pub struct FnParamDocComment { - #[primary_span] - #[label] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_fn_param_forbidden_attr)] -pub struct FnParamForbiddenAttr { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_fn_param_forbidden_self)] -#[note] -pub struct FnParamForbiddenSelf { - #[primary_span] - #[label] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_forbidden_default)] -pub struct ForbiddenDefault { - #[primary_span] - pub span: Span, - #[label] - pub def_span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_assoc_const_without_body)] -pub struct AssocConstWithoutBody { - #[primary_span] - pub span: Span, - #[suggestion(code = " = ;", applicability = "has-placeholders")] - pub replace_span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_assoc_fn_without_body)] -pub struct AssocFnWithoutBody { - #[primary_span] - pub span: Span, - #[suggestion(code = " {{ }}", applicability = "has-placeholders")] - pub replace_span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_assoc_type_without_body)] -pub struct AssocTypeWithoutBody { - #[primary_span] - pub span: Span, - #[suggestion(code = " = ;", applicability = "has-placeholders")] - pub replace_span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_const_without_body)] -pub struct ConstWithoutBody { - #[primary_span] - pub span: Span, - #[suggestion(code = " = ;", applicability = "has-placeholders")] - pub replace_span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_static_without_body)] -pub struct StaticWithoutBody { - #[primary_span] - pub span: Span, - #[suggestion(code = " = ;", applicability = "has-placeholders")] - pub replace_span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_ty_alias_without_body)] -pub struct TyAliasWithoutBody { - #[primary_span] - pub span: Span, - #[suggestion(code = " = ;", applicability = "has-placeholders")] - pub replace_span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_fn_without_body)] -pub struct FnWithoutBody { - #[primary_span] - pub span: Span, - #[suggestion(code = " {{ }}", applicability = "has-placeholders")] - pub replace_span: Span, - #[subdiagnostic] - pub extern_block_suggestion: Option, -} - -#[derive(Subdiagnostic)] -pub enum ExternBlockSuggestion { - #[multipart_suggestion(ast_passes_extern_block_suggestion, applicability = "maybe-incorrect")] - Implicit { - #[suggestion_part(code = "extern {{")] - start_span: Span, - #[suggestion_part(code = " }}")] - end_span: Span, - }, - #[multipart_suggestion(ast_passes_extern_block_suggestion, applicability = "maybe-incorrect")] - Explicit { - #[suggestion_part(code = "extern \"{abi}\" {{")] - start_span: Span, - #[suggestion_part(code = " }}")] - end_span: Span, - abi: Symbol, - }, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_bound_in_context)] -pub struct BoundInContext<'a> { - #[primary_span] - pub span: Span, - pub ctx: &'a str, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_extern_types_cannot)] -#[note(ast_passes_extern_keyword_link)] -pub struct ExternTypesCannotHave<'a> { - #[primary_span] - #[suggestion(code = "", applicability = "maybe-incorrect")] - pub span: Span, - pub descr: &'a str, - pub remove_descr: &'a str, - #[label] - pub block_span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_body_in_extern)] -#[note(ast_passes_extern_keyword_link)] -pub struct BodyInExtern<'a> { - #[primary_span] - #[label(ast_passes_cannot_have)] - pub span: Span, - #[label(ast_passes_invalid)] - pub body: Span, - #[label(ast_passes_existing)] - pub block: Span, - pub kind: &'a str, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_fn_body_extern)] -#[help] -#[note(ast_passes_extern_keyword_link)] -pub struct FnBodyInExtern { - #[primary_span] - #[label(ast_passes_cannot_have)] - pub span: Span, - #[suggestion(code = ";", applicability = "maybe-incorrect")] - pub body: Span, - #[label] - pub block: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_extern_fn_qualifiers)] -pub struct FnQualifierInExtern { - #[primary_span] - pub span: Span, - #[label] - pub block: Span, - #[suggestion(code = "fn ", applicability = "maybe-incorrect", style = "verbose")] - pub sugg_span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_extern_item_ascii)] -#[note] -pub struct ExternItemAscii { - #[primary_span] - pub span: Span, - #[label] - pub block: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_bad_c_variadic)] -pub struct BadCVariadic { - #[primary_span] - pub span: Vec, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_item_underscore)] -pub struct ItemUnderscore<'a> { - #[primary_span] - #[label] - pub span: Span, - pub kind: &'a str, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_nomangle_ascii, code = E0754)] -pub struct NoMangleAscii { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_module_nonascii, code = E0754)] -#[help] -pub struct ModuleNonAscii { - #[primary_span] - pub span: Span, - pub name: Symbol, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_auto_generic, code = E0567)] -pub struct AutoTraitGeneric { - #[primary_span] - #[suggestion(code = "", applicability = "machine-applicable")] - pub span: Span, - #[label] - pub ident: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_auto_super_lifetime, code = E0568)] -pub struct AutoTraitBounds { - #[primary_span] - #[suggestion(code = "", applicability = "machine-applicable")] - pub span: Span, - #[label] - pub ident: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_auto_items, code = E0380)] -pub struct AutoTraitItems { - #[primary_span] - pub spans: Vec, - #[suggestion(code = "", applicability = "machine-applicable")] - pub total: Span, - #[label] - pub ident: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_generic_before_constraints)] -pub struct ArgsBeforeConstraint { - #[primary_span] - pub arg_spans: Vec, - #[label(ast_passes_constraints)] - pub constraints: Span, - #[label(ast_passes_args)] - pub args: Span, - #[suggestion(code = "{suggestion}", applicability = "machine-applicable", style = "verbose")] - pub data: Span, - pub suggestion: String, - pub constraint_len: usize, - pub args_len: usize, - #[subdiagnostic] - pub constraint_spans: EmptyLabelManySpans, - #[subdiagnostic] - pub arg_spans2: EmptyLabelManySpans, -} - -pub struct EmptyLabelManySpans(pub Vec); - -// The derive for `Vec` does multiple calls to `span_label`, adding commas between each -impl Subdiagnostic for EmptyLabelManySpans { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _: F, - ) { - diag.span_labels(self.0, ""); - } -} - -#[derive(Diagnostic)] -#[diag(ast_passes_pattern_in_fn_pointer, code = E0561)] -pub struct PatternFnPointer { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_trait_object_single_bound, code = E0226)] -pub struct TraitObjectBound { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_impl_trait_path, code = E0667)] -pub struct ImplTraitPath { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_nested_impl_trait, code = E0666)] -pub struct NestedImplTrait { - #[primary_span] - pub span: Span, - #[label(ast_passes_outer)] - pub outer: Span, - #[label(ast_passes_inner)] - pub inner: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_at_least_one_trait)] -pub struct AtLeastOneTrait { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_out_of_order_params)] -pub struct OutOfOrderParams<'a> { - #[primary_span] - pub spans: Vec, - #[suggestion(code = "{ordered_params}", applicability = "machine-applicable")] - pub sugg_span: Span, - pub param_ord: &'a ParamKindOrd, - pub max_param: &'a ParamKindOrd, - pub ordered_params: &'a str, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_obsolete_auto)] -#[help] -pub struct ObsoleteAuto { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_unsafe_negative_impl, code = E0198)] -pub struct UnsafeNegativeImpl { - #[primary_span] - pub span: Span, - #[label(ast_passes_negative)] - pub negative: Span, - #[label(ast_passes_unsafe)] - pub r#unsafe: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_inherent_cannot_be)] -pub struct InherentImplCannot<'a> { - #[primary_span] - pub span: Span, - #[label(ast_passes_because)] - pub annotation_span: Span, - pub annotation: &'a str, - #[label(ast_passes_type)] - pub self_ty: Span, - #[note(ast_passes_only_trait)] - pub only_trait: Option<()>, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_inherent_cannot_be, code = E0197)] -pub struct InherentImplCannotUnsafe<'a> { - #[primary_span] - pub span: Span, - #[label(ast_passes_because)] - pub annotation_span: Span, - pub annotation: &'a str, - #[label(ast_passes_type)] - pub self_ty: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_unsafe_item)] -pub struct UnsafeItem { - #[primary_span] - pub span: Span, - pub kind: &'static str, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_fieldless_union)] -pub struct FieldlessUnion { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_where_clause_after_type_alias)] -#[note] -pub struct WhereClauseAfterTypeAlias { - #[primary_span] - pub span: Span, - #[help] - pub help: Option<()>, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_where_clause_before_type_alias)] -#[note] -pub struct WhereClauseBeforeTypeAlias { - #[primary_span] - pub span: Span, - #[subdiagnostic] - pub sugg: WhereClauseBeforeTypeAliasSugg, -} - -#[derive(Subdiagnostic)] - -pub enum WhereClauseBeforeTypeAliasSugg { - #[suggestion(ast_passes_remove_suggestion, applicability = "machine-applicable", code = "")] - Remove { - #[primary_span] - span: Span, - }, - #[multipart_suggestion( - ast_passes_move_suggestion, - applicability = "machine-applicable", - style = "verbose" - )] - Move { - #[suggestion_part(code = "")] - left: Span, - snippet: String, - #[suggestion_part(code = "{snippet}")] - right: Span, - }, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_generic_default_trailing)] -pub struct GenericDefaultTrailing { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_nested_lifetimes, code = E0316)] -pub struct NestedLifetimes { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_optional_trait_supertrait)] -#[note] -pub struct OptionalTraitSupertrait { - #[primary_span] - pub span: Span, - pub path_str: String, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_optional_trait_object)] -pub struct OptionalTraitObject { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_const_bound_trait_object)] -pub struct ConstBoundTraitObject { - #[primary_span] - pub span: Span, -} - -// FIXME(effects): Consider making the note/reason the message of the diagnostic. -// FIXME(effects): Provide structured suggestions (e.g., add `const` / `#[const_trait]` here). -#[derive(Diagnostic)] -#[diag(ast_passes_tilde_const_disallowed)] -pub struct TildeConstDisallowed { - #[primary_span] - pub span: Span, - #[subdiagnostic] - pub reason: TildeConstReason, -} - -#[derive(Subdiagnostic)] -pub enum TildeConstReason { - #[note(ast_passes_closure)] - Closure, - #[note(ast_passes_function)] - Function { - #[primary_span] - ident: Span, - }, - #[note(ast_passes_trait)] - Trait { - #[primary_span] - span: Span, - }, - #[note(ast_passes_trait_impl)] - TraitImpl { - #[primary_span] - span: Span, - }, - #[note(ast_passes_impl)] - Impl { - #[primary_span] - span: Span, - }, - #[note(ast_passes_trait_assoc_ty)] - TraitAssocTy { - #[primary_span] - span: Span, - }, - #[note(ast_passes_trait_impl_assoc_ty)] - TraitImplAssocTy { - #[primary_span] - span: Span, - }, - #[note(ast_passes_inherent_assoc_ty)] - InherentAssocTy { - #[primary_span] - span: Span, - }, - #[note(ast_passes_object)] - TraitObject, - #[note(ast_passes_item)] - Item, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_incompatible_trait_bound_modifiers)] -pub struct IncompatibleTraitBoundModifiers { - #[primary_span] - pub span: Span, - pub left: &'static str, - pub right: &'static str, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_const_and_async)] -pub struct ConstAndAsync { - #[primary_span] - pub spans: Vec, - #[label(ast_passes_const)] - pub cspan: Span, - #[label(ast_passes_async)] - pub aspan: Span, - #[label] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_const_and_c_variadic)] -pub struct ConstAndCVariadic { - #[primary_span] - pub spans: Vec, - #[label(ast_passes_const)] - pub const_span: Span, - #[label(ast_passes_variadic)] - pub variadic_spans: Vec, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_pattern_in_foreign, code = E0130)] -pub struct PatternInForeign { - #[primary_span] - #[label] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_pattern_in_bodiless, code = E0642)] -pub struct PatternInBodiless { - #[primary_span] - #[label] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_equality_in_where)] -#[note] -pub struct EqualityInWhere { - #[primary_span] - #[label] - pub span: Span, - #[subdiagnostic] - pub assoc: Option, - #[subdiagnostic] - pub assoc2: Option, -} - -#[derive(Subdiagnostic)] -#[suggestion( - ast_passes_suggestion, - code = "{param}: {path}", - style = "verbose", - applicability = "maybe-incorrect" -)] -pub struct AssociatedSuggestion { - #[primary_span] - pub span: Span, - pub ident: Ident, - pub param: Ident, - pub path: String, -} - -#[derive(Subdiagnostic)] -#[multipart_suggestion(ast_passes_suggestion_path, applicability = "maybe-incorrect")] -pub struct AssociatedSuggestion2 { - #[suggestion_part(code = "{args}")] - pub span: Span, - pub args: String, - #[suggestion_part(code = "")] - pub predicate: Span, - pub trait_segment: Ident, - pub potential_assoc: Ident, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_stability_outside_std, code = E0734)] -pub struct StabilityOutsideStd { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_feature_on_non_nightly, code = E0554)] -pub struct FeatureOnNonNightly { - #[primary_span] - pub span: Span, - pub channel: &'static str, - #[subdiagnostic] - pub stable_features: Vec, - #[suggestion(code = "", applicability = "machine-applicable")] - pub sugg: Option, -} - -pub struct StableFeature { - pub name: Symbol, - pub since: Symbol, -} - -impl Subdiagnostic for StableFeature { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _: F, - ) { - diag.arg("name", self.name); - diag.arg("since", self.since); - diag.help(fluent::ast_passes_stable_since); - } -} - -#[derive(Diagnostic)] -#[diag(ast_passes_incompatible_features)] -#[help] -pub struct IncompatibleFeatures { - #[primary_span] - pub spans: Vec, - pub f1: Symbol, - pub f2: Symbol, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_show_span)] -pub struct ShowSpan { - #[primary_span] - pub span: Span, - pub msg: &'static str, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_negative_bound_not_supported)] -pub struct NegativeBoundUnsupported { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_constraint_on_negative_bound)] -pub struct ConstraintOnNegativeBound { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_negative_bound_with_parenthetical_notation)] -pub struct NegativeBoundWithParentheticalNotation { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_invalid_unnamed_field_ty)] -pub struct InvalidUnnamedFieldTy { - #[primary_span] - pub span: Span, - #[label] - pub ty_span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_invalid_unnamed_field)] -pub struct InvalidUnnamedField { - #[primary_span] - pub span: Span, - #[label] - pub ident_span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_anon_struct_or_union_not_allowed)] -pub struct AnonStructOrUnionNotAllowed { - #[primary_span] - #[label] - pub span: Span, - pub struct_or_union: &'static str, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_match_arm_with_no_body)] -pub struct MatchArmWithNoBody { - #[primary_span] - pub span: Span, - #[suggestion(code = " => todo!(),", applicability = "has-placeholders")] - pub suggestion: Span, -} +use rustc_ast::ParamKindOrd;use rustc_errors::{codes::*,Applicability,Diag,//(); +EmissionGuarantee,SubdiagMessageOp,Subdiagnostic,};use rustc_macros::{//((),()); +Diagnostic,Subdiagnostic};use rustc_span::{symbol ::Ident,Span,Symbol};use crate +::fluent_generated as fluent;#[derive(Diagnostic)]#[diag(//if true{};let _=||(); +ast_passes_keyword_lifetime)]pub struct KeywordLifetime {#[primary_span]pub span +:Span,}#[derive(Diagnostic)]#[diag(ast_passes_invalid_label)]pub struct//*&*&(); +InvalidLabel{#[primary_span]pub span:Span, pub name:Symbol,}#[derive(Diagnostic) +]#[diag(ast_passes_visibility_not_permitted,code=E0449)]pub struct//loop{break}; +VisibilityNotPermitted{#[primary_span]pub span:Span,#[subdiagnostic]pub note://; +VisibilityNotPermittedNote,}#[derive(Subdiagnostic)]pub enum//let _=();let _=(); +VisibilityNotPermittedNote{#[note(ast_passes_enum_variant)]EnumVariant,#[note(// +ast_passes_trait_impl)]TraitImpl,#[note(ast_passes_individual_impl_items)]//{;}; +IndividualImplItems,#[note(ast_passes_individual_foreign_items)]//if let _=(){}; +IndividualForeignItems,}#[derive(Diagnostic)]#[diag(ast_passes_trait_fn_const,// +code=E0379)]pub struct TraitFnConst{#[primary_span]#[label]pub span:Span,pub//3; +in_impl:bool,#[label(ast_passes_const_context_label)]pub const_context_label://; +Option,#[suggestion(ast_passes_remove_const_sugg,code="")]pub//let _=||(); +remove_const_sugg:(Span,Applicability),pub requires_multiple_changes:bool,#[//3; +suggestion(ast_passes_make_impl_const_sugg,code="const ",applicability=//*&*&(); +"maybe-incorrect")]pub make_impl_const_sugg:Option,#[suggestion(//((),()); +ast_passes_make_trait_const_sugg,code="#[const_trait]\n",applicability=//*&*&(); +"maybe-incorrect")]pub make_trait_const_sugg:Option< Span>,}#[derive(Diagnostic) +]#[diag(ast_passes_forbidden_bound)]pub struct ForbiddenBound{#[primary_span]//; +pub spans:Vec,}#[ derive(Diagnostic)]#[diag(ast_passes_fn_param_too_many)] +pub struct FnParamTooMany{#[primary_span]pub span:Span,pub max_num_args:usize,} +#[derive(Diagnostic)]#[diag(ast_passes_fn_param_c_var_args_only)]pub struct//(); +FnParamCVarArgsOnly{#[primary_span]pub span:Span,}#[derive(Diagnostic)]#[diag(// +ast_passes_fn_param_c_var_args_not_last)]pub struct FnParamCVarArgsNotLast{#[//; +primary_span]pub span:Span,}#[derive(Diagnostic)]#[diag(//let _=||();let _=||(); +ast_passes_fn_param_doc_comment)]pub struct FnParamDocComment{#[primary_span]#[ +label]pub span:Span,}#[derive(Diagnostic)]#[diag(//if let _=(){};*&*&();((),()); +ast_passes_fn_param_forbidden_attr)]pub struct FnParamForbiddenAttr{#[//((),()); +primary_span]pub span:Span,}#[derive(Diagnostic)]#[diag(//let _=||();let _=||(); +ast_passes_fn_param_forbidden_self)]#[note]pub struct FnParamForbiddenSelf{#[//; +primary_span]#[label]pub span:Span,}#[derive(Diagnostic)]#[diag(//if let _=(){}; +ast_passes_forbidden_default)]pub struct ForbiddenDefault{#[primary_span]pub//3; +span:Span,#[label]pub def_span:Span,}#[derive(Diagnostic)]#[diag(//loop{break;}; +ast_passes_assoc_const_without_body)]pub struct AssocConstWithoutBody{#[//{();}; +primary_span]pub span:Span,#[suggestion(code=" = ;",applicability=//{();}; +"has-placeholders")]pub replace_span:Span,}#[derive(Diagnostic)]#[diag(//*&*&(); +ast_passes_assoc_fn_without_body)]pub struct AssocFnWithoutBody{#[primary_span] +pub span:Span,#[suggestion(code=" {{ }}",applicability=//((),());((),()); +"has-placeholders")]pub replace_span:Span,}#[derive(Diagnostic)]#[diag(//*&*&(); +ast_passes_assoc_type_without_body)]pub struct AssocTypeWithoutBody{#[//((),()); +primary_span]pub span:Span,#[suggestion(code=" = ;",applicability=//{();}; +"has-placeholders")]pub replace_span:Span,}#[derive(Diagnostic)]#[diag(//*&*&(); +ast_passes_const_without_body)]pub struct ConstWithoutBody{#[primary_span]pub//; +span:Span,#[suggestion(code=" = ;",applicability="has-placeholders")]pub// +replace_span:Span,}#[derive( Diagnostic)]#[diag(ast_passes_static_without_body)] +pub struct StaticWithoutBody{#[primary_span]pub span:Span,#[suggestion(code=//3; +" = ;",applicability="has-placeholders")]pub replace_span:Span,}#[derive( +Diagnostic)]#[diag(ast_passes_ty_alias_without_body)]pub struct//*&*&();((),()); +TyAliasWithoutBody{#[primary_span]pub span: Span,#[suggestion(code=" = ;", +applicability="has-placeholders")]pub replace_span:Span ,}#[derive(Diagnostic)]# +[diag(ast_passes_fn_without_body)]pub struct FnWithoutBody{#[primary_span]pub//; +span:Span,#[suggestion(code=" {{ }}",applicability="has-placeholders")]// +pub replace_span:Span,#[subdiagnostic]pub extern_block_suggestion:Option,}#[derive( Subdiagnostic)]pub enum ExternBlockSuggestion{ +#[multipart_suggestion(ast_passes_extern_block_suggestion,applicability=//{();}; +"maybe-incorrect")]Implicit{#[suggestion_part (code="extern {{")]start_span:Span +,#[suggestion_part(code=" }}")]end_span:Span,},#[multipart_suggestion(//((),()); +ast_passes_extern_block_suggestion,applicability="maybe-incorrect" )]Explicit{#[ +suggestion_part(code="extern \"{abi}\" {{")]start_span:Span,#[suggestion_part(// +code=" }}")]end_span:Span,abi:Symbol,},}#[derive(Diagnostic)]#[diag(//if true{}; +ast_passes_bound_in_context)]pub struct BoundInContext<'a>{#[primary_span]pub//; +span:Span,pub ctx:&'a str,}#[derive(Diagnostic)]#[diag(//let _=||();loop{break}; +ast_passes_extern_types_cannot)]#[note(ast_passes_extern_keyword_link)]pub//{;}; +struct ExternTypesCannotHave<'a>{#[primary_span]#[suggestion(code="",//let _=(); +applicability="maybe-incorrect")]pub span:Span,pub descr:&'a str,pub//if true{}; +remove_descr:&'a str,#[label]pub block_span:Span,}#[derive(Diagnostic)]#[diag(// +ast_passes_body_in_extern)]#[note(ast_passes_extern_keyword_link)]pub struct//3; +BodyInExtern<'a>{#[primary_span]#[ label(ast_passes_cannot_have)]pub span:Span,# +[label(ast_passes_invalid)]pub body:Span ,#[label(ast_passes_existing)]pub block +:Span,pub kind:&'a str,} #[derive(Diagnostic)]#[diag(ast_passes_fn_body_extern)] +#[help]#[note(ast_passes_extern_keyword_link)]pub struct FnBodyInExtern{#[//{;}; +primary_span]#[label(ast_passes_cannot_have)]pub span:Span,#[suggestion(code=//; +";",applicability="maybe-incorrect")]pub body:Span,#[label]pub block:Span,}#[//; +derive(Diagnostic)]#[diag(ast_passes_extern_fn_qualifiers)]pub struct//let _=(); +FnQualifierInExtern{#[primary_span]pub span:Span,#[label]pub block:Span,#[//{;}; +suggestion(code="fn ",applicability="maybe-incorrect",style="verbose")]pub//{;}; +sugg_span:Span,}#[derive(Diagnostic)]#[diag(ast_passes_extern_item_ascii)]#[//3; +note]pub struct ExternItemAscii{#[primary_span]pub span:Span,#[label]pub block: +Span,}#[derive(Diagnostic)]#[diag(ast_passes_bad_c_variadic)]pub struct//*&*&(); +BadCVariadic{#[primary_span]pub span:Vec,}#[derive(Diagnostic)]#[diag(//3; +ast_passes_item_underscore)]pub struct ItemUnderscore<'a>{#[primary_span]#[//(); +label]pub span:Span,pub kind:&'a str,}#[derive(Diagnostic)]#[diag(//loop{break}; +ast_passes_nomangle_ascii,code=E0754)]pub struct NoMangleAscii{#[primary_span]// +pub span:Span,}#[derive(Diagnostic)]#[diag(ast_passes_module_nonascii,code=//(); +E0754)]#[help]pub struct ModuleNonAscii{#[primary_span]pub span:Span,pub name:// +Symbol,}#[derive(Diagnostic)]#[diag(ast_passes_auto_generic,code=E0567)]pub//(); +struct AutoTraitGeneric{#[primary_span]#[suggestion(code="",applicability=//{;}; +"machine-applicable")]pub span:Span,#[label ]pub ident:Span,}#[derive(Diagnostic +)]#[diag(ast_passes_auto_super_lifetime,code =E0568)]pub struct AutoTraitBounds{ +#[primary_span]#[suggestion(code="",applicability="machine-applicable")]pub//(); +span:Span,#[label]pub ident:Span,}#[derive(Diagnostic)]#[diag(//((),());((),()); +ast_passes_auto_items,code=E0380)]pub struct AutoTraitItems{#[primary_span]pub// +spans:Vec,#[suggestion(code="",applicability="machine-applicable")]pub//3; +total:Span,#[label]pub ident:Span,}#[derive(Diagnostic)]#[diag(//*&*&();((),()); +ast_passes_generic_before_constraints)]pub struct ArgsBeforeConstraint{#[//({}); +primary_span]pub arg_spans:Vec,#[label(ast_passes_constraints)]pub//{();}; +constraints:Span,#[label(ast_passes_args)]pub args:Span,#[suggestion(code=//{;}; +"{suggestion}",applicability="machine-applicable",style="verbose")]pub data://3; +Span,pub suggestion:String,pub constraint_len:usize,pub args_len:usize,#[//({}); +subdiagnostic]pub constraint_spans:EmptyLabelManySpans,#[subdiagnostic]pub//{;}; +arg_spans2:EmptyLabelManySpans,}pub struct EmptyLabelManySpans(pub Vec);// +impl Subdiagnostic for EmptyLabelManySpans{fn add_to_diag_with>(self,diag:&mut Diag<'_,G>,_:F,){3;diag. +span_labels(self.0,"");loop{break;};if let _=(){};}}#[derive(Diagnostic)]#[diag( +ast_passes_pattern_in_fn_pointer,code=E0561)]pub struct PatternFnPointer{#[//(); +primary_span]pub span:Span,}#[derive(Diagnostic)]#[diag(//let _=||();let _=||(); +ast_passes_trait_object_single_bound,code=E0226)] pub struct TraitObjectBound{#[ +primary_span]pub span:Span,}#[derive(Diagnostic)]#[diag(//let _=||();let _=||(); +ast_passes_impl_trait_path,code=E0667)]pub struct ImplTraitPath{#[primary_span] +pub span:Span,}#[derive(Diagnostic)]#[diag(ast_passes_nested_impl_trait,code=//; +E0666)]pub struct NestedImplTrait{#[primary_span]pub span:Span,#[label(//*&*&(); +ast_passes_outer)]pub outer:Span,#[label(ast_passes_inner)]pub inner:Span,}#[//; +derive(Diagnostic)]#[diag(ast_passes_at_least_one_trait)]pub struct//let _=||(); +AtLeastOneTrait{#[primary_span]pub span:Span,}#[derive(Diagnostic)]#[diag(//{;}; +ast_passes_out_of_order_params)]pub struct OutOfOrderParams <'a>{#[primary_span] +pub spans:Vec,#[suggestion(code="{ordered_params}",applicability=//*&*&(); +"machine-applicable")]pub sugg_span:Span,pub param_ord:&'a ParamKindOrd,pub//(); +max_param:&'a ParamKindOrd,pub ordered_params:&'a str,}#[derive(Diagnostic)]#[// +diag(ast_passes_obsolete_auto)]#[help]pub struct ObsoleteAuto{#[primary_span]//; +pub span:Span,}#[derive (Diagnostic)]#[diag(ast_passes_unsafe_negative_impl,code +=E0198)]pub struct UnsafeNegativeImpl{#[primary_span]pub span:Span,#[label(//(); +ast_passes_negative)]pub negative:Span,# [label(ast_passes_unsafe)]pub r#unsafe: +Span,}#[derive(Diagnostic)]#[diag(ast_passes_inherent_cannot_be)]pub struct//(); +InherentImplCannot<'a>{#[primary_span]pub span:Span,#[label(ast_passes_because) +]pub annotation_span:Span,pub annotation:&'a str,#[label(ast_passes_type)]pub//; +self_ty:Span,#[note(ast_passes_only_trait)]pub only_trait:Option<()>,}#[derive( +Diagnostic)]#[diag(ast_passes_inherent_cannot_be,code=E0197)]pub struct//*&*&(); +InherentImplCannotUnsafe<'a>{#[primary_span]pub span:Span,#[label(//loop{break}; +ast_passes_because)]pub annotation_span:Span,pub annotation:&'a str,#[label(//3; +ast_passes_type)]pub self_ty:Span,}#[derive(Diagnostic)]#[diag(//*&*&();((),()); +ast_passes_unsafe_item)]pub struct UnsafeItem{#[primary_span]pub span:Span,pub// +kind:&'static str,}#[derive(Diagnostic)]#[diag(ast_passes_fieldless_union)]pub// +struct FieldlessUnion{#[primary_span]pub span: Span,}#[derive(Diagnostic)]#[diag +(ast_passes_where_clause_after_type_alias)]#[note]pub struct//let _=();let _=(); +WhereClauseAfterTypeAlias{#[primary_span]pub span:Span ,#[help]pub help:Option<( +)>,}#[derive(Diagnostic)]#[diag(ast_passes_where_clause_before_type_alias)]#[//; +note]pub struct WhereClauseBeforeTypeAlias{#[primary_span]pub span:Span,#[//{;}; +subdiagnostic]pub sugg:WhereClauseBeforeTypeAliasSugg, }#[derive(Subdiagnostic)] +pub enum WhereClauseBeforeTypeAliasSugg{#[suggestion(//loop{break};loop{break;}; +ast_passes_remove_suggestion,applicability="machine-applicable", code="")]Remove +{#[primary_span]span:Span,},#[multipart_suggestion(ast_passes_move_suggestion,// +applicability="machine-applicable",style="verbose") ]Move{#[suggestion_part(code +="")]left:Span,snippet:String,# [suggestion_part(code="{snippet}")]right:Span,}, +}#[derive(Diagnostic)]#[diag(ast_passes_generic_default_trailing)]pub struct//3; +GenericDefaultTrailing{#[primary_span]pub span:Span,}#[derive(Diagnostic)]#[//3; +diag(ast_passes_nested_lifetimes,code=E0316)]pub struct NestedLifetimes{#[//{;}; +primary_span]pub span:Span,}#[derive(Diagnostic)]#[diag(//let _=||();let _=||(); +ast_passes_optional_trait_supertrait)]#[note ]pub struct OptionalTraitSupertrait +{#[primary_span]pub span:Span,pub path_str :String,}#[derive(Diagnostic)]#[diag( +ast_passes_optional_trait_object)]pub struct OptionalTraitObject{#[primary_span +]pub span:Span,}#[ derive(Diagnostic)]#[diag(ast_passes_const_bound_trait_object +)]pub struct ConstBoundTraitObject{#[primary_span]pub span:Span,}#[derive(//{;}; +Diagnostic)]#[diag(ast_passes_tilde_const_disallowed)]pub struct//if let _=(){}; +TildeConstDisallowed{#[primary_span]pub span:Span,#[subdiagnostic]pub reason://; +TildeConstReason,}#[derive(Subdiagnostic)]pub enum TildeConstReason{#[note(//(); +ast_passes_closure)]Closure,#[note (ast_passes_function)]Function{#[primary_span +]ident:Span,},#[note(ast_passes_trait)]Trait {#[primary_span]span:Span,},#[note( +ast_passes_trait_impl)]TraitImpl{#[primary_span]span:Span,},#[note(//let _=||(); +ast_passes_impl)]Impl{#[primary_span]span:Span,},#[note(//let _=||();let _=||(); +ast_passes_trait_assoc_ty)]TraitAssocTy{#[primary_span]span:Span,},#[note(//{;}; +ast_passes_trait_impl_assoc_ty)]TraitImplAssocTy{#[primary_span]span:Span,},#[// +note(ast_passes_inherent_assoc_ty)]InherentAssocTy{#[ primary_span]span:Span,},# +[note(ast_passes_object)]TraitObject,#[note(ast_passes_item)]Item,}#[derive(//3; +Diagnostic)]#[diag(ast_passes_incompatible_trait_bound_modifiers)]pub struct//3; +IncompatibleTraitBoundModifiers{#[primary_span]pub span:Span,pub left:&'static// +str,pub right:&'static str,}#[derive(Diagnostic)]#[diag(//let _=||();let _=||(); +ast_passes_const_and_async)]pub struct ConstAndAsync{#[primary_span]pub spans:// +Vec,#[label(ast_passes_const)]pub cspan:Span,#[label(ast_passes_async)]//; +pub aspan:Span,#[label]pub span:Span,}#[derive(Diagnostic)]#[diag(//loop{break}; +ast_passes_const_and_c_variadic)]pub struct ConstAndCVariadic{#[primary_span]//; +pub spans:Vec,#[label(ast_passes_const)]pub const_span:Span,#[label(//{;}; +ast_passes_variadic)]pub variadic_spans:Vec, }#[derive(Diagnostic)]#[diag( +ast_passes_pattern_in_foreign,code=E0130)]pub struct PatternInForeign{#[//{();}; +primary_span]#[label]pub span:Span,}#[derive(Diagnostic)]#[diag(//if let _=(){}; +ast_passes_pattern_in_bodiless,code=E0642)]pub struct PatternInBodiless{#[//{;}; +primary_span]#[label]pub span:Span,}#[derive(Diagnostic)]#[diag(//if let _=(){}; +ast_passes_equality_in_where)]#[note]pub struct EqualityInWhere{#[primary_span] +#[label]pub span:Span,#[ subdiagnostic]pub assoc:Option,#[ +subdiagnostic]pub assoc2:Option,}#[derive(Subdiagnostic) +]#[suggestion(ast_passes_suggestion,code="{param}: {path}",style="verbose",//(); +applicability="maybe-incorrect")]pub struct AssociatedSuggestion{#[primary_span +]pub span:Span,pub ident:Ident,pub param:Ident,pub path:String,}#[derive(//({}); +Subdiagnostic)]#[ multipart_suggestion(ast_passes_suggestion_path,applicability= +"maybe-incorrect")]pub struct AssociatedSuggestion2{#[suggestion_part(code=//(); +"{args}")]pub span:Span,pub args:String,#[suggestion_part(code="")]pub//((),()); +predicate:Span,pub trait_segment:Ident,pub potential_assoc:Ident,}#[derive(//(); +Diagnostic)]#[diag(ast_passes_stability_outside_std,code=E0734)]pub struct//{;}; +StabilityOutsideStd{#[primary_span]pub span:Span,}#[derive(Diagnostic)]#[diag(// +ast_passes_feature_on_non_nightly,code=E0554)] pub struct FeatureOnNonNightly{#[ +primary_span]pub span:Span,pub channel:&'static str,#[subdiagnostic]pub//*&*&(); +stable_features:Vec,#[suggestion(code="",applicability=//((),()); +"machine-applicable")]pub sugg:Option ,}pub struct StableFeature{pub name: +Symbol,pub since:Symbol,}impl Subdiagnostic for StableFeature{fn//if let _=(){}; +add_to_diag_with>(self,diag:&mut Diag +<'_,G>,_:F,){;diag.arg("name",self.name);diag.arg("since",self.since);diag.help( +fluent::ast_passes_stable_since);((),());let _=();}}#[derive(Diagnostic)]#[diag( +ast_passes_incompatible_features)]#[help]pub struct IncompatibleFeatures{#[//(); +primary_span]pub spans:Vec,pub f1:Symbol,pub f2:Symbol,}#[derive(//*&*&(); +Diagnostic)]#[diag(ast_passes_show_span)] pub struct ShowSpan{#[primary_span]pub +span:Span,pub msg:&'static str,}#[derive(Diagnostic)]#[diag(//let _=();let _=(); +ast_passes_negative_bound_not_supported)]pub struct NegativeBoundUnsupported{#[ +primary_span]pub span:Span,}#[derive(Diagnostic)]#[diag(//let _=||();let _=||(); +ast_passes_constraint_on_negative_bound)]pub struct ConstraintOnNegativeBound{# +[primary_span]pub span:Span,}#[derive(Diagnostic)]#[diag(//if true{};let _=||(); +ast_passes_negative_bound_with_parenthetical_notation)]pub struct//loop{break;}; +NegativeBoundWithParentheticalNotation{#[primary_span]pub span:Span,}#[derive(// +Diagnostic)]#[diag(ast_passes_invalid_unnamed_field_ty)]pub struct//loop{break}; +InvalidUnnamedFieldTy{#[primary_span]pub span:Span, #[label]pub ty_span:Span,}#[ +derive(Diagnostic)]#[diag(ast_passes_invalid_unnamed_field)]pub struct//((),()); +InvalidUnnamedField{#[primary_span]pub span:Span, #[label]pub ident_span:Span,}# +[derive(Diagnostic)]#[diag(ast_passes_anon_struct_or_union_not_allowed)]pub//(); +struct AnonStructOrUnionNotAllowed{#[primary_span]#[label]pub span:Span,pub//(); +struct_or_union:&'static str,}#[derive(Diagnostic)]#[diag(//if true{};if true{}; +ast_passes_match_arm_with_no_body)]pub struct MatchArmWithNoBody{#[primary_span +]pub span:Span,#[suggestion(code=" => todo!(),",applicability=//((),());((),()); +"has-placeholders")]pub suggestion:Span,}//let _=();let _=();let _=();if true{}; diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 5912dd3f931b2..1c8c168f4c3d4 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -1,693 +1,227 @@ -use rustc_ast as ast; -use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; -use rustc_ast::{attr, AssocConstraint, AssocConstraintKind, NodeId}; -use rustc_ast::{token, PatKind, RangeEnd}; -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; -use thin_vec::ThinVec; - -use crate::errors; - -/// The common case. -macro_rules! gate { - ($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{ - if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) { - #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable - feature_err(&$visitor.sess, sym::$feature, $span, $explain).emit(); - } - }}; - ($visitor:expr, $feature:ident, $span:expr, $explain:expr, $help:expr) => {{ - if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) { - // FIXME: make this translatable - #[allow(rustc::diagnostic_outside_of_impl)] - #[allow(rustc::untranslatable_diagnostic)] - feature_err(&$visitor.sess, sym::$feature, $span, $explain).with_help($help).emit(); - } - }}; -} - -/// The unusual case, where the `has_feature` condition is non-standard. -macro_rules! gate_alt { - ($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr) => {{ - if !$has_feature && !$span.allows_unstable($name) { - #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable - feature_err(&$visitor.sess, $name, $span, $explain).emit(); - } - }}; -} - -/// The case involving a multispan. -macro_rules! gate_multi { - ($visitor:expr, $feature:ident, $spans:expr, $explain:expr) => {{ - if !$visitor.features.$feature { - let spans: Vec<_> = - $spans.filter(|span| !span.allows_unstable(sym::$feature)).collect(); - if !spans.is_empty() { - feature_err(&$visitor.sess, sym::$feature, spans, $explain).emit(); - } - } - }}; -} - -/// The legacy case. -macro_rules! gate_legacy { - ($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{ - if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) { - feature_warn(&$visitor.sess, sym::$feature, $span, $explain); - } - }}; -} - -pub fn check_attribute(attr: &ast::Attribute, sess: &Session, features: &Features) { - PostExpansionVisitor { sess, features }.visit_attribute(attr) -} - -struct PostExpansionVisitor<'a> { - sess: &'a Session, - - // `sess` contains a `Features`, but this might not be that one. - features: &'a Features, -} - -impl<'a> PostExpansionVisitor<'a> { - #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable - fn check_abi(&self, abi: ast::StrLit, constness: ast::Const) { - let ast::StrLit { symbol_unescaped, span, .. } = abi; - - if let ast::Const::Yes(_) = constness { - match symbol_unescaped { - // Stable - sym::Rust | sym::C => {} - abi => gate!( - &self, - const_extern_fn, - span, - format!("`{}` as a `const fn` ABI is unstable", abi) - ), - } - } - - match abi::is_enabled(self.features, span, symbol_unescaped.as_str()) { - Ok(()) => (), - Err(abi::AbiDisabled::Unstable { feature, explain }) => { - feature_err_issue(&self.sess, feature, span, GateIssue::Language, explain).emit(); - } - Err(abi::AbiDisabled::Unrecognized) => { - if self.sess.opts.pretty.map_or(true, |ppm| ppm.needs_hir()) { - self.sess.dcx().span_delayed_bug( - span, - format!( - "unrecognized ABI not caught in lowering: {}", - symbol_unescaped.as_str() - ), - ); - } - } - } - } - - fn check_extern(&self, ext: ast::Extern, constness: ast::Const) { - if let ast::Extern::Explicit(abi, _) = ext { - self.check_abi(abi, constness); - } - } - - /// Feature gate `impl Trait` inside `type Alias = $type_expr;`. - fn check_impl_trait(&self, ty: &ast::Ty, in_associated_ty: bool) { - struct ImplTraitVisitor<'a> { - vis: &'a PostExpansionVisitor<'a>, - in_associated_ty: bool, - } - impl Visitor<'_> for ImplTraitVisitor<'_> { - fn visit_ty(&mut self, ty: &ast::Ty) { - if let ast::TyKind::ImplTrait(..) = ty.kind { - if self.in_associated_ty { - gate!( - &self.vis, - impl_trait_in_assoc_type, - ty.span, - "`impl Trait` in associated types is unstable" - ); - } else { - gate!( - &self.vis, - type_alias_impl_trait, - ty.span, - "`impl Trait` in type aliases is unstable" - ); - } - } - visit::walk_ty(self, ty); - } - } - ImplTraitVisitor { vis: self, in_associated_ty }.visit_ty(ty); - } - - fn check_late_bound_lifetime_defs(&self, params: &[ast::GenericParam]) { - // Check only lifetime parameters are present and that the - // generic parameters that are present have no bounds. - let non_lt_param_spans = params.iter().filter_map(|param| match param.kind { - ast::GenericParamKind::Lifetime { .. } => None, - _ => Some(param.ident.span), - }); - gate_multi!( - &self, - non_lifetime_binders, - non_lt_param_spans, - crate::fluent_generated::ast_passes_forbidden_non_lifetime_param - ); - - for param in params { - if !param.bounds.is_empty() { - let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect(); - self.sess.dcx().emit_err(errors::ForbiddenBound { spans }); - } - } - } -} - -impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { - fn visit_attribute(&mut self, attr: &ast::Attribute) { - let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)); - // Check feature gates for built-in attributes. - if let Some(BuiltinAttribute { - gate: AttributeGate::Gated(_, name, descr, has_feature), - .. - }) = attr_info - { - gate_alt!(self, has_feature(self.features), *name, attr.span, *descr); - } - // Check unstable flavors of the `#[doc]` attribute. - if attr.has_name(sym::doc) { - for nested_meta in attr.meta_item_list().unwrap_or_default() { - macro_rules! gate_doc { ($($s:literal { $($name:ident => $feature:ident)* })*) => { - $($(if nested_meta.has_name(sym::$name) { - let msg = concat!("`#[doc(", stringify!($name), ")]` is ", $s); - gate!(self, $feature, attr.span, msg); - })*)* - }} - - gate_doc!( - "experimental" { - cfg => doc_cfg - cfg_hide => doc_cfg_hide - masked => doc_masked - notable_trait => doc_notable_trait - } - "meant for internal use only" { - keyword => rustdoc_internals - fake_variadic => rustdoc_internals - } - ); - } - } - - // Emit errors for non-staged-api crates. - if !self.features.staged_api { - if attr.has_name(sym::unstable) - || attr.has_name(sym::stable) - || attr.has_name(sym::rustc_const_unstable) - || attr.has_name(sym::rustc_const_stable) - || attr.has_name(sym::rustc_default_body_unstable) - { - self.sess.dcx().emit_err(errors::StabilityOutsideStd { span: attr.span }); - } - } - } - - fn visit_item(&mut self, i: &'a ast::Item) { - match &i.kind { - ast::ItemKind::ForeignMod(foreign_module) => { - if let Some(abi) = foreign_module.abi { - self.check_abi(abi, ast::Const::No); - } - } - - ast::ItemKind::Fn(..) => { - if attr::contains_name(&i.attrs, sym::start) { - gate!( - &self, - start, - i.span, - "`#[start]` functions are experimental and their signature may change \ +use rustc_ast as ast;use rustc_ast::visit::{self,AssocCtxt,FnCtxt,FnKind,//({}); +Visitor};use rustc_ast::{attr,AssocConstraint,AssocConstraintKind,NodeId};use//; +rustc_ast::{token,PatKind,RangeEnd};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;use thin_vec::ThinVec;use crate::errors;//(); +macro_rules!gate{($visitor:expr,$feature:ident, $span:expr,$explain:expr)=>{{if! +$visitor.features.$feature&&!$span. allows_unstable(sym::$feature){#[allow(rustc +::untranslatable_diagnostic)]feature_err(&$visitor.sess,sym::$feature,$span,$//; +explain).emit();}}};($visitor:expr,$feature:ident,$span:expr,$explain:expr,$//3; +help:expr)=>{{if!$visitor.features.$feature&&!$span.allows_unstable(sym::$//{;}; +feature){#[allow(rustc::diagnostic_outside_of_impl)]#[allow(rustc:://let _=||(); +untranslatable_diagnostic)]feature_err(&$visitor.sess,sym::$feature,$span,$//(); +explain).with_help($help).emit();}}};}macro_rules!gate_alt{($visitor:expr,$//(); +has_feature:expr,$name:expr,$span:expr,$explain:expr)=>{{if!$has_feature&&!$//3; +span.allows_unstable($name){#[allow(rustc::untranslatable_diagnostic)]//((),()); +feature_err(&$visitor.sess,$name,$span,$explain).emit();}}};}macro_rules!//({}); +gate_multi{($visitor:expr,$feature:ident,$spans:expr,$explain:expr)=>{{if!$//(); +visitor.features.$feature{let spans:Vec<_>=$spans.filter(|span|!span.//let _=(); +allows_unstable(sym::$feature)).collect();if!spans.is_empty(){feature_err(&$//3; +visitor.sess,sym::$feature,spans,$explain) .emit();}}}};}macro_rules!gate_legacy +{($visitor:expr,$feature:ident,$span:expr,$explain:expr)=>{{if!$visitor.//{();}; +features.$feature&&!$span.allows_unstable( sym::$feature){feature_warn(&$visitor +.sess,sym::$feature,$span,$explain);}}};}pub fn check_attribute(attr:&ast:://(); +Attribute,sess:&Session,features:&Features ){PostExpansionVisitor{sess,features} +.visit_attribute(attr)}struct PostExpansionVisitor<'a>{sess:&'a Session,//{();}; +features:&'a Features,}impl<'a>PostExpansionVisitor<'a>{#[allow(rustc:://*&*&(); +untranslatable_diagnostic)]fn check_abi(&self,abi:ast::StrLit,constness:ast:://; +Const){;let ast::StrLit{symbol_unescaped,span,..}=abi;if let ast::Const::Yes(_)= +constness{match symbol_unescaped{sym::Rust|sym::C=>{}abi=>gate!(&self,//((),()); +const_extern_fn,span,format!("`{}` as a `const fn` ABI is unstable",abi)),}}//3; +match abi::is_enabled(self.features,span,symbol_unescaped.as_str ()){Ok(())=>(), +Err(abi::AbiDisabled::Unstable{feature,explain})=>{;feature_err_issue(&self.sess +,feature,span,GateIssue::Language,explain).emit();*&*&();}Err(abi::AbiDisabled:: +Unrecognized)=>{if self.sess.opts.pretty.map_or(true,|ppm|ppm.needs_hir()){;self +.sess.dcx().span_delayed_bug(span,format!(//let _=();let _=();let _=();let _=(); +"unrecognized ABI not caught in lowering: {}",symbol_unescaped.as_str()),);;}}}} +fn check_extern(&self,ext:ast::Extern,constness:ast::Const){if let ast::Extern// +::Explicit(abi,_)=ext{;self.check_abi(abi,constness);}}fn check_impl_trait(&self +,ty:&ast::Ty,in_associated_ty:bool){let _=();struct ImplTraitVisitor<'a>{vis:&'a +PostExpansionVisitor<'a>,in_associated_ty:bool,}*&*&();{();};impl Visitor<'_>for +ImplTraitVisitor<'_>{fn visit_ty(&mut self,ty:&ast::Ty){if let ast::TyKind:://3; +ImplTrait(..)=ty.kind{if self.in_associated_ty{((),());let _=();gate!(&self.vis, +impl_trait_in_assoc_type,ty .span,"`impl Trait` in associated types is unstable" +);loop{break;};}else{loop{break;};gate!(&self.vis,type_alias_impl_trait,ty.span, +"`impl Trait` in type aliases is unstable");3;}}3;visit::walk_ty(self,ty);3;}};; +ImplTraitVisitor{vis:self,in_associated_ty}.visit_ty(ty);if true{};if true{};}fn +check_late_bound_lifetime_defs(&self,params:&[ast::GenericParam]){let _=||();let +non_lt_param_spans=(((params.iter()))).filter_map (|param|match param.kind{ast:: +GenericParamKind::Lifetime{..}=>None,_=>Some(param.ident.span),});;gate_multi!(& +self,non_lifetime_binders,non_lt_param_spans,crate::fluent_generated:://((),()); +ast_passes_forbidden_non_lifetime_param);();for param in params{if!param.bounds. +is_empty(){;let spans:Vec<_>=param.bounds.iter().map(|b|b.span()).collect();self +.sess.dcx().emit_err(errors::ForbiddenBound{spans});3;}}}}impl<'a>Visitor<'a>for +PostExpansionVisitor<'a>{fn visit_attribute(&mut self,attr:&ast::Attribute){;let +attr_info=(attr.ident().and_then(|ident|BUILTIN_ATTRIBUTE_MAP.get(&ident.name))) +;let _=||();if let Some(BuiltinAttribute{gate:AttributeGate::Gated(_,name,descr, +has_feature),..})=attr_info{{;};gate_alt!(self,has_feature(self.features),*name, +attr.span,*descr);if true{};}if attr.has_name(sym::doc){for nested_meta in attr. +meta_item_list().unwrap_or_default(){;macro_rules!gate_doc{($($s:literal{$($name +:ident=>$feature:ident)*})*)=>{$( $(if nested_meta.has_name(sym::$name){let msg= +concat!("`#[doc(",stringify!($name),")]` is ", $s);gate!(self,$feature,attr.span +,msg);})*)*}}{;};();gate_doc!("experimental"{cfg=>doc_cfg cfg_hide=>doc_cfg_hide +masked=>doc_masked notable_trait=>doc_notable_trait}//loop{break;};loop{break;}; +"meant for internal use only"{keyword=>rustdoc_internals fake_variadic=>//{();}; +rustdoc_internals});((),());}}if!self.features.staged_api{if attr.has_name(sym:: +unstable)||attr.has_name(sym::stable) ||attr.has_name(sym::rustc_const_unstable) +||(((((((((attr.has_name(sym::rustc_const_stable) )))))))))||attr.has_name(sym:: +rustc_default_body_unstable){let _=();let _=();self.sess.dcx().emit_err(errors:: +StabilityOutsideStd{span:attr.span});;}}}fn visit_item(&mut self,i:&'a ast::Item +){match((&i.kind)){ast::ItemKind::ForeignMod(foreign_module)=>{if let Some(abi)= +foreign_module.abi{;self.check_abi(abi,ast::Const::No);}}ast::ItemKind::Fn(..)=> +{if attr::contains_name(&i.attrs,sym::start){if true{};gate!(&self,start,i.span, +"`#[start]` functions are experimental and their signature may change \ over time" - ); - } - } - - ast::ItemKind::Struct(..) => { - for attr in attr::filter_by_name(&i.attrs, sym::repr) { - for item in attr.meta_item_list().unwrap_or_else(ThinVec::new) { - if item.has_name(sym::simd) { - gate!( - &self, - repr_simd, - attr.span, - "SIMD types are experimental and possibly buggy" - ); - } - } - } - } - - ast::ItemKind::Impl(box ast::Impl { polarity, defaultness, of_trait, .. }) => { - if let &ast::ImplPolarity::Negative(span) = polarity { - gate!( - &self, - negative_impls, - span.to(of_trait.as_ref().map_or(span, |t| t.path.span)), - "negative trait bounds are not yet fully implemented; \ +);;}}ast::ItemKind::Struct(..)=>{for attr in attr::filter_by_name(&i.attrs,sym:: +repr){for item in (attr.meta_item_list( ).unwrap_or_else(ThinVec::new)){if item. +has_name(sym::simd){if let _=(){};if let _=(){};gate!(&self,repr_simd,attr.span, +"SIMD types are experimental and possibly buggy");();}}}}ast::ItemKind::Impl(box +ast::Impl{polarity,defaultness,of_trait,..})=>{if let&ast::ImplPolarity:://({}); +Negative(span)=polarity{();gate!(&self,negative_impls,span.to(of_trait.as_ref(). +map_or(span,|t|t.path.span)),//loop{break};loop{break};loop{break};loop{break;}; +"negative trait bounds are not yet fully implemented; \ use marker types for now" - ); - } - - if let ast::Defaultness::Default(_) = defaultness { - gate!(&self, specialization, i.span, "specialization is unstable"); - } - } - - ast::ItemKind::Trait(box ast::Trait { is_auto: ast::IsAuto::Yes, .. }) => { - gate!( - &self, - auto_traits, - i.span, - "auto traits are experimental and possibly buggy" - ); - } - - ast::ItemKind::TraitAlias(..) => { - gate!(&self, trait_alias, i.span, "trait aliases are experimental"); - } - - ast::ItemKind::MacroDef(ast::MacroDef { macro_rules: false, .. }) => { - let msg = "`macro` is experimental"; - gate!(&self, decl_macro, i.span, msg); - } - - ast::ItemKind::TyAlias(box ast::TyAlias { ty: Some(ty), .. }) => { - self.check_impl_trait(ty, false) - } - - _ => {} - } - - visit::walk_item(self, i); - } - - fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) { - match i.kind { - ast::ForeignItemKind::Fn(..) | ast::ForeignItemKind::Static(..) => { - let link_name = attr::first_attr_value_str_by_name(&i.attrs, sym::link_name); - let links_to_llvm = link_name.is_some_and(|val| val.as_str().starts_with("llvm.")); - if links_to_llvm { - gate!( - &self, - link_llvm_intrinsics, - i.span, - "linking to LLVM intrinsics is experimental" - ); - } - } - ast::ForeignItemKind::TyAlias(..) => { - gate!(&self, extern_types, i.span, "extern types are experimental"); - } - ast::ForeignItemKind::MacCall(..) => {} - } - - visit::walk_foreign_item(self, i) - } - - fn visit_ty(&mut self, ty: &'a ast::Ty) { - match &ty.kind { - ast::TyKind::BareFn(bare_fn_ty) => { - // Function pointers cannot be `const` - self.check_extern(bare_fn_ty.ext, ast::Const::No); - self.check_late_bound_lifetime_defs(&bare_fn_ty.generic_params); - } - ast::TyKind::Never => { - gate!(&self, never_type, ty.span, "the `!` type is experimental"); - } - _ => {} - } - visit::walk_ty(self, ty) - } - - fn visit_generics(&mut self, g: &'a ast::Generics) { - for predicate in &g.where_clause.predicates { - match predicate { - ast::WherePredicate::BoundPredicate(bound_pred) => { - // A type binding, eg `for<'c> Foo: Send+Clone+'c` - self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params); - } - _ => {} - } - } - visit::walk_generics(self, g); - } - - fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FnRetTy) { - if let ast::FnRetTy::Ty(output_ty) = ret_ty { - if let ast::TyKind::Never = output_ty.kind { - // Do nothing. - } else { - self.visit_ty(output_ty) - } - } - } - - fn visit_generic_args(&mut self, args: &'a ast::GenericArgs) { - // This check needs to happen here because the never type can be returned from a function, - // but cannot be used in any other context. If this check was in `visit_fn_ret_ty`, it - // include both functions and generics like `impl Fn() -> !`. - if let ast::GenericArgs::Parenthesized(generic_args) = args - && let ast::FnRetTy::Ty(ref ty) = generic_args.output - && matches!(ty.kind, ast::TyKind::Never) - { - gate!(&self, never_type, ty.span, "the `!` type is experimental"); - } - visit::walk_generic_args(self, args); - } - - fn visit_expr(&mut self, e: &'a ast::Expr) { - match e.kind { - ast::ExprKind::TryBlock(_) => { - gate!(&self, try_blocks, e.span, "`try` expression is experimental"); - } - ast::ExprKind::Lit(token::Lit { kind: token::LitKind::Float, suffix, .. }) => { - match suffix { - Some(sym::f16) => { - gate!(&self, f16, e.span, "the type `f16` is unstable") - } - Some(sym::f128) => { - gate!(&self, f128, e.span, "the type `f128` is unstable") - } - _ => (), - } - } - _ => {} - } - visit::walk_expr(self, e) - } - - fn visit_pat(&mut self, pattern: &'a ast::Pat) { - match &pattern.kind { - PatKind::Slice(pats) => { - for pat in pats { - let inner_pat = match &pat.kind { - PatKind::Ident(.., Some(pat)) => pat, - _ => pat, - }; - if let PatKind::Range(Some(_), None, Spanned { .. }) = inner_pat.kind { - gate!( - &self, - half_open_range_patterns_in_slices, - pat.span, - "`X..` patterns in slices are experimental" - ); - } - } - } - PatKind::Box(..) => { - gate!(&self, box_patterns, pattern.span, "box pattern syntax is experimental"); - } - PatKind::Range(_, Some(_), Spanned { node: RangeEnd::Excluded, .. }) => { - gate!( - &self, - exclusive_range_pattern, - pattern.span, - "exclusive range pattern syntax is experimental", - "use an inclusive range pattern, like N..=M" - ); - } - _ => {} - } - visit::walk_pat(self, pattern) - } - - fn visit_poly_trait_ref(&mut self, t: &'a ast::PolyTraitRef) { - self.check_late_bound_lifetime_defs(&t.bound_generic_params); - visit::walk_poly_trait_ref(self, t); - } - - fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) { - if let Some(header) = fn_kind.header() { - // Stability of const fn methods are covered in `visit_assoc_item` below. - self.check_extern(header.ext, header.constness); - } - - if let FnKind::Closure(ast::ClosureBinder::For { generic_params, .. }, ..) = fn_kind { - self.check_late_bound_lifetime_defs(generic_params); - } - - if fn_kind.ctxt() != Some(FnCtxt::Foreign) && fn_kind.decl().c_variadic() { - gate!(&self, c_variadic, span, "C-variadic functions are unstable"); - } - - visit::walk_fn(self, fn_kind) - } - - fn visit_assoc_constraint(&mut self, constraint: &'a AssocConstraint) { - if let AssocConstraintKind::Bound { .. } = constraint.kind { - if let Some(ast::GenericArgs::Parenthesized(args)) = constraint.gen_args.as_ref() - && args.inputs.is_empty() - && matches!(args.output, ast::FnRetTy::Default(..)) - { - gate!( - &self, - return_type_notation, - constraint.span, - "return type notation is experimental" - ); - } - } - visit::walk_assoc_constraint(self, constraint) - } - - fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) { - let is_fn = match &i.kind { - ast::AssocItemKind::Fn(_) => true, - ast::AssocItemKind::Type(box ast::TyAlias { ty, .. }) => { - if let (Some(_), AssocCtxt::Trait) = (ty, ctxt) { - gate!( - &self, - associated_type_defaults, - i.span, - "associated type defaults are unstable" - ); - } - if let Some(ty) = ty { - self.check_impl_trait(ty, true); - } - false - } - _ => false, - }; - if let ast::Defaultness::Default(_) = i.kind.defaultness() { - // Limit `min_specialization` to only specializing functions. - gate_alt!( - &self, - self.features.specialization || (is_fn && self.features.min_specialization), - sym::specialization, - i.span, - "specialization is unstable" - ); - } - visit::walk_assoc_item(self, i, ctxt) - } -} - -pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { - maybe_stage_features(sess, features, krate); - check_incompatible_features(sess, features); - let mut visitor = PostExpansionVisitor { sess, features }; - - let spans = sess.psess.gated_spans.spans.borrow(); - macro_rules! gate_all { - ($gate:ident, $msg:literal) => { - if let Some(spans) = spans.get(&sym::$gate) { - for span in spans { - gate!(&visitor, $gate, *span, $msg); - } - } - }; - ($gate:ident, $msg:literal, $help:literal) => { - if let Some(spans) = spans.get(&sym::$gate) { - for span in spans { - gate!(&visitor, $gate, *span, $msg, $help); - } - } - }; - } - gate_all!( - if_let_guard, - "`if let` guards are experimental", - "you can write `if matches!(, )` instead of `if let = `" - ); - gate_all!(let_chains, "`let` expressions in this position are unstable"); - gate_all!( - async_closure, - "async closures are unstable", - "to use an async block, remove the `||`: `async {`" - ); - gate_all!(async_for_loop, "`for await` loops are experimental"); - gate_all!( - closure_lifetime_binder, - "`for<...>` binders for closures are experimental", - "consider removing `for<...>`" - ); - gate_all!(more_qualified_paths, "usage of qualified paths in this context is experimental"); - for &span in spans.get(&sym::yield_expr).iter().copied().flatten() { - if !span.at_least_rust_2024() { - gate!(&visitor, coroutines, span, "yield syntax is experimental"); - } - } - gate_all!(gen_blocks, "gen blocks are 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_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"); - gate_all!(yeet_expr, "`do yeet` expression is experimental"); - gate_all!(dyn_star, "`dyn*` trait objects are experimental"); - gate_all!(const_closures, "const closures are experimental"); - gate_all!(builtin_syntax, "`builtin #` syntax is unstable"); - gate_all!(explicit_tail_calls, "`become` expression is experimental"); - gate_all!(generic_const_items, "generic const items are experimental"); - gate_all!(unnamed_fields, "unnamed fields are not yet fully implemented"); - gate_all!(fn_delegation, "functions delegation is not yet fully implemented"); - gate_all!(postfix_match, "postfix match is experimental"); - gate_all!(mut_ref, "mutable by-reference bindings are experimental"); - - if !visitor.features.never_patterns { - if let Some(spans) = spans.get(&sym::never_patterns) { - for &span in spans { - if span.allows_unstable(sym::never_patterns) { - continue; - } - let sm = sess.source_map(); - // We gate two types of spans: the span of a `!` pattern, and the span of a - // match arm without a body. For the latter we want to give the user a normal - // error. - if let Ok(snippet) = sm.span_to_snippet(span) - && snippet == "!" - { - #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable - feature_err(sess, sym::never_patterns, span, "`!` patterns are experimental") - .emit(); - } else { - let suggestion = span.shrink_to_hi(); - sess.dcx().emit_err(errors::MatchArmWithNoBody { span, suggestion }); - } - } - } - } - - if !visitor.features.negative_bounds { - for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() { - sess.dcx().emit_err(errors::NegativeBoundUnsupported { span }); - } - } - - // All uses of `gate_all_legacy_dont_use!` below this point were added in #65742, - // and subsequently disabled (with the non-early gating readded). - // We emit an early future-incompatible warning for these. - // New syntax gates should go above here to get a hard error gate. - macro_rules! gate_all_legacy_dont_use { - ($gate:ident, $msg:literal) => { - for span in spans.get(&sym::$gate).unwrap_or(&vec![]) { - gate_legacy!(&visitor, $gate, *span, $msg); - } - }; - } - - gate_all_legacy_dont_use!(box_patterns, "box pattern syntax is experimental"); - gate_all_legacy_dont_use!(trait_alias, "trait aliases are experimental"); - // Despite being a new feature, `where T: Trait`, which is RTN syntax now, - // used to be gated under associated_type_bounds, which are right above, so RTN needs to - // be too. - gate_all_legacy_dont_use!(return_type_notation, "return type notation is experimental"); - gate_all_legacy_dont_use!(decl_macro, "`macro` is experimental"); - gate_all_legacy_dont_use!( - exclusive_range_pattern, - "exclusive range pattern syntax is experimental" - ); - gate_all_legacy_dont_use!(try_blocks, "`try` blocks are unstable"); - gate_all_legacy_dont_use!(auto_traits, "`auto` traits are unstable"); - - visit::walk_crate(&mut visitor, krate); -} - -fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate) { - // checks if `#![feature]` has been used to enable any lang feature - // does not check the same for lib features unless there's at least one - // declared lang feature - if !sess.opts.unstable_features.is_nightly_build() { - let lang_features = &features.declared_lang_features; - if lang_features.len() == 0 { - return; - } - for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) { - let mut err = errors::FeatureOnNonNightly { - span: attr.span, - channel: option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"), - stable_features: vec![], - sugg: None, - }; - - let mut all_stable = true; - for ident in - attr.meta_item_list().into_iter().flatten().flat_map(|nested| nested.ident()) - { - let name = ident.name; - let stable_since = lang_features - .iter() - .flat_map(|&(feature, _, since)| if feature == name { since } else { None }) - .next(); - if let Some(since) = stable_since { - err.stable_features.push(errors::StableFeature { name, since }); - } else { - all_stable = false; - } - } - if all_stable { - err.sugg = Some(attr.span); - } - sess.dcx().emit_err(err); - } - } -} - -fn check_incompatible_features(sess: &Session, features: &Features) { - let declared_features = features - .declared_lang_features - .iter() - .copied() - .map(|(name, span, _)| (name, span)) - .chain(features.declared_lib_features.iter().copied()); - - for (f1, f2) in rustc_feature::INCOMPATIBLE_FEATURES - .iter() - .filter(|&&(f1, f2)| features.active(f1) && features.active(f2)) - { - if let Some((f1_name, f1_span)) = declared_features.clone().find(|(name, _)| name == f1) { - if let Some((f2_name, f2_span)) = declared_features.clone().find(|(name, _)| name == f2) - { - let spans = vec![f1_span, f2_span]; - sess.dcx().emit_err(errors::IncompatibleFeatures { - spans, - f1: f1_name, - f2: f2_name, - }); - } - } - } -} +);;}if let ast::Defaultness::Default(_)=defaultness{gate!(&self,specialization,i +.span,"specialization is unstable");{();};}}ast::ItemKind::Trait(box ast::Trait{ +is_auto:ast::IsAuto::Yes,..})=>{((),());let _=();gate!(&self,auto_traits,i.span, +"auto traits are experimental and possibly buggy");3;}ast::ItemKind::TraitAlias( +..)=>{3;gate!(&self,trait_alias,i.span,"trait aliases are experimental");;}ast:: +ItemKind::MacroDef(ast::MacroDef{macro_rules:false,..})=>{if let _=(){};let msg= +"`macro` is experimental";;;gate!(&self,decl_macro,i.span,msg);;}ast::ItemKind:: +TyAlias(box ast::TyAlias{ty:Some(ty),..} )=>{self.check_impl_trait(ty,false)}_=> +{}}{;};visit::walk_item(self,i);{;};}fn visit_foreign_item(&mut self,i:&'a ast:: +ForeignItem){match i.kind{ast::ForeignItemKind::Fn(..)|ast::ForeignItemKind:://; +Static(..)=>{{;};let link_name=attr::first_attr_value_str_by_name(&i.attrs,sym:: +link_name);{();};({});let links_to_llvm=link_name.is_some_and(|val|val.as_str(). +starts_with("llvm."));;if links_to_llvm{gate!(&self,link_llvm_intrinsics,i.span, +"linking to LLVM intrinsics is experimental");3;}}ast::ForeignItemKind::TyAlias( +..)=>{3;gate!(&self,extern_types,i.span,"extern types are experimental");;}ast:: +ForeignItemKind::MacCall(..)=>{}}visit:: walk_foreign_item(self,i)}fn visit_ty(& +mut self,ty:&'a ast::Ty){match&ty.kind{ast::TyKind::BareFn(bare_fn_ty)=>{3;self. +check_extern(bare_fn_ty.ext,ast::Const::No);;self.check_late_bound_lifetime_defs +(&bare_fn_ty.generic_params);3;}ast::TyKind::Never=>{;gate!(&self,never_type,ty. +span,"the `!` type is experimental");if true{};}_=>{}}visit::walk_ty(self,ty)}fn +visit_generics(&mut self,g:&'a ast::Generics){for predicate in&g.where_clause.// +predicates{match predicate{ast::WherePredicate::BoundPredicate(bound_pred)=>{(); +self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params);;}_=>{}}}; +visit::walk_generics(self,g);({});}fn visit_fn_ret_ty(&mut self,ret_ty:&'a ast:: +FnRetTy){if let ast::FnRetTy::Ty(output_ty)=ret_ty{if let ast::TyKind::Never=//; +output_ty.kind{}else{self.visit_ty(output_ty )}}}fn visit_generic_args(&mut self +,args:&'a ast::GenericArgs){if let ast::GenericArgs::Parenthesized(generic_args +)=args&&let ast::FnRetTy::Ty(ref ty)=generic_args.output&&matches!(ty.kind,ast// +::TyKind::Never){;gate!(&self,never_type,ty.span,"the `!` type is experimental") +;;}visit::walk_generic_args(self,args);}fn visit_expr(&mut self,e:&'a ast::Expr) +{match e.kind{ast::ExprKind::TryBlock(_)=>{*&*&();gate!(&self,try_blocks,e.span, +"`try` expression is experimental");;}ast::ExprKind::Lit(token::Lit{kind:token:: +LitKind::Float,suffix,..})=>{match suffix{Some(sym::f16)=>{gate!(&self,f16,e.//; +span,"the type `f16` is unstable")}Some(sym::f128)=>{gate!(&self,f128,e.span,//; +"the type `f128` is unstable")}_=>((())),}}_=>{}}((visit::walk_expr(self,e)))}fn +visit_pat(&mut self,pattern:&'a ast::Pat){match((&pattern.kind)){PatKind::Slice( +pats)=>{for pat in pats{;let inner_pat=match&pat.kind{PatKind::Ident(..,Some(pat +))=>pat,_=>pat,};;if let PatKind::Range(Some(_),None,Spanned{..})=inner_pat.kind +{let _=||();loop{break};gate!(&self,half_open_range_patterns_in_slices,pat.span, +"`X..` patterns in slices are experimental");;}}}PatKind::Box(..)=>{gate!(&self, +box_patterns,pattern.span,"box pattern syntax is experimental");;}PatKind::Range +(_,Some(_),Spanned{node:RangeEnd::Excluded,..})=>{let _=();let _=();gate!(&self, +exclusive_range_pattern,pattern.span,//if true{};if true{};if true{};let _=||(); +"exclusive range pattern syntax is experimental",//if let _=(){};*&*&();((),()); +"use an inclusive range pattern, like N..=M");{();};}_=>{}}visit::walk_pat(self, +pattern)}fn visit_poly_trait_ref(&mut self,t:&'a ast::PolyTraitRef){*&*&();self. +check_late_bound_lifetime_defs(&t.bound_generic_params);let _=();((),());visit:: +walk_poly_trait_ref(self,t);;}fn visit_fn(&mut self,fn_kind:FnKind<'a>,span:Span +,_:NodeId){if let Some(header)=fn_kind.header(){();self.check_extern(header.ext, +header.constness);if let _=(){};}if let FnKind::Closure(ast::ClosureBinder::For{ +generic_params,..},..)=fn_kind{loop{break;};self.check_late_bound_lifetime_defs( +generic_params);{();};}if fn_kind.ctxt()!=Some(FnCtxt::Foreign)&&fn_kind.decl(). +c_variadic(){;gate!(&self,c_variadic,span,"C-variadic functions are unstable");} +visit::walk_fn(self,fn_kind)}fn visit_assoc_constraint(&mut self,constraint:&'a +AssocConstraint){if let AssocConstraintKind::Bound{..}=constraint.kind{if let//; +Some(ast::GenericArgs::Parenthesized(args))= constraint.gen_args.as_ref()&&args. +inputs.is_empty()&&matches!(args.output,ast::FnRetTy::Default(..)){;gate!(&self, +return_type_notation,constraint.span,"return type notation is experimental");;}} +visit::walk_assoc_constraint(self,constraint)}fn visit_assoc_item(&mut self,i:& +'a ast::AssocItem,ctxt:AssocCtxt){;let is_fn=match&i.kind{ast::AssocItemKind::Fn +(_)=>(true),ast::AssocItemKind::Type(box ast:: TyAlias{ty,..})=>{if let(Some(_), +AssocCtxt::Trait)=(ty,ctxt){((),());gate!(&self,associated_type_defaults,i.span, +"associated type defaults are unstable");*&*&();}if let Some(ty)=ty{*&*&();self. +check_impl_trait(ty,true);;}false}_=>false,};if let ast::Defaultness::Default(_) +=i.kind.defaultness(){{;};gate_alt!(&self,self.features.specialization||(is_fn&& +self.features.min_specialization),sym::specialization,i.span,//((),());let _=(); +"specialization is unstable");{();};}visit::walk_assoc_item(self,i,ctxt)}}pub fn +check_crate(krate:&ast::Crate,sess:&Session,features:&Features){((),());((),()); +maybe_stage_features(sess,features,krate);();3;check_incompatible_features(sess, +features);;;let mut visitor=PostExpansionVisitor{sess,features};;let spans=sess. +psess.gated_spans.spans.borrow();;macro_rules!gate_all{($gate:ident,$msg:literal +)=>{if let Some(spans)=spans.get(&sym ::$gate){for span in spans{gate!(&visitor, +$gate,*span,$msg);}}};($gate:ident,$msg:literal,$help:literal)=>{if let Some(//; +spans)=spans.get(&sym::$gate){for span in spans{gate!(&visitor,$gate,*span,$msg +,$help);}}};}({});{;};gate_all!(if_let_guard,"`if let` guards are experimental", +"you can write `if matches!(, )` instead of `if let = `" +);3;3;gate_all!(let_chains,"`let` expressions in this position are unstable");;; +gate_all!(async_closure,"async closures are unstable",//loop{break};loop{break}; +"to use an async block, remove the `||`: `async {`");;;gate_all!(async_for_loop, +"`for await` loops are experimental");{;};{;};gate_all!(closure_lifetime_binder, +"`for<...>` binders for closures are experimental",//loop{break;};if let _=(){}; +"consider removing `for<...>`");let _=();((),());gate_all!(more_qualified_paths, +"usage of qualified paths in this context is experimental");3;for&span in spans. +get(&sym::yield_expr).iter().copied().flatten(){if!span.at_least_rust_2024(){(); +gate!(&visitor,coroutines,span,"yield syntax is experimental");();}}3;gate_all!( +gen_blocks,"gen blocks are experimental");let _=();((),());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_in_slices,//if true{};let _=||();let _=||();let _=||(); +"half-open range patterns in slices are unstable");();();gate_all!(inline_const, +"inline-const is experimental");let _=||();if true{};gate_all!(inline_const_pat, +"inline-const in pattern position is experimental");let _=();let _=();gate_all!( +associated_const_equality,"associated const equality is incomplete");;gate_all!( +yeet_expr,"`do yeet` expression is experimental");{();};({});gate_all!(dyn_star, +"`dyn*` trait objects are experimental");*&*&();*&*&();gate_all!(const_closures, +"const closures are experimental");if true{};if true{};gate_all!(builtin_syntax, +"`builtin #` syntax is unstable");((),());((),());gate_all!(explicit_tail_calls, +"`become` expression is experimental");{();};({});gate_all!(generic_const_items, +"generic const items are experimental");((),());*&*&();gate_all!(unnamed_fields, +"unnamed fields are not yet fully implemented");{;};{;};gate_all!(fn_delegation, +"functions delegation is not yet fully implemented");3;;gate_all!(postfix_match, +"postfix match is experimental");*&*&();((),());if let _=(){};gate_all!(mut_ref, +"mutable by-reference bindings are experimental");if true{};if!visitor.features. +never_patterns{if let Some(spans)=(spans. get(&sym::never_patterns)){for&span in +spans{if span.allows_unstable(sym::never_patterns){();continue;3;}3;let sm=sess. +source_map();;if let Ok(snippet)=sm.span_to_snippet(span)&&snippet=="!"{#[allow( +rustc::untranslatable_diagnostic)]feature_err(sess,sym::never_patterns,span,//3; +"`!` patterns are experimental").emit();;}else{let suggestion=span.shrink_to_hi( +);3;3;sess.dcx().emit_err(errors::MatchArmWithNoBody{span,suggestion});3;}}}}if! +visitor.features.negative_bounds{for&span in (spans.get(&sym::negative_bounds)). +iter().copied().flatten(){;sess.dcx().emit_err(errors::NegativeBoundUnsupported{ +span});;}};macro_rules!gate_all_legacy_dont_use{($gate:ident,$msg:literal)=>{for +span in spans.get(&sym::$gate).unwrap_or( &vec![]){gate_legacy!(&visitor,$gate,* +span,$msg);}};}loop{break;};loop{break;};gate_all_legacy_dont_use!(box_patterns, +"box pattern syntax is experimental");3;3;gate_all_legacy_dont_use!(trait_alias, +"trait aliases are experimental");if true{};if true{};gate_all_legacy_dont_use!( +return_type_notation,"return type notation is experimental");if true{};let _=(); +gate_all_legacy_dont_use!(decl_macro,"`macro` is experimental");((),());((),()); +gate_all_legacy_dont_use!(exclusive_range_pattern,//if let _=(){};if let _=(){}; +"exclusive range pattern syntax is experimental");3;3;gate_all_legacy_dont_use!( +try_blocks,"`try` blocks are unstable");;;gate_all_legacy_dont_use!(auto_traits, +"`auto` traits are unstable");();();visit::walk_crate(&mut visitor,krate);();}fn +maybe_stage_features(sess:&Session,features:&Features,krate:&ast::Crate){if!//3; +sess.opts.unstable_features.is_nightly_build(){({});let lang_features=&features. +declared_lang_features;3;if lang_features.len()==0{3;return;;}for attr in krate. +attrs.iter().filter(|attr|attr.has_name(sym::feature)){({});let mut err=errors:: +FeatureOnNonNightly{span:attr.span,channel:(option_env!("CFG_RELEASE_CHANNEL")). +unwrap_or("(unknown)"),stable_features:vec![],sugg:None,};3;;let mut all_stable= +true;;for ident in attr.meta_item_list().into_iter().flatten().flat_map(|nested| +nested.ident()){3;let name=ident.name;3;3;let stable_since=lang_features.iter(). +flat_map(|&(feature,_,since)|if feature==name{since}else{None}).next();();if let +Some(since)=stable_since{();err.stable_features.push(errors::StableFeature{name, +since});;}else{;all_stable=false;}}if all_stable{err.sugg=Some(attr.span);}sess. +dcx().emit_err(err);3;}}}fn check_incompatible_features(sess:&Session,features:& +Features){;let declared_features=features.declared_lang_features.iter().copied() +.map((|(name,span,_)|(name,span ))).chain(features.declared_lib_features.iter(). +copied());3;for(f1,f2)in rustc_feature::INCOMPATIBLE_FEATURES.iter().filter(|&&( +f1,f2)|features.active(f1)&&features.active( f2)){if let Some((f1_name,f1_span)) +=((declared_features.clone()).find((|(name,_) |name==f1))){if let Some((f2_name, +f2_span))=declared_features.clone().find(|(name,_)|name==f2){{;};let spans=vec![ +f1_span,f2_span];();3;sess.dcx().emit_err(errors::IncompatibleFeatures{spans,f1: +f1_name,f2:f2_name,});loop{break;};if let _=(){};loop{break;};if let _=(){};}}}} diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs index 74d0fff2734fc..8e559e7b33083 100644 --- a/compiler/rustc_ast_passes/src/lib.rs +++ b/compiler/rustc_ast_passes/src/lib.rs @@ -1,21 +1,5 @@ -//! The `rustc_ast_passes` crate contains passes which validate the AST in `syntax` -//! parsed by `rustc_parse` and then lowered, after the passes in this crate, -//! by `rustc_ast_lowering`. -//! -//! The crate also contains other misc AST visitors, e.g. `node_count` and `show_span`. - -#![allow(internal_features)] -#![doc(rust_logo)] -#![feature(rustdoc_internals)] -#![feature(box_patterns)] -#![feature(if_let_guard)] -#![feature(iter_is_partitioned)] -#![feature(let_chains)] - -pub mod ast_validation; -mod errors; -pub mod feature_gate; -pub mod node_count; -pub mod show_span; - -rustc_fluent_macro::fluent_messages! { "../messages.ftl" } +#![allow(internal_features)]#![doc( rust_logo)]#![feature(rustdoc_internals)]#![ +feature(box_patterns)]#![feature( if_let_guard)]#![feature(iter_is_partitioned)] +#![feature(let_chains)]pub mod ast_validation;mod errors;pub mod feature_gate;// +pub mod node_count;pub mod show_span;rustc_fluent_macro::fluent_messages!{//{;}; +"../messages.ftl"}//*&*&();((),());*&*&();((),());*&*&();((),());*&*&();((),()); diff --git a/compiler/rustc_ast_passes/src/node_count.rs b/compiler/rustc_ast_passes/src/node_count.rs index fa42f87786de9..324f0368b94bb 100644 --- a/compiler/rustc_ast_passes/src/node_count.rs +++ b/compiler/rustc_ast_passes/src/node_count.rs @@ -1,129 +1,34 @@ -// Simply gives a rough count of the number of nodes in an AST. - -use rustc_ast::visit::*; -use rustc_ast::*; -use rustc_span::symbol::Ident; -use rustc_span::Span; - -pub struct NodeCounter { - pub count: usize, -} - -impl NodeCounter { - pub fn new() -> NodeCounter { - NodeCounter { count: 0 } - } -} - -impl<'ast> Visitor<'ast> for NodeCounter { - fn visit_ident(&mut self, _ident: Ident) { - self.count += 1; - } - fn visit_foreign_item(&mut self, i: &ForeignItem) { - self.count += 1; - walk_foreign_item(self, i) - } - fn visit_item(&mut self, i: &Item) { - self.count += 1; - walk_item(self, i) - } - fn visit_local(&mut self, l: &Local) { - self.count += 1; - walk_local(self, l) - } - fn visit_block(&mut self, b: &Block) { - self.count += 1; - walk_block(self, b) - } - fn visit_stmt(&mut self, s: &Stmt) { - self.count += 1; - walk_stmt(self, s) - } - fn visit_arm(&mut self, a: &Arm) { - self.count += 1; - walk_arm(self, a) - } - fn visit_pat(&mut self, p: &Pat) { - self.count += 1; - walk_pat(self, p) - } - fn visit_expr(&mut self, ex: &Expr) { - self.count += 1; - walk_expr(self, ex) - } - fn visit_ty(&mut self, t: &Ty) { - self.count += 1; - walk_ty(self, t) - } - fn visit_generic_param(&mut self, param: &GenericParam) { - self.count += 1; - walk_generic_param(self, param) - } - fn visit_generics(&mut self, g: &Generics) { - self.count += 1; - walk_generics(self, g) - } - fn visit_fn(&mut self, fk: visit::FnKind<'_>, _: Span, _: NodeId) { - self.count += 1; - walk_fn(self, fk) - } - fn visit_assoc_item(&mut self, ti: &AssocItem, ctxt: AssocCtxt) { - self.count += 1; - walk_assoc_item(self, ti, ctxt); - } - fn visit_trait_ref(&mut self, t: &TraitRef) { - self.count += 1; - walk_trait_ref(self, t) - } - fn visit_param_bound(&mut self, bounds: &GenericBound, _ctxt: BoundKind) { - self.count += 1; - walk_param_bound(self, bounds) - } - fn visit_poly_trait_ref(&mut self, t: &PolyTraitRef) { - self.count += 1; - walk_poly_trait_ref(self, t) - } - fn visit_variant_data(&mut self, s: &VariantData) { - self.count += 1; - walk_struct_def(self, s) - } - fn visit_field_def(&mut self, s: &FieldDef) { - self.count += 1; - walk_field_def(self, s) - } - fn visit_enum_def(&mut self, enum_definition: &EnumDef) { - self.count += 1; - walk_enum_def(self, enum_definition) - } - fn visit_variant(&mut self, v: &Variant) { - self.count += 1; - walk_variant(self, v) - } - fn visit_lifetime(&mut self, lifetime: &Lifetime, _: visit::LifetimeCtxt) { - self.count += 1; - walk_lifetime(self, lifetime) - } - fn visit_mac_call(&mut self, mac: &MacCall) { - self.count += 1; - walk_mac(self, mac) - } - fn visit_path(&mut self, path: &Path, _id: NodeId) { - self.count += 1; - walk_path(self, path) - } - fn visit_use_tree(&mut self, use_tree: &UseTree, id: NodeId, _nested: bool) { - self.count += 1; - walk_use_tree(self, use_tree, id) - } - fn visit_generic_args(&mut self, generic_args: &GenericArgs) { - self.count += 1; - walk_generic_args(self, generic_args) - } - fn visit_assoc_constraint(&mut self, constraint: &AssocConstraint) { - self.count += 1; - walk_assoc_constraint(self, constraint) - } - fn visit_attribute(&mut self, _attr: &Attribute) { - self.count += 1; - } -} +use rustc_ast::visit::*;use rustc_ast::*;use rustc_span::symbol::Ident;use//{;}; +rustc_span::Span;pub struct NodeCounter{pub count:usize,}impl NodeCounter{pub//; +fn new()->NodeCounter{(((NodeCounter{count:((0))})))}}impl<'ast>Visitor<'ast>for +NodeCounter{fn visit_ident(&mut self,_ident:Ident){{();};self.count+=1;{();};}fn +visit_foreign_item(&mut self,i:&ForeignItem){3;self.count+=1;;walk_foreign_item( +self,i)}fn visit_item(&mut self,i:&Item){();self.count+=1;3;walk_item(self,i)}fn +visit_local(&mut self,l:&Local){;self.count+=1;walk_local(self,l)}fn visit_block +(&mut self,b:&Block){;self.count+=1;walk_block(self,b)}fn visit_stmt(&mut self,s +:&Stmt){3;self.count+=1;;walk_stmt(self,s)}fn visit_arm(&mut self,a:&Arm){;self. +count+=1;;walk_arm(self,a)}fn visit_pat(&mut self,p:&Pat){self.count+=1;walk_pat +(self,p)}fn visit_expr(&mut self,ex:&Expr){;self.count+=1;;walk_expr(self,ex)}fn +visit_ty(&mut self,t:&Ty){;self.count+=1;walk_ty(self,t)}fn visit_generic_param( +&mut self,param:&GenericParam){;self.count+=1;;walk_generic_param(self,param)}fn +visit_generics(&mut self,g:&Generics){3;self.count+=1;3;walk_generics(self,g)}fn +visit_fn(&mut self,fk:visit::FnKind<'_>,_:Span,_:NodeId){;self.count+=1;walk_fn( +self,fk)}fn visit_assoc_item(&mut self,ti:&AssocItem,ctxt:AssocCtxt){;self.count ++=1;;;walk_assoc_item(self,ti,ctxt);;}fn visit_trait_ref(&mut self,t:&TraitRef){ +self.count+=1;{;};walk_trait_ref(self,t)}fn visit_param_bound(&mut self,bounds:& +GenericBound,_ctxt:BoundKind){3;self.count+=1;3;walk_param_bound(self,bounds)}fn +visit_poly_trait_ref(&mut self,t:&PolyTraitRef){let _=();self.count+=1;let _=(); +walk_poly_trait_ref(self,t)}fn visit_variant_data(&mut self,s:&VariantData){{;}; +self.count+=1;;walk_struct_def(self,s)}fn visit_field_def(&mut self,s:&FieldDef) +{*&*&();self.count+=1;*&*&();walk_field_def(self,s)}fn visit_enum_def(&mut self, +enum_definition:&EnumDef){;self.count+=1;;walk_enum_def(self,enum_definition)}fn +visit_variant(&mut self,v:&Variant){{;};self.count+=1;();walk_variant(self,v)}fn +visit_lifetime(&mut self,lifetime:&Lifetime,_:visit::LifetimeCtxt){;self.count+= +1;;walk_lifetime(self,lifetime)}fn visit_mac_call(&mut self,mac:&MacCall){;self. +count+=1;;walk_mac(self,mac)}fn visit_path(&mut self,path:&Path,_id:NodeId){self +.count+=1;;walk_path(self,path)}fn visit_use_tree(&mut self,use_tree:&UseTree,id +:NodeId,_nested:bool){({});self.count+=1;({});walk_use_tree(self,use_tree,id)}fn +visit_generic_args(&mut self,generic_args:&GenericArgs){({});self.count+=1;({}); +walk_generic_args(self,generic_args)}fn visit_assoc_constraint(&mut self,//({}); +constraint:&AssocConstraint){({});self.count+=1;({});walk_assoc_constraint(self, +constraint)}fn visit_attribute(&mut self,_attr:&Attribute){();self.count+=1;3;}} diff --git a/compiler/rustc_ast_passes/src/show_span.rs b/compiler/rustc_ast_passes/src/show_span.rs index 1059007428221..b0848ff724719 100644 --- a/compiler/rustc_ast_passes/src/show_span.rs +++ b/compiler/rustc_ast_passes/src/show_span.rs @@ -1,67 +1,15 @@ -//! Span debugger -//! -//! This module shows spans for all expressions in the crate -//! to help with compiler debugging. - -use std::str::FromStr; - -use rustc_ast as ast; -use rustc_ast::visit; -use rustc_ast::visit::Visitor; - -use crate::errors; - -enum Mode { - Expression, - Pattern, - Type, -} - -impl FromStr for Mode { - type Err = (); - fn from_str(s: &str) -> Result { - let mode = match s { - "expr" => Mode::Expression, - "pat" => Mode::Pattern, - "ty" => Mode::Type, - _ => return Err(()), - }; - Ok(mode) - } -} - -struct ShowSpanVisitor<'a> { - dcx: &'a rustc_errors::DiagCtxt, - mode: Mode, -} - -impl<'a> Visitor<'a> for ShowSpanVisitor<'a> { - fn visit_expr(&mut self, e: &'a ast::Expr) { - if let Mode::Expression = self.mode { - self.dcx.emit_warn(errors::ShowSpan { span: e.span, msg: "expression" }); - } - visit::walk_expr(self, e); - } - - fn visit_pat(&mut self, p: &'a ast::Pat) { - if let Mode::Pattern = self.mode { - self.dcx.emit_warn(errors::ShowSpan { span: p.span, msg: "pattern" }); - } - visit::walk_pat(self, p); - } - - fn visit_ty(&mut self, t: &'a ast::Ty) { - if let Mode::Type = self.mode { - self.dcx.emit_warn(errors::ShowSpan { span: t.span, msg: "type" }); - } - visit::walk_ty(self, t); - } -} - -pub fn run(dcx: &rustc_errors::DiagCtxt, mode: &str, krate: &ast::Crate) { - let Ok(mode) = mode.parse() else { - return; - }; - let mut v = ShowSpanVisitor { dcx, mode }; - visit::walk_crate(&mut v, krate); -} +use std::str::FromStr;use rustc_ast as ast;use rustc_ast::visit;use rustc_ast:: +visit::Visitor;use crate::errors;enum Mode{Expression,Pattern,Type,}impl//{();}; +FromStr for Mode{type Err=();fn from_str(s:&str)->Result{({});let mode= +match s{"expr"=>Mode::Expression,"pat"=>Mode::Pattern,"ty"=>Mode::Type,_=>//{;}; +return Err(()),};{;};Ok(mode)}}struct ShowSpanVisitor<'a>{dcx:&'a rustc_errors:: +DiagCtxt,mode:Mode,}impl<'a>Visitor<'a>for ShowSpanVisitor<'a>{fn visit_expr(&// +mut self,e:&'a ast::Expr){if let Mode::Expression=self.mode{;self.dcx.emit_warn( +errors::ShowSpan{span:e.span,msg:"expression"});;};visit::walk_expr(self,e);;}fn +visit_pat(&mut self,p:&'a ast::Pat){if let Mode::Pattern=self.mode{{;};self.dcx. +emit_warn(errors::ShowSpan{span:p.span,msg:"pattern"});;}visit::walk_pat(self,p) +;3;}fn visit_ty(&mut self,t:&'a ast::Ty){if let Mode::Type=self.mode{3;self.dcx. +emit_warn(errors::ShowSpan{span:t.span,msg:"type"});;};visit::walk_ty(self,t);}} +pub fn run(dcx:&rustc_errors::DiagCtxt,mode:&str,krate:&ast::Crate){;let Ok(mode +)=mode.parse()else{3;return;3;};3;;let mut v=ShowSpanVisitor{dcx,mode};;;visit:: +walk_crate(&mut v,krate);loop{break;};if let _=(){};loop{break;};if let _=(){};} diff --git a/compiler/rustc_ast_pretty/src/helpers.rs b/compiler/rustc_ast_pretty/src/helpers.rs index c3e0eccd3d404..8525f6fbee6dc 100644 --- a/compiler/rustc_ast_pretty/src/helpers.rs +++ b/compiler/rustc_ast_pretty/src/helpers.rs @@ -1,48 +1,9 @@ -use crate::pp::Printer; -use std::borrow::Cow; - -impl Printer { - pub fn word_space>>(&mut self, w: W) { - self.word(w); - self.space(); - } - - pub fn popen(&mut self) { - self.word("("); - } - - pub fn pclose(&mut self) { - self.word(")"); - } - - pub fn hardbreak_if_not_bol(&mut self) { - if !self.is_beginning_of_line() { - self.hardbreak() - } - } - - pub fn space_if_not_bol(&mut self) { - if !self.is_beginning_of_line() { - self.space(); - } - } - - pub fn nbsp(&mut self) { - self.word(" ") - } - - pub fn word_nbsp>>(&mut self, w: S) { - self.word(w); - self.nbsp() - } - - /// Synthesizes a comment that was not textually present in the original - /// source file. - pub fn synth_comment(&mut self, text: impl Into>) { - self.word("/*"); - self.space(); - self.word(text); - self.space(); - self.word("*/") - } -} +use crate::pp::Printer;use std::borrow::Cow;impl Printer{pub fn word_space>>(&mut self,w:W){;self.word(w);self.space();}pub fn popen( +&mut self){3;self.word("(");3;}pub fn pclose(&mut self){;self.word(")");;}pub fn +hardbreak_if_not_bol(&mut self){if!self .is_beginning_of_line(){self.hardbreak() +}}pub fn space_if_not_bol(&mut self){if!self.is_beginning_of_line(){;self.space( +);3;}}pub fn nbsp(&mut self){self.word(" ")}pub fn word_nbsp>>(&mut self,w:S){;self.word(w);;self.nbsp()}pub fn synth_comment(&mut self, +text:impl Into>){;self.word("/*");self.space();self.word(text); +self.space();loop{break};loop{break;};loop{break};loop{break;};self.word("*/")}} diff --git a/compiler/rustc_ast_pretty/src/lib.rs b/compiler/rustc_ast_pretty/src/lib.rs index b9e217a21e39f..468838752bed5 100644 --- a/compiler/rustc_ast_pretty/src/lib.rs +++ b/compiler/rustc_ast_pretty/src/lib.rs @@ -1,8 +1,2 @@ -#![allow(internal_features)] -#![feature(rustdoc_internals)] -#![doc(rust_logo)] -#![feature(box_patterns)] - -mod helpers; -pub mod pp; -pub mod pprust; +#![allow(internal_features)]#![feature( rustdoc_internals)]#![doc(rust_logo)]#![ +feature(box_patterns)]mod helpers;pub mod pp;pub mod pprust;//let _=();let _=(); diff --git a/compiler/rustc_ast_pretty/src/pp.rs b/compiler/rustc_ast_pretty/src/pp.rs index 96f5eff68901f..15fdb35aaa7eb 100644 --- a/compiler/rustc_ast_pretty/src/pp.rs +++ b/compiler/rustc_ast_pretty/src/pp.rs @@ -1,450 +1,70 @@ -//! This pretty-printer is a direct reimplementation of Philip Karlton's -//! Mesa pretty-printer, as described in the appendix to -//! Derek C. Oppen, "Pretty Printing" (1979), -//! Stanford Computer Science Department STAN-CS-79-770, -//! . -//! -//! The algorithm's aim is to break a stream into as few lines as possible -//! while respecting the indentation-consistency requirements of the enclosing -//! block, and avoiding breaking at silly places on block boundaries, for -//! example, between "x" and ")" in "x)". -//! -//! I am implementing this algorithm because it comes with 20 pages of -//! documentation explaining its theory, and because it addresses the set of -//! concerns I've seen other pretty-printers fall down on. Weirdly. Even though -//! it's 32 years old. What can I say? -//! -//! Despite some redundancies and quirks in the way it's implemented in that -//! paper, I've opted to keep the implementation here as similar as I can, -//! changing only what was blatantly wrong, a typo, or sufficiently -//! non-idiomatic rust that it really stuck out. -//! -//! In particular you'll see a certain amount of churn related to INTEGER vs. -//! CARDINAL in the Mesa implementation. Mesa apparently interconverts the two -//! somewhat readily? In any case, I've used usize for indices-in-buffers and -//! ints for character-sizes-and-indentation-offsets. This respects the need -//! for ints to "go negative" while carrying a pending-calculation balance, and -//! helps differentiate all the numbers flying around internally (slightly). -//! -//! I also inverted the indentation arithmetic used in the print stack, since -//! the Mesa implementation (somewhat randomly) stores the offset on the print -//! stack in terms of margin-col rather than col itself. I store col. -//! -//! I also implemented a small change in the String token, in that I store an -//! explicit length for the string. For most tokens this is just the length of -//! the accompanying string. But it's necessary to permit it to differ, for -//! encoding things that are supposed to "go on their own line" -- certain -//! classes of comment and blank-line -- where relying on adjacent -//! hardbreak-like Break tokens with long blankness indication doesn't actually -//! work. To see why, consider when there is a "thing that should be on its own -//! line" between two long blocks, say functions. If you put a hardbreak after -//! each function (or before each) and the breaking algorithm decides to break -//! there anyways (because the functions themselves are long) you wind up with -//! extra blank lines. If you don't put hardbreaks you can wind up with the -//! "thing which should be on its own line" not getting its own line in the -//! rare case of "really small functions" or such. This re-occurs with comments -//! and explicit blank lines. So in those cases we use a string with a payload -//! we want isolated to a line and an explicit length that's huge, surrounded -//! by two zero-length breaks. The algorithm will try its best to fit it on a -//! line (which it can't) and so naturally place the content on its own line to -//! avoid combining it with other lines and making matters even worse. -//! -//! # Explanation -//! -//! In case you do not have the paper, here is an explanation of what's going -//! on. -//! -//! There is a stream of input tokens flowing through this printer. -//! -//! The printer buffers up to 3N tokens inside itself, where N is linewidth. -//! Yes, linewidth is chars and tokens are multi-char, but in the worst -//! case every token worth buffering is 1 char long, so it's ok. -//! -//! Tokens are String, Break, and Begin/End to delimit blocks. -//! -//! Begin tokens can carry an offset, saying "how far to indent when you break -//! inside here", as well as a flag indicating "consistent" or "inconsistent" -//! breaking. Consistent breaking means that after the first break, no attempt -//! will be made to flow subsequent breaks together onto lines. Inconsistent -//! is the opposite. Inconsistent breaking example would be, say: -//! -//! ```ignore (illustrative) -//! foo(hello, there, good, friends) -//! ``` -//! -//! breaking inconsistently to become -//! -//! ```ignore (illustrative) -//! foo(hello, there, -//! good, friends); -//! ``` -//! -//! whereas a consistent breaking would yield: -//! -//! ```ignore (illustrative) -//! foo(hello, -//! there, -//! good, -//! friends); -//! ``` -//! -//! That is, in the consistent-break blocks we value vertical alignment -//! more than the ability to cram stuff onto a line. But in all cases if it -//! can make a block a one-liner, it'll do so. -//! -//! Carrying on with high-level logic: -//! -//! The buffered tokens go through a ring-buffer, 'tokens'. The 'left' and -//! 'right' indices denote the active portion of the ring buffer as well as -//! describing hypothetical points-in-the-infinite-stream at most 3N tokens -//! apart (i.e., "not wrapped to ring-buffer boundaries"). The paper will switch -//! between using 'left' and 'right' terms to denote the wrapped-to-ring-buffer -//! and point-in-infinite-stream senses freely. -//! -//! There is a parallel ring buffer, `size`, that holds the calculated size of -//! each token. Why calculated? Because for Begin/End pairs, the "size" -//! includes everything between the pair. That is, the "size" of Begin is -//! actually the sum of the sizes of everything between Begin and the paired -//! End that follows. Since that is arbitrarily far in the future, `size` is -//! being rewritten regularly while the printer runs; in fact most of the -//! machinery is here to work out `size` entries on the fly (and give up when -//! they're so obviously over-long that "infinity" is a good enough -//! approximation for purposes of line breaking). -//! -//! The "input side" of the printer is managed as an abstract process called -//! SCAN, which uses `scan_stack`, to manage calculating `size`. SCAN is, in -//! other words, the process of calculating 'size' entries. -//! -//! The "output side" of the printer is managed by an abstract process called -//! PRINT, which uses `print_stack`, `margin` and `space` to figure out what to -//! do with each token/size pair it consumes as it goes. It's trying to consume -//! the entire buffered window, but can't output anything until the size is >= -//! 0 (sizes are set to negative while they're pending calculation). -//! -//! So SCAN takes input and buffers tokens and pending calculations, while -//! PRINT gobbles up completed calculations and tokens from the buffer. The -//! theory is that the two can never get more than 3N tokens apart, because -//! once there's "obviously" too much data to fit on a line, in a size -//! calculation, SCAN will write "infinity" to the size and let PRINT consume -//! it. -//! -//! In this implementation (following the paper, again) the SCAN process is the -//! methods called `Printer::scan_*`, and the 'PRINT' process is the -//! method called `Printer::print`. - -mod convenience; -mod ring; - -use ring::RingBuffer; -use std::borrow::Cow; -use std::cmp; -use std::collections::VecDeque; -use std::iter; - -/// How to break. Described in more detail in the module docs. -#[derive(Clone, Copy, PartialEq)] -pub enum Breaks { - Consistent, - Inconsistent, -} - -#[derive(Clone, Copy, PartialEq)] -enum IndentStyle { - /// Vertically aligned under whatever column this block begins at. - /// - /// fn demo(arg1: usize, - /// arg2: usize) {} - Visual, - /// Indented relative to the indentation level of the previous line. - /// - /// fn demo( - /// arg1: usize, - /// arg2: usize, - /// ) {} - Block { offset: isize }, -} - -#[derive(Clone, Copy, Default, PartialEq)] -pub(crate) struct BreakToken { - offset: isize, - blank_space: isize, - pre_break: Option, -} - -#[derive(Clone, Copy, PartialEq)] -pub(crate) struct BeginToken { - indent: IndentStyle, - breaks: Breaks, -} - -#[derive(PartialEq)] -pub(crate) enum Token { - // In practice a string token contains either a `&'static str` or a - // `String`. `Cow` is overkill for this because we never modify the data, - // but it's more convenient than rolling our own more specialized type. - String(Cow<'static, str>), - Break(BreakToken), - Begin(BeginToken), - End, -} - -#[derive(Copy, Clone)] -enum PrintFrame { - Fits, - Broken { indent: usize, breaks: Breaks }, -} - -const SIZE_INFINITY: isize = 0xffff; - -/// Target line width. -const MARGIN: isize = 78; -/// Every line is allowed at least this much space, even if highly indented. -const MIN_SPACE: isize = 60; - -pub struct Printer { - out: String, - /// Number of spaces left on line - space: isize, - /// Ring-buffer of tokens and calculated sizes - buf: RingBuffer, - /// Running size of stream "...left" - left_total: isize, - /// Running size of stream "...right" - right_total: isize, - /// Pseudo-stack, really a ring too. Holds the - /// primary-ring-buffers index of the Begin that started the - /// current block, possibly with the most recent Break after that - /// Begin (if there is any) on top of it. Stuff is flushed off the - /// bottom as it becomes irrelevant due to the primary ring-buffer - /// advancing. - scan_stack: VecDeque, - /// Stack of blocks-in-progress being flushed by print - print_stack: Vec, - /// Level of indentation of current line - indent: usize, - /// Buffered indentation to avoid writing trailing whitespace - pending_indentation: isize, - /// The token most recently popped from the left boundary of the - /// ring-buffer for printing - last_printed: Option, -} - -struct BufEntry { - token: Token, - size: isize, -} - -impl Printer { - pub fn new() -> Self { - Printer { - out: String::new(), - space: MARGIN, - buf: RingBuffer::new(), - left_total: 0, - right_total: 0, - scan_stack: VecDeque::new(), - print_stack: Vec::new(), - indent: 0, - pending_indentation: 0, - last_printed: None, - } - } - - pub(crate) fn last_token(&self) -> Option<&Token> { - self.last_token_still_buffered().or_else(|| self.last_printed.as_ref()) - } - - pub(crate) fn last_token_still_buffered(&self) -> Option<&Token> { - self.buf.last().map(|last| &last.token) - } - - /// Be very careful with this! - pub(crate) fn replace_last_token_still_buffered(&mut self, token: Token) { - self.buf.last_mut().unwrap().token = token; - } - - fn scan_eof(&mut self) { - if !self.scan_stack.is_empty() { - self.check_stack(0); - self.advance_left(); - } - } - - fn scan_begin(&mut self, token: BeginToken) { - if self.scan_stack.is_empty() { - self.left_total = 1; - self.right_total = 1; - self.buf.clear(); - } - let right = self.buf.push(BufEntry { token: Token::Begin(token), size: -self.right_total }); - self.scan_stack.push_back(right); - } - - fn scan_end(&mut self) { - if self.scan_stack.is_empty() { - self.print_end(); - } else { - let right = self.buf.push(BufEntry { token: Token::End, size: -1 }); - self.scan_stack.push_back(right); - } - } - - fn scan_break(&mut self, token: BreakToken) { - if self.scan_stack.is_empty() { - self.left_total = 1; - self.right_total = 1; - self.buf.clear(); - } else { - self.check_stack(0); - } - let right = self.buf.push(BufEntry { token: Token::Break(token), size: -self.right_total }); - self.scan_stack.push_back(right); - self.right_total += token.blank_space; - } - - fn scan_string(&mut self, string: Cow<'static, str>) { - if self.scan_stack.is_empty() { - self.print_string(&string); - } else { - let len = string.len() as isize; - self.buf.push(BufEntry { token: Token::String(string), size: len }); - self.right_total += len; - self.check_stream(); - } - } - - pub(crate) fn offset(&mut self, offset: isize) { - if let Some(BufEntry { token: Token::Break(token), .. }) = &mut self.buf.last_mut() { - token.offset += offset; - } - } - - fn check_stream(&mut self) { - while self.right_total - self.left_total > self.space { - if *self.scan_stack.front().unwrap() == self.buf.index_of_first() { - self.scan_stack.pop_front().unwrap(); - self.buf.first_mut().unwrap().size = SIZE_INFINITY; - } - self.advance_left(); - if self.buf.is_empty() { - break; - } - } - } - - fn advance_left(&mut self) { - while self.buf.first().unwrap().size >= 0 { - let left = self.buf.pop_first().unwrap(); - - match &left.token { - Token::String(string) => { - self.left_total += string.len() as isize; - self.print_string(string); - } - Token::Break(token) => { - self.left_total += token.blank_space; - self.print_break(*token, left.size); - } - Token::Begin(token) => self.print_begin(*token, left.size), - Token::End => self.print_end(), - } - - self.last_printed = Some(left.token); - - if self.buf.is_empty() { - break; - } - } - } - - fn check_stack(&mut self, mut depth: usize) { - while let Some(&index) = self.scan_stack.back() { - let entry = &mut self.buf[index]; - match entry.token { - Token::Begin(_) => { - if depth == 0 { - break; - } - self.scan_stack.pop_back().unwrap(); - entry.size += self.right_total; - depth -= 1; - } - Token::End => { - // paper says + not =, but that makes no sense. - self.scan_stack.pop_back().unwrap(); - entry.size = 1; - depth += 1; - } - _ => { - self.scan_stack.pop_back().unwrap(); - entry.size += self.right_total; - if depth == 0 { - break; - } - } - } - } - } - - fn get_top(&self) -> PrintFrame { - *self - .print_stack - .last() - .unwrap_or(&PrintFrame::Broken { indent: 0, breaks: Breaks::Inconsistent }) - } - - fn print_begin(&mut self, token: BeginToken, size: isize) { - if size > self.space { - self.print_stack.push(PrintFrame::Broken { indent: self.indent, breaks: token.breaks }); - self.indent = match token.indent { - IndentStyle::Block { offset } => { - usize::try_from(self.indent as isize + offset).unwrap() - } - IndentStyle::Visual => (MARGIN - self.space) as usize, - }; - } else { - self.print_stack.push(PrintFrame::Fits); - } - } - - fn print_end(&mut self) { - if let PrintFrame::Broken { indent, .. } = self.print_stack.pop().unwrap() { - self.indent = indent; - } - } - - fn print_break(&mut self, token: BreakToken, size: isize) { - let fits = match self.get_top() { - PrintFrame::Fits => true, - PrintFrame::Broken { breaks: Breaks::Consistent, .. } => false, - PrintFrame::Broken { breaks: Breaks::Inconsistent, .. } => size <= self.space, - }; - if fits { - self.pending_indentation += token.blank_space; - self.space -= token.blank_space; - } else { - if let Some(pre_break) = token.pre_break { - self.out.push(pre_break); - } - self.out.push('\n'); - let indent = self.indent as isize + token.offset; - self.pending_indentation = indent; - self.space = cmp::max(MARGIN - indent, MIN_SPACE); - } - } - - fn print_string(&mut self, string: &str) { - // Write the pending indent. A more concise way of doing this would be: - // - // write!(self.out, "{: >n$}", "", n = self.pending_indentation as usize)?; - // - // But that is significantly slower. This code is sufficiently hot, and indents can get - // sufficiently large, that the difference is significant on some workloads. - self.out.reserve(self.pending_indentation as usize); - self.out.extend(iter::repeat(' ').take(self.pending_indentation as usize)); - self.pending_indentation = 0; - - self.out.push_str(string); - self.space -= string.len() as isize; - } -} +mod convenience;mod ring;use ring::RingBuffer ;use std::borrow::Cow;use std::cmp +;use std::collections::VecDeque;use std::iter;#[derive(Clone,Copy,PartialEq)]//; +pub enum Breaks{Consistent,Inconsistent,}#[derive(Clone,Copy,PartialEq)]enum//3; +IndentStyle{Visual,Block{offset:isize},} #[derive(Clone,Copy,Default,PartialEq)] +pub(crate)struct BreakToken{offset:isize,blank_space:isize,pre_break:Option,}#[derive(Clone,Copy,PartialEq)]pub(crate)struct BeginToken{indent://({}); +IndentStyle,breaks:Breaks,}#[derive(PartialEq) ]pub(crate)enum Token{String(Cow< +'static,str>),Break(BreakToken),Begin(BeginToken),End,}#[derive(Copy,Clone)]//3; +enum PrintFrame{Fits,Broken{indent:usize,breaks:Breaks},}const SIZE_INFINITY://; +isize=0xffff;const MARGIN:isize=78; const MIN_SPACE:isize=60;pub struct Printer{ +out:String,space:isize,buf:RingBuffer,left_total:isize,right_total://; +isize,scan_stack:VecDeque,print_stack:Vec,indent:usize,//{;}; +pending_indentation:isize,last_printed:Option,}struct BufEntry{token://3; +Token,size:isize,}impl Printer{pub fn new()->Self{Printer{out:((String::new())), +space:MARGIN,buf:(RingBuffer::new()), left_total:(0),right_total:(0),scan_stack: +VecDeque::new(),print_stack:((Vec::new())),indent:((0)),pending_indentation:(0), +last_printed:None,}}pub(crate)fn last_token(&self)->Option<&Token>{self.//{();}; +last_token_still_buffered().or_else((||self.last_printed.as_ref()))}pub(crate)fn +last_token_still_buffered(&self)->Option<&Token>{((self.buf.last())).map(|last|& +last.token)}pub(crate)fn replace_last_token_still_buffered(&mut self,token://(); +Token){;self.buf.last_mut().unwrap().token=token;}fn scan_eof(&mut self){if!self +.scan_stack.is_empty(){;self.check_stack(0);self.advance_left();}}fn scan_begin( +&mut self,token:BeginToken){if self.scan_stack.is_empty(){3;self.left_total=1;;; +self.right_total=1;;;self.buf.clear();;};let right=self.buf.push(BufEntry{token: +Token::Begin(token),size:-self.right_total});;self.scan_stack.push_back(right);} +fn scan_end(&mut self){if self.scan_stack.is_empty(){;self.print_end();}else{let +right=self.buf.push(BufEntry{token:Token::End,size:-1});{;};{;};self.scan_stack. +push_back(right);;}}fn scan_break(&mut self,token:BreakToken){if self.scan_stack +.is_empty(){;self.left_total=1;;;self.right_total=1;self.buf.clear();}else{self. +check_stack(0);;}let right=self.buf.push(BufEntry{token:Token::Break(token),size +:-self.right_total});;;self.scan_stack.push_back(right);self.right_total+=token. +blank_space;let _=();}fn scan_string(&mut self,string:Cow<'static,str>){if self. +scan_stack.is_empty(){;self.print_string(&string);;}else{;let len=string.len()as +isize;3;3;self.buf.push(BufEntry{token:Token::String(string),size:len});3;;self. +right_total+=len;3;;self.check_stream();;}}pub(crate)fn offset(&mut self,offset: +isize){if let Some(BufEntry{token:Token::Break(token),..})=&mut self.buf.//({}); +last_mut(){{;};token.offset+=offset;{;};}}fn check_stream(&mut self){while self. +right_total-self.left_total>self.space{if(*(self.scan_stack.front().unwrap()))== +self.buf.index_of_first(){();self.scan_stack.pop_front().unwrap();();3;self.buf. +first_mut().unwrap().size=SIZE_INFINITY;();}3;self.advance_left();3;if self.buf. +is_empty(){;break;}}}fn advance_left(&mut self){while self.buf.first().unwrap(). +size>=0{;let left=self.buf.pop_first().unwrap();;match&left.token{Token::String( +string)=>{3;self.left_total+=string.len()as isize;;;self.print_string(string);;} +Token::Break(token)=>{3;self.left_total+=token.blank_space;3;;self.print_break(* +token,left.size);;}Token::Begin(token)=>self.print_begin(*token,left.size),Token +::End=>self.print_end(),}{;};self.last_printed=Some(left.token);{;};if self.buf. +is_empty(){;break;;}}}fn check_stack(&mut self,mut depth:usize){while let Some(& +index)=self.scan_stack.back(){;let entry=&mut self.buf[index];match entry.token{ +Token::Begin(_)=>{if depth==0{;break;}self.scan_stack.pop_back().unwrap();entry. +size+=self.right_total;;depth-=1;}Token::End=>{self.scan_stack.pop_back().unwrap +();;;entry.size=1;depth+=1;}_=>{self.scan_stack.pop_back().unwrap();entry.size+= +self.right_total;3;if depth==0{;break;;}}}}}fn get_top(&self)->PrintFrame{*self. +print_stack.last().unwrap_or(&PrintFrame ::Broken{indent:(((0))),breaks:Breaks:: +Inconsistent})}fn print_begin(&mut self,token:BeginToken,size:isize){if size>//; +self.space{3;self.print_stack.push(PrintFrame::Broken{indent:self.indent,breaks: +token.breaks});();3;self.indent=match token.indent{IndentStyle::Block{offset}=>{ +usize::try_from(((self.indent as isize)+offset)).unwrap()}IndentStyle::Visual=>( +MARGIN-self.space)as usize,};;}else{self.print_stack.push(PrintFrame::Fits);}}fn +print_end(&mut self){if let PrintFrame::Broken{indent,..}=self.print_stack.pop// +().unwrap(){;self.indent=indent;}}fn print_break(&mut self,token:BreakToken,size +:isize){;let fits=match self.get_top(){PrintFrame::Fits=>true,PrintFrame::Broken +{breaks:Breaks::Consistent,..}=>((((false)))),PrintFrame::Broken{breaks:Breaks:: +Inconsistent,..}=>size<=self.space,};3;if fits{;self.pending_indentation+=token. +blank_space;;;self.space-=token.blank_space;;}else{if let Some(pre_break)=token. +pre_break{;self.out.push(pre_break);;}self.out.push('\n');let indent=self.indent +as isize+token.offset;3;3;self.pending_indentation=indent;;;self.space=cmp::max( +MARGIN-indent,MIN_SPACE);();}}fn print_string(&mut self,string:&str){3;self.out. +reserve(self.pending_indentation as usize);3;;self.out.extend(iter::repeat(' '). +take(self.pending_indentation as usize));;;self.pending_indentation=0;;self.out. +push_str(string);if true{};let _=();self.space-=string.len()as isize;let _=();}} diff --git a/compiler/rustc_ast_pretty/src/pp/convenience.rs b/compiler/rustc_ast_pretty/src/pp/convenience.rs index c4c4fdce7fef2..d2a6af57784f6 100644 --- a/compiler/rustc_ast_pretty/src/pp/convenience.rs +++ b/compiler/rustc_ast_pretty/src/pp/convenience.rs @@ -1,94 +1,22 @@ -use crate::pp::{BeginToken, BreakToken, Breaks, IndentStyle, Printer, Token, SIZE_INFINITY}; -use std::borrow::Cow; - -impl Printer { - /// "raw box" - pub fn rbox(&mut self, indent: isize, breaks: Breaks) { - self.scan_begin(BeginToken { indent: IndentStyle::Block { offset: indent }, breaks }) - } - - /// Inconsistent breaking box - pub fn ibox(&mut self, indent: isize) { - self.rbox(indent, Breaks::Inconsistent) - } - - /// Consistent breaking box - pub fn cbox(&mut self, indent: isize) { - self.rbox(indent, Breaks::Consistent) - } - - pub fn visual_align(&mut self) { - self.scan_begin(BeginToken { indent: IndentStyle::Visual, breaks: Breaks::Consistent }); - } - - pub fn break_offset(&mut self, n: usize, off: isize) { - self.scan_break(BreakToken { - offset: off, - blank_space: n as isize, - ..BreakToken::default() - }); - } - - pub fn end(&mut self) { - self.scan_end() - } - - pub fn eof(mut self) -> String { - self.scan_eof(); - self.out - } - - pub fn word>>(&mut self, wrd: S) { - let string = wrd.into(); - self.scan_string(string) - } - - fn spaces(&mut self, n: usize) { - self.break_offset(n, 0) - } - - pub fn zerobreak(&mut self) { - self.spaces(0) - } - - pub fn space(&mut self) { - self.spaces(1) - } - - pub fn hardbreak(&mut self) { - self.spaces(SIZE_INFINITY as usize) - } - - pub fn is_beginning_of_line(&self) -> bool { - match self.last_token() { - Some(last_token) => last_token.is_hardbreak_tok(), - None => true, - } - } - - pub(crate) fn hardbreak_tok_offset(off: isize) -> Token { - Token::Break(BreakToken { - offset: off, - blank_space: SIZE_INFINITY, - ..BreakToken::default() - }) - } - - pub fn trailing_comma(&mut self) { - self.scan_break(BreakToken { pre_break: Some(','), ..BreakToken::default() }); - } - - pub fn trailing_comma_or_space(&mut self) { - self.scan_break(BreakToken { - blank_space: 1, - pre_break: Some(','), - ..BreakToken::default() - }); - } -} - -impl Token { - pub fn is_hardbreak_tok(&self) -> bool { - *self == Printer::hardbreak_tok_offset(0) - } -} +use crate::pp::{BeginToken,BreakToken,Breaks,IndentStyle,Printer,Token,//*&*&(); +SIZE_INFINITY};use std::borrow::Cow;impl Printer{pub fn rbox(&mut self,indent:// +isize,breaks:Breaks){self.scan_begin(BeginToken{indent:IndentStyle::Block{//{;}; +offset:indent},breaks})}pub fn ibox(&mut self,indent:isize){self.rbox(indent,//; +Breaks::Inconsistent)}pub fn cbox(&mut self,indent:isize){self.rbox(indent,//(); +Breaks::Consistent)}pub fn visual_align(&mut self){3;self.scan_begin(BeginToken{ +indent:IndentStyle::Visual,breaks:Breaks::Consistent});();}pub fn break_offset(& +mut self,n:usize,off:isize){;self.scan_break(BreakToken{offset:off,blank_space:n +as isize,..BreakToken::default()});();}pub fn end(&mut self){self.scan_end()}pub +fn eof(mut self)->String{{;};self.scan_eof();();self.out}pub fn word>>(&mut self,wrd:S){;let string=wrd.into();self.scan_string(string)} +fn spaces(&mut self,n:usize){self.break_offset( n,0)}pub fn zerobreak(&mut self) +{(self.spaces((0)))}pub fn space(&mut self){self.spaces(1)}pub fn hardbreak(&mut +self){(self.spaces(SIZE_INFINITY as usize))}pub fn is_beginning_of_line(&self)-> +bool{match (self.last_token()){ Some(last_token)=>last_token.is_hardbreak_tok(), +None=>(true),}}pub(crate)fn hardbreak_tok_offset(off:isize)->Token{Token::Break( +BreakToken{offset:off,blank_space:SIZE_INFINITY,..( BreakToken::default())})}pub +fn trailing_comma(&mut self){3;self.scan_break(BreakToken{pre_break:Some(','),.. +BreakToken::default()});{;};}pub fn trailing_comma_or_space(&mut self){{;};self. +scan_break(BreakToken{blank_space:1,pre_break:Some (','),..BreakToken::default() +});let _=||();}}impl Token{pub fn is_hardbreak_tok(&self)->bool{*self==Printer:: +hardbreak_tok_offset((((((((((((((((((((((((((((0))))))))))))))))))))))))))) )}} diff --git a/compiler/rustc_ast_pretty/src/pp/ring.rs b/compiler/rustc_ast_pretty/src/pp/ring.rs index 8187394fe30e0..e8384b295dfa0 100644 --- a/compiler/rustc_ast_pretty/src/pp/ring.rs +++ b/compiler/rustc_ast_pretty/src/pp/ring.rs @@ -1,77 +1,14 @@ -use std::collections::VecDeque; -use std::ops::{Index, IndexMut}; - -/// A view onto a finite range of an infinitely long sequence of T. -/// -/// The Ts are indexed 0..infinity. A RingBuffer begins as a view of elements -/// 0..0 (i.e. nothing). The user of the RingBuffer advances its left and right -/// position independently, although only in the positive direction, and only -/// with left <= right at all times. -/// -/// Holding a RingBuffer whose view is elements left..right gives the ability to -/// use Index and IndexMut to access elements i in the infinitely long queue for -/// which left <= i < right. -pub struct RingBuffer { - data: VecDeque, - // Abstract index of data[0] in the infinitely sized queue. - offset: usize, -} - -impl RingBuffer { - pub fn new() -> Self { - RingBuffer { data: VecDeque::new(), offset: 0 } - } - - pub fn is_empty(&self) -> bool { - self.data.is_empty() - } - - pub fn push(&mut self, value: T) -> usize { - let index = self.offset + self.data.len(); - self.data.push_back(value); - index - } - - pub fn clear(&mut self) { - self.data.clear(); - } - - pub fn index_of_first(&self) -> usize { - self.offset - } - - pub fn first(&self) -> Option<&T> { - self.data.front() - } - - pub fn first_mut(&mut self) -> Option<&mut T> { - self.data.front_mut() - } - - pub fn pop_first(&mut self) -> Option { - let first = self.data.pop_front()?; - self.offset += 1; - Some(first) - } - - pub fn last(&self) -> Option<&T> { - self.data.back() - } - - pub fn last_mut(&mut self) -> Option<&mut T> { - self.data.back_mut() - } -} - -impl Index for RingBuffer { - type Output = T; - fn index(&self, index: usize) -> &Self::Output { - &self.data[index.checked_sub(self.offset).unwrap()] - } -} - -impl IndexMut for RingBuffer { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - &mut self.data[index.checked_sub(self.offset).unwrap()] - } -} +use std::collections::VecDeque;use std::ops::{Index,IndexMut};pub struct//{();}; +RingBuffer{data:VecDeque,offset:usize,}implRingBuffer{pub fn new()// +->Self{(RingBuffer{data:VecDeque::new(),offset:0})}pub fn is_empty(&self)->bool{ +self.data.is_empty()}pub fn push(&mut self,value:T)->usize{{();};let index=self. +offset+self.data.len();;self.data.push_back(value);index}pub fn clear(&mut self) +{();self.data.clear();();}pub fn index_of_first(&self)->usize{self.offset}pub fn +first(&self)->Option<&T>{self.data.front ()}pub fn first_mut(&mut self)->Option< +&mut T>{self.data.front_mut()}pub fn pop_first(&mut self)->Option{;let first= +self.data.pop_front()?;;self.offset+=1;Some(first)}pub fn last(&self)->Option<&T +>{((((self.data.back()))))}pub fn last_mut(&mut self)->Option<&mut T>{self.data. +back_mut()}}implIndexfor RingBuffer{type Output=T;fn index(&self,// +index:usize)->&Self::Output{&self.data[ index.checked_sub(self.offset).unwrap()] +}}implIndexMutfor RingBuffer{fn index_mut(&mut self,index:usize)-> +&mut Self::Output{(&mut (self.data[ index.checked_sub(self.offset).unwrap()]))}} diff --git a/compiler/rustc_ast_pretty/src/pprust/mod.rs b/compiler/rustc_ast_pretty/src/pprust/mod.rs index 83b7e13905aee..ac29221dee60f 100644 --- a/compiler/rustc_ast_pretty/src/pprust/mod.rs +++ b/compiler/rustc_ast_pretty/src/pprust/mod.rs @@ -1,90 +1,26 @@ -#[cfg(test)] -mod tests; - -pub mod state; -pub use state::{print_crate, AnnNode, Comments, PpAnn, PrintState, State}; - -use rustc_ast as ast; -use rustc_ast::token::{Nonterminal, Token, TokenKind}; -use rustc_ast::tokenstream::{TokenStream, TokenTree}; - -use std::borrow::Cow; - -pub fn nonterminal_to_string(nt: &Nonterminal) -> String { - State::new().nonterminal_to_string(nt) -} - -/// Print the token kind precisely, without converting `$crate` into its respective crate name. -pub fn token_kind_to_string(tok: &TokenKind) -> Cow<'static, str> { - State::new().token_kind_to_string(tok) -} - -/// Print the token precisely, without converting `$crate` into its respective crate name. -pub fn token_to_string(token: &Token) -> Cow<'static, str> { - State::new().token_to_string(token) -} - -pub fn ty_to_string(ty: &ast::Ty) -> String { - State::new().ty_to_string(ty) -} - -pub fn bounds_to_string(bounds: &[ast::GenericBound]) -> String { - State::new().bounds_to_string(bounds) -} - -pub fn where_bound_predicate_to_string(where_bound_predicate: &ast::WhereBoundPredicate) -> String { - State::new().where_bound_predicate_to_string(where_bound_predicate) -} - -pub fn pat_to_string(pat: &ast::Pat) -> String { - State::new().pat_to_string(pat) -} - -pub fn expr_to_string(e: &ast::Expr) -> String { - State::new().expr_to_string(e) -} - -pub fn tt_to_string(tt: &TokenTree) -> String { - State::new().tt_to_string(tt) -} - -pub fn tts_to_string(tokens: &TokenStream) -> String { - State::new().tts_to_string(tokens) -} - -pub fn item_to_string(i: &ast::Item) -> String { - State::new().item_to_string(i) -} - -pub fn path_to_string(p: &ast::Path) -> String { - State::new().path_to_string(p) -} - -pub fn path_segment_to_string(p: &ast::PathSegment) -> String { - State::new().path_segment_to_string(p) -} - -pub fn vis_to_string(v: &ast::Visibility) -> String { - State::new().vis_to_string(v) -} - -pub fn meta_list_item_to_string(li: &ast::NestedMetaItem) -> String { - State::new().meta_list_item_to_string(li) -} - -pub fn attribute_to_string(attr: &ast::Attribute) -> String { - State::new().attribute_to_string(attr) -} - -pub fn to_string(f: impl FnOnce(&mut State<'_>)) -> String { - State::to_string(f) -} - -pub fn crate_to_string_for_macros(krate: &ast::Crate) -> String { - State::to_string(|s| { - s.print_inner_attributes(&krate.attrs); - for item in &krate.items { - s.print_item(item); - } - }) -} +#[cfg(test)]mod tests;pub mod state;pub use state::{print_crate,AnnNode,//{();}; +Comments,PpAnn,PrintState,State};use rustc_ast as ast;use rustc_ast::token::{//; +Nonterminal,Token,TokenKind};use rustc_ast::tokenstream::{TokenStream,TokenTree +};use std::borrow::Cow;pub fn nonterminal_to_string(nt:&Nonterminal)->String{//; +State::new().nonterminal_to_string(nt)}pub fn token_kind_to_string(tok:&//{();}; +TokenKind)->Cow<'static,str>{(((State::new()).token_kind_to_string(tok)))}pub fn +token_to_string(token:&Token)->Cow<'static,str >{(State::new()).token_to_string( +token)}pub fn ty_to_string(ty:&ast::Ty)->String{(State::new().ty_to_string(ty))} +pub fn bounds_to_string(bounds:&[ast::GenericBound])->String{(((State::new()))). +bounds_to_string(bounds)}pub fn where_bound_predicate_to_string(//if let _=(){}; +where_bound_predicate:&ast::WhereBoundPredicate)->String{(((((State::new()))))). +where_bound_predicate_to_string(where_bound_predicate)} pub fn pat_to_string(pat +:&ast::Pat)->String{(State::new() .pat_to_string(pat))}pub fn expr_to_string(e:& +ast::Expr)->String{(((State::new()).expr_to_string(e)))}pub fn tt_to_string(tt:& +TokenTree)->String{(State::new().tt_to_string(tt))}pub fn tts_to_string(tokens:& +TokenStream)->String{State::new() .tts_to_string(tokens)}pub fn item_to_string(i +:&ast::Item)->String{(State::new() .item_to_string(i))}pub fn path_to_string(p:& +ast::Path)->String{State::new( ).path_to_string(p)}pub fn path_segment_to_string +(p:&ast::PathSegment)->String{((State ::new()).path_segment_to_string(p))}pub fn +vis_to_string(v:&ast::Visibility)->String{(State::new().vis_to_string(v))}pub fn +meta_list_item_to_string(li:&ast::NestedMetaItem)-> String{((((State::new())))). +meta_list_item_to_string(li)}pub fn attribute_to_string(attr:&ast::Attribute)-> +String{(State::new().attribute_to_string(attr))}pub fn to_string(f:impl FnOnce(& +mut State<'_>))->String{(State::to_string(f))}pub fn crate_to_string_for_macros( +krate:&ast::Crate)->String{State::to_string(|s|{;s.print_inner_attributes(&krate +.attrs);let _=();for item in&krate.items{((),());s.print_item(item);((),());}})} diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 3ea182c586752..8700742f88b6c 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1,2040 +1,539 @@ -//! AST pretty printing. -//! -//! Note that HIR pretty printing is layered on top of this crate. - -mod expr; -mod item; - -use crate::pp::Breaks::{Consistent, Inconsistent}; -use crate::pp::{self, Breaks}; -use crate::pprust::state::expr::FixupContext; -use ast::TraitBoundModifiers; -use rustc_ast::attr::AttrIdGenerator; -use rustc_ast::ptr::P; -use rustc_ast::token::{self, BinOpToken, CommentKind, Delimiter, Nonterminal, Token, TokenKind}; -use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree}; -use rustc_ast::util::classify; -use rustc_ast::util::comments::{Comment, CommentStyle}; -use rustc_ast::util::parser; -use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, BlockCheckMode, PatKind}; -use rustc_ast::{attr, BindingAnnotation, ByRef, DelimArgs, RangeEnd, RangeSyntax, Term}; -use rustc_ast::{GenericArg, GenericBound, SelfKind}; -use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass}; -use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; -use rustc_span::edition::Edition; -use rustc_span::source_map::{SourceMap, Spanned}; -use rustc_span::symbol::{kw, sym, Ident, IdentPrinter, Symbol}; -use rustc_span::{BytePos, CharPos, FileName, Pos, Span, DUMMY_SP}; -use std::borrow::Cow; -use thin_vec::ThinVec; - -pub enum MacHeader<'a> { - Path(&'a ast::Path), - Keyword(&'static str), -} - -pub enum AnnNode<'a> { - Ident(&'a Ident), - Name(&'a Symbol), - Block(&'a ast::Block), - Item(&'a ast::Item), - SubItem(ast::NodeId), - Expr(&'a ast::Expr), - Pat(&'a ast::Pat), - Crate(&'a ast::Crate), -} - -pub trait PpAnn { - fn pre(&self, _state: &mut State<'_>, _node: AnnNode<'_>) {} - fn post(&self, _state: &mut State<'_>, _node: AnnNode<'_>) {} -} - -struct NoAnn; - -impl PpAnn for NoAnn {} - -pub struct Comments<'a> { - sm: &'a SourceMap, - comments: Vec, - current: usize, -} - -/// Returns `None` if the first `col` chars of `s` contain a non-whitespace char. -/// Otherwise returns `Some(k)` where `k` is first char offset after that leading -/// whitespace. Note that `k` may be outside bounds of `s`. -fn all_whitespace(s: &str, col: CharPos) -> Option { - let mut idx = 0; - for (i, ch) in s.char_indices().take(col.to_usize()) { - if !ch.is_whitespace() { - return None; - } - idx = i + ch.len_utf8(); - } - Some(idx) -} - -fn trim_whitespace_prefix(s: &str, col: CharPos) -> &str { - let len = s.len(); - match all_whitespace(s, col) { - Some(col) => { - if col < len { - &s[col..] - } else { - "" - } - } - None => s, - } -} - -fn split_block_comment_into_lines(text: &str, col: CharPos) -> Vec { - let mut res: Vec = vec![]; - let mut lines = text.lines(); - // just push the first line - res.extend(lines.next().map(|it| it.to_string())); - // for other lines, strip common whitespace prefix - for line in lines { - res.push(trim_whitespace_prefix(line, col).to_string()) - } - res -} - -fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec { - let sm = SourceMap::new(sm.path_mapping().clone()); - let source_file = sm.new_source_file(path, src); - let text = (*source_file.src.as_ref().unwrap()).clone(); - - let text: &str = text.as_str(); - let start_bpos = source_file.start_pos; - let mut pos = 0; - let mut comments: Vec = Vec::new(); - let mut code_to_the_left = false; - - if let Some(shebang_len) = rustc_lexer::strip_shebang(text) { - comments.push(Comment { - style: CommentStyle::Isolated, - lines: vec![text[..shebang_len].to_string()], - pos: start_bpos, - }); - pos += shebang_len; - } - - for token in rustc_lexer::tokenize(&text[pos..]) { - let token_text = &text[pos..pos + token.len as usize]; - match token.kind { - rustc_lexer::TokenKind::Whitespace => { - if let Some(mut idx) = token_text.find('\n') { - code_to_the_left = false; - while let Some(next_newline) = &token_text[idx + 1..].find('\n') { - idx += 1 + next_newline; - comments.push(Comment { - style: CommentStyle::BlankLine, - lines: vec![], - pos: start_bpos + BytePos((pos + idx) as u32), - }); - } - } - } - rustc_lexer::TokenKind::BlockComment { doc_style, .. } => { - if doc_style.is_none() { - let code_to_the_right = !matches!( - text[pos + token.len as usize..].chars().next(), - Some('\r' | '\n') - ); - let style = match (code_to_the_left, code_to_the_right) { - (_, true) => CommentStyle::Mixed, - (false, false) => CommentStyle::Isolated, - (true, false) => CommentStyle::Trailing, - }; - - // Count the number of chars since the start of the line by rescanning. - let pos_in_file = start_bpos + BytePos(pos as u32); - let line_begin_in_file = source_file.line_begin_pos(pos_in_file); - let line_begin_pos = (line_begin_in_file - start_bpos).to_usize(); - let col = CharPos(text[line_begin_pos..pos].chars().count()); - - let lines = split_block_comment_into_lines(token_text, col); - comments.push(Comment { style, lines, pos: pos_in_file }) - } - } - rustc_lexer::TokenKind::LineComment { doc_style } => { - if doc_style.is_none() { - comments.push(Comment { - style: if code_to_the_left { - CommentStyle::Trailing - } else { - CommentStyle::Isolated - }, - lines: vec![token_text.to_string()], - pos: start_bpos + BytePos(pos as u32), - }) - } - } - _ => { - code_to_the_left = true; - } - } - pos += token.len as usize; - } - - comments -} - -impl<'a> Comments<'a> { - pub fn new(sm: &'a SourceMap, filename: FileName, input: String) -> Comments<'a> { - let comments = gather_comments(sm, filename, input); - Comments { sm, comments, current: 0 } - } - - // FIXME: This shouldn't probably clone lmao - fn next(&self) -> Option { - self.comments.get(self.current).cloned() - } - - fn trailing_comment( - &self, - span: rustc_span::Span, - next_pos: Option, - ) -> Option { - if let Some(cmnt) = self.next() { - if cmnt.style != CommentStyle::Trailing { - return None; - } - let span_line = self.sm.lookup_char_pos(span.hi()); - let comment_line = self.sm.lookup_char_pos(cmnt.pos); - let next = next_pos.unwrap_or_else(|| cmnt.pos + BytePos(1)); - if span.hi() < cmnt.pos && cmnt.pos < next && span_line.line == comment_line.line { - return Some(cmnt); - } - } - - None - } -} - -pub struct State<'a> { - pub s: pp::Printer, - comments: Option>, - ann: &'a (dyn PpAnn + 'a), -} - -const INDENT_UNIT: isize = 4; - -/// Requires you to pass an input filename and reader so that -/// it can scan the input text for comments to copy forward. -pub fn print_crate<'a>( - sm: &'a SourceMap, - krate: &ast::Crate, - filename: FileName, - input: String, - ann: &'a dyn PpAnn, - is_expanded: bool, - edition: Edition, - g: &AttrIdGenerator, -) -> String { - let mut s = - State { s: pp::Printer::new(), comments: Some(Comments::new(sm, filename, input)), ann }; - - if is_expanded && !krate.attrs.iter().any(|attr| attr.has_name(sym::no_core)) { - // We need to print `#![no_std]` (and its feature gate) so that - // compiling pretty-printed source won't inject libstd again. - // However, we don't want these attributes in the AST because - // of the feature gate, so we fake them up here. - - // `#![feature(prelude_import)]` - let fake_attr = attr::mk_attr_nested_word( - g, - ast::AttrStyle::Inner, - sym::feature, - sym::prelude_import, - DUMMY_SP, - ); - s.print_attribute(&fake_attr); - - // Currently, in Rust 2018 we don't have `extern crate std;` at the crate - // root, so this is not needed, and actually breaks things. - if edition.is_rust_2015() { - // `#![no_std]` - let fake_attr = attr::mk_attr_word(g, ast::AttrStyle::Inner, sym::no_std, DUMMY_SP); - s.print_attribute(&fake_attr); - } - } - - s.print_inner_attributes(&krate.attrs); - for item in &krate.items { - s.print_item(item); - } - s.print_remaining_comments(); - s.ann.post(&mut s, AnnNode::Crate(krate)); - s.s.eof() -} - -/// Should two consecutive tokens be printed with a space between them? -/// -/// Note: some old proc macros parse pretty-printed output, so changes here can -/// break old code. For example: -/// - #63896: `#[allow(unused,` must be printed rather than `#[allow(unused ,` -/// - #73345: `#[allow(unused)]` must be printed rather than `# [allow(unused)]` -/// -fn space_between(tt1: &TokenTree, tt2: &TokenTree) -> bool { - use token::*; - use Delimiter::*; - use TokenTree::Delimited as Del; - use TokenTree::Token as Tok; - - fn is_punct(tt: &TokenTree) -> bool { - matches!(tt, TokenTree::Token(tok, _) if tok.is_punct()) - } - - // Each match arm has one or more examples in comments. The default is to - // insert space between adjacent tokens, except for the cases listed in - // this match. - match (tt1, tt2) { - // No space after line doc comments. - (Tok(Token { kind: DocComment(CommentKind::Line, ..), .. }, _), _) => false, - - // `.` + NON-PUNCT: `x.y`, `tup.0` - (Tok(Token { kind: Dot, .. }, _), tt2) if !is_punct(tt2) => false, - - // `$` + IDENT: `$e` - (Tok(Token { kind: Dollar, .. }, _), Tok(Token { kind: Ident(..), .. }, _)) => false, - - // NON-PUNCT + `,`: `foo,` - // NON-PUNCT + `;`: `x = 3;`, `[T; 3]` - // NON-PUNCT + `.`: `x.y`, `tup.0` - (tt1, Tok(Token { kind: Comma | Semi | Dot, .. }, _)) if !is_punct(tt1) => false, - - // IDENT + `!`: `println!()`, but `if !x { ... }` needs a space after the `if` - (Tok(Token { kind: Ident(sym, is_raw), span }, _), Tok(Token { kind: Not, .. }, _)) - if !Ident::new(*sym, *span).is_reserved() || matches!(is_raw, IdentIsRaw::Yes) => - { - false - } - - // IDENT|`fn`|`Self`|`pub` + `(`: `f(3)`, `fn(x: u8)`, `Self()`, `pub(crate)`, - // but `let (a, b) = (1, 2)` needs a space after the `let` - (Tok(Token { kind: Ident(sym, is_raw), span }, _), Del(_, _, Parenthesis, _)) - if !Ident::new(*sym, *span).is_reserved() - || *sym == kw::Fn - || *sym == kw::SelfUpper - || *sym == kw::Pub - || matches!(is_raw, IdentIsRaw::Yes) => - { - false - } - - // `#` + `[`: `#[attr]` - (Tok(Token { kind: Pound, .. }, _), Del(_, _, Bracket, _)) => false, - - _ => true, - } -} - -fn binop_to_string(op: BinOpToken) -> &'static str { - match op { - token::Plus => "+", - token::Minus => "-", - token::Star => "*", - token::Slash => "/", - token::Percent => "%", - token::Caret => "^", - token::And => "&", - token::Or => "|", - token::Shl => "<<", - token::Shr => ">>", - } -} - -fn doc_comment_to_string( - comment_kind: CommentKind, - attr_style: ast::AttrStyle, - data: Symbol, -) -> String { - match (comment_kind, attr_style) { - (CommentKind::Line, ast::AttrStyle::Outer) => format!("///{data}"), - (CommentKind::Line, ast::AttrStyle::Inner) => format!("//!{data}"), - (CommentKind::Block, ast::AttrStyle::Outer) => format!("/**{data}*/"), - (CommentKind::Block, ast::AttrStyle::Inner) => format!("/*!{data}*/"), - } -} - -fn literal_to_string(lit: token::Lit) -> String { - let token::Lit { kind, symbol, suffix } = lit; - let mut out = match kind { - token::Byte => format!("b'{symbol}'"), - token::Char => format!("'{symbol}'"), - token::Str => format!("\"{symbol}\""), - token::StrRaw(n) => { - format!("r{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = symbol) - } - token::ByteStr => format!("b\"{symbol}\""), - token::ByteStrRaw(n) => { - format!("br{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = symbol) - } - token::CStr => format!("c\"{symbol}\""), - token::CStrRaw(n) => { - format!("cr{delim}\"{symbol}\"{delim}", delim = "#".repeat(n as usize)) - } - token::Integer | token::Float | token::Bool | token::Err(_) => symbol.to_string(), - }; - - if let Some(suffix) = suffix { - out.push_str(suffix.as_str()) - } - - out -} - -impl std::ops::Deref for State<'_> { - type Target = pp::Printer; - fn deref(&self) -> &Self::Target { - &self.s - } -} - -impl std::ops::DerefMut for State<'_> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.s - } -} - -/// This trait is used for both AST and HIR pretty-printing. -pub trait PrintState<'a>: std::ops::Deref + std::ops::DerefMut { - fn comments(&mut self) -> &mut Option>; - fn ann_post(&mut self, ident: Ident); - fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool); - - fn print_ident(&mut self, ident: Ident) { - self.word(IdentPrinter::for_ast_ident(ident, ident.is_raw_guess()).to_string()); - self.ann_post(ident) - } - - fn strsep( - &mut self, - sep: &'static str, - space_before: bool, - b: Breaks, - elts: &[T], - mut op: F, - ) where - F: FnMut(&mut Self, &T), - { - self.rbox(0, b); - if let Some((first, rest)) = elts.split_first() { - op(self, first); - for elt in rest { - if space_before { - self.space(); - } - self.word_space(sep); - op(self, elt); - } - } - self.end(); - } - - fn commasep(&mut self, b: Breaks, elts: &[T], op: F) - where - F: FnMut(&mut Self, &T), - { - self.strsep(",", false, b, elts, op) - } - - fn maybe_print_comment(&mut self, pos: BytePos) -> bool { - let mut has_comment = false; - while let Some(cmnt) = self.next_comment() { - if cmnt.pos < pos { - has_comment = true; - self.print_comment(&cmnt); - } else { - break; - } - } - has_comment - } - - fn print_comment(&mut self, cmnt: &Comment) { - match cmnt.style { - CommentStyle::Mixed => { - if !self.is_beginning_of_line() { - self.zerobreak(); - } - if let Some((last, lines)) = cmnt.lines.split_last() { - self.ibox(0); - - for line in lines { - self.word(line.clone()); - self.hardbreak() - } - - self.word(last.clone()); - self.space(); - - self.end(); - } - self.zerobreak() - } - CommentStyle::Isolated => { - self.hardbreak_if_not_bol(); - for line in &cmnt.lines { - // Don't print empty lines because they will end up as trailing - // whitespace. - if !line.is_empty() { - self.word(line.clone()); - } - self.hardbreak(); - } - } - CommentStyle::Trailing => { - if !self.is_beginning_of_line() { - self.word(" "); - } - if cmnt.lines.len() == 1 { - self.word(cmnt.lines[0].clone()); - self.hardbreak() - } else { - self.visual_align(); - for line in &cmnt.lines { - if !line.is_empty() { - self.word(line.clone()); - } - self.hardbreak(); - } - self.end(); - } - } - CommentStyle::BlankLine => { - // We need to do at least one, possibly two hardbreaks. - let twice = match self.last_token() { - Some(pp::Token::String(s)) => ";" == s, - Some(pp::Token::Begin(_)) => true, - Some(pp::Token::End) => true, - _ => false, - }; - if twice { - self.hardbreak(); - } - self.hardbreak(); - } - } - if let Some(cmnts) = self.comments() { - cmnts.current += 1; - } - } - - fn next_comment(&mut self) -> Option { - self.comments().as_mut().and_then(|c| c.next()) - } - - fn maybe_print_trailing_comment(&mut self, span: rustc_span::Span, next_pos: Option) { - if let Some(cmnts) = self.comments() { - if let Some(cmnt) = cmnts.trailing_comment(span, next_pos) { - self.print_comment(&cmnt); - } - } - } - - fn print_remaining_comments(&mut self) { - // If there aren't any remaining comments, then we need to manually - // make sure there is a line break at the end. - if self.next_comment().is_none() { - self.hardbreak(); - } - while let Some(cmnt) = self.next_comment() { - self.print_comment(&cmnt) - } - } - - fn print_string(&mut self, st: &str, style: ast::StrStyle) { - let st = match style { - ast::StrStyle::Cooked => format!("\"{}\"", st.escape_debug()), - ast::StrStyle::Raw(n) => { - format!("r{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = st) - } - }; - self.word(st) - } - - fn print_inner_attributes(&mut self, attrs: &[ast::Attribute]) -> bool { - self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, true) - } - - fn print_outer_attributes(&mut self, attrs: &[ast::Attribute]) -> bool { - self.print_either_attributes(attrs, ast::AttrStyle::Outer, false, true) - } - - fn print_either_attributes( - &mut self, - attrs: &[ast::Attribute], - kind: ast::AttrStyle, - is_inline: bool, - trailing_hardbreak: bool, - ) -> bool { - let mut printed = false; - for attr in attrs { - if attr.style == kind { - self.print_attribute_inline(attr, is_inline); - if is_inline { - self.nbsp(); - } - printed = true; - } - } - if printed && trailing_hardbreak && !is_inline { - self.hardbreak_if_not_bol(); - } - printed - } - - fn print_attribute_inline(&mut self, attr: &ast::Attribute, is_inline: bool) { - if !is_inline { - self.hardbreak_if_not_bol(); - } - self.maybe_print_comment(attr.span.lo()); - match &attr.kind { - ast::AttrKind::Normal(normal) => { - match attr.style { - ast::AttrStyle::Inner => self.word("#!["), - ast::AttrStyle::Outer => self.word("#["), - } - self.print_attr_item(&normal.item, attr.span); - self.word("]"); - } - ast::AttrKind::DocComment(comment_kind, data) => { - self.word(doc_comment_to_string(*comment_kind, attr.style, *data)); - self.hardbreak() - } - } - } - - fn print_attr_item(&mut self, item: &ast::AttrItem, span: Span) { - self.ibox(0); - match &item.args { - AttrArgs::Delimited(DelimArgs { dspan: _, delim, tokens }) => self.print_mac_common( - Some(MacHeader::Path(&item.path)), - false, - None, - *delim, - tokens, - true, - span, - ), - AttrArgs::Empty => { - self.print_path(&item.path, false, 0); - } - AttrArgs::Eq(_, AttrArgsEq::Ast(expr)) => { - self.print_path(&item.path, false, 0); - self.space(); - self.word_space("="); - let token_str = self.expr_to_string(expr); - self.word(token_str); - } - AttrArgs::Eq(_, AttrArgsEq::Hir(lit)) => { - self.print_path(&item.path, false, 0); - self.space(); - self.word_space("="); - let token_str = self.meta_item_lit_to_string(lit); - self.word(token_str); - } - } - self.end(); - } - - /// This doesn't deserve to be called "pretty" printing, but it should be - /// meaning-preserving. A quick hack that might help would be to look at the - /// spans embedded in the TTs to decide where to put spaces and newlines. - /// But it'd be better to parse these according to the grammar of the - /// appropriate macro, transcribe back into the grammar we just parsed from, - /// and then pretty-print the resulting AST nodes (so, e.g., we print - /// expression arguments as expressions). It can be done! I think. - fn print_tt(&mut self, tt: &TokenTree, convert_dollar_crate: bool) -> Spacing { - match tt { - TokenTree::Token(token, spacing) => { - let token_str = self.token_to_string_ext(token, convert_dollar_crate); - self.word(token_str); - if let token::DocComment(..) = token.kind { - self.hardbreak() - } - *spacing - } - TokenTree::Delimited(dspan, spacing, delim, tts) => { - self.print_mac_common( - None, - false, - None, - *delim, - tts, - convert_dollar_crate, - dspan.entire(), - ); - spacing.close - } - } - } - - fn print_tts(&mut self, tts: &TokenStream, convert_dollar_crate: bool) { - let mut iter = tts.trees().peekable(); - while let Some(tt) = iter.next() { - let spacing = self.print_tt(tt, convert_dollar_crate); - if let Some(next) = iter.peek() { - // Should we print a space after `tt`? There are two guiding - // factors. - // - `spacing` is the more important and accurate one. Most - // tokens have good spacing information, and - // `Joint`/`JointHidden` get used a lot. - // - `space_between` is the backup. Code produced by proc - // macros has worse spacing information, with no - // `JointHidden` usage and too much `Alone` usage, which - // would result in over-spaced output such as - // `( x () , y . z )`. `space_between` avoids some of the - // excess whitespace. - if spacing == Spacing::Alone && space_between(tt, next) { - self.space(); - } - } - } - } - - fn print_mac_common( - &mut self, - header: Option>, - has_bang: bool, - ident: Option, - delim: Delimiter, - tts: &TokenStream, - convert_dollar_crate: bool, - span: Span, - ) { - if delim == Delimiter::Brace { - self.cbox(INDENT_UNIT); - } - match header { - Some(MacHeader::Path(path)) => self.print_path(path, false, 0), - Some(MacHeader::Keyword(kw)) => self.word(kw), - None => {} - } - if has_bang { - self.word("!"); - } - if let Some(ident) = ident { - self.nbsp(); - self.print_ident(ident); - } - match delim { - Delimiter::Brace => { - if header.is_some() || has_bang || ident.is_some() { - self.nbsp(); - } - self.word("{"); - if !tts.is_empty() { - self.space(); - } - self.ibox(0); - self.print_tts(tts, convert_dollar_crate); - self.end(); - let empty = tts.is_empty(); - self.bclose(span, empty); - } - delim => { - let token_str = self.token_kind_to_string(&token::OpenDelim(delim)); - self.word(token_str); - self.ibox(0); - self.print_tts(tts, convert_dollar_crate); - self.end(); - let token_str = self.token_kind_to_string(&token::CloseDelim(delim)); - self.word(token_str); - } - } - } - - fn print_mac_def( - &mut self, - macro_def: &ast::MacroDef, - ident: &Ident, - sp: Span, - print_visibility: impl FnOnce(&mut Self), - ) { - let (kw, has_bang) = if macro_def.macro_rules { - ("macro_rules", true) - } else { - print_visibility(self); - ("macro", false) - }; - self.print_mac_common( - Some(MacHeader::Keyword(kw)), - has_bang, - Some(*ident), - macro_def.body.delim, - ¯o_def.body.tokens.clone(), - true, - sp, - ); - if macro_def.body.need_semicolon() { - self.word(";"); - } - } - - fn print_path(&mut self, path: &ast::Path, colons_before_params: bool, depth: usize) { - self.maybe_print_comment(path.span.lo()); - - for (i, segment) in path.segments[..path.segments.len() - depth].iter().enumerate() { - if i > 0 { - self.word("::") - } - self.print_path_segment(segment, colons_before_params); - } - } - - fn print_path_segment(&mut self, segment: &ast::PathSegment, colons_before_params: bool) { - if segment.ident.name != kw::PathRoot { - self.print_ident(segment.ident); - if let Some(args) = &segment.args { - self.print_generic_args(args, colons_before_params); - } - } - } - - fn head>>(&mut self, w: S) { - let w = w.into(); - // Outer-box is consistent. - self.cbox(INDENT_UNIT); - // Head-box is inconsistent. - self.ibox(0); - // Keyword that starts the head. - if !w.is_empty() { - self.word_nbsp(w); - } - } - - fn bopen(&mut self) { - self.word("{"); - self.end(); // Close the head-box. - } - - fn bclose_maybe_open(&mut self, span: rustc_span::Span, empty: bool, close_box: bool) { - let has_comment = self.maybe_print_comment(span.hi()); - if !empty || has_comment { - self.break_offset_if_not_bol(1, -INDENT_UNIT); - } - self.word("}"); - if close_box { - self.end(); // Close the outer-box. - } - } - - fn bclose(&mut self, span: rustc_span::Span, empty: bool) { - let close_box = true; - self.bclose_maybe_open(span, empty, close_box) - } - - fn break_offset_if_not_bol(&mut self, n: usize, off: isize) { - if !self.is_beginning_of_line() { - self.break_offset(n, off) - } else if off != 0 { - if let Some(last_token) = self.last_token_still_buffered() { - if last_token.is_hardbreak_tok() { - // We do something pretty sketchy here: tuck the nonzero - // offset-adjustment we were going to deposit along with the - // break into the previous hardbreak. - self.replace_last_token_still_buffered(pp::Printer::hardbreak_tok_offset(off)); - } - } - } - } - - fn nonterminal_to_string(&self, nt: &Nonterminal) -> String { - match nt { - token::NtExpr(e) => self.expr_to_string(e), - token::NtMeta(e) => self.attr_item_to_string(e), - token::NtTy(e) => self.ty_to_string(e), - token::NtPath(e) => self.path_to_string(e), - token::NtItem(e) => self.item_to_string(e), - token::NtBlock(e) => self.block_to_string(e), - token::NtStmt(e) => self.stmt_to_string(e), - token::NtPat(e) => self.pat_to_string(e), - &token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(e, is_raw.into()).to_string(), - token::NtLifetime(e) => e.to_string(), - token::NtLiteral(e) => self.expr_to_string(e), - token::NtVis(e) => self.vis_to_string(e), - } - } - - /// Print the token kind precisely, without converting `$crate` into its respective crate name. - fn token_kind_to_string(&self, tok: &TokenKind) -> Cow<'static, str> { - self.token_kind_to_string_ext(tok, None) - } - - fn token_kind_to_string_ext( - &self, - tok: &TokenKind, - convert_dollar_crate: Option, - ) -> Cow<'static, str> { - match *tok { - token::Eq => "=".into(), - token::Lt => "<".into(), - token::Le => "<=".into(), - token::EqEq => "==".into(), - token::Ne => "!=".into(), - token::Ge => ">=".into(), - token::Gt => ">".into(), - token::Not => "!".into(), - token::Tilde => "~".into(), - token::OrOr => "||".into(), - token::AndAnd => "&&".into(), - token::BinOp(op) => binop_to_string(op).into(), - token::BinOpEq(op) => format!("{}=", binop_to_string(op)).into(), - - /* Structural symbols */ - token::At => "@".into(), - token::Dot => ".".into(), - token::DotDot => "..".into(), - token::DotDotDot => "...".into(), - token::DotDotEq => "..=".into(), - token::Comma => ",".into(), - token::Semi => ";".into(), - token::Colon => ":".into(), - token::ModSep => "::".into(), - token::RArrow => "->".into(), - token::LArrow => "<-".into(), - token::FatArrow => "=>".into(), - token::OpenDelim(Delimiter::Parenthesis) => "(".into(), - token::CloseDelim(Delimiter::Parenthesis) => ")".into(), - token::OpenDelim(Delimiter::Bracket) => "[".into(), - token::CloseDelim(Delimiter::Bracket) => "]".into(), - token::OpenDelim(Delimiter::Brace) => "{".into(), - token::CloseDelim(Delimiter::Brace) => "}".into(), - token::OpenDelim(Delimiter::Invisible) | token::CloseDelim(Delimiter::Invisible) => { - "".into() - } - token::Pound => "#".into(), - token::Dollar => "$".into(), - token::Question => "?".into(), - token::SingleQuote => "'".into(), - - /* Literals */ - token::Literal(lit) => literal_to_string(lit).into(), - - /* Name components */ - token::Ident(s, is_raw) => { - IdentPrinter::new(s, is_raw.into(), convert_dollar_crate).to_string().into() - } - token::Lifetime(s) => s.to_string().into(), - - /* Other */ - token::DocComment(comment_kind, attr_style, data) => { - doc_comment_to_string(comment_kind, attr_style, data).into() - } - token::Eof => "".into(), - - token::Interpolated(ref nt) => self.nonterminal_to_string(&nt.0).into(), - } - } - - /// Print the token precisely, without converting `$crate` into its respective crate name. - fn token_to_string(&self, token: &Token) -> Cow<'static, str> { - self.token_to_string_ext(token, false) - } - - fn token_to_string_ext(&self, token: &Token, convert_dollar_crate: bool) -> Cow<'static, str> { - let convert_dollar_crate = convert_dollar_crate.then_some(token.span); - self.token_kind_to_string_ext(&token.kind, convert_dollar_crate) - } - - fn ty_to_string(&self, ty: &ast::Ty) -> String { - Self::to_string(|s| s.print_type(ty)) - } - - fn pat_to_string(&self, pat: &ast::Pat) -> String { - Self::to_string(|s| s.print_pat(pat)) - } - - fn expr_to_string(&self, e: &ast::Expr) -> String { - Self::to_string(|s| s.print_expr(e, FixupContext::default())) - } - - fn meta_item_lit_to_string(&self, lit: &ast::MetaItemLit) -> String { - Self::to_string(|s| s.print_meta_item_lit(lit)) - } - - fn stmt_to_string(&self, stmt: &ast::Stmt) -> String { - Self::to_string(|s| s.print_stmt(stmt)) - } - - fn item_to_string(&self, i: &ast::Item) -> String { - Self::to_string(|s| s.print_item(i)) - } - - fn path_to_string(&self, p: &ast::Path) -> String { - Self::to_string(|s| s.print_path(p, false, 0)) - } - - fn vis_to_string(&self, v: &ast::Visibility) -> String { - Self::to_string(|s| s.print_visibility(v)) - } - - fn block_to_string(&self, blk: &ast::Block) -> String { - Self::to_string(|s| { - // Containing cbox, will be closed by `print_block` at `}`. - s.cbox(INDENT_UNIT); - // Head-ibox, will be closed by `print_block` after `{`. - s.ibox(0); - s.print_block(blk) - }) - } - - fn attr_item_to_string(&self, ai: &ast::AttrItem) -> String { - Self::to_string(|s| s.print_attr_item(ai, ai.path.span)) - } - - fn to_string(f: impl FnOnce(&mut State<'_>)) -> String { - let mut printer = State::new(); - f(&mut printer); - printer.s.eof() - } -} - -impl<'a> PrintState<'a> for State<'a> { - fn comments(&mut self) -> &mut Option> { - &mut self.comments - } - - fn ann_post(&mut self, ident: Ident) { - self.ann.post(self, AnnNode::Ident(&ident)); - } - - fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool) { - if colons_before_params { - self.word("::") - } - - match args { - ast::GenericArgs::AngleBracketed(data) => { - self.word("<"); - self.commasep(Inconsistent, &data.args, |s, arg| match arg { - ast::AngleBracketedArg::Arg(a) => s.print_generic_arg(a), - ast::AngleBracketedArg::Constraint(c) => s.print_assoc_constraint(c), - }); - self.word(">") - } - - ast::GenericArgs::Parenthesized(data) => { - self.word("("); - self.commasep(Inconsistent, &data.inputs, |s, ty| s.print_type(ty)); - self.word(")"); - self.print_fn_ret_ty(&data.output); - } - } - } -} - -impl<'a> State<'a> { - pub fn new() -> State<'a> { - State { s: pp::Printer::new(), comments: None, ann: &NoAnn } - } - - fn commasep_cmnt(&mut self, b: Breaks, elts: &[T], mut op: F, mut get_span: G) - where - F: FnMut(&mut State<'_>, &T), - G: FnMut(&T) -> rustc_span::Span, - { - self.rbox(0, b); - let len = elts.len(); - let mut i = 0; - for elt in elts { - self.maybe_print_comment(get_span(elt).hi()); - op(self, elt); - i += 1; - if i < len { - self.word(","); - self.maybe_print_trailing_comment(get_span(elt), Some(get_span(&elts[i]).hi())); - self.space_if_not_bol(); - } - } - self.end(); - } - - fn commasep_exprs(&mut self, b: Breaks, exprs: &[P]) { - self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e, FixupContext::default()), |e| e.span) - } - - pub fn print_opt_lifetime(&mut self, lifetime: &Option) { - if let Some(lt) = *lifetime { - self.print_lifetime(lt); - self.nbsp(); - } - } - - pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocConstraint) { - self.print_ident(constraint.ident); - if let Some(args) = constraint.gen_args.as_ref() { - self.print_generic_args(args, false) - } - self.space(); - match &constraint.kind { - ast::AssocConstraintKind::Equality { term } => { - self.word_space("="); - match term { - Term::Ty(ty) => self.print_type(ty), - Term::Const(c) => self.print_expr_anon_const(c, &[]), - } - } - ast::AssocConstraintKind::Bound { bounds } => { - if !bounds.is_empty() { - self.word_nbsp(":"); - self.print_type_bounds(bounds); - } - } - } - } - - pub fn print_generic_arg(&mut self, generic_arg: &GenericArg) { - match generic_arg { - GenericArg::Lifetime(lt) => self.print_lifetime(*lt), - GenericArg::Type(ty) => self.print_type(ty), - GenericArg::Const(ct) => self.print_expr(&ct.value, FixupContext::default()), - } - } - - pub fn print_type(&mut self, ty: &ast::Ty) { - self.maybe_print_comment(ty.span.lo()); - self.ibox(0); - match &ty.kind { - ast::TyKind::Slice(ty) => { - self.word("["); - self.print_type(ty); - self.word("]"); - } - ast::TyKind::Ptr(mt) => { - self.word("*"); - self.print_mt(mt, true); - } - ast::TyKind::Ref(lifetime, mt) => { - self.word("&"); - self.print_opt_lifetime(lifetime); - self.print_mt(mt, false); - } - ast::TyKind::Never => { - self.word("!"); - } - ast::TyKind::Tup(elts) => { - self.popen(); - self.commasep(Inconsistent, elts, |s, ty| s.print_type(ty)); - if elts.len() == 1 { - self.word(","); - } - self.pclose(); - } - ast::TyKind::AnonStruct(_, fields) => { - self.head("struct"); - self.print_record_struct_body(fields, ty.span); - } - ast::TyKind::AnonUnion(_, fields) => { - self.head("union"); - self.print_record_struct_body(fields, ty.span); - } - ast::TyKind::Paren(typ) => { - self.popen(); - self.print_type(typ); - self.pclose(); - } - ast::TyKind::BareFn(f) => { - self.print_ty_fn(f.ext, f.unsafety, &f.decl, None, &f.generic_params); - } - ast::TyKind::Path(None, path) => { - self.print_path(path, false, 0); - } - ast::TyKind::Path(Some(qself), path) => self.print_qpath(path, qself, false), - ast::TyKind::TraitObject(bounds, syntax) => { - if *syntax == ast::TraitObjectSyntax::Dyn { - self.word_nbsp("dyn"); - } - self.print_type_bounds(bounds); - } - ast::TyKind::ImplTrait(_, bounds) => { - self.word_nbsp("impl"); - self.print_type_bounds(bounds); - } - ast::TyKind::Array(ty, length) => { - self.word("["); - self.print_type(ty); - self.word("; "); - self.print_expr(&length.value, FixupContext::default()); - self.word("]"); - } - ast::TyKind::Typeof(e) => { - self.word("typeof("); - self.print_expr(&e.value, FixupContext::default()); - self.word(")"); - } - ast::TyKind::Infer => { - self.word("_"); - } - ast::TyKind::Err(_) => { - self.popen(); - self.word("/*ERROR*/"); - self.pclose(); - } - ast::TyKind::Dummy => { - self.popen(); - self.word("/*DUMMY*/"); - self.pclose(); - } - ast::TyKind::ImplicitSelf => { - self.word("Self"); - } - ast::TyKind::MacCall(m) => { - self.print_mac(m); - } - ast::TyKind::CVarArgs => { - self.word("..."); - } - } - self.end(); - } - - fn print_trait_ref(&mut self, t: &ast::TraitRef) { - self.print_path(&t.path, false, 0) - } - - fn print_formal_generic_params(&mut self, generic_params: &[ast::GenericParam]) { - if !generic_params.is_empty() { - self.word("for"); - self.print_generic_params(generic_params); - self.nbsp(); - } - } - - fn print_poly_trait_ref(&mut self, t: &ast::PolyTraitRef) { - self.print_formal_generic_params(&t.bound_generic_params); - self.print_trait_ref(&t.trait_ref) - } - - fn print_stmt(&mut self, st: &ast::Stmt) { - self.maybe_print_comment(st.span.lo()); - match &st.kind { - ast::StmtKind::Let(loc) => { - self.print_outer_attributes(&loc.attrs); - self.space_if_not_bol(); - self.ibox(INDENT_UNIT); - self.word_nbsp("let"); - - self.ibox(INDENT_UNIT); - self.print_local_decl(loc); - self.end(); - if let Some((init, els)) = loc.kind.init_else_opt() { - self.nbsp(); - self.word_space("="); - self.print_expr(init, FixupContext::default()); - if let Some(els) = els { - self.cbox(INDENT_UNIT); - self.ibox(INDENT_UNIT); - self.word(" else "); - self.print_block(els); - } - } - self.word(";"); - self.end(); // `let` ibox - } - ast::StmtKind::Item(item) => self.print_item(item), - ast::StmtKind::Expr(expr) => { - self.space_if_not_bol(); - self.print_expr_outer_attr_style( - expr, - false, - FixupContext { stmt: true, ..FixupContext::default() }, - ); - if classify::expr_requires_semi_to_be_stmt(expr) { - self.word(";"); - } - } - ast::StmtKind::Semi(expr) => { - self.space_if_not_bol(); - self.print_expr_outer_attr_style( - expr, - false, - FixupContext { stmt: true, ..FixupContext::default() }, - ); - self.word(";"); - } - ast::StmtKind::Empty => { - self.space_if_not_bol(); - self.word(";"); - } - ast::StmtKind::MacCall(mac) => { - self.space_if_not_bol(); - self.print_outer_attributes(&mac.attrs); - self.print_mac(&mac.mac); - if mac.style == ast::MacStmtStyle::Semicolon { - self.word(";"); - } - } - } - self.maybe_print_trailing_comment(st.span, None) - } - - fn print_block(&mut self, blk: &ast::Block) { - self.print_block_with_attrs(blk, &[]) - } - - fn print_block_unclosed_indent(&mut self, blk: &ast::Block) { - self.print_block_maybe_unclosed(blk, &[], false) - } - - fn print_block_with_attrs(&mut self, blk: &ast::Block, attrs: &[ast::Attribute]) { - self.print_block_maybe_unclosed(blk, attrs, true) - } - - fn print_block_maybe_unclosed( - &mut self, - blk: &ast::Block, - attrs: &[ast::Attribute], - close_box: bool, - ) { - match blk.rules { - BlockCheckMode::Unsafe(..) => self.word_space("unsafe"), - BlockCheckMode::Default => (), - } - self.maybe_print_comment(blk.span.lo()); - self.ann.pre(self, AnnNode::Block(blk)); - self.bopen(); - - let has_attrs = self.print_inner_attributes(attrs); - - for (i, st) in blk.stmts.iter().enumerate() { - match &st.kind { - ast::StmtKind::Expr(expr) if i == blk.stmts.len() - 1 => { - self.maybe_print_comment(st.span.lo()); - self.space_if_not_bol(); - self.print_expr_outer_attr_style( - expr, - false, - FixupContext { stmt: true, ..FixupContext::default() }, - ); - self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi())); - } - _ => self.print_stmt(st), - } - } - - let empty = !has_attrs && blk.stmts.is_empty(); - self.bclose_maybe_open(blk.span, empty, close_box); - self.ann.post(self, AnnNode::Block(blk)) - } - - /// Print a `let pat = expr` expression. - /// - /// Parentheses are inserted surrounding `expr` if a round-trip through the - /// parser would otherwise work out the wrong way in a condition position. - /// - /// For example each of the following would mean the wrong thing without - /// parentheses. - /// - /// ```ignore (illustrative) - /// if let _ = (Struct {}) {} - /// - /// if let _ = (true && false) {} - /// ``` - /// - /// In a match guard, the second case still requires parens, but the first - /// case no longer does because anything until `=>` is considered part of - /// the match guard expression. Parsing of the expression is not terminated - /// by `{` in that position. - /// - /// ```ignore (illustrative) - /// match () { - /// () if let _ = Struct {} => {} - /// () if let _ = (true && false) => {} - /// } - /// ``` - fn print_let(&mut self, pat: &ast::Pat, expr: &ast::Expr, fixup: FixupContext) { - self.word("let "); - self.print_pat(pat); - self.space(); - self.word_space("="); - self.print_expr_cond_paren( - expr, - fixup.parenthesize_exterior_struct_lit && parser::contains_exterior_struct_lit(expr) - || parser::needs_par_as_let_scrutinee(expr.precedence().order()), - FixupContext::default(), - ); - } - - fn print_mac(&mut self, m: &ast::MacCall) { - self.print_mac_common( - Some(MacHeader::Path(&m.path)), - true, - None, - m.args.delim, - &m.args.tokens.clone(), - true, - m.span(), - ); - } - - fn print_inline_asm(&mut self, asm: &ast::InlineAsm) { - enum AsmArg<'a> { - Template(String), - Operand(&'a InlineAsmOperand), - ClobberAbi(Symbol), - Options(InlineAsmOptions), - } - - let mut args = vec![AsmArg::Template(InlineAsmTemplatePiece::to_string(&asm.template))]; - args.extend(asm.operands.iter().map(|(o, _)| AsmArg::Operand(o))); - for (abi, _) in &asm.clobber_abis { - args.push(AsmArg::ClobberAbi(*abi)); - } - if !asm.options.is_empty() { - args.push(AsmArg::Options(asm.options)); - } - - self.popen(); - self.commasep(Consistent, &args, |s, arg| match arg { - AsmArg::Template(template) => s.print_string(template, ast::StrStyle::Cooked), - AsmArg::Operand(op) => { - let print_reg_or_class = |s: &mut Self, r: &InlineAsmRegOrRegClass| match r { - InlineAsmRegOrRegClass::Reg(r) => s.print_symbol(*r, ast::StrStyle::Cooked), - InlineAsmRegOrRegClass::RegClass(r) => s.word(r.to_string()), - }; - match op { - InlineAsmOperand::In { reg, expr } => { - s.word("in"); - s.popen(); - print_reg_or_class(s, reg); - s.pclose(); - s.space(); - s.print_expr(expr, FixupContext::default()); - } - InlineAsmOperand::Out { reg, late, expr } => { - s.word(if *late { "lateout" } else { "out" }); - s.popen(); - print_reg_or_class(s, reg); - s.pclose(); - s.space(); - match expr { - Some(expr) => s.print_expr(expr, FixupContext::default()), - None => s.word("_"), - } - } - InlineAsmOperand::InOut { reg, late, expr } => { - s.word(if *late { "inlateout" } else { "inout" }); - s.popen(); - print_reg_or_class(s, reg); - s.pclose(); - s.space(); - s.print_expr(expr, FixupContext::default()); - } - InlineAsmOperand::SplitInOut { reg, late, in_expr, out_expr } => { - s.word(if *late { "inlateout" } else { "inout" }); - s.popen(); - print_reg_or_class(s, reg); - s.pclose(); - s.space(); - s.print_expr(in_expr, FixupContext::default()); - s.space(); - s.word_space("=>"); - match out_expr { - Some(out_expr) => s.print_expr(out_expr, FixupContext::default()), - None => s.word("_"), - } - } - InlineAsmOperand::Const { anon_const } => { - s.word("const"); - s.space(); - s.print_expr(&anon_const.value, FixupContext::default()); - } - InlineAsmOperand::Sym { sym } => { - s.word("sym"); - s.space(); - if let Some(qself) = &sym.qself { - s.print_qpath(&sym.path, qself, true); - } else { - s.print_path(&sym.path, true, 0); - } - } - InlineAsmOperand::Label { block } => { - s.head("label"); - s.print_block(block); - } - } - } - AsmArg::ClobberAbi(abi) => { - s.word("clobber_abi"); - s.popen(); - s.print_symbol(*abi, ast::StrStyle::Cooked); - s.pclose(); - } - AsmArg::Options(opts) => { - s.word("options"); - s.popen(); - let mut options = vec![]; - if opts.contains(InlineAsmOptions::PURE) { - options.push("pure"); - } - if opts.contains(InlineAsmOptions::NOMEM) { - options.push("nomem"); - } - if opts.contains(InlineAsmOptions::READONLY) { - options.push("readonly"); - } - if opts.contains(InlineAsmOptions::PRESERVES_FLAGS) { - options.push("preserves_flags"); - } - if opts.contains(InlineAsmOptions::NORETURN) { - options.push("noreturn"); - } - if opts.contains(InlineAsmOptions::NOSTACK) { - options.push("nostack"); - } - if opts.contains(InlineAsmOptions::ATT_SYNTAX) { - options.push("att_syntax"); - } - if opts.contains(InlineAsmOptions::RAW) { - options.push("raw"); - } - if opts.contains(InlineAsmOptions::MAY_UNWIND) { - options.push("may_unwind"); - } - s.commasep(Inconsistent, &options, |s, &opt| { - s.word(opt); - }); - s.pclose(); - } - }); - self.pclose(); - } - - fn print_local_decl(&mut self, loc: &ast::Local) { - self.print_pat(&loc.pat); - if let Some(ty) = &loc.ty { - self.word_space(":"); - self.print_type(ty); - } - } - - fn print_name(&mut self, name: Symbol) { - self.word(name.to_string()); - self.ann.post(self, AnnNode::Name(&name)) - } - - fn print_qpath(&mut self, path: &ast::Path, qself: &ast::QSelf, colons_before_params: bool) { - self.word("<"); - self.print_type(&qself.ty); - if qself.position > 0 { - self.space(); - self.word_space("as"); - let depth = path.segments.len() - qself.position; - self.print_path(path, false, depth); - } - self.word(">"); - for item_segment in &path.segments[qself.position..] { - self.word("::"); - self.print_ident(item_segment.ident); - if let Some(args) = &item_segment.args { - self.print_generic_args(args, colons_before_params) - } - } - } - - fn print_pat(&mut self, pat: &ast::Pat) { - self.maybe_print_comment(pat.span.lo()); - self.ann.pre(self, AnnNode::Pat(pat)); - /* Pat isn't normalized, but the beauty of it - is that it doesn't matter */ - match &pat.kind { - PatKind::Wild => self.word("_"), - PatKind::Never => self.word("!"), - PatKind::Ident(BindingAnnotation(by_ref, mutbl), ident, sub) => { - if mutbl.is_mut() { - self.word_nbsp("mut"); - } - if let ByRef::Yes(rmutbl) = by_ref { - self.word_nbsp("ref"); - if rmutbl.is_mut() { - self.word_nbsp("mut"); - } - } - self.print_ident(*ident); - if let Some(p) = sub { - self.space(); - self.word_space("@"); - self.print_pat(p); - } - } - PatKind::TupleStruct(qself, path, elts) => { - if let Some(qself) = qself { - self.print_qpath(path, qself, true); - } else { - self.print_path(path, true, 0); - } - self.popen(); - self.commasep(Inconsistent, elts, |s, p| s.print_pat(p)); - self.pclose(); - } - PatKind::Or(pats) => { - self.strsep("|", true, Inconsistent, pats, |s, p| s.print_pat(p)); - } - PatKind::Path(None, path) => { - self.print_path(path, true, 0); - } - PatKind::Path(Some(qself), path) => { - self.print_qpath(path, qself, false); - } - PatKind::Struct(qself, path, fields, etc) => { - if let Some(qself) = qself { - self.print_qpath(path, qself, true); - } else { - self.print_path(path, true, 0); - } - self.nbsp(); - self.word("{"); - let empty = fields.is_empty() && *etc == ast::PatFieldsRest::None; - if !empty { - self.space(); - } - self.commasep_cmnt( - Consistent, - fields, - |s, f| { - s.cbox(INDENT_UNIT); - if !f.is_shorthand { - s.print_ident(f.ident); - s.word_nbsp(":"); - } - s.print_pat(&f.pat); - s.end(); - }, - |f| f.pat.span, - ); - if *etc == ast::PatFieldsRest::Rest { - if !fields.is_empty() { - self.word_space(","); - } - self.word(".."); - } - if !empty { - self.space(); - } - self.word("}"); - } - PatKind::Tuple(elts) => { - self.popen(); - self.commasep(Inconsistent, elts, |s, p| s.print_pat(p)); - if elts.len() == 1 { - self.word(","); - } - self.pclose(); - } - PatKind::Box(inner) => { - self.word("box "); - self.print_pat(inner); - } - PatKind::Deref(inner) => { - self.word("deref!"); - self.popen(); - self.print_pat(inner); - self.pclose(); - } - PatKind::Ref(inner, mutbl) => { - self.word("&"); - if mutbl.is_mut() { - self.word("mut "); - } - if let PatKind::Ident(ast::BindingAnnotation::MUT, ..) = inner.kind { - self.popen(); - self.print_pat(inner); - self.pclose(); - } else { - self.print_pat(inner); - } - } - PatKind::Lit(e) => self.print_expr(e, FixupContext::default()), - PatKind::Range(begin, end, Spanned { node: end_kind, .. }) => { - if let Some(e) = begin { - self.print_expr(e, FixupContext::default()); - } - match end_kind { - RangeEnd::Included(RangeSyntax::DotDotDot) => self.word("..."), - RangeEnd::Included(RangeSyntax::DotDotEq) => self.word("..="), - RangeEnd::Excluded => self.word(".."), - } - if let Some(e) = end { - self.print_expr(e, FixupContext::default()); - } - } - PatKind::Slice(elts) => { - self.word("["); - self.commasep(Inconsistent, elts, |s, p| s.print_pat(p)); - self.word("]"); - } - PatKind::Rest => self.word(".."), - PatKind::Paren(inner) => { - self.popen(); - self.print_pat(inner); - self.pclose(); - } - PatKind::MacCall(m) => self.print_mac(m), - PatKind::Err(_) => { - self.popen(); - self.word("/*ERROR*/"); - self.pclose(); - } - } - self.ann.post(self, AnnNode::Pat(pat)) - } - - fn print_explicit_self(&mut self, explicit_self: &ast::ExplicitSelf) { - match &explicit_self.node { - SelfKind::Value(m) => { - self.print_mutability(*m, false); - self.word("self") - } - SelfKind::Region(lt, m) => { - self.word("&"); - self.print_opt_lifetime(lt); - self.print_mutability(*m, false); - self.word("self") - } - SelfKind::Explicit(typ, m) => { - self.print_mutability(*m, false); - self.word("self"); - self.word_space(":"); - self.print_type(typ) - } - } - } - - fn print_coroutine_kind(&mut self, coroutine_kind: ast::CoroutineKind) { - match coroutine_kind { - ast::CoroutineKind::Gen { .. } => { - self.word_nbsp("gen"); - } - ast::CoroutineKind::Async { .. } => { - self.word_nbsp("async"); - } - ast::CoroutineKind::AsyncGen { .. } => { - self.word_nbsp("async"); - self.word_nbsp("gen"); - } - } - } - - pub fn print_type_bounds(&mut self, bounds: &[ast::GenericBound]) { - let mut first = true; - for bound in bounds { - if first { - first = false; - } else { - self.nbsp(); - self.word_space("+"); - } - - match bound { - GenericBound::Trait( - tref, - TraitBoundModifiers { constness, asyncness, polarity }, - ) => { - match constness { - ast::BoundConstness::Never => {} - ast::BoundConstness::Always(_) | ast::BoundConstness::Maybe(_) => { - self.word_space(constness.as_str()); - } - } - - match asyncness { - ast::BoundAsyncness::Normal => {} - ast::BoundAsyncness::Async(_) => { - self.word_space(asyncness.as_str()); - } - } - - match polarity { - ast::BoundPolarity::Positive => {} - ast::BoundPolarity::Negative(_) | ast::BoundPolarity::Maybe(_) => { - self.word(polarity.as_str()); - } - } - - self.print_poly_trait_ref(tref); - } - GenericBound::Outlives(lt) => self.print_lifetime(*lt), - } - } - } - - fn print_lifetime(&mut self, lifetime: ast::Lifetime) { - self.print_name(lifetime.ident.name) - } - - fn print_lifetime_bounds(&mut self, bounds: &ast::GenericBounds) { - for (i, bound) in bounds.iter().enumerate() { - if i != 0 { - self.word(" + "); - } - match bound { - ast::GenericBound::Outlives(lt) => self.print_lifetime(*lt), - _ => { - panic!("expected a lifetime bound, found a trait bound") - } - } - } - } - - fn print_generic_params(&mut self, generic_params: &[ast::GenericParam]) { - if generic_params.is_empty() { - return; - } - - self.word("<"); - - self.commasep(Inconsistent, generic_params, |s, param| { - s.print_outer_attributes_inline(¶m.attrs); - - match ¶m.kind { - ast::GenericParamKind::Lifetime => { - let lt = ast::Lifetime { id: param.id, ident: param.ident }; - s.print_lifetime(lt); - if !param.bounds.is_empty() { - s.word_nbsp(":"); - s.print_lifetime_bounds(¶m.bounds) - } - } - ast::GenericParamKind::Type { default } => { - s.print_ident(param.ident); - if !param.bounds.is_empty() { - s.word_nbsp(":"); - s.print_type_bounds(¶m.bounds); - } - if let Some(default) = default { - s.space(); - s.word_space("="); - s.print_type(default) - } - } - ast::GenericParamKind::Const { ty, default, .. } => { - s.word_space("const"); - s.print_ident(param.ident); - s.space(); - s.word_space(":"); - s.print_type(ty); - if !param.bounds.is_empty() { - s.word_nbsp(":"); - s.print_type_bounds(¶m.bounds); - } - if let Some(default) = default { - s.space(); - s.word_space("="); - s.print_expr(&default.value, FixupContext::default()); - } - } - } - }); - - self.word(">"); - } - - pub fn print_mutability(&mut self, mutbl: ast::Mutability, print_const: bool) { - match mutbl { - ast::Mutability::Mut => self.word_nbsp("mut"), - ast::Mutability::Not => { - if print_const { - self.word_nbsp("const"); - } - } - } - } - - fn print_mt(&mut self, mt: &ast::MutTy, print_const: bool) { - self.print_mutability(mt.mutbl, print_const); - self.print_type(&mt.ty) - } - - fn print_param(&mut self, input: &ast::Param, is_closure: bool) { - self.ibox(INDENT_UNIT); - - self.print_outer_attributes_inline(&input.attrs); - - match input.ty.kind { - ast::TyKind::Infer if is_closure => self.print_pat(&input.pat), - _ => { - if let Some(eself) = input.to_self() { - self.print_explicit_self(&eself); - } else { - let invalid = if let PatKind::Ident(_, ident, _) = input.pat.kind { - ident.name == kw::Empty - } else { - false - }; - if !invalid { - self.print_pat(&input.pat); - self.word(":"); - self.space(); - } - self.print_type(&input.ty); - } - } - } - self.end(); - } - - fn print_fn_ret_ty(&mut self, fn_ret_ty: &ast::FnRetTy) { - if let ast::FnRetTy::Ty(ty) = fn_ret_ty { - self.space_if_not_bol(); - self.ibox(INDENT_UNIT); - self.word_space("->"); - self.print_type(ty); - self.end(); - self.maybe_print_comment(ty.span.lo()); - } - } - - fn print_ty_fn( - &mut self, - ext: ast::Extern, - unsafety: ast::Unsafe, - decl: &ast::FnDecl, - name: Option, - generic_params: &[ast::GenericParam], - ) { - self.ibox(INDENT_UNIT); - self.print_formal_generic_params(generic_params); - let generics = ast::Generics { - params: ThinVec::new(), - where_clause: ast::WhereClause { - has_where_token: false, - predicates: ThinVec::new(), - span: DUMMY_SP, - }, - span: DUMMY_SP, - }; - let header = ast::FnHeader { unsafety, ext, ..ast::FnHeader::default() }; - self.print_fn(decl, header, name, &generics); - self.end(); - } - - fn print_fn_header_info(&mut self, header: ast::FnHeader) { - self.print_constness(header.constness); - header.coroutine_kind.map(|coroutine_kind| self.print_coroutine_kind(coroutine_kind)); - self.print_unsafety(header.unsafety); - - match header.ext { - ast::Extern::None => {} - ast::Extern::Implicit(_) => { - self.word_nbsp("extern"); - } - ast::Extern::Explicit(abi, _) => { - self.word_nbsp("extern"); - self.print_token_literal(abi.as_token_lit(), abi.span); - self.nbsp(); - } - } - - self.word("fn") - } - - fn print_unsafety(&mut self, s: ast::Unsafe) { - match s { - ast::Unsafe::No => {} - ast::Unsafe::Yes(_) => self.word_nbsp("unsafe"), - } - } - - fn print_constness(&mut self, s: ast::Const) { - match s { - ast::Const::No => {} - ast::Const::Yes(_) => self.word_nbsp("const"), - } - } - - fn print_is_auto(&mut self, s: ast::IsAuto) { - match s { - ast::IsAuto::Yes => self.word_nbsp("auto"), - ast::IsAuto::No => {} - } - } - - fn print_meta_item_lit(&mut self, lit: &ast::MetaItemLit) { - self.print_token_literal(lit.as_token_lit(), lit.span) - } - - fn print_token_literal(&mut self, token_lit: token::Lit, span: Span) { - self.maybe_print_comment(span.lo()); - self.word(token_lit.to_string()) - } - - fn print_symbol(&mut self, sym: Symbol, style: ast::StrStyle) { - self.print_string(sym.as_str(), style); - } - - fn print_inner_attributes_no_trailing_hardbreak(&mut self, attrs: &[ast::Attribute]) -> bool { - self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, false) - } - - fn print_outer_attributes_inline(&mut self, attrs: &[ast::Attribute]) -> bool { - self.print_either_attributes(attrs, ast::AttrStyle::Outer, true, true) - } - - fn print_attribute(&mut self, attr: &ast::Attribute) { - self.print_attribute_inline(attr, false) - } - - fn print_meta_list_item(&mut self, item: &ast::NestedMetaItem) { - match item { - ast::NestedMetaItem::MetaItem(mi) => self.print_meta_item(mi), - ast::NestedMetaItem::Lit(lit) => self.print_meta_item_lit(lit), - } - } - - fn print_meta_item(&mut self, item: &ast::MetaItem) { - self.ibox(INDENT_UNIT); - match &item.kind { - ast::MetaItemKind::Word => self.print_path(&item.path, false, 0), - ast::MetaItemKind::NameValue(value) => { - self.print_path(&item.path, false, 0); - self.space(); - self.word_space("="); - self.print_meta_item_lit(value); - } - ast::MetaItemKind::List(items) => { - self.print_path(&item.path, false, 0); - self.popen(); - self.commasep(Consistent, items, |s, i| s.print_meta_list_item(i)); - self.pclose(); - } - } - self.end(); - } - - pub(crate) fn bounds_to_string(&self, bounds: &[ast::GenericBound]) -> String { - Self::to_string(|s| s.print_type_bounds(bounds)) - } - - pub(crate) fn where_bound_predicate_to_string( - &self, - where_bound_predicate: &ast::WhereBoundPredicate, - ) -> String { - Self::to_string(|s| s.print_where_bound_predicate(where_bound_predicate)) - } - - pub(crate) fn tt_to_string(&self, tt: &TokenTree) -> String { - Self::to_string(|s| { - s.print_tt(tt, false); - }) - } - - pub(crate) fn tts_to_string(&self, tokens: &TokenStream) -> String { - Self::to_string(|s| s.print_tts(tokens, false)) - } - - pub(crate) fn path_segment_to_string(&self, p: &ast::PathSegment) -> String { - Self::to_string(|s| s.print_path_segment(p, false)) - } - - pub(crate) fn meta_list_item_to_string(&self, li: &ast::NestedMetaItem) -> String { - Self::to_string(|s| s.print_meta_list_item(li)) - } - - pub(crate) fn attribute_to_string(&self, attr: &ast::Attribute) -> String { - Self::to_string(|s| s.print_attribute(attr)) - } -} +mod expr;mod item;use crate::pp::Breaks::{Consistent,Inconsistent};use crate::// +pp::{self,Breaks};use crate::pprust::state::expr::FixupContext;use ast:://{();}; +TraitBoundModifiers;use rustc_ast::attr::AttrIdGenerator ;use rustc_ast::ptr::P; +use rustc_ast::token::{self, BinOpToken,CommentKind,Delimiter,Nonterminal,Token, +TokenKind};use rustc_ast::tokenstream::{Spacing,TokenStream,TokenTree};use//{;}; +rustc_ast::util::classify;use rustc_ast ::util::comments::{Comment,CommentStyle} +;use rustc_ast::util::parser;use rustc_ast::{self as ast,AttrArgs,AttrArgsEq,//; +BlockCheckMode,PatKind};use rustc_ast:: {attr,BindingAnnotation,ByRef,DelimArgs, +RangeEnd,RangeSyntax,Term};use rustc_ast::{GenericArg,GenericBound,SelfKind};//; +use rustc_ast::{InlineAsmOperand,InlineAsmRegOrRegClass};use rustc_ast::{//({}); +InlineAsmOptions,InlineAsmTemplatePiece};use rustc_span::edition::Edition;use//; +rustc_span::source_map::{SourceMap,Spanned};use rustc_span::symbol::{kw,sym,//3; +Ident,IdentPrinter,Symbol};use rustc_span::{BytePos,CharPos,FileName,Pos,Span,// +DUMMY_SP};use std::borrow::Cow;use thin_vec::ThinVec;pub enum MacHeader<'a>{//3; +Path(&'a ast::Path),Keyword(&'static str) ,}pub enum AnnNode<'a>{Ident(&'a Ident +),Name(&'a Symbol),Block(&'a ast::Block),Item(&'a ast::Item),SubItem(ast:://{;}; +NodeId),Expr(&'a ast::Expr),Pat(&'a ast::Pat),Crate(&'a ast::Crate),}pub trait// +PpAnn{fn pre(&self,_state:&mut State<'_>,_node:AnnNode<'_>){}fn post(&self,//(); +_state:&mut State<'_>,_node:AnnNode<'_>){}}struct NoAnn;impl PpAnn for NoAnn{}// +pub struct Comments<'a>{sm:&'a SourceMap,comments:Vec,current:usize,}// +fn all_whitespace(s:&str,col:CharPos)->Option{;let mut idx=0;for(i,ch)in +s.char_indices().take(col.to_usize()){if!ch.is_whitespace(){;return None;}idx=i+ +ch.len_utf8();3;}Some(idx)}fn trim_whitespace_prefix(s:&str,col:CharPos)->&str{; +let len=s.len();();match all_whitespace(s,col){Some(col)=>{if cols,}} fn split_block_comment_into_lines(text:&str,col:CharPos)-> +Vec{3;let mut res:Vec=vec![];;;let mut lines=text.lines();;;res. +extend(lines.next().map(|it|it.to_string()));((),());for line in lines{res.push( +trim_whitespace_prefix(line,col).to_string())}res}fn gather_comments(sm:&//({}); +SourceMap,path:FileName,src:String)->Vec{({});let sm=SourceMap::new(sm. +path_mapping().clone());;let source_file=sm.new_source_file(path,src);let text=( +*source_file.src.as_ref().unwrap()).clone();3;;let text:&str=text.as_str();;;let +start_bpos=source_file.start_pos;;;let mut pos=0;;let mut comments:Vec= +Vec::new();;;let mut code_to_the_left=false;if let Some(shebang_len)=rustc_lexer +::strip_shebang(text){;comments.push(Comment{style:CommentStyle::Isolated,lines: +vec![text[..shebang_len].to_string()],pos:start_bpos,});;;pos+=shebang_len;;}for +token in rustc_lexer::tokenize(&text[pos..]){({});let token_text=&text[pos..pos+ +token.len as usize];{;};match token.kind{rustc_lexer::TokenKind::Whitespace=>{if +let Some(mut idx)=token_text.find('\n'){;code_to_the_left=false;;while let Some( +next_newline)=&token_text[idx+1..].find('\n'){;idx+=1+next_newline;comments.push +(Comment{style:CommentStyle::BlankLine,lines:vec![ ],pos:start_bpos+BytePos((pos ++idx)as u32),});({});}}}rustc_lexer::TokenKind::BlockComment{doc_style,..}=>{if +doc_style.is_none(){;let code_to_the_right=!matches!(text[pos+token.len as usize +..].chars().next(),Some('\r'|'\n'));{();};({});let style=match(code_to_the_left, +code_to_the_right){(_,true)=>CommentStyle::Mixed,(false,false)=>CommentStyle::// +Isolated,(true,false)=>CommentStyle::Trailing,};();3;let pos_in_file=start_bpos+ +BytePos(pos as u32);({});({});let line_begin_in_file=source_file.line_begin_pos( +pos_in_file);;;let line_begin_pos=(line_begin_in_file-start_bpos).to_usize();let +col=CharPos(text[line_begin_pos..pos].chars().count());((),());*&*&();let lines= +split_block_comment_into_lines(token_text,col);({});comments.push(Comment{style, +lines,pos:pos_in_file})}}rustc_lexer::TokenKind::LineComment{doc_style}=>{if //; +doc_style.is_none(){comments.push(Comment{style:if code_to_the_left{//if true{}; +CommentStyle::Trailing}else{CommentStyle::Isolated},lines:vec![token_text.//{;}; +to_string()],pos:start_bpos+BytePos(pos as u32),})}}_=>{;code_to_the_left=true;} +}{;};pos+=token.len as usize;();}comments}impl<'a>Comments<'a>{pub fn new(sm:&'a +SourceMap,filename:FileName,input:String)->Comments<'a>{let _=||();let comments= +gather_comments(sm,filename,input);{;};Comments{sm,comments,current:0}}fn next(& +self)->Option{(((((((self.comments.get(self.current)))).cloned()))))}fn +trailing_comment(&self,span:rustc_span::Span ,next_pos:Option,)->Option +{if let Some(cmnt)=self.next(){if cmnt.style!=CommentStyle::Trailing{3; +return None;;}let span_line=self.sm.lookup_char_pos(span.hi());let comment_line= +self.sm.lookup_char_pos(cmnt.pos);;;let next=next_pos.unwrap_or_else(||cmnt.pos+ +BytePos(1));;if span.hi(){pub s:pp::Printer,comments: +Option>,ann:&'a(dyn PpAnn+'a),}const INDENT_UNIT:isize=((4));pub fn +print_crate<'a>(sm:&'a SourceMap,krate:&ast::Crate,filename:FileName,input://(); +String,ann:&'a dyn PpAnn,is_expanded:bool,edition:Edition,g:&AttrIdGenerator,)// +->String{();let mut s=State{s:pp::Printer::new(),comments:Some(Comments::new(sm, +filename,input)),ann};*&*&();if is_expanded&&!krate.attrs.iter().any(|attr|attr. +has_name(sym::no_core)){let _=();let fake_attr=attr::mk_attr_nested_word(g,ast:: +AttrStyle::Inner,sym::feature,sym::prelude_import,DUMMY_SP,);;s.print_attribute( +&fake_attr);;if edition.is_rust_2015(){;let fake_attr=attr::mk_attr_word(g,ast:: +AttrStyle::Inner,sym::no_std,DUMMY_SP);3;3;s.print_attribute(&fake_attr);3;}};s. +print_inner_attributes(&krate.attrs);;for item in&krate.items{s.print_item(item) +;;}s.print_remaining_comments();s.ann.post(&mut s,AnnNode::Crate(krate));s.s.eof +()}fn space_between(tt1:&TokenTree,tt2:&TokenTree)->bool{();use token::*;3;3;use +Delimiter::*;;;use TokenTree::Delimited as Del;;;use TokenTree::Token as Tok;;fn +is_punct(tt:&TokenTree)->bool{matches!(tt,TokenTree::Token(tok,_)if tok.//{();}; +is_punct())};match(tt1,tt2){(Tok(Token{kind:DocComment(CommentKind::Line,..),..} +,_),_)=>false,(Tok(Token{kind:Dot,..}, _),tt2)if!is_punct(tt2)=>false,(Tok(Token +{kind:Dollar,..},_),Tok(Token{kind:Ident(.. ),..},_))=>false,(tt1,Tok(Token{kind +:Comma|Semi|Dot,..},_))if!is_punct(tt1 )=>false,(Tok(Token{kind:Ident(sym,is_raw +),span},_),Tok(Token{kind:Not,..},_))if(!Ident::new(*sym,*span).is_reserved())|| +matches!(is_raw,IdentIsRaw::Yes)=>{false }(Tok(Token{kind:Ident(sym,is_raw),span +},_),Del(_,_,Parenthesis,_))if!Ident:: new(*sym,*span).is_reserved()||*sym==kw:: +Fn||((*sym)==kw::SelfUpper)||*sym ==kw::Pub||matches!(is_raw,IdentIsRaw::Yes)=>{ +false}(Tok(Token{kind:Pound,..},_),Del(_,_,Bracket,_))=>((false)),_=>(true),}}fn +binop_to_string(op:BinOpToken)->&'static str{match op{token::Plus=>("+"),token:: +Minus=>("-"),token::Star=>"*",token::Slash=>"/",token::Percent=>"%",token::Caret +=>("^"),token::And=>("&"),token::Or=>"|" ,token::Shl=>"<<",token::Shr=>">>",}}fn +doc_comment_to_string(comment_kind:CommentKind,attr_style:ast::AttrStyle,data:// +Symbol,)->String{match(((((comment_kind,attr_style))))){(CommentKind::Line,ast:: +AttrStyle::Outer)=>((format!("///{data}") )),(CommentKind::Line,ast::AttrStyle:: +Inner)=>format!("//!{data}"),( CommentKind::Block,ast::AttrStyle::Outer)=>format +!("/**{data}*/"),(CommentKind::Block,ast::AttrStyle::Inner)=>format!(//let _=(); +"/*!{data}*/"),}}fn literal_to_string(lit:token::Lit)->String{();let token::Lit{ +kind,symbol,suffix}=lit;{();};{();};let mut out=match kind{token::Byte=>format!( +"b'{symbol}'"),token::Char=>(((((format!("'{symbol}'")))))),token::Str=>format!( +"\"{symbol}\""),token::StrRaw(n) =>{format!("r{delim}\"{string}\"{delim}",delim= +"#".repeat(n as usize),string=symbol )}token::ByteStr=>format!("b\"{symbol}\""), +token::ByteStrRaw(n)=>{format !("br{delim}\"{string}\"{delim}",delim="#".repeat( +n as usize),string=symbol)}token ::CStr=>format!("c\"{symbol}\""),token::CStrRaw +(n)=>{((format!("cr{delim}\"{symbol}\"{delim}",delim= "#".repeat(n as usize))))} +token::Integer|token::Float|token::Bool|token::Err(_)=>symbol.to_string(),};3;if +let Some(suffix)=suffix{(out.push_str(suffix.as_str()))}out}impl std::ops::Deref +for State<'_>{type Target=pp::Printer;fn deref(&self)->&Self::Target{(&self.s)}} +impl std::ops::DerefMut for State<'_>{fn deref_mut(&mut self)->&mut Self:://{;}; +Target{&mut self.s}}pub trait PrintState<'a>:std::ops::Deref+std::ops::DerefMut{fn comments(&mut self)->&mut Option>;fn//({}); +ann_post(&mut self,ident:Ident);fn print_generic_args(&mut self,args:&ast:://(); +GenericArgs,colons_before_params:bool);fn print_ident(&mut self,ident:Ident){(); +self.word(IdentPrinter::for_ast_ident(ident,ident.is_raw_guess()).to_string());; +self.ann_post(ident)}fn strsep(&mut self,sep:&'static str,space_before://3; +bool,b:Breaks,elts:&[T],mut op:F,)where F:FnMut(&mut Self,&T),{;self.rbox(0,b);; +if let Some((first,rest))=elts.split_first(){;op(self,first);;for elt in rest{if +space_before{;self.space();;};self.word_space(sep);op(self,elt);}}self.end();}fn +commasep(&mut self,b:Breaks,elts:&[T],op:F)where F:FnMut(&mut Self,&T),{//; +self.strsep((","),false,b,elts,op)}fn maybe_print_comment(&mut self,pos:BytePos) +->bool{3;let mut has_comment=false;;while let Some(cmnt)=self.next_comment(){if +cmnt.pos{if!self.is_beginning_of_line(){3;self.zerobreak();;}if let +Some((last,lines))=cmnt.lines.split_last(){;self.ibox(0);for line in lines{self. +word(line.clone());;self.hardbreak()};self.word(last.clone());self.space();self. +end();;}self.zerobreak()}CommentStyle::Isolated=>{;self.hardbreak_if_not_bol();; +for line in&cmnt.lines{if!line.is_empty(){();self.word(line.clone());();}3;self. +hardbreak();;}}CommentStyle::Trailing=>{if!self.is_beginning_of_line(){self.word +(" ");;}if cmnt.lines.len()==1{self.word(cmnt.lines[0].clone());self.hardbreak() +}else{;self.visual_align();;for line in&cmnt.lines{if!line.is_empty(){self.word( +line.clone());;};self.hardbreak();;};self.end();;}}CommentStyle::BlankLine=>{let +twice=match self.last_token(){Some(pp::Token:: String(s))=>";"==s,Some(pp::Token +::Begin(_))=>true,Some(pp::Token::End)=>true,_=>false,};;if twice{self.hardbreak +();;}self.hardbreak();}}if let Some(cmnts)=self.comments(){cmnts.current+=1;}}fn +next_comment(&mut self)->Option{(self.comments().as_mut()).and_then(|c| +c.next())}fn maybe_print_trailing_comment(&mut self,span:rustc_span::Span,//{;}; +next_pos:Option){if let Some(cmnts)= self.comments(){if let Some(cmnt)= +cmnts.trailing_comment(span,next_pos){{();};self.print_comment(&cmnt);({});}}}fn +print_remaining_comments(&mut self){if self.next_comment().is_none(){{();};self. +hardbreak();;}while let Some(cmnt)=self.next_comment(){self.print_comment(&cmnt) +}}fn print_string(&mut self,st:&str,style:ast::StrStyle){;let st=match style{ast +::StrStyle::Cooked=>format!("\"{}\"",st.escape_debug ()),ast::StrStyle::Raw(n)=> +{format!("r{delim}\"{string}\"{delim}",delim="#".repeat( n as usize),string=st)} +};3;self.word(st)}fn print_inner_attributes(&mut self,attrs:&[ast::Attribute])-> +bool{(self.print_either_attributes(attrs,ast::AttrStyle::Inner,(false),true))}fn +print_outer_attributes(&mut self,attrs:&[ast::Attribute])->bool{self.//let _=(); +print_either_attributes(attrs,ast::AttrStyle::Outer,((((false)))),(((true))))}fn +print_either_attributes(&mut self,attrs:&[ast::Attribute],kind:ast::AttrStyle,// +is_inline:bool,trailing_hardbreak:bool,)->bool{3;let mut printed=false;;for attr +in attrs{if attr.style==kind{();self.print_attribute_inline(attr,is_inline);3;if +is_inline{();self.nbsp();3;}3;printed=true;3;}}if printed&&trailing_hardbreak&&! +is_inline{3;self.hardbreak_if_not_bol();;}printed}fn print_attribute_inline(&mut +self,attr:&ast::Attribute,is_inline:bool){if!is_inline{if true{};if true{};self. +hardbreak_if_not_bol();3;};self.maybe_print_comment(attr.span.lo());;match&attr. +kind{ast::AttrKind::Normal(normal)=>{match attr.style{ast::AttrStyle::Inner=>//; +self.word("#!["),ast::AttrStyle::Outer=>self.word("#["),};self.print_attr_item(& +normal.item,attr.span);;;self.word("]");}ast::AttrKind::DocComment(comment_kind, +data)=>{;self.word(doc_comment_to_string(*comment_kind,attr.style,*data));;self. +hardbreak()}}}fn print_attr_item(&mut self,item:&ast::AttrItem,span:Span){;self. +ibox(0);3;match&item.args{AttrArgs::Delimited(DelimArgs{dspan:_,delim,tokens})=> +self.print_mac_common((Some((MacHeader::Path((&item.path))))),false,None,*delim, +tokens,true,span,),AttrArgs::Empty=>{();self.print_path(&item.path,false,0);();} +AttrArgs::Eq(_,AttrArgsEq::Ast(expr))=>{3;self.print_path(&item.path,false,0);;; +self.space();;self.word_space("=");let token_str=self.expr_to_string(expr);self. +word(token_str);;}AttrArgs::Eq(_,AttrArgsEq::Hir(lit))=>{;self.print_path(&item. +path,false,0);();3;self.space();3;3;self.word_space("=");3;3;let token_str=self. +meta_item_lit_to_string(lit);;;self.word(token_str);;}}self.end();}fn print_tt(& +mut self,tt:&TokenTree,convert_dollar_crate: bool)->Spacing{match tt{TokenTree:: +Token(token,spacing)=>{loop{break};let token_str=self.token_to_string_ext(token, +convert_dollar_crate);;;self.word(token_str);if let token::DocComment(..)=token. +kind{self.hardbreak()}*spacing}TokenTree::Delimited(dspan,spacing,delim,tts)=>{; +self.print_mac_common(None,(false),None,(*delim),tts,convert_dollar_crate,dspan. +entire(),);loop{break;};spacing.close}}}fn print_tts(&mut self,tts:&TokenStream, +convert_dollar_crate:bool){;let mut iter=tts.trees().peekable();;while let Some( +tt)=iter.next(){;let spacing=self.print_tt(tt,convert_dollar_crate);if let Some( +next)=iter.peek(){if spacing==Spacing::Alone&&space_between(tt,next){;self.space +();;}}}}fn print_mac_common(&mut self,header:Option>,has_bang:bool +,ident:Option,delim: Delimiter,tts:&TokenStream,convert_dollar_crate:bool +,span:Span,){if delim==Delimiter::Brace{3;self.cbox(INDENT_UNIT);;}match header{ +Some(MacHeader::Path(path))=>(self.print_path( path,(false),0)),Some(MacHeader:: +Keyword(kw))=>self.word(kw),None=>{}}if has_bang{3;self.word("!");;}if let Some( +ident)=ident{;self.nbsp();;self.print_ident(ident);}match delim{Delimiter::Brace +=>{if header.is_some()||has_bang||ident.is_some(){;self.nbsp();;}self.word("{"); +if!tts.is_empty(){{;};self.space();();}();self.ibox(0);();();self.print_tts(tts, +convert_dollar_crate);;;self.end();;;let empty=tts.is_empty();;self.bclose(span, +empty);;}delim=>{let token_str=self.token_kind_to_string(&token::OpenDelim(delim +));;;self.word(token_str);self.ibox(0);self.print_tts(tts,convert_dollar_crate); +self.end();;;let token_str=self.token_kind_to_string(&token::CloseDelim(delim)); +self.word(token_str);{;};}}}fn print_mac_def(&mut self,macro_def:&ast::MacroDef, +ident:&Ident,sp:Span,print_visibility:impl FnOnce(&mut Self),){;let(kw,has_bang) +=if macro_def.macro_rules{("macro_rules",true)}else{3;print_visibility(self);3;( +"macro",false)};3;3;self.print_mac_common(Some(MacHeader::Keyword(kw)),has_bang, +Some(*ident),macro_def.body.delim,¯o_def.body.tokens.clone(),true,sp,);3;if +macro_def.body.need_semicolon(){;self.word(";");}}fn print_path(&mut self,path:& +ast::Path,colons_before_params:bool,depth:usize){;self.maybe_print_comment(path. +span.lo());3;for(i,segment)in path.segments[..path.segments.len()-depth].iter(). +enumerate(){if i>0{self.word("::")}loop{break;};self.print_path_segment(segment, +colons_before_params);if true{};}}fn print_path_segment(&mut self,segment:&ast:: +PathSegment,colons_before_params:bool){if segment.ident.name!=kw::PathRoot{;self +.print_ident(segment.ident);((),());if let Some(args)=&segment.args{*&*&();self. +print_generic_args(args,colons_before_params);;}}}fn head>>(&mut self,w:S){;let w=w.into();;;self.cbox(INDENT_UNIT);;;self.ibox(0);if!w. +is_empty(){;self.word_nbsp(w);;}}fn bopen(&mut self){self.word("{");self.end();} +fn bclose_maybe_open(&mut self,span: rustc_span::Span,empty:bool,close_box:bool) +{;let has_comment=self.maybe_print_comment(span.hi());if!empty||has_comment{self +.break_offset_if_not_bol(1,-INDENT_UNIT);;}self.word("}");if close_box{self.end( +);;}}fn bclose(&mut self,span:rustc_span::Span,empty:bool){;let close_box=true;; +self.bclose_maybe_open(span,empty,close_box)}fn break_offset_if_not_bol(&mut//3; +self,n:usize,off:isize){if!self .is_beginning_of_line(){self.break_offset(n,off) +}else if (off!=(0)){if let Some(last_token)=self.last_token_still_buffered(){if +last_token.is_hardbreak_tok(){*&*&();self.replace_last_token_still_buffered(pp:: +Printer::hardbreak_tok_offset(off));({});}}}}fn nonterminal_to_string(&self,nt:& +Nonterminal)->String{match nt{token::NtExpr(e)=>(self.expr_to_string(e)),token:: +NtMeta(e)=>(self.attr_item_to_string(e)),token::NtTy(e)=>(self.ty_to_string(e)), +token::NtPath(e)=>self.path_to_string(e) ,token::NtItem(e)=>self.item_to_string( +e),token::NtBlock(e)=>(((((self.block_to_string (e)))))),token::NtStmt(e)=>self. +stmt_to_string(e),token::NtPat(e)=>(( self.pat_to_string(e))),&token::NtIdent(e, +is_raw)=>((IdentPrinter::for_ast_ident(e,(is_raw. into()))).to_string()),token:: +NtLifetime(e)=>(e.to_string()),token::NtLiteral(e)=>self.expr_to_string(e),token +::NtVis(e)=>((((self.vis_to_string(e) )))),}}fn token_kind_to_string(&self,tok:& +TokenKind)->Cow<'static,str>{(((( self.token_kind_to_string_ext(tok,None)))))}fn +token_kind_to_string_ext(&self,tok:& TokenKind,convert_dollar_crate:Option +,)->Cow<'static,str>{match(*tok){token::Eq=>( "=".into()),token::Lt=>"<".into(), +token::Le=>("<=".into()),token::EqEq=>"==".into(),token::Ne=>"!=".into(),token:: +Ge=>">=".into(),token::Gt=>">".into() ,token::Not=>"!".into(),token::Tilde=>"~". +into(),token::OrOr=>("||".into()),token:: AndAnd=>"&&".into(),token::BinOp(op)=> +binop_to_string(op).into(),token::BinOpEq (op)=>format!("{}=",binop_to_string(op +)).into(),token::At=>"@".into(), token::Dot=>".".into(),token::DotDot=>"..".into +(),token::DotDotDot=>("...".into()),token::DotDotEq=>"..=".into(),token::Comma=> +",".into(),token::Semi=>";".into(), token::Colon=>":".into(),token::ModSep=>"::" +.into(),token::RArrow=>"->".into(), token::LArrow=>"<-".into(),token::FatArrow=> +"=>".into(),token::OpenDelim(Delimiter::Parenthesis)=>(((("(")).into())),token:: +CloseDelim(Delimiter::Parenthesis)=>((")") .into()),token::OpenDelim(Delimiter:: +Bracket)=>("[".into()),token::CloseDelim(Delimiter::Bracket)=>"]".into(),token:: +OpenDelim(Delimiter::Brace)=>("{".into( )),token::CloseDelim(Delimiter::Brace)=> +"}".into(),token::OpenDelim (Delimiter::Invisible)|token::CloseDelim(Delimiter:: +Invisible)=>{"".into()}token::Pound=>"#" .into(),token::Dollar=>"$".into(),token +::Question=>(("?").into()),token::SingleQuote=> "'".into(),token::Literal(lit)=> +literal_to_string(lit).into(),token::Ident(s,is_raw)=>{IdentPrinter::new(s,//(); +is_raw.into(),convert_dollar_crate).to_string().into()}token::Lifetime(s)=>s.//; +to_string().into(),token::DocComment(comment_kind,attr_style,data)=>{//let _=(); +doc_comment_to_string(comment_kind,attr_style,data).into( )}token::Eof=>"". +into(),token::Interpolated(ref nt)=>self. nonterminal_to_string(&nt.0).into(),}} +fn token_to_string(&self,token:&Token)->Cow<'static,str>{self.//((),());((),()); +token_to_string_ext(token,((false)))}fn token_to_string_ext(&self,token:&Token, +convert_dollar_crate:bool)->Cow<'static,str>{if true{};let convert_dollar_crate= +convert_dollar_crate.then_some(token.span);;self.token_kind_to_string_ext(&token +.kind,convert_dollar_crate)}fn ty_to_string(&self,ty:&ast::Ty)->String{Self:://; +to_string((|s|s.print_type(ty)))} fn pat_to_string(&self,pat:&ast::Pat)->String{ +Self::to_string((|s|(s.print_pat(pat))))}fn expr_to_string(&self,e:&ast::Expr)-> +String{((Self::to_string((|s|(s.print_expr( e,(FixupContext::default())))))))}fn +meta_item_lit_to_string(&self,lit:&ast::MetaItemLit )->String{Self::to_string(|s +|(s.print_meta_item_lit(lit)))}fn stmt_to_string(&self,stmt:&ast::Stmt)->String{ +Self::to_string((|s|s.print_stmt(stmt)))}fn item_to_string(&self,i:&ast::Item)-> +String{Self::to_string(|s|s.print_item(i) )}fn path_to_string(&self,p:&ast::Path +)->String{Self::to_string(|s|s.print_path(p, false,0))}fn vis_to_string(&self,v: +&ast::Visibility)->String{((Self::to_string(((|s|(s.print_visibility(v)))))))}fn +block_to_string(&self,blk:&ast::Block)->String{Self::to_string(|s|{{();};s.cbox( +INDENT_UNIT);;;s.ibox(0);;s.print_block(blk)})}fn attr_item_to_string(&self,ai:& +ast::AttrItem)->String{(Self::to_string(|s|s.print_attr_item(ai,ai.path.span)))} +fn to_string(f:impl FnOnce(&mut State<'_>))->String{;let mut printer=State::new( +);();3;f(&mut printer);3;printer.s.eof()}}impl<'a>PrintState<'a>for State<'a>{fn +comments(&mut self)->&mut Option>{&mut self.comments}fn ann_post(& +mut self,ident:Ident){{();};self.ann.post(self,AnnNode::Ident(&ident));{();};}fn +print_generic_args(&mut self,args: &ast::GenericArgs,colons_before_params:bool){ +if colons_before_params{(((self.word((("::" ))))))}match args{ast::GenericArgs:: +AngleBracketed(data)=>{;self.word("<");self.commasep(Inconsistent,&data.args,|s, +arg|match arg{ast::AngleBracketedArg::Arg(a)=>(((s.print_generic_arg(a)))),ast:: +AngleBracketedArg::Constraint(c)=>s.print_assoc_constraint(c),});;self.word(">") +}ast::GenericArgs::Parenthesized(data)=>{{;};self.word("(");();();self.commasep( +Inconsistent,&data.inputs,|s,ty|s.print_type(ty));();();self.word(")");3;3;self. +print_fn_ret_ty(&data.output);{;};}}}}impl<'a>State<'a>{pub fn new()->State<'a>{ +State{s:(pp::Printer::new()),comments:None,ann:&NoAnn}}fn commasep_cmnt(& +mut self,b:Breaks,elts:&[T],mut op: F,mut get_span:G)where F:FnMut(&mut State<'_ +>,&T),G:FnMut(&T)->rustc_span::Span,{;self.rbox(0,b);;let len=elts.len();let mut +i=0;;for elt in elts{self.maybe_print_comment(get_span(elt).hi());op(self,elt);i ++=1;;if i]){self.commasep_cmnt(b,// +exprs,((|s,e|((s.print_expr(e,(FixupContext::default())))))),(|e|e.span))}pub fn +print_opt_lifetime(&mut self,lifetime:&Option){if let Some(lt)=* +lifetime{;self.print_lifetime(lt);;self.nbsp();}}pub fn print_assoc_constraint(& +mut self,constraint:&ast::AssocConstraint){;self.print_ident(constraint.ident);; +if let Some(args)=((constraint.gen_args.as_ref())){self.print_generic_args(args, +false)}3;self.space();;match&constraint.kind{ast::AssocConstraintKind::Equality{ +term}=>{;self.word_space("=");;match term{Term::Ty(ty)=>self.print_type(ty),Term +::Const(c)=>self.print_expr_anon_const(c,& []),}}ast::AssocConstraintKind::Bound +{bounds}=>{if!bounds.is_empty(){3;self.word_nbsp(":");3;;self.print_type_bounds( +bounds);();}}}}pub fn print_generic_arg(&mut self,generic_arg:&GenericArg){match +generic_arg{GenericArg::Lifetime(lt)=>self. print_lifetime(*lt),GenericArg::Type +(ty)=>(self.print_type(ty)),GenericArg::Const (ct)=>self.print_expr((&ct.value), +FixupContext::default()),}}pub fn print_type(&mut self,ty:&ast::Ty){*&*&();self. +maybe_print_comment(ty.span.lo());;self.ibox(0);match&ty.kind{ast::TyKind::Slice +(ty)=>{;self.word("[");;self.print_type(ty);self.word("]");}ast::TyKind::Ptr(mt) +=>{;self.word("*");self.print_mt(mt,true);}ast::TyKind::Ref(lifetime,mt)=>{self. +word("&");3;;self.print_opt_lifetime(lifetime);;;self.print_mt(mt,false);;}ast:: +TyKind::Never=>{;self.word("!");;}ast::TyKind::Tup(elts)=>{;self.popen();;;self. +commasep(Inconsistent,elts,|s,ty|s.print_type(ty));;if elts.len()==1{;self.word( +",");;};self.pclose();;}ast::TyKind::AnonStruct(_,fields)=>{self.head("struct"); +self.print_record_struct_body(fields,ty.span);;}ast::TyKind::AnonUnion(_,fields) +=>{3;self.head("union");3;;self.print_record_struct_body(fields,ty.span);;}ast:: +TyKind::Paren(typ)=>{;self.popen();;;self.print_type(typ);;;self.pclose();}ast:: +TyKind::BareFn(f)=>{if true{};self.print_ty_fn(f.ext,f.unsafety,&f.decl,None,&f. +generic_params);;}ast::TyKind::Path(None,path)=>{self.print_path(path,false,0);} +ast::TyKind::Path(Some(qself),path)=>( self.print_qpath(path,qself,false)),ast:: +TyKind::TraitObject(bounds,syntax)=>{if*syntax==ast::TraitObjectSyntax::Dyn{{;}; +self.word_nbsp("dyn");;}self.print_type_bounds(bounds);}ast::TyKind::ImplTrait(_ +,bounds)=>{;self.word_nbsp("impl");self.print_type_bounds(bounds);}ast::TyKind:: +Array(ty,length)=>{;self.word("[");;;self.print_type(ty);;;self.word("; ");self. +print_expr(&length.value,FixupContext::default());;self.word("]");}ast::TyKind:: +Typeof(e)=>{;self.word("typeof(");self.print_expr(&e.value,FixupContext::default +());;self.word(")");}ast::TyKind::Infer=>{self.word("_");}ast::TyKind::Err(_)=>{ +self.popen();;;self.word("/*ERROR*/");;self.pclose();}ast::TyKind::Dummy=>{self. +popen();;self.word("/*DUMMY*/");self.pclose();}ast::TyKind::ImplicitSelf=>{self. +word("Self");();}ast::TyKind::MacCall(m)=>{();self.print_mac(m);3;}ast::TyKind:: +CVarArgs=>{;self.word("...");}}self.end();}fn print_trait_ref(&mut self,t:&ast:: +TraitRef){(self.print_path(&t.path,false,0))}fn print_formal_generic_params(&mut +self,generic_params:&[ast::GenericParam]){if!generic_params.is_empty(){{;};self. +word("for");3;3;self.print_generic_params(generic_params);3;3;self.nbsp();3;}}fn +print_poly_trait_ref(&mut self,t:&ast::PolyTraitRef){let _=||();let _=||();self. +print_formal_generic_params(&t.bound_generic_params);();self.print_trait_ref(&t. +trait_ref)}fn print_stmt(&mut self,st:&ast::Stmt){3;self.maybe_print_comment(st. +span.lo());;match&st.kind{ast::StmtKind::Let(loc)=>{self.print_outer_attributes( +&loc.attrs);;self.space_if_not_bol();self.ibox(INDENT_UNIT);self.word_nbsp("let" +);;;self.ibox(INDENT_UNIT);;;self.print_local_decl(loc);self.end();if let Some(( +init,els))=loc.kind.init_else_opt(){3;self.nbsp();;;self.word_space("=");;;self. +print_expr(init,FixupContext::default());{;};if let Some(els)=els{{;};self.cbox( +INDENT_UNIT);;self.ibox(INDENT_UNIT);self.word(" else ");self.print_block(els);} +};self.word(";");;;self.end();}ast::StmtKind::Item(item)=>self.print_item(item), +ast::StmtKind::Expr(expr)=>{((),());self.space_if_not_bol();((),());*&*&();self. +print_expr_outer_attr_style(expr,(false),FixupContext{stmt:true,..FixupContext:: +default()},);;if classify::expr_requires_semi_to_be_stmt(expr){self.word(";");}} +ast::StmtKind::Semi(expr)=>{((),());self.space_if_not_bol();((),());*&*&();self. +print_expr_outer_attr_style(expr,(false),FixupContext{stmt:true,..FixupContext:: +default()},);;;self.word(";");;}ast::StmtKind::Empty=>{;self.space_if_not_bol(); +self.word(";");3;}ast::StmtKind::MacCall(mac)=>{;self.space_if_not_bol();;;self. +print_outer_attributes(&mac.attrs);;self.print_mac(&mac.mac);if mac.style==ast:: +MacStmtStyle::Semicolon{;self.word(";");}}}self.maybe_print_trailing_comment(st. +span,None)}fn print_block(&mut self,blk:&ast::Block){self.//if true{};if true{}; +print_block_with_attrs(blk,(&[]))}fn print_block_unclosed_indent(&mut self,blk:& +ast::Block){(((self.print_block_maybe_unclosed(blk,(( &(([])))),((false))))))}fn +print_block_with_attrs(&mut self,blk:&ast::Block ,attrs:&[ast::Attribute]){self. +print_block_maybe_unclosed(blk,attrs,(true) )}fn print_block_maybe_unclosed(&mut +self,blk:&ast::Block,attrs:&[ast::Attribute],close_box:bool,){match blk.rules{// +BlockCheckMode::Unsafe(..)=>self.word_space ("unsafe"),BlockCheckMode::Default=> +(),};self.maybe_print_comment(blk.span.lo());;;self.ann.pre(self,AnnNode::Block( +blk));;self.bopen();let has_attrs=self.print_inner_attributes(attrs);for(i,st)in +(blk.stmts.iter().enumerate()){match&st.kind{ast::StmtKind::Expr(expr)if i==blk. +stmts.len()-1=>{;self.maybe_print_comment(st.span.lo());self.space_if_not_bol(); +self.print_expr_outer_attr_style(expr,(((false))), FixupContext{stmt:((true)),.. +FixupContext::default()},);;self.maybe_print_trailing_comment(expr.span,Some(blk +.span.hi()));;}_=>self.print_stmt(st),}}let empty=!has_attrs&&blk.stmts.is_empty +();;;self.bclose_maybe_open(blk.span,empty,close_box);self.ann.post(self,AnnNode +::Block(blk))}fn print_let(&mut self,pat:&ast::Pat,expr:&ast::Expr,fixup://({}); +FixupContext){3;self.word("let ");3;3;self.print_pat(pat);;;self.space();;;self. +word_space("=");loop{break;};loop{break;};self.print_expr_cond_paren(expr,fixup. +parenthesize_exterior_struct_lit&&(parser::contains_exterior_struct_lit(expr))|| +parser::needs_par_as_let_scrutinee(((expr.precedence()).order())),FixupContext:: +default(),);;}fn print_mac(&mut self,m:&ast::MacCall){self.print_mac_common(Some +(MacHeader::Path(&m.path)),true,None,m. args.delim,&m.args.tokens.clone(),true,m +.span(),);;}fn print_inline_asm(&mut self,asm:&ast::InlineAsm){;enum AsmArg<'a>{ +Template(String),Operand(&'a InlineAsmOperand),ClobberAbi(Symbol),Options(//{;}; +InlineAsmOptions),};;let mut args=vec![AsmArg::Template(InlineAsmTemplatePiece:: +to_string(&asm.template))];;;args.extend(asm.operands.iter().map(|(o,_)|AsmArg:: +Operand(o)));;for(abi,_)in&asm.clobber_abis{args.push(AsmArg::ClobberAbi(*abi)); +}if!asm.options.is_empty(){;args.push(AsmArg::Options(asm.options));}self.popen( +);;self.commasep(Consistent,&args,|s,arg|match arg{AsmArg::Template(template)=>s +.print_string(template,ast::StrStyle::Cooked),AsmArg::Operand(op)=>{let _=();let +print_reg_or_class=|s:&mut Self,r:&InlineAsmRegOrRegClass|match r{//loop{break}; +InlineAsmRegOrRegClass::Reg(r)=>((s.print_symbol( (*r),ast::StrStyle::Cooked))), +InlineAsmRegOrRegClass::RegClass(r)=>s.word(r.to_string()),};if true{};match op{ +InlineAsmOperand::In{reg,expr}=>{;s.word("in");;;s.popen();print_reg_or_class(s, +reg);3;3;s.pclose();3;;s.space();;;s.print_expr(expr,FixupContext::default());;} +InlineAsmOperand::Out{reg,late,expr}=>{;s.word(if*late{"lateout"}else{"out"});s. +popen();;print_reg_or_class(s,reg);s.pclose();s.space();match expr{Some(expr)=>s +.print_expr(expr,(FixupContext::default())),None=>s.word("_"),}}InlineAsmOperand +::InOut{reg,late,expr}=>{;s.word(if*late{"inlateout"}else{"inout"});;;s.popen(); +print_reg_or_class(s,reg);;s.pclose();s.space();s.print_expr(expr,FixupContext:: +default());;}InlineAsmOperand::SplitInOut{reg,late,in_expr,out_expr}=>{s.word(if +*late{"inlateout"}else{"inout"});;s.popen();print_reg_or_class(s,reg);s.pclose() +;;s.space();s.print_expr(in_expr,FixupContext::default());s.space();s.word_space +("=>");{();};match out_expr{Some(out_expr)=>s.print_expr(out_expr,FixupContext:: +default()),None=>s.word("_"),}}InlineAsmOperand::Const{anon_const}=>{{;};s.word( +"const");;;s.space();;;s.print_expr(&anon_const.value,FixupContext::default());} +InlineAsmOperand::Sym{sym}=>{;s.word("sym");;;s.space();if let Some(qself)=&sym. +qself{;s.print_qpath(&sym.path,qself,true);}else{s.print_path(&sym.path,true,0); +}}InlineAsmOperand::Label{block}=>{3;s.head("label");;;s.print_block(block);;}}} +AsmArg::ClobberAbi(abi)=>{;s.word("clobber_abi");;s.popen();s.print_symbol(*abi, +ast::StrStyle::Cooked);;s.pclose();}AsmArg::Options(opts)=>{s.word("options");s. +popen();;let mut options=vec![];if opts.contains(InlineAsmOptions::PURE){options +.push("pure");;}if opts.contains(InlineAsmOptions::NOMEM){options.push("nomem"); +}if opts.contains(InlineAsmOptions::READONLY){;options.push("readonly");}if opts +.contains(InlineAsmOptions::PRESERVES_FLAGS){;options.push("preserves_flags");;} +if opts.contains(InlineAsmOptions::NORETURN){;options.push("noreturn");}if opts. +contains(InlineAsmOptions::NOSTACK){;options.push("nostack");;}if opts.contains( +InlineAsmOptions::ATT_SYNTAX){();options.push("att_syntax");3;}if opts.contains( +InlineAsmOptions::RAW){;options.push("raw");}if opts.contains(InlineAsmOptions:: +MAY_UNWIND){;options.push("may_unwind");;};s.commasep(Inconsistent,&options,|s,& +opt|{;s.word(opt);});s.pclose();}});self.pclose();}fn print_local_decl(&mut self +,loc:&ast::Local){();self.print_pat(&loc.pat);();if let Some(ty)=&loc.ty{3;self. +word_space(":");;self.print_type(ty);}}fn print_name(&mut self,name:Symbol){self +.word(name.to_string());;self.ann.post(self,AnnNode::Name(&name))}fn print_qpath +(&mut self,path:&ast::Path,qself:&ast::QSelf,colons_before_params:bool){();self. +word("<");;;self.print_type(&qself.ty);;if qself.position>0{;self.space();;self. +word_space("as");;;let depth=path.segments.len()-qself.position;self.print_path( +path,false,depth);3;}3;self.word(">");3;for item_segment in&path.segments[qself. +position..]{;self.word("::");;;self.print_ident(item_segment.ident);if let Some( +args)=(&item_segment.args){self.print_generic_args(args,colons_before_params)}}} +fn print_pat(&mut self,pat:&ast::Pat){;self.maybe_print_comment(pat.span.lo());; +self.ann.pre(self,AnnNode::Pat(pat));();match&pat.kind{PatKind::Wild=>self.word( +"_"),PatKind::Never=>(self.word(("!"))),PatKind::Ident(BindingAnnotation(by_ref, +mutbl),ident,sub)=>{if mutbl.is_mut(){;self.word_nbsp("mut");}if let ByRef::Yes( +rmutbl)=by_ref{;self.word_nbsp("ref");if rmutbl.is_mut(){self.word_nbsp("mut");} +};self.print_ident(*ident);if let Some(p)=sub{self.space();self.word_space("@"); +self.print_pat(p);;}}PatKind::TupleStruct(qself,path,elts)=>{if let Some(qself)= +qself{;self.print_qpath(path,qself,true);;}else{;self.print_path(path,true,0);;} +self.popen();;self.commasep(Inconsistent,elts,|s,p|s.print_pat(p));self.pclose() +;;}PatKind::Or(pats)=>{self.strsep("|",true,Inconsistent,pats,|s,p|s.print_pat(p +));;}PatKind::Path(None,path)=>{self.print_path(path,true,0);}PatKind::Path(Some +(qself),path)=>{;self.print_qpath(path,qself,false);}PatKind::Struct(qself,path, +fields,etc)=>{if let Some(qself)=qself{;self.print_qpath(path,qself,true);}else{ +self.print_path(path,true,0);;};self.nbsp();;;self.word("{");;;let empty=fields. +is_empty()&&*etc==ast::PatFieldsRest::None;();if!empty{3;self.space();3;}3;self. +commasep_cmnt(Consistent,fields,|s,f|{;s.cbox(INDENT_UNIT);;if!f.is_shorthand{s. +print_ident(f.ident);;;s.word_nbsp(":");}s.print_pat(&f.pat);s.end();},|f|f.pat. +span,);3;if*etc==ast::PatFieldsRest::Rest{if!fields.is_empty(){;self.word_space( +",");;};self.word("..");;}if!empty{self.space();}self.word("}");}PatKind::Tuple( +elts)=>{;self.popen();;;self.commasep(Inconsistent,elts,|s,p|s.print_pat(p));if +elts.len()==1{;self.word(",");;};self.pclose();}PatKind::Box(inner)=>{self.word( +"box ");;self.print_pat(inner);}PatKind::Deref(inner)=>{self.word("deref!");self +.popen();;self.print_pat(inner);self.pclose();}PatKind::Ref(inner,mutbl)=>{self. +word("&");3;if mutbl.is_mut(){3;self.word("mut ");3;}if let PatKind::Ident(ast:: +BindingAnnotation::MUT,..)=inner.kind{;self.popen();;self.print_pat(inner);self. +pclose();3;}else{3;self.print_pat(inner);3;}}PatKind::Lit(e)=>self.print_expr(e, +FixupContext::default()),PatKind::Range(begin ,end,Spanned{node:end_kind,..})=>{ +if let Some(e)=begin{;self.print_expr(e,FixupContext::default());}match end_kind +{RangeEnd::Included(RangeSyntax::DotDotDot)=>((self.word((("..."))))),RangeEnd:: +Included(RangeSyntax::DotDotEq)=>self.word( "..="),RangeEnd::Excluded=>self.word +(".."),}if let Some(e)=end{;self.print_expr(e,FixupContext::default());}}PatKind +::Slice(elts)=>{;self.word("[");self.commasep(Inconsistent,elts,|s,p|s.print_pat +(p));;;self.word("]");;}PatKind::Rest=>self.word(".."),PatKind::Paren(inner)=>{; +self.popen();;;self.print_pat(inner);;;self.pclose();}PatKind::MacCall(m)=>self. +print_mac(m),PatKind::Err(_)=>{;self.popen();self.word("/*ERROR*/");self.pclose( +);({});}}self.ann.post(self,AnnNode::Pat(pat))}fn print_explicit_self(&mut self, +explicit_self:&ast::ExplicitSelf){match& explicit_self.node{SelfKind::Value(m)=> +{3;self.print_mutability(*m,false);;self.word("self")}SelfKind::Region(lt,m)=>{; +self.word("&");;self.print_opt_lifetime(lt);self.print_mutability(*m,false);self +.word("self")}SelfKind::Explicit(typ,m)=>{;self.print_mutability(*m,false);self. +word("self");*&*&();*&*&();self.word_space(":");*&*&();self.print_type(typ)}}}fn +print_coroutine_kind(&mut self,coroutine_kind:ast::CoroutineKind){match//*&*&(); +coroutine_kind{ast::CoroutineKind::Gen{..}=>{{;};self.word_nbsp("gen");();}ast:: +CoroutineKind::Async{..}=>{{;};self.word_nbsp("async");{;};}ast::CoroutineKind:: +AsyncGen{..}=>{();self.word_nbsp("async");();3;self.word_nbsp("gen");3;}}}pub fn +print_type_bounds(&mut self,bounds:&[ast::GenericBound]){;let mut first=true;for +bound in bounds{if first{;first=false;;}else{;self.nbsp();self.word_space("+");} +match bound{GenericBound::Trait(tref,TraitBoundModifiers{constness,asyncness,//; +polarity},)=>{match constness{ ast::BoundConstness::Never=>{}ast::BoundConstness +::Always(_)|ast::BoundConstness::Maybe(_)=>{;self.word_space(constness.as_str()) +;;}}match asyncness{ast::BoundAsyncness::Normal=>{}ast::BoundAsyncness::Async(_) +=>{3;self.word_space(asyncness.as_str());3;}}match polarity{ast::BoundPolarity:: +Positive=>{}ast::BoundPolarity::Negative(_)|ast::BoundPolarity::Maybe(_)=>{;self +.word(polarity.as_str());3;}}3;self.print_poly_trait_ref(tref);3;}GenericBound:: +Outlives(lt)=>self.print_lifetime(*lt) ,}}}fn print_lifetime(&mut self,lifetime: +ast::Lifetime){(self.print_name(lifetime.ident.name))}fn print_lifetime_bounds(& +mut self,bounds:&ast::GenericBounds){for(i,bound)in (bounds.iter().enumerate()){ +if i!=0{3;self.word(" + ");3;}match bound{ast::GenericBound::Outlives(lt)=>self. +print_lifetime(*lt) ,_=>{panic!("expected a lifetime bound, found a trait bound" +)}}}}fn print_generic_params(&mut self ,generic_params:&[ast::GenericParam]){if +generic_params.is_empty(){;return;;};self.word("<");;self.commasep(Inconsistent, +generic_params,|s,param|{3;s.print_outer_attributes_inline(¶m.attrs);;match& +param.kind{ast::GenericParamKind::Lifetime=>{3;let lt=ast::Lifetime{id:param.id, +ident:param.ident};;s.print_lifetime(lt);if!param.bounds.is_empty(){s.word_nbsp( +":");*&*&();s.print_lifetime_bounds(¶m.bounds)}}ast::GenericParamKind::Type{ +default}=>{;s.print_ident(param.ident);;if!param.bounds.is_empty(){;s.word_nbsp( +":");;s.print_type_bounds(¶m.bounds);}if let Some(default)=default{s.space() +;3;3;s.word_space("=");3;s.print_type(default)}}ast::GenericParamKind::Const{ty, +default,..}=>{;s.word_space("const");;;s.print_ident(param.ident);;;s.space();s. +word_space(":");;s.print_type(ty);if!param.bounds.is_empty(){s.word_nbsp(":");s. +print_type_bounds(¶m.bounds);3;}if let Some(default)=default{;s.space();;;s. +word_space("=");;s.print_expr(&default.value,FixupContext::default());}}}});self +.word(">");;}pub fn print_mutability(&mut self,mutbl:ast::Mutability,print_const +:bool){match mutbl{ast::Mutability::Mut=>(self.word_nbsp("mut")),ast::Mutability +::Not=>{if print_const{3;self.word_nbsp("const");;}}}}fn print_mt(&mut self,mt:& +ast::MutTy,print_const:bool){;self.print_mutability(mt.mutbl,print_const);;self. +print_type(&mt.ty)}fn print_param(&mut self,input:&ast::Param,is_closure:bool){; +self.ibox(INDENT_UNIT);;;self.print_outer_attributes_inline(&input.attrs);;match +input.ty.kind{ast::TyKind::Infer if is_closure=> self.print_pat(&input.pat),_=>{ +if let Some(eself)=input.to_self(){;self.print_explicit_self(&eself);;}else{;let +invalid=if let PatKind::Ident(_,ident,_)=input.pat.kind{(ident.name==kw::Empty)} +else{false};;if!invalid{self.print_pat(&input.pat);self.word(":");self.space();} +self.print_type(&input.ty);();}}}();self.end();();}fn print_fn_ret_ty(&mut self, +fn_ret_ty:&ast::FnRetTy){if let ast::FnRetTy::Ty(ty)=fn_ret_ty{loop{break};self. +space_if_not_bol();;self.ibox(INDENT_UNIT);self.word_space("->");self.print_type +(ty);;;self.end();;;self.maybe_print_comment(ty.span.lo());}}fn print_ty_fn(&mut +self,ext:ast::Extern,unsafety:ast::Unsafe, decl:&ast::FnDecl,name:Option, +generic_params:&[ast::GenericParam],){({});self.ibox(INDENT_UNIT);({});{;};self. +print_formal_generic_params(generic_params);;;let generics=ast::Generics{params: +ThinVec::new(),where_clause:ast::WhereClause{has_where_token:(false),predicates: +ThinVec::new(),span:DUMMY_SP,},span:DUMMY_SP,};{;};{;};let header=ast::FnHeader{ +unsafety,ext,..ast::FnHeader::default()};{;};();self.print_fn(decl,header,name,& +generics);;;self.end();}fn print_fn_header_info(&mut self,header:ast::FnHeader){ +self.print_constness(header.constness);*&*&();*&*&();header.coroutine_kind.map(| +coroutine_kind|self.print_coroutine_kind(coroutine_kind));;;self.print_unsafety( +header.unsafety);;match header.ext{ast::Extern::None=>{}ast::Extern::Implicit(_) +=>{3;self.word_nbsp("extern");3;}ast::Extern::Explicit(abi,_)=>{;self.word_nbsp( +"extern");;;self.print_token_literal(abi.as_token_lit(),abi.span);self.nbsp();}} +self.word(("fn"))}fn print_unsafety(&mut self,s:ast::Unsafe){match s{ast::Unsafe +::No=>{}ast::Unsafe::Yes(_)=>self .word_nbsp("unsafe"),}}fn print_constness(&mut +self,s:ast::Const){match s{ast::Const::No=>{}ast::Const::Yes(_)=>self.//((),()); +word_nbsp((("const"))),}}fn print_is_auto(&mut self,s:ast::IsAuto){match s{ast:: +IsAuto::Yes=>self.word_nbsp("auto") ,ast::IsAuto::No=>{}}}fn print_meta_item_lit +(&mut self,lit:&ast::MetaItemLit){self.print_token_literal((lit.as_token_lit()), +lit.span)}fn print_token_literal(&mut self,token_lit:token::Lit,span:Span){;self +.maybe_print_comment(span.lo());loop{break;};self.word(token_lit.to_string())}fn +print_symbol(&mut self,sym:Symbol,style:ast::StrStyle){();self.print_string(sym. +as_str(),style);({});}fn print_inner_attributes_no_trailing_hardbreak(&mut self, +attrs:&[ast::Attribute])->bool{self.print_either_attributes(attrs,ast:://*&*&(); +AttrStyle::Inner,false,false) }fn print_outer_attributes_inline(&mut self,attrs: +&[ast::Attribute])->bool{self.print_either_attributes(attrs,ast::AttrStyle:://3; +Outer,((true)),(true))}fn print_attribute( &mut self,attr:&ast::Attribute){self. +print_attribute_inline(attr,(false))}fn print_meta_list_item(&mut self,item:&ast +::NestedMetaItem){match item{ast::NestedMetaItem::MetaItem(mi)=>self.//let _=(); +print_meta_item(mi),ast::NestedMetaItem:: Lit(lit)=>self.print_meta_item_lit(lit +),}}fn print_meta_item(&mut self,item:&ast::MetaItem){3;self.ibox(INDENT_UNIT);; +match(&item.kind){ast::MetaItemKind::Word=>self.print_path (&item.path,false,0), +ast::MetaItemKind::NameValue(value)=>{;self.print_path(&item.path,false,0);self. +space();;self.word_space("=");self.print_meta_item_lit(value);}ast::MetaItemKind +::List(items)=>{;self.print_path(&item.path,false,0);self.popen();self.commasep( +Consistent,items,|s,i|s.print_meta_list_item(i));;;self.pclose();;}}self.end();} +pub(crate)fn bounds_to_string(&self,bounds: &[ast::GenericBound])->String{Self:: +to_string((((((((|s|((((((s.print_type_bounds(bounds)))))))))))))))}pub(crate)fn +where_bound_predicate_to_string(&self,where_bound_predicate:&ast:://loop{break}; +WhereBoundPredicate,)->String{Self::to_string (|s|s.print_where_bound_predicate( +where_bound_predicate))}pub(crate)fn tt_to_string(&self,tt:&TokenTree)->String{ +Self::to_string(|s|{3;s.print_tt(tt,false);;})}pub(crate)fn tts_to_string(&self, +tokens:&TokenStream)->String{Self::to_string(|s| s.print_tts(tokens,false))}pub( +crate)fn path_segment_to_string(&self,p:&ast::PathSegment)->String{Self:://({}); +to_string(((((|s|((((s.print_path_segment(p,((((false))))))))))))))}pub(crate)fn +meta_list_item_to_string(&self,li:&ast ::NestedMetaItem)->String{Self::to_string +((|s|s.print_meta_list_item(li))) }pub(crate)fn attribute_to_string(&self,attr:& +ast::Attribute)->String{((Self::to_string(((| s|(s.print_attribute(attr)))))))}} diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 6eff70410cbbb..e38fa85412a36 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -1,1081 +1,251 @@ -use crate::pp::Breaks::Inconsistent; -use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT}; -use ast::{ForLoopKind, MatchKind}; -use itertools::{Itertools, Position}; -use rustc_ast::ptr::P; -use rustc_ast::token; -use rustc_ast::util::classify; -use rustc_ast::util::literal::escape_byte_str_symbol; -use rustc_ast::util::parser::{self, AssocOp, Fixity}; -use rustc_ast::{self as ast, BlockCheckMode}; -use rustc_ast::{ - FormatAlignment, FormatArgPosition, FormatArgsPiece, FormatCount, FormatDebugHex, FormatSign, - FormatTrait, -}; -use std::fmt::Write; - -#[derive(Copy, Clone, Debug)] -pub(crate) struct FixupContext { - /// Print expression such that it can be parsed back as a statement - /// consisting of the original expression. - /// - /// The effect of this is for binary operators in statement position to set - /// `leftmost_subexpression_in_stmt` when printing their left-hand operand. - /// - /// ```ignore (illustrative) - /// (match x {}) - 1; // match needs parens when LHS of binary operator - /// - /// match x {}; // not when its own statement - /// ``` - pub stmt: bool, - - /// This is the difference between: - /// - /// ```ignore (illustrative) - /// (match x {}) - 1; // subexpression needs parens - /// - /// let _ = match x {} - 1; // no parens - /// ``` - /// - /// There are 3 distinguishable contexts in which `print_expr` might be - /// called with the expression `$match` as its argument, where `$match` - /// represents an expression of kind `ExprKind::Match`: - /// - /// - stmt=false leftmost_subexpression_in_stmt=false - /// - /// Example: `let _ = $match - 1;` - /// - /// No parentheses required. - /// - /// - stmt=false leftmost_subexpression_in_stmt=true - /// - /// Example: `$match - 1;` - /// - /// Must parenthesize `($match)`, otherwise parsing back the output as a - /// statement would terminate the statement after the closing brace of - /// the match, parsing `-1;` as a separate statement. - /// - /// - stmt=true leftmost_subexpression_in_stmt=false - /// - /// Example: `$match;` - /// - /// No parentheses required. - pub leftmost_subexpression_in_stmt: bool, - - /// This is the difference between: - /// - /// ```ignore (illustrative) - /// if let _ = (Struct {}) {} // needs parens - /// - /// match () { - /// () if let _ = Struct {} => {} // no parens - /// } - /// ``` - pub parenthesize_exterior_struct_lit: bool, -} - -/// The default amount of fixing is minimal fixing. Fixups should be turned on -/// in a targeted fashion where needed. -impl Default for FixupContext { - fn default() -> Self { - FixupContext { - stmt: false, - leftmost_subexpression_in_stmt: false, - parenthesize_exterior_struct_lit: false, - } - } -} - -impl<'a> State<'a> { - fn print_else(&mut self, els: Option<&ast::Expr>) { - if let Some(_else) = els { - match &_else.kind { - // Another `else if` block. - ast::ExprKind::If(i, then, e) => { - self.cbox(INDENT_UNIT - 1); - self.ibox(0); - self.word(" else if "); - self.print_expr_as_cond(i); - self.space(); - self.print_block(then); - self.print_else(e.as_deref()) - } - // Final `else` block. - ast::ExprKind::Block(b, _) => { - self.cbox(INDENT_UNIT - 1); - self.ibox(0); - self.word(" else "); - self.print_block(b) - } - // Constraints would be great here! - _ => { - panic!("print_if saw if with weird alternative"); - } - } - } - } - - fn print_if(&mut self, test: &ast::Expr, blk: &ast::Block, elseopt: Option<&ast::Expr>) { - self.head("if"); - self.print_expr_as_cond(test); - self.space(); - self.print_block(blk); - self.print_else(elseopt) - } - - fn print_call_post(&mut self, args: &[P]) { - self.popen(); - self.commasep_exprs(Inconsistent, args); - self.pclose() - } - - fn print_expr_maybe_paren(&mut self, expr: &ast::Expr, prec: i8, fixup: FixupContext) { - self.print_expr_cond_paren(expr, expr.precedence().order() < prec, fixup); - } - - /// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in - /// `if cond { ... }`. - fn print_expr_as_cond(&mut self, expr: &ast::Expr) { - let fixup = - FixupContext { parenthesize_exterior_struct_lit: true, ..FixupContext::default() }; - self.print_expr_cond_paren(expr, Self::cond_needs_par(expr), fixup) - } - - /// Does `expr` need parentheses when printed in a condition position? - /// - /// These cases need parens due to the parse error observed in #26461: `if return {}` - /// parses as the erroneous construct `if (return {})`, not `if (return) {}`. - fn cond_needs_par(expr: &ast::Expr) -> bool { - match expr.kind { - ast::ExprKind::Break(..) - | ast::ExprKind::Closure(..) - | ast::ExprKind::Ret(..) - | ast::ExprKind::Yeet(..) => true, - _ => parser::contains_exterior_struct_lit(expr), - } - } - - /// Prints `expr` or `(expr)` when `needs_par` holds. - pub(super) fn print_expr_cond_paren( - &mut self, - expr: &ast::Expr, - needs_par: bool, - mut fixup: FixupContext, - ) { - if needs_par { - self.popen(); - - // If we are surrounding the whole cond in parentheses, such as: - // - // if (return Struct {}) {} - // - // then there is no need for parenthesizing the individual struct - // expressions within. On the other hand if the whole cond is not - // parenthesized, then print_expr must parenthesize exterior struct - // literals. - // - // if x == (Struct {}) {} - // - fixup = FixupContext::default(); - } - - self.print_expr(expr, fixup); - - if needs_par { - self.pclose(); - } - } - - fn print_expr_vec(&mut self, exprs: &[P]) { - self.ibox(INDENT_UNIT); - self.word("["); - self.commasep_exprs(Inconsistent, exprs); - self.word("]"); - self.end(); - } - - pub(super) fn print_expr_anon_const( - &mut self, - expr: &ast::AnonConst, - attrs: &[ast::Attribute], - ) { - self.ibox(INDENT_UNIT); - self.word("const"); - self.nbsp(); - if let ast::ExprKind::Block(block, None) = &expr.value.kind { - self.cbox(0); - self.ibox(0); - self.print_block_with_attrs(block, attrs); - } else { - self.print_expr(&expr.value, FixupContext::default()); - } - self.end(); - } - - fn print_expr_repeat(&mut self, element: &ast::Expr, count: &ast::AnonConst) { - self.ibox(INDENT_UNIT); - self.word("["); - self.print_expr(element, FixupContext::default()); - self.word_space(";"); - self.print_expr(&count.value, FixupContext::default()); - self.word("]"); - self.end(); - } - - fn print_expr_struct( - &mut self, - qself: &Option>, - path: &ast::Path, - fields: &[ast::ExprField], - rest: &ast::StructRest, - ) { - if let Some(qself) = qself { - self.print_qpath(path, qself, true); - } else { - self.print_path(path, true, 0); - } - self.nbsp(); - self.word("{"); - let has_rest = match rest { - ast::StructRest::Base(_) | ast::StructRest::Rest(_) => true, - ast::StructRest::None => false, - }; - if fields.is_empty() && !has_rest { - self.word("}"); - return; - } - self.cbox(0); - for (pos, field) in fields.iter().with_position() { - let is_first = matches!(pos, Position::First | Position::Only); - let is_last = matches!(pos, Position::Last | Position::Only); - self.maybe_print_comment(field.span.hi()); - self.print_outer_attributes(&field.attrs); - if is_first { - self.space_if_not_bol(); - } - if !field.is_shorthand { - self.print_ident(field.ident); - self.word_nbsp(":"); - } - self.print_expr(&field.expr, FixupContext::default()); - if !is_last || has_rest { - self.word_space(","); - } else { - self.trailing_comma_or_space(); - } - } - if has_rest { - if fields.is_empty() { - self.space(); - } - self.word(".."); - if let ast::StructRest::Base(expr) = rest { - self.print_expr(expr, FixupContext::default()); - } - self.space(); - } - self.offset(-INDENT_UNIT); - self.end(); - self.word("}"); - } - - fn print_expr_tup(&mut self, exprs: &[P]) { - self.popen(); - self.commasep_exprs(Inconsistent, exprs); - if exprs.len() == 1 { - self.word(","); - } - self.pclose() - } - - fn print_expr_call(&mut self, func: &ast::Expr, args: &[P], fixup: FixupContext) { - let prec = match func.kind { - ast::ExprKind::Field(..) => parser::PREC_FORCE_PAREN, - _ => parser::PREC_POSTFIX, - }; - - // Independent of parenthesization related to precedence, we must - // parenthesize `func` if this is a statement context in which without - // parentheses, a statement boundary would occur inside `func` or - // immediately after `func`. - // - // Suppose `func` represents `match () { _ => f }`. We must produce: - // - // (match () { _ => f })(); - // - // instead of: - // - // match () { _ => f } (); - // - // because the latter is valid syntax but with the incorrect meaning. - // It's a match-expression followed by tuple-expression, not a function - // call. - self.print_expr_maybe_paren( - func, - prec, - FixupContext { - stmt: false, - leftmost_subexpression_in_stmt: fixup.stmt || fixup.leftmost_subexpression_in_stmt, - ..fixup - }, - ); - - self.print_call_post(args) - } - - fn print_expr_method_call( - &mut self, - segment: &ast::PathSegment, - receiver: &ast::Expr, - base_args: &[P], - fixup: FixupContext, - ) { - // Unlike in `print_expr_call`, no change to fixup here because - // statement boundaries never occur in front of a `.` (or `?`) token. - // - // match () { _ => f }.method(); - // - // Parenthesizing only for precedence and not with regard to statement - // boundaries, `$receiver.method()` can be parsed back as a statement - // containing an expression if and only if `$receiver` can be parsed as - // a statement containing an expression. - self.print_expr_maybe_paren(receiver, parser::PREC_POSTFIX, fixup); - - self.word("."); - self.print_ident(segment.ident); - if let Some(args) = &segment.args { - self.print_generic_args(args, true); - } - self.print_call_post(base_args) - } - - fn print_expr_binary( - &mut self, - op: ast::BinOp, - lhs: &ast::Expr, - rhs: &ast::Expr, - fixup: FixupContext, - ) { - let assoc_op = AssocOp::from_ast_binop(op.node); - let prec = assoc_op.precedence() as i8; - let fixity = assoc_op.fixity(); - - let (left_prec, right_prec) = match fixity { - Fixity::Left => (prec, prec + 1), - Fixity::Right => (prec + 1, prec), - Fixity::None => (prec + 1, prec + 1), - }; - - let left_prec = match (&lhs.kind, op.node) { - // These cases need parens: `x as i32 < y` has the parser thinking that `i32 < y` is - // the beginning of a path type. It starts trying to parse `x as (i32 < y ...` instead - // of `(x as i32) < ...`. We need to convince it _not_ to do that. - (&ast::ExprKind::Cast { .. }, ast::BinOpKind::Lt | ast::BinOpKind::Shl) => { - parser::PREC_FORCE_PAREN - } - // We are given `(let _ = a) OP b`. - // - // - When `OP <= LAnd` we should print `let _ = a OP b` to avoid redundant parens - // as the parser will interpret this as `(let _ = a) OP b`. - // - // - Otherwise, e.g. when we have `(let a = b) < c` in AST, - // parens are required since the parser would interpret `let a = b < c` as - // `let a = (b < c)`. To achieve this, we force parens. - (&ast::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(prec) => { - parser::PREC_FORCE_PAREN - } - _ => left_prec, - }; - - self.print_expr_maybe_paren( - lhs, - left_prec, - FixupContext { - stmt: false, - leftmost_subexpression_in_stmt: fixup.stmt || fixup.leftmost_subexpression_in_stmt, - ..fixup - }, - ); - - self.space(); - self.word_space(op.node.as_str()); - - self.print_expr_maybe_paren( - rhs, - right_prec, - FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, ..fixup }, - ); - } - - fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr, fixup: FixupContext) { - self.word(op.as_str()); - self.print_expr_maybe_paren( - expr, - parser::PREC_PREFIX, - FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, ..fixup }, - ); - } - - fn print_expr_addr_of( - &mut self, - kind: ast::BorrowKind, - mutability: ast::Mutability, - expr: &ast::Expr, - fixup: FixupContext, - ) { - self.word("&"); - match kind { - ast::BorrowKind::Ref => self.print_mutability(mutability, false), - ast::BorrowKind::Raw => { - self.word_nbsp("raw"); - self.print_mutability(mutability, true); - } - } - self.print_expr_maybe_paren( - expr, - parser::PREC_PREFIX, - FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, ..fixup }, - ); - } - - pub(super) fn print_expr(&mut self, expr: &ast::Expr, fixup: FixupContext) { - self.print_expr_outer_attr_style(expr, true, fixup) - } - - pub(super) fn print_expr_outer_attr_style( - &mut self, - expr: &ast::Expr, - is_inline: bool, - mut fixup: FixupContext, - ) { - self.maybe_print_comment(expr.span.lo()); - - let attrs = &expr.attrs; - if is_inline { - self.print_outer_attributes_inline(attrs); - } else { - self.print_outer_attributes(attrs); - } - - self.ibox(INDENT_UNIT); - - // The Match subexpression in `match x {} - 1` must be parenthesized if - // it is the leftmost subexpression in a statement: - // - // (match x {}) - 1; - // - // But not otherwise: - // - // let _ = match x {} - 1; - // - // Same applies to a small set of other expression kinds which eagerly - // terminate a statement which opens with them. - let needs_par = - fixup.leftmost_subexpression_in_stmt && !classify::expr_requires_semi_to_be_stmt(expr); - if needs_par { - self.popen(); - fixup = FixupContext::default(); - } - - self.ann.pre(self, AnnNode::Expr(expr)); - - match &expr.kind { - ast::ExprKind::Array(exprs) => { - self.print_expr_vec(exprs); - } - ast::ExprKind::ConstBlock(anon_const) => { - self.print_expr_anon_const(anon_const, attrs); - } - ast::ExprKind::Repeat(element, count) => { - self.print_expr_repeat(element, count); - } - ast::ExprKind::Struct(se) => { - self.print_expr_struct(&se.qself, &se.path, &se.fields, &se.rest); - } - ast::ExprKind::Tup(exprs) => { - self.print_expr_tup(exprs); - } - ast::ExprKind::Call(func, args) => { - self.print_expr_call(func, args, fixup); - } - ast::ExprKind::MethodCall(box ast::MethodCall { seg, receiver, args, .. }) => { - self.print_expr_method_call(seg, receiver, args, fixup); - } - ast::ExprKind::Binary(op, lhs, rhs) => { - self.print_expr_binary(*op, lhs, rhs, fixup); - } - ast::ExprKind::Unary(op, expr) => { - self.print_expr_unary(*op, expr, fixup); - } - ast::ExprKind::AddrOf(k, m, expr) => { - self.print_expr_addr_of(*k, *m, expr, fixup); - } - ast::ExprKind::Lit(token_lit) => { - self.print_token_literal(*token_lit, expr.span); - } - ast::ExprKind::IncludedBytes(bytes) => { - let lit = token::Lit::new(token::ByteStr, escape_byte_str_symbol(bytes), None); - self.print_token_literal(lit, expr.span) - } - ast::ExprKind::Cast(expr, ty) => { - let prec = AssocOp::As.precedence() as i8; - self.print_expr_maybe_paren( - expr, - prec, - FixupContext { - stmt: false, - leftmost_subexpression_in_stmt: fixup.stmt - || fixup.leftmost_subexpression_in_stmt, - ..fixup - }, - ); - self.space(); - self.word_space("as"); - self.print_type(ty); - } - ast::ExprKind::Type(expr, ty) => { - self.word("type_ascribe!("); - self.ibox(0); - self.print_expr(expr, FixupContext::default()); - - self.word(","); - self.space_if_not_bol(); - self.print_type(ty); - - self.end(); - self.word(")"); - } - ast::ExprKind::Let(pat, scrutinee, _, _) => { - self.print_let(pat, scrutinee, fixup); - } - ast::ExprKind::If(test, blk, elseopt) => self.print_if(test, blk, elseopt.as_deref()), - ast::ExprKind::While(test, blk, opt_label) => { - if let Some(label) = opt_label { - self.print_ident(label.ident); - self.word_space(":"); - } - self.cbox(0); - self.ibox(0); - self.word_nbsp("while"); - self.print_expr_as_cond(test); - self.space(); - self.print_block_with_attrs(blk, attrs); - } - ast::ExprKind::ForLoop { pat, iter, body, label, kind } => { - if let Some(label) = label { - self.print_ident(label.ident); - self.word_space(":"); - } - self.cbox(0); - self.ibox(0); - self.word_nbsp("for"); - if kind == &ForLoopKind::ForAwait { - self.word_nbsp("await"); - } - self.print_pat(pat); - self.space(); - self.word_space("in"); - self.print_expr_as_cond(iter); - self.space(); - self.print_block_with_attrs(body, attrs); - } - ast::ExprKind::Loop(blk, opt_label, _) => { - if let Some(label) = opt_label { - self.print_ident(label.ident); - self.word_space(":"); - } - self.cbox(0); - self.ibox(0); - self.word_nbsp("loop"); - self.print_block_with_attrs(blk, attrs); - } - ast::ExprKind::Match(expr, arms, match_kind) => { - self.cbox(0); - self.ibox(0); - - match match_kind { - MatchKind::Prefix => { - self.word_nbsp("match"); - self.print_expr_as_cond(expr); - self.space(); - } - MatchKind::Postfix => { - self.print_expr_as_cond(expr); - self.word_nbsp(".match"); - } - } - - self.bopen(); - self.print_inner_attributes_no_trailing_hardbreak(attrs); - for arm in arms { - self.print_arm(arm); - } - let empty = attrs.is_empty() && arms.is_empty(); - self.bclose(expr.span, empty); - } - ast::ExprKind::Closure(box ast::Closure { - binder, - capture_clause, - constness, - coroutine_kind, - movability, - fn_decl, - body, - fn_decl_span: _, - fn_arg_span: _, - }) => { - self.print_closure_binder(binder); - self.print_constness(*constness); - self.print_movability(*movability); - coroutine_kind.map(|coroutine_kind| self.print_coroutine_kind(coroutine_kind)); - self.print_capture_clause(*capture_clause); - - self.print_fn_params_and_ret(fn_decl, true); - self.space(); - self.print_expr(body, FixupContext::default()); - self.end(); // need to close a box - - // a box will be closed by print_expr, but we didn't want an overall - // wrapper so we closed the corresponding opening. so create an - // empty box to satisfy the close. - self.ibox(0); - } - ast::ExprKind::Block(blk, opt_label) => { - if let Some(label) = opt_label { - self.print_ident(label.ident); - self.word_space(":"); - } - // containing cbox, will be closed by print-block at } - self.cbox(0); - // head-box, will be closed by print-block after { - self.ibox(0); - self.print_block_with_attrs(blk, attrs); - } - ast::ExprKind::Gen(capture_clause, blk, kind) => { - self.word_nbsp(kind.modifier()); - self.print_capture_clause(*capture_clause); - // cbox/ibox in analogy to the `ExprKind::Block` arm above - self.cbox(0); - self.ibox(0); - self.print_block_with_attrs(blk, attrs); - } - ast::ExprKind::Await(expr, _) => { - // Same fixups as ExprKind::MethodCall. - self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX, fixup); - self.word(".await"); - } - ast::ExprKind::Assign(lhs, rhs, _) => { - // Same fixups as ExprKind::Binary. - let prec = AssocOp::Assign.precedence() as i8; - self.print_expr_maybe_paren( - lhs, - prec + 1, - FixupContext { - stmt: false, - leftmost_subexpression_in_stmt: fixup.stmt - || fixup.leftmost_subexpression_in_stmt, - ..fixup - }, - ); - self.space(); - self.word_space("="); - self.print_expr_maybe_paren( - rhs, - prec, - FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, ..fixup }, - ); - } - ast::ExprKind::AssignOp(op, lhs, rhs) => { - // Same fixups as ExprKind::Binary. - let prec = AssocOp::Assign.precedence() as i8; - self.print_expr_maybe_paren( - lhs, - prec + 1, - FixupContext { - stmt: false, - leftmost_subexpression_in_stmt: fixup.stmt - || fixup.leftmost_subexpression_in_stmt, - ..fixup - }, - ); - self.space(); - self.word(op.node.as_str()); - self.word_space("="); - self.print_expr_maybe_paren( - rhs, - prec, - FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, ..fixup }, - ); - } - ast::ExprKind::Field(expr, ident) => { - // Same fixups as ExprKind::MethodCall. - self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX, fixup); - self.word("."); - self.print_ident(*ident); - } - ast::ExprKind::Index(expr, index, _) => { - // Same fixups as ExprKind::Call. - self.print_expr_maybe_paren( - expr, - parser::PREC_POSTFIX, - FixupContext { - stmt: false, - leftmost_subexpression_in_stmt: fixup.stmt - || fixup.leftmost_subexpression_in_stmt, - ..fixup - }, - ); - self.word("["); - self.print_expr(index, FixupContext::default()); - self.word("]"); - } - ast::ExprKind::Range(start, end, limits) => { - // Special case for `Range`. `AssocOp` claims that `Range` has higher precedence - // than `Assign`, but `x .. x = x` gives a parse error instead of `x .. (x = x)`. - // Here we use a fake precedence value so that any child with lower precedence than - // a "normal" binop gets parenthesized. (`LOr` is the lowest-precedence binop.) - let fake_prec = AssocOp::LOr.precedence() as i8; - if let Some(e) = start { - self.print_expr_maybe_paren( - e, - fake_prec, - FixupContext { - stmt: false, - leftmost_subexpression_in_stmt: fixup.stmt - || fixup.leftmost_subexpression_in_stmt, - ..fixup - }, - ); - } - match limits { - ast::RangeLimits::HalfOpen => self.word(".."), - ast::RangeLimits::Closed => self.word("..="), - } - if let Some(e) = end { - self.print_expr_maybe_paren( - e, - fake_prec, - FixupContext { - stmt: false, - leftmost_subexpression_in_stmt: false, - ..fixup - }, - ); - } - } - ast::ExprKind::Underscore => self.word("_"), - ast::ExprKind::Path(None, path) => self.print_path(path, true, 0), - ast::ExprKind::Path(Some(qself), path) => self.print_qpath(path, qself, true), - ast::ExprKind::Break(opt_label, opt_expr) => { - self.word("break"); - if let Some(label) = opt_label { - self.space(); - self.print_ident(label.ident); - } - if let Some(expr) = opt_expr { - self.space(); - self.print_expr_maybe_paren( - expr, - parser::PREC_JUMP, - FixupContext { - stmt: false, - leftmost_subexpression_in_stmt: false, - ..fixup - }, - ); - } - } - ast::ExprKind::Continue(opt_label) => { - self.word("continue"); - if let Some(label) = opt_label { - self.space(); - self.print_ident(label.ident); - } - } - ast::ExprKind::Ret(result) => { - self.word("return"); - if let Some(expr) = result { - self.word(" "); - self.print_expr_maybe_paren( - expr, - parser::PREC_JUMP, - FixupContext { - stmt: false, - leftmost_subexpression_in_stmt: false, - ..fixup - }, - ); - } - } - ast::ExprKind::Yeet(result) => { - self.word("do"); - self.word(" "); - self.word("yeet"); - if let Some(expr) = result { - self.word(" "); - self.print_expr_maybe_paren( - expr, - parser::PREC_JUMP, - FixupContext { - stmt: false, - leftmost_subexpression_in_stmt: false, - ..fixup - }, - ); - } - } - ast::ExprKind::Become(result) => { - self.word("become"); - self.word(" "); - self.print_expr_maybe_paren( - result, - parser::PREC_JUMP, - FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, ..fixup }, - ); - } - ast::ExprKind::InlineAsm(a) => { - // FIXME: This should have its own syntax, distinct from a macro invocation. - self.word("asm!"); - self.print_inline_asm(a); - } - ast::ExprKind::FormatArgs(fmt) => { - // FIXME: This should have its own syntax, distinct from a macro invocation. - self.word("format_args!"); - self.popen(); - self.rbox(0, Inconsistent); - self.word(reconstruct_format_args_template_string(&fmt.template)); - for arg in fmt.arguments.all_args() { - self.word_space(","); - self.print_expr(&arg.expr, FixupContext::default()); - } - self.end(); - self.pclose(); - } - ast::ExprKind::OffsetOf(container, fields) => { - self.word("builtin # offset_of"); - self.popen(); - self.rbox(0, Inconsistent); - self.print_type(container); - self.word(","); - self.space(); - - if let Some((&first, rest)) = fields.split_first() { - self.print_ident(first); - - for &field in rest { - self.word("."); - self.print_ident(field); - } - } - self.pclose(); - self.end(); - } - ast::ExprKind::MacCall(m) => self.print_mac(m), - ast::ExprKind::Paren(e) => { - self.popen(); - self.print_expr(e, FixupContext::default()); - self.pclose(); - } - ast::ExprKind::Yield(e) => { - self.word("yield"); - - if let Some(expr) = e { - self.space(); - self.print_expr_maybe_paren( - expr, - parser::PREC_JUMP, - FixupContext { - stmt: false, - leftmost_subexpression_in_stmt: false, - ..fixup - }, - ); - } - } - ast::ExprKind::Try(e) => { - // Same fixups as ExprKind::MethodCall. - self.print_expr_maybe_paren(e, parser::PREC_POSTFIX, fixup); - self.word("?") - } - ast::ExprKind::TryBlock(blk) => { - self.cbox(0); - self.ibox(0); - self.word_nbsp("try"); - self.print_block_with_attrs(blk, attrs) - } - ast::ExprKind::Err(_) => { - self.popen(); - self.word("/*ERROR*/"); - self.pclose() - } - ast::ExprKind::Dummy => { - self.popen(); - self.word("/*DUMMY*/"); - self.pclose(); - } - } - - self.ann.post(self, AnnNode::Expr(expr)); - - if needs_par { - self.pclose(); - } - - self.end(); - } - - fn print_arm(&mut self, arm: &ast::Arm) { - // Note, I have no idea why this check is necessary, but here it is. - if arm.attrs.is_empty() { - self.space(); - } - self.cbox(INDENT_UNIT); - self.ibox(0); - self.maybe_print_comment(arm.pat.span.lo()); - self.print_outer_attributes(&arm.attrs); - self.print_pat(&arm.pat); - self.space(); - if let Some(e) = &arm.guard { - self.word_space("if"); - self.print_expr(e, FixupContext::default()); - self.space(); - } - - if let Some(body) = &arm.body { - self.word_space("=>"); - - match &body.kind { - ast::ExprKind::Block(blk, opt_label) => { - if let Some(label) = opt_label { - self.print_ident(label.ident); - self.word_space(":"); - } - - // The block will close the pattern's ibox. - self.print_block_unclosed_indent(blk); - - // If it is a user-provided unsafe block, print a comma after it. - if let BlockCheckMode::Unsafe(ast::UserProvided) = blk.rules { - self.word(","); - } - } - _ => { - self.end(); // Close the ibox for the pattern. - self.print_expr(body, FixupContext { stmt: true, ..FixupContext::default() }); - self.word(","); - } - } - } else { - self.word(","); - } - self.end(); // Close enclosing cbox. - } - - fn print_closure_binder(&mut self, binder: &ast::ClosureBinder) { - match binder { - ast::ClosureBinder::NotPresent => {} - ast::ClosureBinder::For { generic_params, .. } => { - self.print_formal_generic_params(generic_params) - } - } - } - - fn print_movability(&mut self, movability: ast::Movability) { - match movability { - ast::Movability::Static => self.word_space("static"), - ast::Movability::Movable => {} - } - } - - fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy) { - match capture_clause { - ast::CaptureBy::Value { .. } => self.word_space("move"), - ast::CaptureBy::Ref => {} - } - } -} - -fn reconstruct_format_args_template_string(pieces: &[FormatArgsPiece]) -> String { - let mut template = "\"".to_string(); - for piece in pieces { - match piece { - FormatArgsPiece::Literal(s) => { - for c in s.as_str().chars() { - template.extend(c.escape_debug()); - if let '{' | '}' = c { - template.push(c); - } - } - } - FormatArgsPiece::Placeholder(p) => { - template.push('{'); - let (Ok(n) | Err(n)) = p.argument.index; - write!(template, "{n}").unwrap(); - if p.format_options != Default::default() || p.format_trait != FormatTrait::Display - { - template.push(':'); - } - if let Some(fill) = p.format_options.fill { - template.push(fill); - } - match p.format_options.alignment { - Some(FormatAlignment::Left) => template.push('<'), - Some(FormatAlignment::Right) => template.push('>'), - Some(FormatAlignment::Center) => template.push('^'), - None => {} - } - match p.format_options.sign { - Some(FormatSign::Plus) => template.push('+'), - Some(FormatSign::Minus) => template.push('-'), - None => {} - } - if p.format_options.alternate { - template.push('#'); - } - if p.format_options.zero_pad { - template.push('0'); - } - if let Some(width) = &p.format_options.width { - match width { - FormatCount::Literal(n) => write!(template, "{n}").unwrap(), - FormatCount::Argument(FormatArgPosition { - index: Ok(n) | Err(n), .. - }) => { - write!(template, "{n}$").unwrap(); - } - } - } - if let Some(precision) = &p.format_options.precision { - template.push('.'); - match precision { - FormatCount::Literal(n) => write!(template, "{n}").unwrap(), - FormatCount::Argument(FormatArgPosition { - index: Ok(n) | Err(n), .. - }) => { - write!(template, "{n}$").unwrap(); - } - } - } - match p.format_options.debug_hex { - Some(FormatDebugHex::Lower) => template.push('x'), - Some(FormatDebugHex::Upper) => template.push('X'), - None => {} - } - template.push_str(match p.format_trait { - FormatTrait::Display => "", - FormatTrait::Debug => "?", - FormatTrait::LowerExp => "e", - FormatTrait::UpperExp => "E", - FormatTrait::Octal => "o", - FormatTrait::Pointer => "p", - FormatTrait::Binary => "b", - FormatTrait::LowerHex => "x", - FormatTrait::UpperHex => "X", - }); - template.push('}'); - } - } - } - template.push('"'); - template -} +use crate::pp::Breaks::Inconsistent;use crate::pprust::state::{AnnNode,//*&*&(); +PrintState,State,INDENT_UNIT};use ast:: {ForLoopKind,MatchKind};use itertools::{ +Itertools,Position};use rustc_ast::ptr::P;use rustc_ast::token;use rustc_ast::// +util::classify;use rustc_ast::util::literal::escape_byte_str_symbol;use//*&*&(); +rustc_ast::util::parser::{self,AssocOp,Fixity};use rustc_ast::{self as ast,//(); +BlockCheckMode};use rustc_ast::{FormatAlignment,FormatArgPosition,//loop{break}; +FormatArgsPiece,FormatCount,FormatDebugHex,FormatSign,FormatTrait,};use std:://; +fmt::Write;#[derive(Copy,Clone,Debug)]pub(crate)struct FixupContext{pub stmt://; +bool,pub leftmost_subexpression_in_stmt:bool,pub//*&*&();((),());*&*&();((),()); +parenthesize_exterior_struct_lit:bool,}impl Default for FixupContext{fn default +()->Self{FixupContext{stmt:(((false))),leftmost_subexpression_in_stmt:((false)), +parenthesize_exterior_struct_lit:(false),}}}impl<'a>State<'a>{fn print_else(&mut +self,els:Option<&ast::Expr>){if let Some(_else)=els{match(((&_else.kind))){ast:: +ExprKind::If(i,then,e)=>{3;self.cbox(INDENT_UNIT-1);3;;self.ibox(0);;;self.word( +" else if ");;;self.print_expr_as_cond(i);;;self.space();self.print_block(then); +self.print_else(e.as_deref())}ast::ExprKind::Block(b,_)=>{;self.cbox(INDENT_UNIT +-1);3;3;self.ibox(0);3;3;self.word(" else ");3;self.print_block(b)}_=>{3;panic!( +"print_if saw if with weird alternative");;}}}}fn print_if(&mut self,test:&ast:: +Expr,blk:&ast::Block,elseopt:Option<&ast::Expr>){{;};self.head("if");();();self. +print_expr_as_cond(test);;;self.space();;;self.print_block(blk);self.print_else( +elseopt)}fn print_call_post(&mut self,args:&[P]){;self.popen();;self. +commasep_exprs(Inconsistent,args);3;self.pclose()}fn print_expr_maybe_paren(&mut +self,expr:&ast::Expr,prec:i8,fixup:FixupContext){{;};self.print_expr_cond_paren( +expr,expr.precedence().order()bool{match expr.kind{ast:://3; +ExprKind::Break(..)|ast::ExprKind::Closure(..)|ast::ExprKind::Ret(..)|ast:://(); +ExprKind::Yeet(..)=>(true),_=> parser::contains_exterior_struct_lit(expr),}}pub( +super)fn print_expr_cond_paren(&mut self,expr:&ast::Expr,needs_par:bool,mut//(); +fixup:FixupContext,){if needs_par{;self.popen();;fixup=FixupContext::default();} +self.print_expr(expr,fixup);;if needs_par{self.pclose();}}fn print_expr_vec(&mut +self,exprs:&[P]){3;self.ibox(INDENT_UNIT);3;3;self.word("[");3;;self. +commasep_exprs(Inconsistent,exprs);3;;self.word("]");;;self.end();;}pub(super)fn +print_expr_anon_const(&mut self,expr:&ast::AnonConst,attrs:&[ast::Attribute],){; +self.ibox(INDENT_UNIT);;;self.word("const");;;self.nbsp();if let ast::ExprKind:: +Block(block,None)=&expr.value.kind{();self.cbox(0);();();self.ibox(0);();3;self. +print_block_with_attrs(block,attrs);({});}else{({});self.print_expr(&expr.value, +FixupContext::default());;};self.end();}fn print_expr_repeat(&mut self,element:& +ast::Expr,count:&ast::AnonConst){;self.ibox(INDENT_UNIT);;;self.word("[");;self. +print_expr(element,FixupContext::default());();();self.word_space(";");3;3;self. +print_expr(&count.value,FixupContext::default());;;self.word("]");self.end();}fn +print_expr_struct(&mut self,qself:&Option

>,path:&ast::Path,fields +:&[ast::ExprField],rest:&ast::StructRest,){if let Some(qself)=qself{*&*&();self. +print_qpath(path,qself,true);;}else{;self.print_path(path,true,0);;}self.nbsp(); +self.word("{");;let has_rest=match rest{ast::StructRest::Base(_)|ast::StructRest +::Rest(_)=>true,ast::StructRest::None=>false,};;if fields.is_empty()&&!has_rest{ +self.word("}");();();return;();}3;self.cbox(0);3;for(pos,field)in fields.iter(). +with_position(){;let is_first=matches!(pos,Position::First|Position::Only);;;let +is_last=matches!(pos,Position::Last|Position::Only);3;;self.maybe_print_comment( +field.span.hi());;;self.print_outer_attributes(&field.attrs);;if is_first{;self. +space_if_not_bol();;}if!field.is_shorthand{;self.print_ident(field.ident);;self. +word_nbsp(":");;}self.print_expr(&field.expr,FixupContext::default());if!is_last +||has_rest{3;self.word_space(",");3;}else{3;self.trailing_comma_or_space();;}}if +has_rest{if fields.is_empty(){3;self.space();3;}3;self.word("..");3;if let ast:: +StructRest::Base(expr)=rest{;self.print_expr(expr,FixupContext::default());}self +.space();();}3;self.offset(-INDENT_UNIT);3;3;self.end();3;3;self.word("}");3;}fn +print_expr_tup(&mut self,exprs:&[P]){({});self.popen();({});{;};self. +commasep_exprs(Inconsistent,exprs);3;if exprs.len()==1{3;self.word(",");3;}self. +pclose()}fn print_expr_call(&mut self,func:&ast::Expr,args:&[P],//(); +fixup:FixupContext){;let prec=match func.kind{ast::ExprKind::Field(..)=>parser:: +PREC_FORCE_PAREN,_=>parser::PREC_POSTFIX,};3;3;self.print_expr_maybe_paren(func, +prec,FixupContext{stmt:(false),leftmost_subexpression_in_stmt:fixup.stmt||fixup. +leftmost_subexpression_in_stmt,..fixup},);let _=();self.print_call_post(args)}fn +print_expr_method_call(&mut self,segment:& ast::PathSegment,receiver:&ast::Expr, +base_args:&[P],fixup:FixupContext,){({});self.print_expr_maybe_paren( +receiver,parser::PREC_POSTFIX,fixup);;;self.word(".");;self.print_ident(segment. +ident);;if let Some(args)=&segment.args{self.print_generic_args(args,true);}self +.print_call_post(base_args)}fn print_expr_binary(&mut self,op:ast::BinOp,lhs:&// +ast::Expr,rhs:&ast::Expr,fixup:FixupContext,){loop{break};let assoc_op=AssocOp:: +from_ast_binop(op.node);;let prec=assoc_op.precedence()as i8;let fixity=assoc_op +.fixity();3;;let(left_prec,right_prec)=match fixity{Fixity::Left=>(prec,prec+1), +Fixity::Right=>(prec+1,prec),Fixity::None=>(prec+1,prec+1),};();3;let left_prec= +match(((&lhs.kind),op.node)){( &ast::ExprKind::Cast{..},ast::BinOpKind::Lt|ast:: +BinOpKind::Shl)=>{parser::PREC_FORCE_PAREN}(&ast:: ExprKind::Let{..},_)if!parser +::needs_par_as_let_scrutinee(prec)=>{parser::PREC_FORCE_PAREN}_=>left_prec,};3;; +self.print_expr_maybe_paren(lhs,left_prec,FixupContext{stmt:(((((((false))))))), +leftmost_subexpression_in_stmt:fixup. stmt||fixup.leftmost_subexpression_in_stmt +,..fixup},);();();self.space();();();self.word_space(op.node.as_str());3;3;self. +print_expr_maybe_paren(rhs,right_prec,FixupContext{stmt:(((((((((false))))))))), +leftmost_subexpression_in_stmt:false,..fixup},);;}fn print_expr_unary(&mut self, +op:ast::UnOp,expr:&ast::Expr,fixup:FixupContext){;self.word(op.as_str());;;self. +print_expr_maybe_paren(expr,parser::PREC_PREFIX,FixupContext{stmt:((((false)))), +leftmost_subexpression_in_stmt:false,..fixup},);({});}fn print_expr_addr_of(&mut +self,kind:ast::BorrowKind,mutability:ast::Mutability,expr:&ast::Expr,fixup://(); +FixupContext,){{();};self.word("&");{();};match kind{ast::BorrowKind::Ref=>self. +print_mutability(mutability,false),ast::BorrowKind::Raw=>{;self.word_nbsp("raw") +;3;;self.print_mutability(mutability,true);;}};self.print_expr_maybe_paren(expr, +parser::PREC_PREFIX,FixupContext{stmt :((false)),leftmost_subexpression_in_stmt: +false,..fixup},);{();};}pub(super)fn print_expr(&mut self,expr:&ast::Expr,fixup: +FixupContext){(self.print_expr_outer_attr_style(expr,(true),fixup))}pub(super)fn +print_expr_outer_attr_style(&mut self,expr:&ast ::Expr,is_inline:bool,mut fixup: +FixupContext,){;self.maybe_print_comment(expr.span.lo());;let attrs=&expr.attrs; +if is_inline{({});self.print_outer_attributes_inline(attrs);({});}else{{;};self. +print_outer_attributes(attrs);3;}3;self.ibox(INDENT_UNIT);;;let needs_par=fixup. +leftmost_subexpression_in_stmt&&!classify::expr_requires_semi_to_be_stmt(expr);; +if needs_par{;self.popen();;;fixup=FixupContext::default();;};self.ann.pre(self, +AnnNode::Expr(expr));{;};match&expr.kind{ast::ExprKind::Array(exprs)=>{{;};self. +print_expr_vec(exprs);{();};}ast::ExprKind::ConstBlock(anon_const)=>{{();};self. +print_expr_anon_const(anon_const,attrs);;}ast::ExprKind::Repeat(element,count)=> +{();self.print_expr_repeat(element,count);3;}ast::ExprKind::Struct(se)=>{3;self. +print_expr_struct(&se.qself,&se.path,&se.fields,&se.rest);3;}ast::ExprKind::Tup( +exprs)=>{3;self.print_expr_tup(exprs);3;}ast::ExprKind::Call(func,args)=>{;self. +print_expr_call(func,args,fixup);;}ast::ExprKind::MethodCall(box ast::MethodCall +{seg,receiver,args,..})=>{;self.print_expr_method_call(seg,receiver,args,fixup); +}ast::ExprKind::Binary(op,lhs,rhs)=>{;self.print_expr_binary(*op,lhs,rhs,fixup); +}ast::ExprKind::Unary(op,expr)=>{3;self.print_expr_unary(*op,expr,fixup);;}ast:: +ExprKind::AddrOf(k,m,expr)=>{3;self.print_expr_addr_of(*k,*m,expr,fixup);;}ast:: +ExprKind::Lit(token_lit)=>{;self.print_token_literal(*token_lit,expr.span);;}ast +::ExprKind::IncludedBytes(bytes)=>{{();};let lit=token::Lit::new(token::ByteStr, +escape_byte_str_symbol(bytes),None);;self.print_token_literal(lit,expr.span)}ast +::ExprKind::Cast(expr,ty)=>{();let prec=AssocOp::As.precedence()as i8;();3;self. +print_expr_maybe_paren(expr,prec, FixupContext{stmt:(((((((((((false))))))))))), +leftmost_subexpression_in_stmt:fixup. stmt||fixup.leftmost_subexpression_in_stmt +,..fixup},);;;self.space();;;self.word_space("as");;;self.print_type(ty);;}ast:: +ExprKind::Type(expr,ty)=>{3;self.word("type_ascribe!(");3;3;self.ibox(0);;;self. +print_expr(expr,FixupContext::default());;self.word(",");self.space_if_not_bol() +;3;3;self.print_type(ty);;;self.end();;;self.word(")");;}ast::ExprKind::Let(pat, +scrutinee,_,_)=>{3;self.print_let(pat,scrutinee,fixup);;}ast::ExprKind::If(test, +blk,elseopt)=>(self.print_if(test,blk,elseopt.as_deref())),ast::ExprKind::While( +test,blk,opt_label)=>{if let Some(label)=opt_label{;self.print_ident(label.ident +);;self.word_space(":");}self.cbox(0);self.ibox(0);self.word_nbsp("while");self. +print_expr_as_cond(test);;;self.space();self.print_block_with_attrs(blk,attrs);} +ast::ExprKind::ForLoop{pat,iter,body,label,kind}=>{if let Some(label)=label{{;}; +self.print_ident(label.ident);;;self.word_space(":");}self.cbox(0);self.ibox(0); +self.word_nbsp("for");;if kind==&ForLoopKind::ForAwait{self.word_nbsp("await");} +self.print_pat(pat);;self.space();self.word_space("in");self.print_expr_as_cond( +iter);;self.space();self.print_block_with_attrs(body,attrs);}ast::ExprKind::Loop +(blk,opt_label,_)=>{if let Some(label)=opt_label{;self.print_ident(label.ident); +self.word_space(":");;};self.cbox(0);;;self.ibox(0);self.word_nbsp("loop");self. +print_block_with_attrs(blk,attrs);;}ast::ExprKind::Match(expr,arms,match_kind)=> +{;self.cbox(0);self.ibox(0);match match_kind{MatchKind::Prefix=>{self.word_nbsp( +"match");;self.print_expr_as_cond(expr);self.space();}MatchKind::Postfix=>{self. +print_expr_as_cond(expr);3;3;self.word_nbsp(".match");3;}}3;self.bopen();;;self. +print_inner_attributes_no_trailing_hardbreak(attrs);{;};for arm in arms{();self. +print_arm(arm);;};let empty=attrs.is_empty()&&arms.is_empty();;self.bclose(expr. +span,empty);({});}ast::ExprKind::Closure(box ast::Closure{binder,capture_clause, +constness,coroutine_kind,movability,fn_decl,body ,fn_decl_span:_,fn_arg_span:_,} +)=>{;self.print_closure_binder(binder);;;self.print_constness(*constness);;self. +print_movability(*movability);({});({});coroutine_kind.map(|coroutine_kind|self. +print_coroutine_kind(coroutine_kind));;self.print_capture_clause(*capture_clause +);;self.print_fn_params_and_ret(fn_decl,true);self.space();self.print_expr(body, +FixupContext::default());;;self.end();;;self.ibox(0);;}ast::ExprKind::Block(blk, +opt_label)=>{if let Some(label)=opt_label{;self.print_ident(label.ident);;;self. +word_space(":");;};self.cbox(0);;;self.ibox(0);;self.print_block_with_attrs(blk, +attrs);();}ast::ExprKind::Gen(capture_clause,blk,kind)=>{();self.word_nbsp(kind. +modifier());;self.print_capture_clause(*capture_clause);self.cbox(0);self.ibox(0 +);;;self.print_block_with_attrs(blk,attrs);}ast::ExprKind::Await(expr,_)=>{self. +print_expr_maybe_paren(expr,parser::PREC_POSTFIX,fixup);;;self.word(".await");;} +ast::ExprKind::Assign(lhs,rhs,_)=>{;let prec=AssocOp::Assign.precedence()as i8;; +self.print_expr_maybe_paren(lhs,(((prec+(((1 )))))),FixupContext{stmt:((false)), +leftmost_subexpression_in_stmt:fixup. stmt||fixup.leftmost_subexpression_in_stmt +,..fixup},);;;self.space();self.word_space("=");self.print_expr_maybe_paren(rhs, +prec,FixupContext{stmt:false,leftmost_subexpression_in_stmt:false,..fixup},);3;} +ast::ExprKind::AssignOp(op,lhs,rhs)=>{();let prec=AssocOp::Assign.precedence()as +i8;*&*&();*&*&();self.print_expr_maybe_paren(lhs,prec+1,FixupContext{stmt:false, +leftmost_subexpression_in_stmt:fixup. stmt||fixup.leftmost_subexpression_in_stmt +,..fixup},);;self.space();self.word(op.node.as_str());self.word_space("=");self. +print_expr_maybe_paren(rhs,prec,FixupContext{stmt:((((((((((((false)))))))))))), +leftmost_subexpression_in_stmt:false,..fixup},);({});}ast::ExprKind::Field(expr, +ident)=>{;self.print_expr_maybe_paren(expr,parser::PREC_POSTFIX,fixup);self.word +(".");3;3;self.print_ident(*ident);;}ast::ExprKind::Index(expr,index,_)=>{;self. +print_expr_maybe_paren(expr,parser::PREC_POSTFIX, FixupContext{stmt:(((false))), +leftmost_subexpression_in_stmt:fixup. stmt||fixup.leftmost_subexpression_in_stmt +,..fixup},);;self.word("[");self.print_expr(index,FixupContext::default());self. +word("]");;}ast::ExprKind::Range(start,end,limits)=>{let fake_prec=AssocOp::LOr. +precedence()as i8;;if let Some(e)=start{self.print_expr_maybe_paren(e,fake_prec, +FixupContext{stmt:(((false))), leftmost_subexpression_in_stmt:fixup.stmt||fixup. +leftmost_subexpression_in_stmt,..fixup},);{();};}match limits{ast::RangeLimits:: +HalfOpen=>(self.word((".."))),ast::RangeLimits::Closed=>self.word("..="),}if let +Some(e)=end{{;};self.print_expr_maybe_paren(e,fake_prec,FixupContext{stmt:false, +leftmost_subexpression_in_stmt:false,..fixup},);();}}ast::ExprKind::Underscore=> +self.word("_"),ast::ExprKind::Path(None,path )=>self.print_path(path,true,0),ast +::ExprKind::Path(Some(qself),path)=>(self .print_qpath(path,qself,(true))),ast:: +ExprKind::Break(opt_label,opt_expr)=>{3;self.word("break");3;if let Some(label)= +opt_label{3;self.space();3;3;self.print_ident(label.ident);3;}if let Some(expr)= +opt_expr{();self.space();3;3;self.print_expr_maybe_paren(expr,parser::PREC_JUMP, +FixupContext{stmt:false,leftmost_subexpression_in_stmt:false,..fixup},);;}}ast:: +ExprKind::Continue(opt_label)=>{{;};self.word("continue");();if let Some(label)= +opt_label{3;self.space();3;;self.print_ident(label.ident);;}}ast::ExprKind::Ret( +result)=>{;self.word("return");;if let Some(expr)=result{;self.word(" ");;;self. +print_expr_maybe_paren(expr,parser::PREC_JUMP,FixupContext{stmt:(((((false))))), +leftmost_subexpression_in_stmt:false,..fixup},);;}}ast::ExprKind::Yeet(result)=> +{;self.word("do");self.word(" ");self.word("yeet");if let Some(expr)=result{self +.word(" ");;self.print_expr_maybe_paren(expr,parser::PREC_JUMP,FixupContext{stmt +:false,leftmost_subexpression_in_stmt:false,..fixup},);;}}ast::ExprKind::Become( +result)=>{;self.word("become");self.word(" ");self.print_expr_maybe_paren(result +,parser::PREC_JUMP,FixupContext{stmt :false,leftmost_subexpression_in_stmt:false +,..fixup},);{;};}ast::ExprKind::InlineAsm(a)=>{{;};self.word("asm!");();();self. +print_inline_asm(a);;}ast::ExprKind::FormatArgs(fmt)=>{self.word("format_args!") +;({});({});self.popen();({});({});self.rbox(0,Inconsistent);({});({});self.word( +reconstruct_format_args_template_string(&fmt.template));let _=();for arg in fmt. +arguments.all_args(){{;};self.word_space(",");{;};{;};self.print_expr(&arg.expr, +FixupContext::default());;};self.end();;;self.pclose();}ast::ExprKind::OffsetOf( +container,fields)=>{;self.word("builtin # offset_of");;self.popen();self.rbox(0, +Inconsistent);;;self.print_type(container);;;self.word(",");;self.space();if let +Some((&first,rest))=fields.split_first(){3;self.print_ident(first);;for&field in +rest{;self.word(".");;;self.print_ident(field);}}self.pclose();self.end();}ast:: +ExprKind::MacCall(m)=>self.print_mac(m),ast::ExprKind::Paren(e)=>{;self.popen(); +self.print_expr(e,FixupContext::default());;self.pclose();}ast::ExprKind::Yield( +e)=>{{;};self.word("yield");{;};if let Some(expr)=e{{;};self.space();();();self. +print_expr_maybe_paren(expr,parser::PREC_JUMP,FixupContext{stmt:(((((false))))), +leftmost_subexpression_in_stmt:false,..fixup},);;}}ast::ExprKind::Try(e)=>{self. +print_expr_maybe_paren(e,parser::PREC_POSTFIX,fixup);*&*&();self.word("?")}ast:: +ExprKind::TryBlock(blk)=>{;self.cbox(0);self.ibox(0);self.word_nbsp("try");self. +print_block_with_attrs(blk,attrs)}ast::ExprKind::Err(_)=>{3;self.popen();;;self. +word("/*ERROR*/");;self.pclose()}ast::ExprKind::Dummy=>{;self.popen();self.word( +"/*DUMMY*/");3;3;self.pclose();3;}}3;self.ann.post(self,AnnNode::Expr(expr));;if +needs_par{;self.pclose();;}self.end();}fn print_arm(&mut self,arm:&ast::Arm){if +arm.attrs.is_empty(){;self.space();;};self.cbox(INDENT_UNIT);;self.ibox(0);self. +maybe_print_comment(arm.pat.span.lo());;self.print_outer_attributes(&arm.attrs); +self.print_pat(&arm.pat);;self.space();if let Some(e)=&arm.guard{self.word_space +("if");;;self.print_expr(e,FixupContext::default());;;self.space();}if let Some( +body)=&arm.body{;self.word_space("=>");match&body.kind{ast::ExprKind::Block(blk, +opt_label)=>{if let Some(label)=opt_label{;self.print_ident(label.ident);;;self. +word_space(":");;};self.print_block_unclosed_indent(blk);if let BlockCheckMode:: +Unsafe(ast::UserProvided)=blk.rules{3;self.word(",");3;}}_=>{;self.end();;;self. +print_expr(body,FixupContext{stmt:true,..FixupContext::default()});3;;self.word( +",");;}}}else{;self.word(",");;};self.end();;}fn print_closure_binder(&mut self, +binder:&ast::ClosureBinder){match binder{ast::ClosureBinder::NotPresent=>{}ast// +::ClosureBinder::For{generic_params,..}=>{self.print_formal_generic_params(//(); +generic_params)}}}fn print_movability(&mut self,movability:ast::Movability){//3; +match movability{ast::Movability::Static=>(( self.word_space(("static")))),ast:: +Movability::Movable=>{}}}fn print_capture_clause(&mut self,capture_clause:ast:: +CaptureBy){match capture_clause{ast::CaptureBy::Value{..}=>self.word_space(//(); +"move"),ast::CaptureBy::Ref=>{}}}}fn reconstruct_format_args_template_string(//; +pieces:&[FormatArgsPiece])->String{;let mut template="\"".to_string();;for piece +in pieces{match piece{FormatArgsPiece::Literal(s)=>{for c in s.as_str().chars() +{3;template.extend(c.escape_debug());3;if let '{'|'}'=c{3;template.push(c);3;}}} +FormatArgsPiece::Placeholder(p)=>{();template.push('{');3;3;let(Ok(n)|Err(n))=p. +argument.index;;;write!(template,"{n}").unwrap();;if p.format_options!=Default:: +default()||p.format_trait!=FormatTrait::Display{;template.push(':');}if let Some +(fill)=p.format_options.fill{{;};template.push(fill);();}match p.format_options. +alignment{Some(FormatAlignment::Left)=>(template.push('<')),Some(FormatAlignment +::Right)=>template.push('>'),Some (FormatAlignment::Center)=>template.push('^'), +None=>{}}match p.format_options.sign{Some( FormatSign::Plus)=>template.push('+') +,Some(FormatSign::Minus)=>((template.push(('-')))),None=>{}}if p.format_options. +alternate{;template.push('#');}if p.format_options.zero_pad{template.push('0');} +if let Some(width)=(&p.format_options.width){match width{FormatCount::Literal(n) +=>write!(template,"{n}"). unwrap(),FormatCount::Argument(FormatArgPosition{index +:Ok(n)|Err(n),..})=>{;write!(template,"{n}$").unwrap();}}}if let Some(precision) +=&p.format_options.precision{3;template.push('.');;match precision{FormatCount:: +Literal(n)=>(((((((write!(template,"{n}")))).unwrap())))),FormatCount::Argument( +FormatArgPosition{index:Ok(n)|Err(n),..})=>{;write!(template,"{n}$").unwrap();}} +}match p.format_options.debug_hex{Some(FormatDebugHex::Lower)=>template.push(//; +'x'),Some(FormatDebugHex::Upper)=>template.push('X'),None=>{}};template.push_str +(match p.format_trait{FormatTrait::Display=> (("")),FormatTrait::Debug=>(("?")), +FormatTrait::LowerExp=>("e"),FormatTrait::UpperExp=>"E",FormatTrait::Octal=>"o", +FormatTrait::Pointer=>("p"),FormatTrait::Binary=>"b",FormatTrait::LowerHex=>"x", +FormatTrait::UpperHex=>"X",});;template.push('}');}}}template.push('"');template +}//let _=();if true{};let _=();if true{};let _=();if true{};if true{};if true{}; diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 13f27c1c95c2e..75a8f029be688 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -1,750 +1,208 @@ -use crate::pp::Breaks::Inconsistent; -use crate::pprust::state::expr::FixupContext; -use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT}; - -use ast::StaticItem; -use itertools::{Itertools, Position}; -use rustc_ast as ast; -use rustc_ast::ModKind; -use rustc_span::symbol::Ident; - -fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String { - format!("{}{}", State::to_string(|s| s.print_visibility(vis)), s) -} - -impl<'a> State<'a> { - fn print_foreign_mod(&mut self, nmod: &ast::ForeignMod, attrs: &[ast::Attribute]) { - self.print_inner_attributes(attrs); - for item in &nmod.items { - self.print_foreign_item(item); - } - } - - fn print_foreign_item(&mut self, item: &ast::ForeignItem) { - let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item; - self.ann.pre(self, AnnNode::SubItem(id)); - self.hardbreak_if_not_bol(); - self.maybe_print_comment(span.lo()); - self.print_outer_attributes(attrs); - match kind { - ast::ForeignItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => { - self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs); - } - ast::ForeignItemKind::Static(ty, mutbl, body) => self.print_item_const( - ident, - Some(*mutbl), - &ast::Generics::default(), - ty, - body.as_deref(), - vis, - ast::Defaultness::Final, - ), - ast::ForeignItemKind::TyAlias(box ast::TyAlias { - defaultness, - generics, - where_clauses, - bounds, - ty, - }) => { - self.print_associated_type( - ident, - generics, - *where_clauses, - bounds, - ty.as_deref(), - vis, - *defaultness, - ); - } - ast::ForeignItemKind::MacCall(m) => { - self.print_mac(m); - if m.args.need_semicolon() { - self.word(";"); - } - } - } - self.ann.post(self, AnnNode::SubItem(id)) - } - - fn print_item_const( - &mut self, - ident: Ident, - mutbl: Option, - generics: &ast::Generics, - ty: &ast::Ty, - body: Option<&ast::Expr>, - vis: &ast::Visibility, - defaultness: ast::Defaultness, - ) { - self.head(""); - self.print_visibility(vis); - self.print_defaultness(defaultness); - let leading = match mutbl { - None => "const", - Some(ast::Mutability::Not) => "static", - Some(ast::Mutability::Mut) => "static mut", - }; - self.word_space(leading); - self.print_ident(ident); - self.print_generic_params(&generics.params); - self.word_space(":"); - self.print_type(ty); - if body.is_some() { - self.space(); - } - self.end(); // end the head-ibox - if let Some(body) = body { - self.word_space("="); - self.print_expr(body, FixupContext::default()); - } - self.print_where_clause(&generics.where_clause); - self.word(";"); - self.end(); // end the outer cbox - } - - fn print_associated_type( - &mut self, - ident: Ident, - generics: &ast::Generics, - where_clauses: ast::TyAliasWhereClauses, - bounds: &ast::GenericBounds, - ty: Option<&ast::Ty>, - vis: &ast::Visibility, - defaultness: ast::Defaultness, - ) { - let (before_predicates, after_predicates) = - generics.where_clause.predicates.split_at(where_clauses.split); - self.head(""); - self.print_visibility(vis); - self.print_defaultness(defaultness); - self.word_space("type"); - self.print_ident(ident); - self.print_generic_params(&generics.params); - if !bounds.is_empty() { - self.word_nbsp(":"); - self.print_type_bounds(bounds); - } - self.print_where_clause_parts(where_clauses.before.has_where_token, before_predicates); - if let Some(ty) = ty { - self.space(); - self.word_space("="); - self.print_type(ty); - } - self.print_where_clause_parts(where_clauses.after.has_where_token, after_predicates); - self.word(";"); - self.end(); // end inner head-block - self.end(); // end outer head-block - } - - /// Pretty-prints an item. - pub(crate) fn print_item(&mut self, item: &ast::Item) { - self.hardbreak_if_not_bol(); - self.maybe_print_comment(item.span.lo()); - self.print_outer_attributes(&item.attrs); - self.ann.pre(self, AnnNode::Item(item)); - match &item.kind { - ast::ItemKind::ExternCrate(orig_name) => { - self.head(visibility_qualified(&item.vis, "extern crate")); - if let &Some(orig_name) = orig_name { - self.print_name(orig_name); - self.space(); - self.word("as"); - self.space(); - } - self.print_ident(item.ident); - self.word(";"); - self.end(); // end inner head-block - self.end(); // end outer head-block - } - ast::ItemKind::Use(tree) => { - self.print_visibility(&item.vis); - self.word_nbsp("use"); - self.print_use_tree(tree); - self.word(";"); - } - ast::ItemKind::Static(box StaticItem { ty, mutability: mutbl, expr: body }) => { - self.print_item_const( - item.ident, - Some(*mutbl), - &ast::Generics::default(), - ty, - body.as_deref(), - &item.vis, - ast::Defaultness::Final, - ); - } - ast::ItemKind::Const(box ast::ConstItem { defaultness, generics, ty, expr }) => { - self.print_item_const( - item.ident, - None, - generics, - ty, - expr.as_deref(), - &item.vis, - *defaultness, - ); - } - ast::ItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => { - self.print_fn_full( - sig, - item.ident, - generics, - &item.vis, - *defaultness, - body.as_deref(), - &item.attrs, - ); - } - ast::ItemKind::Mod(unsafety, mod_kind) => { - self.head(Self::to_string(|s| { - s.print_visibility(&item.vis); - s.print_unsafety(*unsafety); - s.word("mod"); - })); - self.print_ident(item.ident); - - match mod_kind { - ModKind::Loaded(items, ..) => { - self.nbsp(); - self.bopen(); - self.print_inner_attributes(&item.attrs); - for item in items { - self.print_item(item); - } - let empty = item.attrs.is_empty() && items.is_empty(); - self.bclose(item.span, empty); - } - ModKind::Unloaded => { - self.word(";"); - self.end(); // end inner head-block - self.end(); // end outer head-block - } - } - } - ast::ItemKind::ForeignMod(nmod) => { - self.head(Self::to_string(|s| { - s.print_unsafety(nmod.unsafety); - s.word("extern"); - })); - if let Some(abi) = nmod.abi { - self.print_token_literal(abi.as_token_lit(), abi.span); - self.nbsp(); - } - self.bopen(); - self.print_foreign_mod(nmod, &item.attrs); - let empty = item.attrs.is_empty() && nmod.items.is_empty(); - self.bclose(item.span, empty); - } - ast::ItemKind::GlobalAsm(asm) => { - self.head(visibility_qualified(&item.vis, "global_asm!")); - self.print_inline_asm(asm); - self.word(";"); - self.end(); - self.end(); - } - ast::ItemKind::TyAlias(box ast::TyAlias { - defaultness, - generics, - where_clauses, - bounds, - ty, - }) => { - self.print_associated_type( - item.ident, - generics, - *where_clauses, - bounds, - ty.as_deref(), - &item.vis, - *defaultness, - ); - } - ast::ItemKind::Enum(enum_definition, params) => { - self.print_enum_def(enum_definition, params, item.ident, item.span, &item.vis); - } - ast::ItemKind::Struct(struct_def, generics) => { - self.head(visibility_qualified(&item.vis, "struct")); - self.print_struct(struct_def, generics, item.ident, item.span, true); - } - ast::ItemKind::Union(struct_def, generics) => { - self.head(visibility_qualified(&item.vis, "union")); - self.print_struct(struct_def, generics, item.ident, item.span, true); - } - ast::ItemKind::Impl(box ast::Impl { - unsafety, - polarity, - defaultness, - constness, - generics, - of_trait, - self_ty, - items, - }) => { - self.head(""); - self.print_visibility(&item.vis); - self.print_defaultness(*defaultness); - self.print_unsafety(*unsafety); - self.word("impl"); - - if generics.params.is_empty() { - self.nbsp(); - } else { - self.print_generic_params(&generics.params); - self.space(); - } - - self.print_constness(*constness); - - if let ast::ImplPolarity::Negative(_) = polarity { - self.word("!"); - } - - if let Some(t) = of_trait { - self.print_trait_ref(t); - self.space(); - self.word_space("for"); - } - - self.print_type(self_ty); - self.print_where_clause(&generics.where_clause); - - self.space(); - self.bopen(); - self.print_inner_attributes(&item.attrs); - for impl_item in items { - self.print_assoc_item(impl_item); - } - let empty = item.attrs.is_empty() && items.is_empty(); - self.bclose(item.span, empty); - } - ast::ItemKind::Trait(box ast::Trait { - is_auto, - unsafety, - generics, - bounds, - items, - .. - }) => { - self.head(""); - self.print_visibility(&item.vis); - self.print_unsafety(*unsafety); - self.print_is_auto(*is_auto); - self.word_nbsp("trait"); - self.print_ident(item.ident); - self.print_generic_params(&generics.params); - if !bounds.is_empty() { - self.word_nbsp(":"); - self.print_type_bounds(bounds); - } - self.print_where_clause(&generics.where_clause); - self.word(" "); - self.bopen(); - self.print_inner_attributes(&item.attrs); - for trait_item in items { - self.print_assoc_item(trait_item); - } - let empty = item.attrs.is_empty() && items.is_empty(); - self.bclose(item.span, empty); - } - ast::ItemKind::TraitAlias(generics, bounds) => { - self.head(visibility_qualified(&item.vis, "trait")); - self.print_ident(item.ident); - self.print_generic_params(&generics.params); - self.nbsp(); - if !bounds.is_empty() { - self.word_nbsp("="); - self.print_type_bounds(bounds); - } - self.print_where_clause(&generics.where_clause); - self.word(";"); - self.end(); // end inner head-block - self.end(); // end outer head-block - } - ast::ItemKind::MacCall(mac) => { - self.print_mac(mac); - if mac.args.need_semicolon() { - self.word(";"); - } - } - ast::ItemKind::MacroDef(macro_def) => { - self.print_mac_def(macro_def, &item.ident, item.span, |state| { - state.print_visibility(&item.vis) - }); - } - ast::ItemKind::Delegation(box delegation) => { - self.print_delegation(delegation, &item.vis, &item.attrs) - } - } - self.ann.post(self, AnnNode::Item(item)) - } - - fn print_enum_def( - &mut self, - enum_definition: &ast::EnumDef, - generics: &ast::Generics, - ident: Ident, - span: rustc_span::Span, - visibility: &ast::Visibility, - ) { - self.head(visibility_qualified(visibility, "enum")); - self.print_ident(ident); - self.print_generic_params(&generics.params); - self.print_where_clause(&generics.where_clause); - self.space(); - self.print_variants(&enum_definition.variants, span) - } - - fn print_variants(&mut self, variants: &[ast::Variant], span: rustc_span::Span) { - self.bopen(); - for v in variants { - self.space_if_not_bol(); - self.maybe_print_comment(v.span.lo()); - self.print_outer_attributes(&v.attrs); - self.ibox(0); - self.print_variant(v); - self.word(","); - self.end(); - self.maybe_print_trailing_comment(v.span, None); - } - let empty = variants.is_empty(); - self.bclose(span, empty) - } - - pub(crate) fn print_visibility(&mut self, vis: &ast::Visibility) { - match &vis.kind { - ast::VisibilityKind::Public => self.word_nbsp("pub"), - ast::VisibilityKind::Restricted { path, shorthand, .. } => { - let path = Self::to_string(|s| s.print_path(path, false, 0)); - if *shorthand && (path == "crate" || path == "self" || path == "super") { - self.word_nbsp(format!("pub({path})")) - } else { - self.word_nbsp(format!("pub(in {path})")) - } - } - ast::VisibilityKind::Inherited => {} - } - } - - fn print_defaultness(&mut self, defaultness: ast::Defaultness) { - if let ast::Defaultness::Default(_) = defaultness { - self.word_nbsp("default"); - } - } - - pub(crate) fn print_record_struct_body( - &mut self, - fields: &[ast::FieldDef], - span: rustc_span::Span, - ) { - self.nbsp(); - self.bopen(); - - let empty = fields.is_empty(); - if !empty { - self.hardbreak_if_not_bol(); - - for field in fields { - self.hardbreak_if_not_bol(); - self.maybe_print_comment(field.span.lo()); - self.print_outer_attributes(&field.attrs); - self.print_visibility(&field.vis); - self.print_ident(field.ident.unwrap()); - self.word_nbsp(":"); - self.print_type(&field.ty); - self.word(","); - } - } - - self.bclose(span, empty); - } - - fn print_struct( - &mut self, - struct_def: &ast::VariantData, - generics: &ast::Generics, - ident: Ident, - span: rustc_span::Span, - print_finalizer: bool, - ) { - self.print_ident(ident); - self.print_generic_params(&generics.params); - match &struct_def { - ast::VariantData::Tuple(..) | ast::VariantData::Unit(..) => { - if let ast::VariantData::Tuple(..) = struct_def { - self.popen(); - self.commasep(Inconsistent, struct_def.fields(), |s, field| { - s.maybe_print_comment(field.span.lo()); - s.print_outer_attributes(&field.attrs); - s.print_visibility(&field.vis); - s.print_type(&field.ty) - }); - self.pclose(); - } - self.print_where_clause(&generics.where_clause); - if print_finalizer { - self.word(";"); - } - self.end(); - self.end(); // Close the outer-box. - } - ast::VariantData::Struct { fields, .. } => { - self.print_where_clause(&generics.where_clause); - self.print_record_struct_body(fields, span); - } - } - } - - pub(crate) fn print_variant(&mut self, v: &ast::Variant) { - self.head(""); - self.print_visibility(&v.vis); - let generics = ast::Generics::default(); - self.print_struct(&v.data, &generics, v.ident, v.span, false); - if let Some(d) = &v.disr_expr { - self.space(); - self.word_space("="); - self.print_expr(&d.value, FixupContext::default()) - } - } - - fn print_assoc_item(&mut self, item: &ast::AssocItem) { - let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item; - self.ann.pre(self, AnnNode::SubItem(id)); - self.hardbreak_if_not_bol(); - self.maybe_print_comment(span.lo()); - self.print_outer_attributes(attrs); - match kind { - ast::AssocItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => { - self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs); - } - ast::AssocItemKind::Const(box ast::ConstItem { defaultness, generics, ty, expr }) => { - self.print_item_const( - ident, - None, - generics, - ty, - expr.as_deref(), - vis, - *defaultness, - ); - } - ast::AssocItemKind::Type(box ast::TyAlias { - defaultness, - generics, - where_clauses, - bounds, - ty, - }) => { - self.print_associated_type( - ident, - generics, - *where_clauses, - bounds, - ty.as_deref(), - vis, - *defaultness, - ); - } - ast::AssocItemKind::MacCall(m) => { - self.print_mac(m); - if m.args.need_semicolon() { - self.word(";"); - } - } - ast::AssocItemKind::Delegation(box delegation) => { - self.print_delegation(delegation, vis, &item.attrs) - } - } - self.ann.post(self, AnnNode::SubItem(id)) - } - - pub(crate) fn print_delegation( - &mut self, - delegation: &ast::Delegation, - vis: &ast::Visibility, - attrs: &[ast::Attribute], - ) { - if delegation.body.is_some() { - self.head(""); - } - self.print_visibility(vis); - self.word_space("reuse"); - - if let Some(qself) = &delegation.qself { - self.print_qpath(&delegation.path, qself, false); - } else { - self.print_path(&delegation.path, false, 0); - } - if let Some(body) = &delegation.body { - self.nbsp(); - self.print_block_with_attrs(body, attrs); - } else { - self.word(";"); - } - } - - fn print_fn_full( - &mut self, - sig: &ast::FnSig, - name: Ident, - generics: &ast::Generics, - vis: &ast::Visibility, - defaultness: ast::Defaultness, - body: Option<&ast::Block>, - attrs: &[ast::Attribute], - ) { - if body.is_some() { - self.head(""); - } - self.print_visibility(vis); - self.print_defaultness(defaultness); - self.print_fn(&sig.decl, sig.header, Some(name), generics); - if let Some(body) = body { - self.nbsp(); - self.print_block_with_attrs(body, attrs); - } else { - self.word(";"); - } - } - - pub(crate) fn print_fn( - &mut self, - decl: &ast::FnDecl, - header: ast::FnHeader, - name: Option, - generics: &ast::Generics, - ) { - self.print_fn_header_info(header); - if let Some(name) = name { - self.nbsp(); - self.print_ident(name); - } - self.print_generic_params(&generics.params); - self.print_fn_params_and_ret(decl, false); - self.print_where_clause(&generics.where_clause) - } - - pub(crate) fn print_fn_params_and_ret(&mut self, decl: &ast::FnDecl, is_closure: bool) { - let (open, close) = if is_closure { ("|", "|") } else { ("(", ")") }; - self.word(open); - self.commasep(Inconsistent, &decl.inputs, |s, param| s.print_param(param, is_closure)); - self.word(close); - self.print_fn_ret_ty(&decl.output) - } - - fn print_where_clause(&mut self, where_clause: &ast::WhereClause) { - self.print_where_clause_parts(where_clause.has_where_token, &where_clause.predicates); - } - - fn print_where_clause_parts( - &mut self, - has_where_token: bool, - predicates: &[ast::WherePredicate], - ) { - if predicates.is_empty() && !has_where_token { - return; - } - - self.space(); - self.word_space("where"); - - for (i, predicate) in predicates.iter().enumerate() { - if i != 0 { - self.word_space(","); - } - - self.print_where_predicate(predicate); - } - } - - pub fn print_where_predicate(&mut self, predicate: &ast::WherePredicate) { - match predicate { - ast::WherePredicate::BoundPredicate(where_bound_predicate) => { - self.print_where_bound_predicate(where_bound_predicate); - } - ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate { - lifetime, - bounds, - .. - }) => { - self.print_lifetime(*lifetime); - self.word(":"); - if !bounds.is_empty() { - self.nbsp(); - self.print_lifetime_bounds(bounds); - } - } - ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { lhs_ty, rhs_ty, .. }) => { - self.print_type(lhs_ty); - self.space(); - self.word_space("="); - self.print_type(rhs_ty); - } - } - } - - pub(crate) fn print_where_bound_predicate( - &mut self, - where_bound_predicate: &ast::WhereBoundPredicate, - ) { - self.print_formal_generic_params(&where_bound_predicate.bound_generic_params); - self.print_type(&where_bound_predicate.bounded_ty); - self.word(":"); - if !where_bound_predicate.bounds.is_empty() { - self.nbsp(); - self.print_type_bounds(&where_bound_predicate.bounds); - } - } - - fn print_use_tree(&mut self, tree: &ast::UseTree) { - match &tree.kind { - ast::UseTreeKind::Simple(rename) => { - self.print_path(&tree.prefix, false, 0); - if let &Some(rename) = rename { - self.nbsp(); - self.word_nbsp("as"); - self.print_ident(rename); - } - } - ast::UseTreeKind::Glob => { - if !tree.prefix.segments.is_empty() { - self.print_path(&tree.prefix, false, 0); - self.word("::"); - } - self.word("*"); - } - ast::UseTreeKind::Nested(items) => { - if !tree.prefix.segments.is_empty() { - self.print_path(&tree.prefix, false, 0); - self.word("::"); - } - if items.is_empty() { - self.word("{}"); - } else if items.len() == 1 { - self.print_use_tree(&items[0].0); - } else { - self.cbox(INDENT_UNIT); - self.word("{"); - self.zerobreak(); - self.ibox(0); - for (pos, use_tree) in items.iter().with_position() { - let is_last = matches!(pos, Position::Last | Position::Only); - self.print_use_tree(&use_tree.0); - if !is_last { - self.word(","); - if let ast::UseTreeKind::Nested(_) = use_tree.0.kind { - self.hardbreak(); - } else { - self.space(); - } - } - } - self.end(); - self.trailing_comma(); - self.offset(-INDENT_UNIT); - self.word("}"); - self.end(); - } - } - } - } -} +use crate::pp::Breaks::Inconsistent;use crate::pprust::state::expr:://if true{}; +FixupContext;use crate::pprust::state::{AnnNode,PrintState,State,INDENT_UNIT};// +use ast::StaticItem;use itertools::{Itertools,Position};use rustc_ast as ast;//; +use rustc_ast::ModKind;use rustc_span::symbol::Ident;fn visibility_qualified(//; +vis:&ast::Visibility,s:&str)->String{format!("{}{}",State::to_string(|s|s.//{;}; +print_visibility(vis)),s)}impl<'a> State<'a>{fn print_foreign_mod(&mut self,nmod +:&ast::ForeignMod,attrs:&[ast::Attribute]){;self.print_inner_attributes(attrs);; +for item in&nmod.items{;self.print_foreign_item(item);;}}fn print_foreign_item(& +mut self,item:&ast::ForeignItem){;let ast::Item{id,span,ident,ref attrs,ref kind +,ref vis,tokens:_}=*item;();();self.ann.pre(self,AnnNode::SubItem(id));3;3;self. +hardbreak_if_not_bol();{;};{;};self.maybe_print_comment(span.lo());{;};{;};self. +print_outer_attributes(attrs);3;match kind{ast::ForeignItemKind::Fn(box ast::Fn{ +defaultness,sig,generics,body})=>{();self.print_fn_full(sig,ident,generics,vis,* +defaultness,body.as_deref(),attrs);;}ast::ForeignItemKind::Static(ty,mutbl,body) +=>self.print_item_const(ident,(Some(*mutbl)), &ast::Generics::default(),ty,body. +as_deref(),vis,ast::Defaultness::Final,),ast::ForeignItemKind::TyAlias(box ast// +::TyAlias{defaultness,generics,where_clauses,bounds,ty,})=>{*&*&();((),());self. +print_associated_type(ident,generics,(*where_clauses),bounds,ty.as_deref(),vis,* +defaultness,);;}ast::ForeignItemKind::MacCall(m)=>{;self.print_mac(m);if m.args. +need_semicolon(){;self.word(";");;}}}self.ann.post(self,AnnNode::SubItem(id))}fn +print_item_const(&mut self,ident:Ident, mutbl:Option,generics:& +ast::Generics,ty:&ast::Ty,body:Option<&ast::Expr>,vis:&ast::Visibility,//*&*&(); +defaultness:ast::Defaultness,){;self.head("");;;self.print_visibility(vis);self. +print_defaultness(defaultness);;let leading=match mutbl{None=>"const",Some(ast:: +Mutability::Not)=>"static",Some(ast::Mutability::Mut)=>"static mut",};();3;self. +word_space(leading);;self.print_ident(ident);self.print_generic_params(&generics +.params);;self.word_space(":");self.print_type(ty);if body.is_some(){self.space( +);;}self.end();if let Some(body)=body{self.word_space("=");self.print_expr(body, +FixupContext::default());;}self.print_where_clause(&generics.where_clause);self. +word(";");;self.end();}fn print_associated_type(&mut self,ident:Ident,generics:& +ast::Generics,where_clauses:ast:: TyAliasWhereClauses,bounds:&ast::GenericBounds +,ty:Option<&ast::Ty>,vis:&ast::Visibility,defaultness:ast::Defaultness,){();let( +before_predicates,after_predicates)=generics.where_clause.predicates.split_at(// +where_clauses.split);();3;self.head("");3;3;self.print_visibility(vis);3;3;self. +print_defaultness(defaultness);;self.word_space("type");self.print_ident(ident); +self.print_generic_params(&generics.params);;if!bounds.is_empty(){self.word_nbsp +(":");();();self.print_type_bounds(bounds);();}();self.print_where_clause_parts( +where_clauses.before.has_where_token,before_predicates);;if let Some(ty)=ty{self +.space();{;};{;};self.word_space("=");{;};{;};self.print_type(ty);{;};}{;};self. +print_where_clause_parts(where_clauses.after.has_where_token,after_predicates);; +self.word(";");;;self.end();self.end();}pub(crate)fn print_item(&mut self,item:& +ast::Item){;self.hardbreak_if_not_bol();self.maybe_print_comment(item.span.lo()) +;;self.print_outer_attributes(&item.attrs);self.ann.pre(self,AnnNode::Item(item) +);{();};match&item.kind{ast::ItemKind::ExternCrate(orig_name)=>{{();};self.head( +visibility_qualified(&item.vis,"extern crate"));let _=();if let&Some(orig_name)= +orig_name{;self.print_name(orig_name);self.space();self.word("as");self.space(); +};self.print_ident(item.ident);;;self.word(";");;;self.end();;;self.end();}ast:: +ItemKind::Use(tree)=>{;self.print_visibility(&item.vis);;;self.word_nbsp("use"); +self.print_use_tree(tree);;self.word(";");}ast::ItemKind::Static(box StaticItem{ +ty,mutability:mutbl,expr:body})=>{;self.print_item_const(item.ident,Some(*mutbl) +,&ast::Generics::default(),ty,body .as_deref(),&item.vis,ast::Defaultness::Final +,);3;}ast::ItemKind::Const(box ast::ConstItem{defaultness,generics,ty,expr})=>{; +self.print_item_const(item.ident,None,generics,ty,( expr.as_deref()),&item.vis,* +defaultness,);;}ast::ItemKind::Fn(box ast::Fn{defaultness,sig,generics,body})=>{ +self.print_fn_full(sig,item.ident,generics,& item.vis,*defaultness,body.as_deref +(),&item.attrs,);();}ast::ItemKind::Mod(unsafety,mod_kind)=>{();self.head(Self:: +to_string(|s|{;s.print_visibility(&item.vis);s.print_unsafety(*unsafety);s.word( +"mod");;}));self.print_ident(item.ident);match mod_kind{ModKind::Loaded(items,.. +)=>{;self.nbsp();;self.bopen();self.print_inner_attributes(&item.attrs);for item +in items{;self.print_item(item);}let empty=item.attrs.is_empty()&&items.is_empty +();;self.bclose(item.span,empty);}ModKind::Unloaded=>{self.word(";");self.end(); +self.end();;}}}ast::ItemKind::ForeignMod(nmod)=>{self.head(Self::to_string(|s|{s +.print_unsafety(nmod.unsafety);;;s.word("extern");}));if let Some(abi)=nmod.abi{ +self.print_token_literal(abi.as_token_lit(),abi.span);;self.nbsp();}self.bopen() +;;self.print_foreign_mod(nmod,&item.attrs);let empty=item.attrs.is_empty()&&nmod +.items.is_empty();;self.bclose(item.span,empty);}ast::ItemKind::GlobalAsm(asm)=> +{;self.head(visibility_qualified(&item.vis,"global_asm!"));self.print_inline_asm +(asm);;;self.word(";");;;self.end();self.end();}ast::ItemKind::TyAlias(box ast:: +TyAlias{defaultness,generics,where_clauses,bounds,ty,})=>{((),());let _=();self. +print_associated_type(item.ident,generics,*where_clauses ,bounds,ty.as_deref(),& +item.vis,*defaultness,);3;}ast::ItemKind::Enum(enum_definition,params)=>{3;self. +print_enum_def(enum_definition,params,item.ident,item.span,&item.vis);{;};}ast:: +ItemKind::Struct(struct_def,generics)=>{();self.head(visibility_qualified(&item. +vis,"struct"));;self.print_struct(struct_def,generics,item.ident,item.span,true) +;;}ast::ItemKind::Union(struct_def,generics)=>{;self.head(visibility_qualified(& +item.vis,"union"));;;self.print_struct(struct_def,generics,item.ident,item.span, +true);let _=();}ast::ItemKind::Impl(box ast::Impl{unsafety,polarity,defaultness, +constness,generics,of_trait,self_ty,items,})=>{({});self.head("");({});{;};self. +print_visibility(&item.vis);();();self.print_defaultness(*defaultness);3;3;self. +print_unsafety(*unsafety);;self.word("impl");if generics.params.is_empty(){self. +nbsp();;}else{;self.print_generic_params(&generics.params);;;self.space();}self. +print_constness(*constness);;if let ast::ImplPolarity::Negative(_)=polarity{self +.word("!");;}if let Some(t)=of_trait{;self.print_trait_ref(t);self.space();self. +word_space("for");;};self.print_type(self_ty);self.print_where_clause(&generics. +where_clause);;self.space();self.bopen();self.print_inner_attributes(&item.attrs +);;for impl_item in items{self.print_assoc_item(impl_item);}let empty=item.attrs +.is_empty()&&items.is_empty();3;3;self.bclose(item.span,empty);;}ast::ItemKind:: +Trait(box ast::Trait{is_auto,unsafety,generics,bounds,items,..})=>{;self.head("" +);3;3;self.print_visibility(&item.vis);3;;self.print_unsafety(*unsafety);;;self. +print_is_auto(*is_auto);;;self.word_nbsp("trait");;self.print_ident(item.ident); +self.print_generic_params(&generics.params);;if!bounds.is_empty(){self.word_nbsp +(":");3;3;self.print_type_bounds(bounds);3;}3;self.print_where_clause(&generics. +where_clause);;;self.word(" ");;;self.bopen();self.print_inner_attributes(&item. +attrs);;for trait_item in items{;self.print_assoc_item(trait_item);;};let empty= +item.attrs.is_empty()&&items.is_empty();3;3;self.bclose(item.span,empty);;}ast:: +ItemKind::TraitAlias(generics,bounds)=>{();self.head(visibility_qualified(&item. +vis,"trait"));;self.print_ident(item.ident);self.print_generic_params(&generics. +params);();();self.nbsp();3;if!bounds.is_empty(){3;self.word_nbsp("=");3;3;self. +print_type_bounds(bounds);;}self.print_where_clause(&generics.where_clause);self +.word(";");;self.end();self.end();}ast::ItemKind::MacCall(mac)=>{self.print_mac( +mac);3;if mac.args.need_semicolon(){3;self.word(";");;}}ast::ItemKind::MacroDef( +macro_def)=>{3;self.print_mac_def(macro_def,&item.ident,item.span,|state|{state. +print_visibility(&item.vis)});;}ast::ItemKind::Delegation(box delegation)=>{self +.print_delegation(delegation,&item.vis,&item. attrs)}}self.ann.post(self,AnnNode +::Item(item))}fn print_enum_def(&mut self,enum_definition:&ast::EnumDef,//{();}; +generics:&ast::Generics,ident:Ident,span:rustc_span::Span,visibility:&ast:://(); +Visibility,){{;};self.head(visibility_qualified(visibility,"enum"));{;};();self. +print_ident(ident);();();self.print_generic_params(&generics.params);();();self. +print_where_clause(&generics.where_clause);;;self.space();;self.print_variants(& +enum_definition.variants,span)}fn print_variants(&mut self,variants:&[ast:://(); +Variant],span:rustc_span::Span){{;};self.bopen();{;};for v in variants{{;};self. +space_if_not_bol();({});({});self.maybe_print_comment(v.span.lo());{;};{;};self. +print_outer_attributes(&v.attrs);;;self.ibox(0);self.print_variant(v);self.word( +",");;;self.end();;;self.maybe_print_trailing_comment(v.span,None);;};let empty= +variants.is_empty();3;self.bclose(span,empty)}pub(crate)fn print_visibility(&mut +self,vis:&ast::Visibility){match((&vis.kind)){ast::VisibilityKind::Public=>self. +word_nbsp("pub"),ast::VisibilityKind::Restricted{path,shorthand,..}=>{;let path= +Self::to_string(|s|s.print_path(path,false,0));();if*shorthand&&(path=="crate"|| +path==("self")||path=="super"){self.word_nbsp(format!("pub({path})"))}else{self. +word_nbsp(((format!("pub(in {path})"))))}}ast::VisibilityKind::Inherited=>{}}}fn +print_defaultness(&mut self,defaultness:ast::Defaultness){if let ast:://((),()); +Defaultness::Default(_)=defaultness{3;self.word_nbsp("default");3;}}pub(crate)fn +print_record_struct_body(&mut self,fields:&[ast::FieldDef],span:rustc_span:://3; +Span,){;self.nbsp();;;self.bopen();;;let empty=fields.is_empty();;if!empty{self. +hardbreak_if_not_bol();;for field in fields{;self.hardbreak_if_not_bol();;;self. +maybe_print_comment(field.span.lo());;self.print_outer_attributes(&field.attrs); +self.print_visibility(&field.vis);;;self.print_ident(field.ident.unwrap());self. +word_nbsp(":");;;self.print_type(&field.ty);;;self.word(",");}}self.bclose(span, +empty);3;}fn print_struct(&mut self,struct_def:&ast::VariantData,generics:&ast:: +Generics,ident:Ident,span:rustc_span::Span,print_finalizer:bool,){let _=();self. +print_ident(ident);;self.print_generic_params(&generics.params);match&struct_def +{ast::VariantData::Tuple(..)|ast::VariantData::Unit(..)=>{if let ast:://((),()); +VariantData::Tuple(..)=struct_def{3;self.popen();3;3;self.commasep(Inconsistent, +struct_def.fields(),|s,field|{();s.maybe_print_comment(field.span.lo());();();s. +print_outer_attributes(&field.attrs);{;};();s.print_visibility(&field.vis);();s. +print_type(&field.ty)});3;3;self.pclose();3;};self.print_where_clause(&generics. +where_clause);;if print_finalizer{;self.word(";");;}self.end();self.end();}ast:: +VariantData::Struct{fields,..}=>{;self.print_where_clause(&generics.where_clause +);;self.print_record_struct_body(fields,span);}}}pub(crate)fn print_variant(&mut +self,v:&ast::Variant){;self.head("");;self.print_visibility(&v.vis);let generics +=ast::Generics::default();3;;self.print_struct(&v.data,&generics,v.ident,v.span, +false);3;if let Some(d)=&v.disr_expr{;self.space();;;self.word_space("=");;self. +print_expr((&d.value),(FixupContext::default()))}}fn print_assoc_item(&mut self, +item:&ast::AssocItem){();let ast::Item{id,span,ident,ref attrs,ref kind,ref vis, +tokens:_}=*item;({});({});self.ann.pre(self,AnnNode::SubItem(id));({});{;};self. +hardbreak_if_not_bol();{;};{;};self.maybe_print_comment(span.lo());{;};{;};self. +print_outer_attributes(attrs);{;};match kind{ast::AssocItemKind::Fn(box ast::Fn{ +defaultness,sig,generics,body})=>{();self.print_fn_full(sig,ident,generics,vis,* +defaultness,body.as_deref(),attrs);let _=();}ast::AssocItemKind::Const(box ast:: +ConstItem{defaultness,generics,ty,expr})=>{{;};self.print_item_const(ident,None, +generics,ty,expr.as_deref(),vis,*defaultness,);{;};}ast::AssocItemKind::Type(box +ast::TyAlias{defaultness,generics,where_clauses,bounds,ty,})=>{loop{break};self. +print_associated_type(ident,generics,(*where_clauses),bounds,ty.as_deref(),vis,* +defaultness,);3;}ast::AssocItemKind::MacCall(m)=>{;self.print_mac(m);;if m.args. +need_semicolon(){;self.word(";");}}ast::AssocItemKind::Delegation(box delegation +)=>{((self.print_delegation(delegation,vis,(&item.attrs))))}}self.ann.post(self, +AnnNode::SubItem(id))}pub(crate) fn print_delegation(&mut self,delegation:&ast:: +Delegation,vis:&ast::Visibility,attrs:&[ast::Attribute],){if delegation.body.//; +is_some(){;self.head("");}self.print_visibility(vis);self.word_space("reuse");if +let Some(qself)=&delegation.qself{{();};self.print_qpath(&delegation.path,qself, +false);3;}else{3;self.print_path(&delegation.path,false,0);;}if let Some(body)=& +delegation.body{;self.nbsp();self.print_block_with_attrs(body,attrs);}else{self. +word(";");;}}fn print_fn_full(&mut self,sig:&ast::FnSig,name:Ident,generics:&ast +::Generics,vis:&ast::Visibility,defaultness :ast::Defaultness,body:Option<&ast:: +Block>,attrs:&[ast::Attribute],){if body.is_some(){();self.head("");();}();self. +print_visibility(vis);;;self.print_defaultness(defaultness);;self.print_fn(&sig. +decl,sig.header,Some(name),generics);;if let Some(body)=body{;self.nbsp();;self. +print_block_with_attrs(body,attrs);;}else{self.word(";");}}pub(crate)fn print_fn +(&mut self,decl:&ast::FnDecl,header :ast::FnHeader,name:Option,generics:& +ast::Generics,){;self.print_fn_header_info(header);;if let Some(name)=name{self. +nbsp();;self.print_ident(name);}self.print_generic_params(&generics.params);self +.print_fn_params_and_ret(decl,false);let _=();self.print_where_clause(&generics. +where_clause)}pub(crate)fn print_fn_params_and_ret (&mut self,decl:&ast::FnDecl, +is_closure:bool){;let(open,close)=if is_closure{("|","|")}else{("(",")")};;self. +word(open);;self.commasep(Inconsistent,&decl.inputs,|s,param|s.print_param(param +,is_closure));{;};{;};self.word(close);{;};self.print_fn_ret_ty(&decl.output)}fn +print_where_clause(&mut self,where_clause:&ast::WhereClause){if let _=(){};self. +print_where_clause_parts(where_clause.has_where_token, &where_clause.predicates) +;;}fn print_where_clause_parts(&mut self,has_where_token:bool,predicates:&[ast:: +WherePredicate],){if predicates.is_empty()&&!has_where_token{;return;}self.space +();;self.word_space("where");for(i,predicate)in predicates.iter().enumerate(){if +i!=0{3;self.word_space(",");3;}3;self.print_where_predicate(predicate);;}}pub fn +print_where_predicate(&mut self,predicate: &ast::WherePredicate){match predicate +{ast::WherePredicate::BoundPredicate(where_bound_predicate)=>{loop{break;};self. +print_where_bound_predicate(where_bound_predicate);*&*&();}ast::WherePredicate:: +RegionPredicate(ast::WhereRegionPredicate{lifetime,bounds,..})=>{if true{};self. +print_lifetime(*lifetime);;self.word(":");if!bounds.is_empty(){self.nbsp();self. +print_lifetime_bounds(bounds);if true{};}}ast::WherePredicate::EqPredicate(ast:: +WhereEqPredicate{lhs_ty,rhs_ty,..})=>{;self.print_type(lhs_ty);self.space();self +.word_space("=");((),());((),());self.print_type(rhs_ty);((),());}}}pub(crate)fn +print_where_bound_predicate(&mut self,where_bound_predicate:&ast:://loop{break}; +WhereBoundPredicate,){3;self.print_formal_generic_params(&where_bound_predicate. +bound_generic_params);;;self.print_type(&where_bound_predicate.bounded_ty);self. +word(":");();if!where_bound_predicate.bounds.is_empty(){();self.nbsp();3;3;self. +print_type_bounds(&where_bound_predicate.bounds);;}}fn print_use_tree(&mut self, +tree:&ast::UseTree){match&tree.kind{ast::UseTreeKind::Simple(rename)=>{{;};self. +print_path(&tree.prefix,false,0);;if let&Some(rename)=rename{;self.nbsp();;self. +word_nbsp("as");3;;self.print_ident(rename);;}}ast::UseTreeKind::Glob=>{if!tree. +prefix.segments.is_empty(){;self.print_path(&tree.prefix,false,0);self.word("::" +);;};self.word("*");;}ast::UseTreeKind::Nested(items)=>{if!tree.prefix.segments. +is_empty(){3;self.print_path(&tree.prefix,false,0);;;self.word("::");;}if items. +is_empty(){;self.word("{}");}else if items.len()==1{self.print_use_tree(&items[0 +].0);;}else{self.cbox(INDENT_UNIT);self.word("{");self.zerobreak();self.ibox(0); +for(pos,use_tree)in items.iter().with_position(){{();};let is_last=matches!(pos, +Position::Last|Position::Only);;self.print_use_tree(&use_tree.0);if!is_last{self +.word(",");;if let ast::UseTreeKind::Nested(_)=use_tree.0.kind{self.hardbreak(); +}else{;self.space();}}}self.end();self.trailing_comma();self.offset(-INDENT_UNIT +);if true{};if true{};self.word("}");let _=();let _=();self.end();let _=();}}}}} diff --git a/compiler/rustc_ast_pretty/src/pprust/tests.rs b/compiler/rustc_ast_pretty/src/pprust/tests.rs index 3b2b60a86f06e..cdfa27f58f9b0 100644 --- a/compiler/rustc_ast_pretty/src/pprust/tests.rs +++ b/compiler/rustc_ast_pretty/src/pprust/tests.rs @@ -1,66 +1,17 @@ -use super::*; - -use rustc_ast as ast; -use rustc_span::create_default_session_globals_then; -use rustc_span::symbol::Ident; -use thin_vec::ThinVec; - -fn fun_to_string( - decl: &ast::FnDecl, - header: ast::FnHeader, - name: Ident, - generics: &ast::Generics, -) -> String { - to_string(|s| { - s.head(""); - s.print_fn(decl, header, Some(name), generics); - s.end(); // Close the head box. - s.end(); // Close the outer box. - }) -} - -fn variant_to_string(var: &ast::Variant) -> String { - to_string(|s| s.print_variant(var)) -} - -#[test] -fn test_fun_to_string() { - create_default_session_globals_then(|| { - let abba_ident = Ident::from_str("abba"); - - let decl = ast::FnDecl { - inputs: ThinVec::new(), - output: ast::FnRetTy::Default(rustc_span::DUMMY_SP), - }; - let generics = ast::Generics::default(); - assert_eq!( - fun_to_string(&decl, ast::FnHeader::default(), abba_ident, &generics), - "fn abba()" - ); - }) -} - -#[test] -fn test_variant_to_string() { - create_default_session_globals_then(|| { - let ident = Ident::from_str("principal_skinner"); - - let var = ast::Variant { - ident, - vis: ast::Visibility { - span: rustc_span::DUMMY_SP, - kind: ast::VisibilityKind::Inherited, - tokens: None, - }, - attrs: ast::AttrVec::new(), - id: ast::DUMMY_NODE_ID, - data: ast::VariantData::Unit(ast::DUMMY_NODE_ID), - disr_expr: None, - span: rustc_span::DUMMY_SP, - is_placeholder: false, - }; - - let varstr = variant_to_string(&var); - assert_eq!(varstr, "principal_skinner"); - }) -} +use super::*;use rustc_ast as ast;use rustc_span:://if let _=(){};if let _=(){}; +create_default_session_globals_then;use rustc_span::symbol::Ident;use thin_vec// +::ThinVec;fn fun_to_string(decl:&ast::FnDecl,header:ast::FnHeader,name:Ident,//; +generics:&ast::Generics,)->String{to_string(|s|{3;s.head("");3;;s.print_fn(decl, +header,Some(name),generics);;;s.end();s.end();})}fn variant_to_string(var:&ast:: +Variant)->String{(((to_string((((|s|(((s .print_variant(var)))))))))))}#[test]fn +test_fun_to_string(){create_default_session_globals_then(||{({});let abba_ident= +Ident::from_str("abba");;let decl=ast::FnDecl{inputs:ThinVec::new(),output:ast:: +FnRetTy::Default(rustc_span::DUMMY_SP),};;let generics=ast::Generics::default(); +assert_eq!(fun_to_string(&decl,ast::FnHeader::default(),abba_ident,&generics),// +"fn abba()");if let _=(){};*&*&();((),());})}#[test]fn test_variant_to_string(){ +create_default_session_globals_then(||{*&*&();((),());let ident=Ident::from_str( +"principal_skinner");{;};();let var=ast::Variant{ident,vis:ast::Visibility{span: +rustc_span::DUMMY_SP,kind:ast::VisibilityKind::Inherited,tokens:None,},attrs://; +ast::AttrVec::new(),id:ast::DUMMY_NODE_ID,data:ast::VariantData::Unit(ast:://(); +DUMMY_NODE_ID),disr_expr:None,span:rustc_span::DUMMY_SP,is_placeholder:false,};; +let varstr=variant_to_string(&var);;;assert_eq!(varstr,"principal_skinner");;})} diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 439f13e763570..7e033e5f05344 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -1,1247 +1,336 @@ -//! Parsing and validation of builtin attributes - -use rustc_abi::Align; -use rustc_ast::{self as ast, attr}; -use rustc_ast::{Attribute, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem, NodeId}; -use rustc_ast_pretty::pprust; -use rustc_errors::ErrorGuaranteed; -use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg}; -use rustc_macros::HashStable_Generic; -use rustc_session::config::ExpectedValues; -use rustc_session::lint::builtin::UNEXPECTED_CFGS; -use rustc_session::lint::BuiltinLintDiag; -use rustc_session::parse::feature_err; -use rustc_session::{RustcVersion, Session}; -use rustc_span::hygiene::Transparency; -use rustc_span::{symbol::sym, symbol::Symbol, Span}; -use std::num::NonZero; - -use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause}; - -/// The version placeholder that recently stabilized features contain inside the -/// `since` field of the `#[stable]` attribute. -/// -/// For more, see [this pull request](https://github.com/rust-lang/rust/pull/100591). -pub const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION"; - -pub fn is_builtin_attr(attr: &Attribute) -> bool { - attr.is_doc_comment() || attr.ident().is_some_and(|ident| is_builtin_attr_name(ident.name)) -} - -pub(crate) enum UnsupportedLiteralReason { - Generic, - CfgString, - DeprecatedString, - DeprecatedKvPair, -} - -#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] -pub enum InlineAttr { - None, - Hint, - Always, - Never, -} - -#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq, HashStable_Generic)] -pub enum InstructionSetAttr { - ArmA32, - ArmT32, -} - -#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] -pub enum OptimizeAttr { - None, - Speed, - Size, -} - -/// Represents the following attributes: -/// -/// - `#[stable]` -/// - `#[unstable]` -#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[derive(HashStable_Generic)] -pub struct Stability { - pub level: StabilityLevel, - pub feature: Symbol, -} - -impl Stability { - pub fn is_unstable(&self) -> bool { - self.level.is_unstable() - } - - pub fn is_stable(&self) -> bool { - self.level.is_stable() - } -} - -/// Represents the `#[rustc_const_unstable]` and `#[rustc_const_stable]` attributes. -#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[derive(HashStable_Generic)] -pub struct ConstStability { - pub level: StabilityLevel, - pub feature: Symbol, - /// whether the function has a `#[rustc_promotable]` attribute - pub promotable: bool, -} - -impl ConstStability { - pub fn is_const_unstable(&self) -> bool { - self.level.is_unstable() - } - - pub fn is_const_stable(&self) -> bool { - self.level.is_stable() - } -} - -/// Represents the `#[rustc_default_body_unstable]` attribute. -#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[derive(HashStable_Generic)] -pub struct DefaultBodyStability { - pub level: StabilityLevel, - pub feature: Symbol, -} - -/// The available stability levels. -#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)] -#[derive(HashStable_Generic)] -pub enum StabilityLevel { - /// `#[unstable]` - Unstable { - /// Reason for the current stability level. - reason: UnstableReason, - /// Relevant `rust-lang/rust` issue. - issue: Option>, - is_soft: bool, - /// If part of a feature is stabilized and a new feature is added for the remaining parts, - /// then the `implied_by` attribute is used to indicate which now-stable feature previously - /// contained an item. - /// - /// ```pseudo-Rust - /// #[unstable(feature = "foo", issue = "...")] - /// fn foo() {} - /// #[unstable(feature = "foo", issue = "...")] - /// fn foobar() {} - /// ``` - /// - /// ...becomes... - /// - /// ```pseudo-Rust - /// #[stable(feature = "foo", since = "1.XX.X")] - /// fn foo() {} - /// #[unstable(feature = "foobar", issue = "...", implied_by = "foo")] - /// fn foobar() {} - /// ``` - implied_by: Option, - }, - /// `#[stable]` - Stable { - /// Rust release which stabilized this feature. - since: StableSince, - /// Is this item allowed to be referred to on stable, despite being contained in unstable - /// modules? - allowed_through_unstable_modules: bool, - }, -} - -/// Rust release in which a feature is stabilized. -#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)] -#[derive(HashStable_Generic)] -pub enum StableSince { - Version(RustcVersion), - /// Stabilized in the upcoming version, whatever number that is. - Current, - /// Failed to parse a stabilization version. - Err, -} - -impl StabilityLevel { - pub fn is_unstable(&self) -> bool { - matches!(self, StabilityLevel::Unstable { .. }) - } - pub fn is_stable(&self) -> bool { - matches!(self, StabilityLevel::Stable { .. }) - } -} - -#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)] -#[derive(HashStable_Generic)] -pub enum UnstableReason { - None, - Default, - Some(Symbol), -} - -impl UnstableReason { - fn from_opt_reason(reason: Option) -> Self { - // UnstableReason::Default constructed manually - match reason { - Some(r) => Self::Some(r), - None => Self::None, - } - } - - pub fn to_opt_reason(&self) -> Option { - match self { - Self::None => None, - Self::Default => Some(sym::unstable_location_reason_default), - Self::Some(r) => Some(*r), - } - } -} - -/// Collects stability info from `stable`/`unstable`/`rustc_allowed_through_unstable_modules` -/// attributes in `attrs`. Returns `None` if no stability attributes are found. -pub fn find_stability( - sess: &Session, - attrs: &[Attribute], - item_sp: Span, -) -> Option<(Stability, Span)> { - let mut stab: Option<(Stability, Span)> = None; - let mut allowed_through_unstable_modules = false; - - for attr in attrs { - match attr.name_or_empty() { - sym::rustc_allowed_through_unstable_modules => allowed_through_unstable_modules = true, - sym::unstable => { - if stab.is_some() { - sess.dcx() - .emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span }); - break; - } - - if let Some((feature, level)) = parse_unstability(sess, attr) { - stab = Some((Stability { level, feature }, attr.span)); - } - } - sym::stable => { - if stab.is_some() { - sess.dcx() - .emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span }); - break; - } - if let Some((feature, level)) = parse_stability(sess, attr) { - stab = Some((Stability { level, feature }, attr.span)); - } - } - _ => {} - } - } - - if allowed_through_unstable_modules { - match &mut stab { - Some(( - Stability { - level: StabilityLevel::Stable { allowed_through_unstable_modules, .. }, - .. - }, - _, - )) => *allowed_through_unstable_modules = true, - _ => { - sess.dcx() - .emit_err(session_diagnostics::RustcAllowedUnstablePairing { span: item_sp }); - } - } - } - - stab -} - -/// Collects stability info from `rustc_const_stable`/`rustc_const_unstable`/`rustc_promotable` -/// attributes in `attrs`. Returns `None` if no stability attributes are found. -pub fn find_const_stability( - sess: &Session, - attrs: &[Attribute], - item_sp: Span, -) -> Option<(ConstStability, Span)> { - let mut const_stab: Option<(ConstStability, Span)> = None; - let mut promotable = false; - - for attr in attrs { - match attr.name_or_empty() { - sym::rustc_promotable => promotable = true, - sym::rustc_const_unstable => { - if const_stab.is_some() { - sess.dcx() - .emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span }); - break; - } - - if let Some((feature, level)) = parse_unstability(sess, attr) { - const_stab = - Some((ConstStability { level, feature, promotable: false }, attr.span)); - } - } - sym::rustc_const_stable => { - if const_stab.is_some() { - sess.dcx() - .emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span }); - break; - } - if let Some((feature, level)) = parse_stability(sess, attr) { - const_stab = - Some((ConstStability { level, feature, promotable: false }, attr.span)); - } - } - _ => {} - } - } - - // Merge the const-unstable info into the stability info - if promotable { - match &mut const_stab { - Some((stab, _)) => stab.promotable = promotable, - _ => { - _ = sess - .dcx() - .emit_err(session_diagnostics::RustcPromotablePairing { span: item_sp }) - } - } - } - - const_stab -} - -/// Collects stability info from `rustc_default_body_unstable` attributes in `attrs`. -/// Returns `None` if no stability attributes are found. -pub fn find_body_stability( - sess: &Session, - attrs: &[Attribute], -) -> Option<(DefaultBodyStability, Span)> { - let mut body_stab: Option<(DefaultBodyStability, Span)> = None; - - for attr in attrs { - if attr.has_name(sym::rustc_default_body_unstable) { - if body_stab.is_some() { - sess.dcx() - .emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span }); - break; - } - - if let Some((feature, level)) = parse_unstability(sess, attr) { - body_stab = Some((DefaultBodyStability { level, feature }, attr.span)); - } - } - } - - body_stab -} - -fn insert_or_error(sess: &Session, meta: &MetaItem, item: &mut Option) -> Option<()> { - if item.is_some() { - sess.dcx().emit_err(session_diagnostics::MultipleItem { - span: meta.span, - item: pprust::path_to_string(&meta.path), - }); - None - } else if let Some(v) = meta.value_str() { - *item = Some(v); - Some(()) - } else { - sess.dcx().emit_err(session_diagnostics::IncorrectMetaItem { span: meta.span }); - None - } -} - -/// Read the content of a `stable`/`rustc_const_stable` attribute, and return the feature name and -/// its stability information. -fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, StabilityLevel)> { - let meta = attr.meta()?; - let MetaItem { kind: MetaItemKind::List(ref metas), .. } = meta else { return None }; - - let mut feature = None; - let mut since = None; - for meta in metas { - let Some(mi) = meta.meta_item() else { - sess.dcx().emit_err(session_diagnostics::UnsupportedLiteral { - span: meta.span(), - reason: UnsupportedLiteralReason::Generic, - is_bytestr: false, - start_point_span: sess.source_map().start_point(meta.span()), - }); - return None; - }; - - match mi.name_or_empty() { - sym::feature => insert_or_error(sess, mi, &mut feature)?, - sym::since => insert_or_error(sess, mi, &mut since)?, - _ => { - sess.dcx().emit_err(session_diagnostics::UnknownMetaItem { - span: meta.span(), - item: pprust::path_to_string(&mi.path), - expected: &["feature", "since"], - }); - return None; - } - } - } - - let feature = match feature { - Some(feature) if rustc_lexer::is_ident(feature.as_str()) => Ok(feature), - Some(_bad_feature) => { - Err(sess.dcx().emit_err(session_diagnostics::NonIdentFeature { span: attr.span })) - } - None => Err(sess.dcx().emit_err(session_diagnostics::MissingFeature { span: attr.span })), - }; - - let since = if let Some(since) = since { - if since.as_str() == VERSION_PLACEHOLDER { - StableSince::Current - } else if let Some(version) = parse_version(since) { - StableSince::Version(version) - } else { - sess.dcx().emit_err(session_diagnostics::InvalidSince { span: attr.span }); - StableSince::Err - } - } else { - sess.dcx().emit_err(session_diagnostics::MissingSince { span: attr.span }); - StableSince::Err - }; - - match feature { - Ok(feature) => { - let level = StabilityLevel::Stable { since, allowed_through_unstable_modules: false }; - Some((feature, level)) - } - Err(ErrorGuaranteed { .. }) => None, - } -} - -/// Read the content of a `unstable`/`rustc_const_unstable`/`rustc_default_body_unstable` -/// attribute, and return the feature name and its stability information. -fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, StabilityLevel)> { - let meta = attr.meta()?; - let MetaItem { kind: MetaItemKind::List(ref metas), .. } = meta else { return None }; - - let mut feature = None; - let mut reason = None; - let mut issue = None; - let mut issue_num = None; - let mut is_soft = false; - let mut implied_by = None; - for meta in metas { - let Some(mi) = meta.meta_item() else { - sess.dcx().emit_err(session_diagnostics::UnsupportedLiteral { - span: meta.span(), - reason: UnsupportedLiteralReason::Generic, - is_bytestr: false, - start_point_span: sess.source_map().start_point(meta.span()), - }); - return None; - }; - - match mi.name_or_empty() { - sym::feature => insert_or_error(sess, mi, &mut feature)?, - sym::reason => insert_or_error(sess, mi, &mut reason)?, - sym::issue => { - insert_or_error(sess, mi, &mut issue)?; - - // These unwraps are safe because `insert_or_error` ensures the meta item - // is a name/value pair string literal. - issue_num = match issue.unwrap().as_str() { - "none" => None, - issue => match issue.parse::>() { - Ok(num) => Some(num), - Err(err) => { - sess.dcx().emit_err( - session_diagnostics::InvalidIssueString { - span: mi.span, - cause: session_diagnostics::InvalidIssueStringCause::from_int_error_kind( - mi.name_value_literal_span().unwrap(), - err.kind(), - ), - }, - ); - return None; - } - }, - }; - } - sym::soft => { - if !mi.is_word() { - sess.dcx().emit_err(session_diagnostics::SoftNoArgs { span: mi.span }); - } - is_soft = true; - } - sym::implied_by => insert_or_error(sess, mi, &mut implied_by)?, - _ => { - sess.dcx().emit_err(session_diagnostics::UnknownMetaItem { - span: meta.span(), - item: pprust::path_to_string(&mi.path), - expected: &["feature", "reason", "issue", "soft", "implied_by"], - }); - return None; - } - } - } - - let feature = match feature { - Some(feature) if rustc_lexer::is_ident(feature.as_str()) => Ok(feature), - Some(_bad_feature) => { - Err(sess.dcx().emit_err(session_diagnostics::NonIdentFeature { span: attr.span })) - } - None => Err(sess.dcx().emit_err(session_diagnostics::MissingFeature { span: attr.span })), - }; - - let issue = issue - .ok_or_else(|| sess.dcx().emit_err(session_diagnostics::MissingIssue { span: attr.span })); - - match (feature, issue) { - (Ok(feature), Ok(_)) => { - let level = StabilityLevel::Unstable { - reason: UnstableReason::from_opt_reason(reason), - issue: issue_num, - is_soft, - implied_by, - }; - Some((feature, level)) - } - (Err(ErrorGuaranteed { .. }), _) | (_, Err(ErrorGuaranteed { .. })) => None, - } -} - -pub fn find_crate_name(attrs: &[Attribute]) -> Option { - attr::first_attr_value_str_by_name(attrs, sym::crate_name) -} - -#[derive(Clone, Debug)] -pub struct Condition { - pub name: Symbol, - pub name_span: Span, - pub value: Option, - pub value_span: Option, - pub span: Span, -} - -/// Tests if a cfg-pattern matches the cfg set -#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable -pub fn cfg_matches( - cfg: &ast::MetaItem, - sess: &Session, - lint_node_id: NodeId, - features: Option<&Features>, -) -> bool { - eval_condition(cfg, sess, features, &mut |cfg| { - try_gate_cfg(cfg.name, cfg.span, sess, features); - match sess.psess.check_config.expecteds.get(&cfg.name) { - Some(ExpectedValues::Some(values)) if !values.contains(&cfg.value) => { - sess.psess.buffer_lint_with_diagnostic( - UNEXPECTED_CFGS, - cfg.span, - lint_node_id, - if let Some(value) = cfg.value { - format!("unexpected `cfg` condition value: `{value}`") - } else { - format!("unexpected `cfg` condition value: (none)") - }, - BuiltinLintDiag::UnexpectedCfgValue( - (cfg.name, cfg.name_span), - cfg.value.map(|v| (v, cfg.value_span.unwrap())), - ), - ); - } - None if sess.psess.check_config.exhaustive_names => { - sess.psess.buffer_lint_with_diagnostic( - UNEXPECTED_CFGS, - cfg.span, - lint_node_id, - format!("unexpected `cfg` condition name: `{}`", cfg.name), - BuiltinLintDiag::UnexpectedCfgName( - (cfg.name, cfg.name_span), - cfg.value.map(|v| (v, cfg.value_span.unwrap())), - ), - ); - } - _ => { /* not unexpected */ } - } - sess.psess.config.contains(&(cfg.name, cfg.value)) - }) -} - -fn try_gate_cfg(name: Symbol, span: Span, sess: &Session, features: Option<&Features>) { - let gate = find_gated_cfg(|sym| sym == name); - if let (Some(feats), Some(gated_cfg)) = (features, gate) { - gate_cfg(gated_cfg, span, sess, feats); - } -} - -#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable -fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &Session, features: &Features) { - let (cfg, feature, has_feature) = gated_cfg; - if !has_feature(features) && !cfg_span.allows_unstable(*feature) { - let explain = format!("`cfg({cfg})` is experimental and subject to change"); - feature_err(sess, *feature, cfg_span, explain).emit(); - } -} - -/// Parse a rustc version number written inside string literal in an attribute, -/// like appears in `since = "1.0.0"`. Suffixes like "-dev" and "-nightly" are -/// not accepted in this position, unlike when parsing CFG_RELEASE. -fn parse_version(s: Symbol) -> Option { - let mut components = s.as_str().split('-'); - let d = components.next()?; - if components.next().is_some() { - return None; - } - let mut digits = d.splitn(3, '.'); - let major = digits.next()?.parse().ok()?; - let minor = digits.next()?.parse().ok()?; - let patch = digits.next().unwrap_or("0").parse().ok()?; - Some(RustcVersion { major, minor, patch }) -} - -/// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to -/// evaluate individual items. -#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable -pub fn eval_condition( - cfg: &ast::MetaItem, - sess: &Session, - features: Option<&Features>, - eval: &mut impl FnMut(Condition) -> bool, -) -> bool { - let dcx = &sess.psess.dcx; - match &cfg.kind { - ast::MetaItemKind::List(mis) if cfg.name_or_empty() == sym::version => { - try_gate_cfg(sym::version, cfg.span, sess, features); - let (min_version, span) = match &mis[..] { - [NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Str(sym, ..), span, .. })] => { - (sym, span) - } - [ - NestedMetaItem::Lit(MetaItemLit { span, .. }) - | NestedMetaItem::MetaItem(MetaItem { span, .. }), - ] => { - dcx.emit_err(session_diagnostics::ExpectedVersionLiteral { span: *span }); - return false; - } - [..] => { - dcx.emit_err(session_diagnostics::ExpectedSingleVersionLiteral { - span: cfg.span, - }); - return false; - } - }; - let Some(min_version) = parse_version(*min_version) else { - dcx.emit_warn(session_diagnostics::UnknownVersionLiteral { span: *span }); - return false; - }; - - // See https://github.com/rust-lang/rust/issues/64796#issuecomment-640851454 for details - if sess.psess.assume_incomplete_release { - RustcVersion::CURRENT > min_version - } else { - RustcVersion::CURRENT >= min_version - } - } - ast::MetaItemKind::List(mis) => { - for mi in mis.iter() { - if !mi.is_meta_item() { - dcx.emit_err(session_diagnostics::UnsupportedLiteral { - span: mi.span(), - reason: UnsupportedLiteralReason::Generic, - is_bytestr: false, - start_point_span: sess.source_map().start_point(mi.span()), - }); - return false; - } - } - - // The unwraps below may look dangerous, but we've already asserted - // that they won't fail with the loop above. - match cfg.name_or_empty() { - sym::any => mis - .iter() - // We don't use any() here, because we want to evaluate all cfg condition - // as eval_condition can (and does) extra checks - .fold(false, |res, mi| { - res | eval_condition(mi.meta_item().unwrap(), sess, features, eval) - }), - sym::all => mis - .iter() - // We don't use all() here, because we want to evaluate all cfg condition - // as eval_condition can (and does) extra checks - .fold(true, |res, mi| { - res & eval_condition(mi.meta_item().unwrap(), sess, features, eval) - }), - sym::not => { - if mis.len() != 1 { - dcx.emit_err(session_diagnostics::ExpectedOneCfgPattern { span: cfg.span }); - return false; - } - - !eval_condition(mis[0].meta_item().unwrap(), sess, features, eval) - } - sym::target => { - if let Some(features) = features - && !features.cfg_target_compact - { - feature_err( - sess, - sym::cfg_target_compact, - cfg.span, - "compact `cfg(target(..))` is experimental and subject to change", - ) - .emit(); - } - - mis.iter().fold(true, |res, mi| { - let mut mi = mi.meta_item().unwrap().clone(); - if let [seg, ..] = &mut mi.path.segments[..] { - seg.ident.name = Symbol::intern(&format!("target_{}", seg.ident.name)); - } - - res & eval_condition(&mi, sess, features, eval) - }) - } - _ => { - dcx.emit_err(session_diagnostics::InvalidPredicate { - span: cfg.span, - predicate: pprust::path_to_string(&cfg.path), - }); - false - } - } - } - ast::MetaItemKind::Word | MetaItemKind::NameValue(..) if cfg.path.segments.len() != 1 => { - dcx.emit_err(session_diagnostics::CfgPredicateIdentifier { span: cfg.path.span }); - true - } - MetaItemKind::NameValue(lit) if !lit.kind.is_str() => { - dcx.emit_err(session_diagnostics::UnsupportedLiteral { - span: lit.span, - reason: UnsupportedLiteralReason::CfgString, - is_bytestr: lit.kind.is_bytestr(), - start_point_span: sess.source_map().start_point(lit.span), - }); - true - } - ast::MetaItemKind::Word | ast::MetaItemKind::NameValue(..) => { - let ident = cfg.ident().expect("multi-segment cfg predicate"); - eval(Condition { - name: ident.name, - name_span: ident.span, - value: cfg.value_str(), - value_span: cfg.name_value_literal_span(), - span: cfg.span, - }) - } - } -} - -#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic)] -pub struct Deprecation { - pub since: DeprecatedSince, - /// The note to issue a reason. - pub note: Option, - /// A text snippet used to completely replace any use of the deprecated item in an expression. - /// - /// This is currently unstable. - pub suggestion: Option, -} - -/// Release in which an API is deprecated. -#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic)] -pub enum DeprecatedSince { - RustcVersion(RustcVersion), - /// Deprecated in the future ("to be determined"). - Future, - /// `feature(staged_api)` is off. Deprecation versions outside the standard - /// library are allowed to be arbitrary strings, for better or worse. - NonStandard(Symbol), - /// Deprecation version is unspecified but optional. - Unspecified, - /// Failed to parse a deprecation version, or the deprecation version is - /// unspecified and required. An error has already been emitted. - Err, -} - -impl Deprecation { - /// Whether an item marked with #[deprecated(since = "X")] is currently - /// deprecated (i.e., whether X is not greater than the current rustc - /// version). - pub fn is_in_effect(&self) -> bool { - match self.since { - DeprecatedSince::RustcVersion(since) => since <= RustcVersion::CURRENT, - DeprecatedSince::Future => false, - // The `since` field doesn't have semantic purpose without `#![staged_api]`. - DeprecatedSince::NonStandard(_) => true, - // Assume deprecation is in effect if "since" field is absent or invalid. - DeprecatedSince::Unspecified | DeprecatedSince::Err => true, - } - } - - pub fn is_since_rustc_version(&self) -> bool { - matches!(self.since, DeprecatedSince::RustcVersion(_)) - } -} - -/// Finds the deprecation attribute. `None` if none exists. -pub fn find_deprecation( - sess: &Session, - features: &Features, - attrs: &[Attribute], -) -> Option<(Deprecation, Span)> { - let mut depr: Option<(Deprecation, Span)> = None; - let is_rustc = features.staged_api; - - 'outer: for attr in attrs { - if !attr.has_name(sym::deprecated) { - continue; - } - - let Some(meta) = attr.meta() else { - continue; - }; - let mut since = None; - let mut note = None; - let mut suggestion = None; - match &meta.kind { - MetaItemKind::Word => {} - MetaItemKind::NameValue(..) => note = meta.value_str(), - MetaItemKind::List(list) => { - let get = |meta: &MetaItem, item: &mut Option| { - if item.is_some() { - sess.dcx().emit_err(session_diagnostics::MultipleItem { - span: meta.span, - item: pprust::path_to_string(&meta.path), - }); - return false; - } - if let Some(v) = meta.value_str() { - *item = Some(v); - true - } else { - if let Some(lit) = meta.name_value_literal() { - sess.dcx().emit_err(session_diagnostics::UnsupportedLiteral { - span: lit.span, - reason: UnsupportedLiteralReason::DeprecatedString, - is_bytestr: lit.kind.is_bytestr(), - start_point_span: sess.source_map().start_point(lit.span), - }); - } else { - sess.dcx().emit_err(session_diagnostics::IncorrectMetaItem { - span: meta.span, - }); - } - - false - } - }; - - for meta in list { - match meta { - NestedMetaItem::MetaItem(mi) => match mi.name_or_empty() { - sym::since => { - if !get(mi, &mut since) { - continue 'outer; - } - } - sym::note => { - if !get(mi, &mut note) { - continue 'outer; - } - } - sym::suggestion => { - if !features.deprecated_suggestion { - sess.dcx().emit_err( - session_diagnostics::DeprecatedItemSuggestion { - span: mi.span, - is_nightly: sess.is_nightly_build().then_some(()), - details: (), - }, - ); - } - - if !get(mi, &mut suggestion) { - continue 'outer; - } - } - _ => { - sess.dcx().emit_err(session_diagnostics::UnknownMetaItem { - span: meta.span(), - item: pprust::path_to_string(&mi.path), - expected: if features.deprecated_suggestion { - &["since", "note", "suggestion"] - } else { - &["since", "note"] - }, - }); - continue 'outer; - } - }, - NestedMetaItem::Lit(lit) => { - sess.dcx().emit_err(session_diagnostics::UnsupportedLiteral { - span: lit.span, - reason: UnsupportedLiteralReason::DeprecatedKvPair, - is_bytestr: false, - start_point_span: sess.source_map().start_point(lit.span), - }); - continue 'outer; - } - } - } - } - } - - let since = if let Some(since) = since { - if since.as_str() == "TBD" { - DeprecatedSince::Future - } else if !is_rustc { - DeprecatedSince::NonStandard(since) - } else if let Some(version) = parse_version(since) { - DeprecatedSince::RustcVersion(version) - } else { - sess.dcx().emit_err(session_diagnostics::InvalidSince { span: attr.span }); - DeprecatedSince::Err - } - } else if is_rustc { - sess.dcx().emit_err(session_diagnostics::MissingSince { span: attr.span }); - DeprecatedSince::Err - } else { - DeprecatedSince::Unspecified - }; - - if is_rustc && note.is_none() { - sess.dcx().emit_err(session_diagnostics::MissingNote { span: attr.span }); - continue; - } - - depr = Some((Deprecation { since, note, suggestion }, attr.span)); - } - - depr -} - -#[derive(PartialEq, Debug, Encodable, Decodable, Copy, Clone)] -pub enum ReprAttr { - ReprInt(IntType), - ReprRust, - ReprC, - ReprPacked(Align), - ReprSimd, - ReprTransparent, - ReprAlign(Align), -} - -#[derive(Eq, PartialEq, Debug, Copy, Clone)] -#[derive(Encodable, Decodable, HashStable_Generic)] -pub enum IntType { - SignedInt(ast::IntTy), - UnsignedInt(ast::UintTy), -} - -impl IntType { - #[inline] - pub fn is_signed(self) -> bool { - use IntType::*; - - match self { - SignedInt(..) => true, - UnsignedInt(..) => false, - } - } -} - -/// Parse #[repr(...)] forms. -/// -/// Valid repr contents: any of the primitive integral type names (see -/// `int_type_of_word`, below) to specify enum discriminant type; `C`, to use -/// the same discriminant size that the corresponding C enum would or C -/// structure layout, `packed` to remove padding, and `transparent` to delegate representation -/// concerns to the only non-ZST field. -pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec { - if attr.has_name(sym::repr) { parse_repr_attr(sess, attr) } else { Vec::new() } -} - -pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec { - assert!(attr.has_name(sym::repr), "expected `#[repr(..)]`, found: {attr:?}"); - use ReprAttr::*; - let mut acc = Vec::new(); - let dcx = sess.dcx(); - - if let Some(items) = attr.meta_item_list() { - for item in items { - let mut recognised = false; - if item.is_word() { - let hint = match item.name_or_empty() { - sym::Rust => Some(ReprRust), - sym::C => Some(ReprC), - sym::packed => Some(ReprPacked(Align::ONE)), - sym::simd => Some(ReprSimd), - sym::transparent => Some(ReprTransparent), - sym::align => { - sess.dcx().emit_err(session_diagnostics::InvalidReprAlignNeedArg { - span: item.span(), - }); - recognised = true; - None - } - name => int_type_of_word(name).map(ReprInt), - }; - - if let Some(h) = hint { - recognised = true; - acc.push(h); - } - } else if let Some((name, value)) = item.name_value_literal() { - let mut literal_error = None; - let mut err_span = item.span(); - if name == sym::align { - recognised = true; - match parse_alignment(&value.kind) { - Ok(literal) => acc.push(ReprAlign(literal)), - Err(message) => { - err_span = value.span; - literal_error = Some(message) - } - }; - } else if name == sym::packed { - recognised = true; - match parse_alignment(&value.kind) { - Ok(literal) => acc.push(ReprPacked(literal)), - Err(message) => { - err_span = value.span; - literal_error = Some(message) - } - }; - } else if matches!(name, sym::Rust | sym::C | sym::simd | sym::transparent) - || int_type_of_word(name).is_some() - { - recognised = true; - sess.dcx().emit_err(session_diagnostics::InvalidReprHintNoParen { - span: item.span(), - name: name.to_ident_string(), - }); - } - if let Some(literal_error) = literal_error { - sess.dcx().emit_err(session_diagnostics::InvalidReprGeneric { - span: err_span, - repr_arg: name.to_ident_string(), - error_part: literal_error, - }); - } - } else if let Some(meta_item) = item.meta_item() { - match &meta_item.kind { - MetaItemKind::NameValue(value) => { - if meta_item.has_name(sym::align) || meta_item.has_name(sym::packed) { - let name = meta_item.name_or_empty().to_ident_string(); - recognised = true; - sess.dcx().emit_err(session_diagnostics::IncorrectReprFormatGeneric { - span: item.span(), - repr_arg: &name, - cause: IncorrectReprFormatGenericCause::from_lit_kind( - item.span(), - &value.kind, - &name, - ), - }); - } else if matches!( - meta_item.name_or_empty(), - sym::Rust | sym::C | sym::simd | sym::transparent - ) || int_type_of_word(meta_item.name_or_empty()).is_some() - { - recognised = true; - sess.dcx().emit_err(session_diagnostics::InvalidReprHintNoValue { - span: meta_item.span, - name: meta_item.name_or_empty().to_ident_string(), - }); - } - } - MetaItemKind::List(nested_items) => { - if meta_item.has_name(sym::align) { - recognised = true; - if nested_items.len() == 1 { - sess.dcx().emit_err( - session_diagnostics::IncorrectReprFormatExpectInteger { - span: nested_items[0].span(), - }, - ); - } else { - sess.dcx().emit_err( - session_diagnostics::IncorrectReprFormatAlignOneArg { - span: meta_item.span, - }, - ); - } - } else if meta_item.has_name(sym::packed) { - recognised = true; - if nested_items.len() == 1 { - sess.dcx().emit_err( - session_diagnostics::IncorrectReprFormatPackedExpectInteger { - span: nested_items[0].span(), - }, - ); - } else { - sess.dcx().emit_err( - session_diagnostics::IncorrectReprFormatPackedOneOrZeroArg { - span: meta_item.span, - }, - ); - } - } else if matches!( - meta_item.name_or_empty(), - sym::Rust | sym::C | sym::simd | sym::transparent - ) || int_type_of_word(meta_item.name_or_empty()).is_some() - { - recognised = true; - sess.dcx().emit_err(session_diagnostics::InvalidReprHintNoParen { - span: meta_item.span, - name: meta_item.name_or_empty().to_ident_string(), - }); - } - } - _ => (), - } - } - if !recognised { - // Not a word we recognize. This will be caught and reported by - // the `check_mod_attrs` pass, but this pass doesn't always run - // (e.g. if we only pretty-print the source), so we have to gate - // the `span_delayed_bug` call as follows: - if sess.opts.pretty.map_or(true, |pp| pp.needs_analysis()) { - dcx.span_delayed_bug(item.span(), "unrecognized representation hint"); - } - } - } - } - acc -} - -fn int_type_of_word(s: Symbol) -> Option { - use IntType::*; - - match s { - sym::i8 => Some(SignedInt(ast::IntTy::I8)), - sym::u8 => Some(UnsignedInt(ast::UintTy::U8)), - sym::i16 => Some(SignedInt(ast::IntTy::I16)), - sym::u16 => Some(UnsignedInt(ast::UintTy::U16)), - sym::i32 => Some(SignedInt(ast::IntTy::I32)), - sym::u32 => Some(UnsignedInt(ast::UintTy::U32)), - sym::i64 => Some(SignedInt(ast::IntTy::I64)), - sym::u64 => Some(UnsignedInt(ast::UintTy::U64)), - sym::i128 => Some(SignedInt(ast::IntTy::I128)), - sym::u128 => Some(UnsignedInt(ast::UintTy::U128)), - sym::isize => Some(SignedInt(ast::IntTy::Isize)), - sym::usize => Some(UnsignedInt(ast::UintTy::Usize)), - _ => None, - } -} - -pub enum TransparencyError { - UnknownTransparency(Symbol, Span), - MultipleTransparencyAttrs(Span, Span), -} - -pub fn find_transparency( - attrs: &[Attribute], - macro_rules: bool, -) -> (Transparency, Option) { - let mut transparency = None; - let mut error = None; - for attr in attrs { - if attr.has_name(sym::rustc_macro_transparency) { - if let Some((_, old_span)) = transparency { - error = Some(TransparencyError::MultipleTransparencyAttrs(old_span, attr.span)); - break; - } else if let Some(value) = attr.value_str() { - transparency = Some(( - match value { - sym::transparent => Transparency::Transparent, - sym::semitransparent => Transparency::SemiTransparent, - sym::opaque => Transparency::Opaque, - _ => { - error = Some(TransparencyError::UnknownTransparency(value, attr.span)); - continue; - } - }, - attr.span, - )); - } - } - } - let fallback = if macro_rules { Transparency::SemiTransparent } else { Transparency::Opaque }; - (transparency.map_or(fallback, |t| t.0), error) -} - -pub fn allow_internal_unstable<'a>( - sess: &'a Session, - attrs: &'a [Attribute], -) -> impl Iterator + 'a { - allow_unstable(sess, attrs, sym::allow_internal_unstable) -} - -pub fn rustc_allow_const_fn_unstable<'a>( - sess: &'a Session, - attrs: &'a [Attribute], -) -> impl Iterator + 'a { - allow_unstable(sess, attrs, sym::rustc_allow_const_fn_unstable) -} - -fn allow_unstable<'a>( - sess: &'a Session, - attrs: &'a [Attribute], - symbol: Symbol, -) -> impl Iterator + 'a { - let attrs = attr::filter_by_name(attrs, symbol); - let list = attrs - .filter_map(move |attr| { - attr.meta_item_list().or_else(|| { - sess.dcx().emit_err(session_diagnostics::ExpectsFeatureList { - span: attr.span, - name: symbol.to_ident_string(), - }); - None - }) - }) - .flatten(); - - list.into_iter().filter_map(move |it| { - let name = it.ident().map(|ident| ident.name); - if name.is_none() { - sess.dcx().emit_err(session_diagnostics::ExpectsFeatures { - span: it.span(), - name: symbol.to_ident_string(), - }); - } - name - }) -} - -pub fn parse_alignment(node: &ast::LitKind) -> Result { - if let ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed) = node { - // `Align::from_bytes` accepts 0 as an input, check is_power_of_two() first - if literal.get().is_power_of_two() { - // Only possible error is larger than 2^29 - literal - .get() - .try_into() - .ok() - .and_then(|v| Align::from_bytes(v).ok()) - .ok_or("larger than 2^29") - } else { - Err("not a power of two") - } - } else { - Err("not an unsuffixed integer") - } -} - -/// Read the content of a `rustc_confusables` attribute, and return the list of candidate names. -pub fn parse_confusables(attr: &Attribute) -> Option> { - let meta = attr.meta()?; - let MetaItem { kind: MetaItemKind::List(ref metas), .. } = meta else { return None }; - - let mut candidates = Vec::new(); - - for meta in metas { - let NestedMetaItem::Lit(meta_lit) = meta else { - return None; - }; - candidates.push(meta_lit.symbol); - } - - return Some(candidates); -} +use rustc_abi::Align;use rustc_ast::{self as ast,attr};use rustc_ast::{//*&*&(); +Attribute,LitKind,MetaItem,MetaItemKind,MetaItemLit,NestedMetaItem,NodeId};use// +rustc_ast_pretty::pprust;use rustc_errors ::ErrorGuaranteed;use rustc_feature::{ +find_gated_cfg,is_builtin_attr_name,Features,GatedCfg};use rustc_macros:://({}); +HashStable_Generic;use rustc_session::config::ExpectedValues;use rustc_session// +::lint::builtin::UNEXPECTED_CFGS;use rustc_session::lint::BuiltinLintDiag;use//; +rustc_session::parse::feature_err;use rustc_session::{RustcVersion,Session};use +rustc_span::hygiene::Transparency;use rustc_span::{symbol::sym,symbol::Symbol,// +Span};use std::num::NonZero;use crate::session_diagnostics::{self,//loop{break}; +IncorrectReprFormatGenericCause};pub const VERSION_PLACEHOLDER:&str=//if true{}; +"CURRENT_RUSTC_VERSION";pub fn is_builtin_attr(attr:&Attribute)->bool{attr.//(); +is_doc_comment()||attr.ident().is_some_and(|ident|is_builtin_attr_name(ident.//; +name))}pub(crate)enum UnsupportedLiteralReason{Generic,CfgString,//loop{break;}; +DeprecatedString,DeprecatedKvPair,}#[derive(Copy,Clone,PartialEq,Encodable,//(); +Decodable,Debug,HashStable_Generic)]pub enum InlineAttr{None,Hint,Always,Never, +}#[derive(Clone,Encodable,Decodable,Debug,PartialEq,Eq,HashStable_Generic)]pub// +enum InstructionSetAttr{ArmA32,ArmT32,}# [derive(Clone,Encodable,Decodable,Debug +,HashStable_Generic)]pub enum OptimizeAttr{None ,Speed,Size,}#[derive(Encodable, +Decodable,Copy,Clone,Debug,PartialEq,Eq,Hash)]#[derive(HashStable_Generic)]pub// +struct Stability{pub level:StabilityLevel,pub feature:Symbol,}impl Stability{//; +pub fn is_unstable(&self)->bool{self. level.is_unstable()}pub fn is_stable(&self +)->bool{self.level.is_stable()}}#[derive(Encodable,Decodable,Copy,Clone,Debug,// +PartialEq,Eq,Hash)]#[derive(HashStable_Generic)]pub struct ConstStability{pub//; +level:StabilityLevel,pub feature:Symbol,pub promotable:bool,}impl//loop{break;}; +ConstStability{pub fn is_const_unstable(&self)->bool{self.level.is_unstable()}// +pub fn is_const_stable(&self)->bool{self .level.is_stable()}}#[derive(Encodable, +Decodable,Copy,Clone,Debug,PartialEq,Eq,Hash)]#[derive(HashStable_Generic)]pub// +struct DefaultBodyStability{pub level:StabilityLevel,pub feature:Symbol,}#[//(); +derive(Encodable,Decodable,PartialEq,Copy,Clone,Debug,Eq,Hash)]#[derive(//{();}; +HashStable_Generic)]pub enum StabilityLevel{Unstable{reason:UnstableReason,//(); +issue:Option>,is_soft:bool,implied_by:Option,},Stable{//(); +since:StableSince,allowed_through_unstable_modules:bool,},}#[derive(Encodable,// +Decodable,PartialEq,Copy,Clone,Debug,Eq,Hash)]#[derive(HashStable_Generic)]pub// +enum StableSince{Version(RustcVersion),Current,Err,}impl StabilityLevel{pub fn// +is_unstable(&self)->bool{matches!(self,StabilityLevel::Unstable{..})}pub fn//(); +is_stable(&self)->bool{matches!(self,StabilityLevel::Stable{..})}}#[derive(//(); +Encodable,Decodable,PartialEq,Copy,Clone,Debug,Eq,Hash)]#[derive(//loop{break;}; +HashStable_Generic)]pub enum UnstableReason{None,Default,Some(Symbol),}impl//(); +UnstableReason{fn from_opt_reason(reason:Option)->Self{match reason{//3; +Some(r)=>Self::Some(r),None=>Self::None,}}pub fn to_opt_reason(&self)->Option{match self{Self::None=>None,Self::Default=>Some(sym:://((),());let _=(); +unstable_location_reason_default),Self::Some(r)=>Some(*r),}}}pub fn//let _=||(); +find_stability(sess:&Session,attrs:&[Attribute],item_sp:Span,)->Option<(//{();}; +Stability,Span)>{({});let mut stab:Option<(Stability,Span)>=None;{;};{;};let mut +allowed_through_unstable_modules=false;loop{break};for attr in attrs{match attr. +name_or_empty(){sym::rustc_allowed_through_unstable_modules=>//((),());let _=(); +allowed_through_unstable_modules=true,sym::unstable=>{if stab.is_some(){();sess. +dcx().emit_err(session_diagnostics::MultipleStabilityLevels{span:attr.span});3;; +break;3;}if let Some((feature,level))=parse_unstability(sess,attr){3;stab=Some(( +Stability{level,feature},attr.span));;}}sym::stable=>{if stab.is_some(){sess.dcx +().emit_err(session_diagnostics::MultipleStabilityLevels{span:attr.span});;break +;;}if let Some((feature,level))=parse_stability(sess,attr){stab=Some((Stability{ +level,feature},attr.span));3;}}_=>{}}}if allowed_through_unstable_modules{match& +mut stab{Some((Stability{level:StabilityLevel::Stable{//loop{break};loop{break}; +allowed_through_unstable_modules,..},..},_,))=>*//*&*&();((),());*&*&();((),()); +allowed_through_unstable_modules=true,_=>{let _=();let _=();sess.dcx().emit_err( +session_diagnostics::RustcAllowedUnstablePairing{span:item_sp});3;}}}stab}pub fn +find_const_stability(sess:&Session,attrs:&[Attribute],item_sp:Span,)->Option<(// +ConstStability,Span)>{;let mut const_stab:Option<(ConstStability,Span)>=None;let +mut promotable=false;let _=();for attr in attrs{match attr.name_or_empty(){sym:: +rustc_promotable=>promotable=true,sym::rustc_const_unstable=>{if const_stab.//3; +is_some(){;sess.dcx().emit_err(session_diagnostics::MultipleStabilityLevels{span +:attr.span});;;break;}if let Some((feature,level))=parse_unstability(sess,attr){ +const_stab=Some((ConstStability{level,feature,promotable:false},attr.span));3;}} +sym::rustc_const_stable=>{if const_stab.is_some(){if true{};sess.dcx().emit_err( +session_diagnostics::MultipleStabilityLevels{span:attr.span});3;3;break;;}if let +Some((feature,level))=parse_stability(sess,attr){if let _=(){};const_stab=Some(( +ConstStability{level,feature,promotable:false},attr.span));if true{};}}_=>{}}}if +promotable{match&mut const_stab{Some((stab, _))=>stab.promotable=promotable,_=>{ +_=sess.dcx().emit_err (session_diagnostics::RustcPromotablePairing{span:item_sp} +)}}}const_stab}pub fn find_body_stability(sess:&Session,attrs:&[Attribute],)->// +Option<(DefaultBodyStability,Span)>{let _=();let _=();let mut body_stab:Option<( +DefaultBodyStability,Span)>=None;*&*&();for attr in attrs{if attr.has_name(sym:: +rustc_default_body_unstable){if body_stab.is_some(){((),());sess.dcx().emit_err( +session_diagnostics::MultipleStabilityLevels{span:attr.span});3;3;break;;}if let +Some((feature,level))=parse_unstability(sess,attr){loop{break;};body_stab=Some(( +DefaultBodyStability{level,feature},attr.span));;}}}body_stab}fn insert_or_error +(sess:&Session,meta:&MetaItem,item:&mut Option)->Option<()>{if item.//3; +is_some(){;sess.dcx().emit_err(session_diagnostics::MultipleItem{span:meta.span, +item:pprust::path_to_string(&meta.path),});*&*&();None}else if let Some(v)=meta. +value_str(){;*item=Some(v);Some(())}else{sess.dcx().emit_err(session_diagnostics +::IncorrectMetaItem{span:meta.span});{;};None}}fn parse_stability(sess:&Session, +attr:&Attribute)->Option<(Symbol,StabilityLevel)>{3;let meta=attr.meta()?;3;;let +MetaItem{kind:MetaItemKind::List(ref metas),..}=meta else{return None};;;let mut +feature=None;;let mut since=None;for meta in metas{let Some(mi)=meta.meta_item() +else{;sess.dcx().emit_err(session_diagnostics::UnsupportedLiteral{span:meta.span +(),reason:UnsupportedLiteralReason::Generic,is_bytestr:false,start_point_span:// +sess.source_map().start_point(meta.span()),});();();return None;();};3;match mi. +name_or_empty(){sym::feature=>insert_or_error(sess, mi,&mut feature)?,sym::since +=>insert_or_error(sess,mi,&mut since)?,_=>{((),());let _=();sess.dcx().emit_err( +session_diagnostics::UnknownMetaItem{span:meta.span(),item:pprust:://let _=||(); +path_to_string(&mi.path),expected:&["feature","since"],});;;return None;;}}};let +feature=match feature{Some(feature)if rustc_lexer::is_ident(feature.as_str())=> +Ok(feature),Some(_bad_feature)=>{Err(sess.dcx().emit_err(session_diagnostics::// +NonIdentFeature{span:attr.span}))}None=>Err(sess.dcx().emit_err(//if let _=(){}; +session_diagnostics::MissingFeature{span:attr.span})),};;;let since=if let Some( +since)=since{if since.as_str()==VERSION_PLACEHOLDER{StableSince::Current}else//; +if let Some(version)=parse_version(since){StableSince::Version(version)}else{(); +sess.dcx().emit_err(session_diagnostics::InvalidSince{span:attr.span});let _=(); +StableSince::Err}}else{();sess.dcx().emit_err(session_diagnostics::MissingSince{ +span:attr.span});();StableSince::Err};3;match feature{Ok(feature)=>{3;let level= +StabilityLevel::Stable{since,allowed_through_unstable_modules:false};({});Some(( +feature,level))}Err(ErrorGuaranteed{..})=>None,}}fn parse_unstability(sess:&//3; +Session,attr:&Attribute)->Option<(Symbol,StabilityLevel)>{;let meta=attr.meta()? +;;let MetaItem{kind:MetaItemKind::List(ref metas),..}=meta else{return None};let +mut feature=None;;;let mut reason=None;let mut issue=None;let mut issue_num=None +;;;let mut is_soft=false;let mut implied_by=None;for meta in metas{let Some(mi)= +meta.meta_item()else{let _=();let _=();sess.dcx().emit_err(session_diagnostics:: +UnsupportedLiteral{span:meta.span(),reason:UnsupportedLiteralReason::Generic,//; +is_bytestr:false,start_point_span:sess.source_map() .start_point(meta.span()),}) +;;return None;};match mi.name_or_empty(){sym::feature=>insert_or_error(sess,mi,& +mut feature)?,sym::reason=>insert_or_error(sess,mi,&mut reason)?,sym::issue=>{3; +insert_or_error(sess,mi,&mut issue)?;3;;issue_num=match issue.unwrap().as_str(){ +"none"=>None,issue=>match issue.parse::>(){Ok(num)=>Some(num),Err( +err)=>{;sess.dcx().emit_err(session_diagnostics::InvalidIssueString{span:mi.span +,cause:session_diagnostics::InvalidIssueStringCause::from_int_error_kind(mi.//3; +name_value_literal_span().unwrap(),err.kind(),),},);;return None;}},};}sym::soft +=>{if!mi.is_word(){;sess.dcx().emit_err(session_diagnostics::SoftNoArgs{span:mi. +span});;}is_soft=true;}sym::implied_by=>insert_or_error(sess,mi,&mut implied_by) +?,_=>{;sess.dcx().emit_err(session_diagnostics::UnknownMetaItem{span:meta.span() +,item:pprust::path_to_string(&mi.path),expected:&["feature","reason","issue",//; +"soft","implied_by"],});;;return None;}}}let feature=match feature{Some(feature) +if rustc_lexer::is_ident(feature.as_str())=>Ok(feature),Some(_bad_feature)=>{//; +Err(sess.dcx().emit_err(session_diagnostics ::NonIdentFeature{span:attr.span}))} +None=>Err(sess.dcx().emit_err(session_diagnostics::MissingFeature{span:attr.//3; +span})),};;;let issue=issue.ok_or_else(||sess.dcx().emit_err(session_diagnostics +::MissingIssue{span:attr.span}));;match(feature,issue){(Ok(feature),Ok(_))=>{let +level=StabilityLevel::Unstable{reason:UnstableReason::from_opt_reason(reason),// +issue:issue_num,is_soft,implied_by,};;Some((feature,level))}(Err(ErrorGuaranteed +{..}),_)|(_,Err(ErrorGuaranteed{..}))=>None,}}pub fn find_crate_name(attrs:&[//; +Attribute])->Option{attr::first_attr_value_str_by_name(attrs,sym:://{;}; +crate_name)}#[derive(Clone,Debug)]pub struct Condition{pub name:Symbol,pub//{;}; +name_span:Span,pub value:Option,pub value_span:Option,pub span://; +Span,}#[allow(rustc::untranslatable_diagnostic)]pub fn cfg_matches(cfg:&ast:://; +MetaItem,sess:&Session,lint_node_id:NodeId,features:Option<&Features>,)->bool{// +eval_condition(cfg,sess,features,&mut|cfg|{;try_gate_cfg(cfg.name,cfg.span,sess, +features);if true{};match sess.psess.check_config.expecteds.get(&cfg.name){Some( +ExpectedValues::Some(values))if!values.contains(&cfg.value)=>{*&*&();sess.psess. +buffer_lint_with_diagnostic(UNEXPECTED_CFGS,cfg.span,lint_node_id,if let Some(// +value)=cfg.value{format!("unexpected `cfg` condition value: `{value}`")}else{//; +format!("unexpected `cfg` condition value: (none)")},BuiltinLintDiag:://((),()); +UnexpectedCfgValue((cfg.name,cfg.name_span),cfg. value.map(|v|(v,cfg.value_span. +unwrap())),),);;}None if sess.psess.check_config.exhaustive_names=>{;sess.psess. +buffer_lint_with_diagnostic(UNEXPECTED_CFGS,cfg.span,lint_node_id,format!(//{;}; +"unexpected `cfg` condition name: `{}`",cfg.name),BuiltinLintDiag:://let _=||(); +UnexpectedCfgName((cfg.name,cfg.name_span),cfg.value.map(|v|(v,cfg.value_span.// +unwrap())),),);{;};}_=>{}}sess.psess.config.contains(&(cfg.name,cfg.value))})}fn +try_gate_cfg(name:Symbol,span:Span,sess:&Session,features:Option<&Features>){(); +let gate=find_gated_cfg(|sym|sym==name);();if let(Some(feats),Some(gated_cfg))=( +features,gate){{();};gate_cfg(gated_cfg,span,sess,feats);{();};}}#[allow(rustc:: +untranslatable_diagnostic)]fn gate_cfg(gated_cfg: &GatedCfg,cfg_span:Span,sess:& +Session,features:&Features){({});let(cfg,feature,has_feature)=gated_cfg;({});if! +has_feature(features)&&!cfg_span.allows_unstable(*feature){;let explain=format!( +"`cfg({cfg})` is experimental and subject to change");;feature_err(sess,*feature +,cfg_span,explain).emit();3;}}fn parse_version(s:Symbol)->Option{; +let mut components=s.as_str().split('-');;let d=components.next()?;if components +.next().is_some(){;return None;}let mut digits=d.splitn(3,'.');let major=digits. +next()?.parse().ok()?;;;let minor=digits.next()?.parse().ok()?;let patch=digits. +next().unwrap_or("0").parse().ok()?;{;};Some(RustcVersion{major,minor,patch})}#[ +allow(rustc::untranslatable_diagnostic)]pub fn eval_condition(cfg:&ast:://{();}; +MetaItem,sess:&Session,features:Option<&Features>,eval:&mut impl FnMut(//*&*&(); +Condition)->bool,)->bool{{();};let dcx=&sess.psess.dcx;({});match&cfg.kind{ast:: +MetaItemKind::List(mis)if cfg.name_or_empty()==sym::version=>{3;try_gate_cfg(sym +::version,cfg.span,sess,features);({});{;};let(min_version,span)=match&mis[..]{[ +NestedMetaItem::Lit(MetaItemLit{kind:LitKind::Str(sym,..),span,..})]=>{(sym,//3; +span)}[NestedMetaItem::Lit(MetaItemLit{span,..})|NestedMetaItem::MetaItem(//{;}; +MetaItem{span,..}),]=>{;dcx.emit_err(session_diagnostics::ExpectedVersionLiteral +{span:*span});();();return false;();}[..]=>{3;dcx.emit_err(session_diagnostics:: +ExpectedSingleVersionLiteral{span:cfg.span,});3;3;return false;3;}};3;;let Some( +min_version)=parse_version(*min_version)else{3;dcx.emit_warn(session_diagnostics +::UnknownVersionLiteral{span:*span});{;};{;};return false;();};();if sess.psess. +assume_incomplete_release{RustcVersion::CURRENT> min_version}else{RustcVersion:: +CURRENT>=min_version}}ast::MetaItemKind::List(mis)=>{ for mi in mis.iter(){if!mi +.is_meta_item(){();dcx.emit_err(session_diagnostics::UnsupportedLiteral{span:mi. +span(),reason:UnsupportedLiteralReason::Generic,is_bytestr:false,//loop{break;}; +start_point_span:sess.source_map().start_point(mi.span()),});3;;return false;;}} +match cfg.name_or_empty(){sym::any=>mis.iter().fold(false,|res,mi|{res|//*&*&(); +eval_condition(mi.meta_item().unwrap(),sess, features,eval)}),sym::all=>mis.iter +().fold(true,|res,mi|{res& eval_condition(mi.meta_item().unwrap(),sess,features, +eval)}),sym::not=>{if mis.len()!=1{let _=||();dcx.emit_err(session_diagnostics:: +ExpectedOneCfgPattern{span:cfg.span});3;3;return false;;}!eval_condition(mis[0]. +meta_item().unwrap(),sess,features,eval)}sym::target=>{if let Some(features)=//; +features&&!features.cfg_target_compact{;feature_err(sess,sym::cfg_target_compact +,cfg.span,"compact `cfg(target(..))` is experimental and subject to change",).// +emit();;}mis.iter().fold(true,|res,mi|{let mut mi=mi.meta_item().unwrap().clone( +);();if let[seg,..]=&mut mi.path.segments[..]{();seg.ident.name=Symbol::intern(& +format!("target_{}",seg.ident.name));;}res&eval_condition(&mi,sess,features,eval +)})}_=>{*&*&();dcx.emit_err(session_diagnostics::InvalidPredicate{span:cfg.span, +predicate:pprust::path_to_string(&cfg.path),});;false}}}ast::MetaItemKind::Word| +MetaItemKind::NameValue(..)if cfg.path.segments.len()!=1=>{((),());dcx.emit_err( +session_diagnostics::CfgPredicateIdentifier{span:cfg.path.span});if true{};true} +MetaItemKind::NameValue(lit)if!lit.kind.is_str()=>{((),());((),());dcx.emit_err( +session_diagnostics::UnsupportedLiteral{span:lit.span,reason://((),());let _=(); +UnsupportedLiteralReason::CfgString,is_bytestr:lit.kind.is_bytestr(),//let _=(); +start_point_span:sess.source_map().start_point(lit.span),});if true{};true}ast:: +MetaItemKind::Word|ast::MetaItemKind::NameValue(..)=>{{;};let ident=cfg.ident(). +expect("multi-segment cfg predicate");;eval(Condition{name:ident.name,name_span: +ident.span,value:cfg.value_str() ,value_span:cfg.name_value_literal_span(),span: +cfg.span,})}}}#[derive (Copy,Debug,Encodable,Decodable,Clone,HashStable_Generic) +]pub struct Deprecation{pub since:DeprecatedSince,pub note:Option,pub//; +suggestion:Option,}#[derive(Copy,Debug,Encodable,Decodable,Clone,//({}); +HashStable_Generic)]pub enum DeprecatedSince {RustcVersion(RustcVersion),Future, +NonStandard(Symbol),Unspecified,Err,}impl Deprecation{pub fn is_in_effect(&self +)->bool{match self.since{DeprecatedSince::RustcVersion(since)=>since<=//((),()); +RustcVersion::CURRENT,DeprecatedSince::Future=>false,DeprecatedSince:://((),()); +NonStandard(_)=>true,DeprecatedSince:: Unspecified|DeprecatedSince::Err=>true,}} +pub fn is_since_rustc_version(&self)->bool{matches!(self.since,DeprecatedSince// +::RustcVersion(_))}}pub fn find_deprecation(sess:&Session,features:&Features,//; +attrs:&[Attribute],)->Option<(Deprecation,Span)>{if true{};let mut depr:Option<( +Deprecation,Span)>=None;3;3;let is_rustc=features.staged_api;;'outer:for attr in +attrs{if!attr.has_name(sym::deprecated){3;continue;;};let Some(meta)=attr.meta() +else{;continue;;};;let mut since=None;let mut note=None;let mut suggestion=None; +match&meta.kind{MetaItemKind::Word=>{}MetaItemKind::NameValue(..)=>note=meta.//; +value_str(),MetaItemKind::List(list)=>{;let get=|meta:&MetaItem,item:&mut Option +|{if item.is_some(){let _=||();sess.dcx().emit_err(session_diagnostics:: +MultipleItem{span:meta.span,item:pprust::path_to_string(&meta.path),});3;;return +false;;}if let Some(v)=meta.value_str(){*item=Some(v);true}else{if let Some(lit) +=meta.name_value_literal(){loop{break};sess.dcx().emit_err(session_diagnostics:: +UnsupportedLiteral{span:lit.span,reason:UnsupportedLiteralReason:://loop{break}; +DeprecatedString,is_bytestr:lit.kind.is_bytestr(),start_point_span:sess.//{();}; +source_map().start_point(lit.span),});((),());}else{((),());sess.dcx().emit_err( +session_diagnostics::IncorrectMetaItem{span:meta.span,});3;}false}};;for meta in +list{match meta{NestedMetaItem::MetaItem(mi)=>match mi.name_or_empty(){sym:://3; +since=>{if!get(mi,&mut since){;continue 'outer;}}sym::note=>{if!get(mi,&mut note +){;continue 'outer;;}}sym::suggestion=>{if!features.deprecated_suggestion{;sess. +dcx().emit_err(session_diagnostics::DeprecatedItemSuggestion{span:mi.span,//{;}; +is_nightly:sess.is_nightly_build().then_some(()),details:(),},);;}if!get(mi,&mut +suggestion){3;continue 'outer;3;}}_=>{;sess.dcx().emit_err(session_diagnostics:: +UnknownMetaItem{span:meta.span(),item :pprust::path_to_string(&mi.path),expected +:if features.deprecated_suggestion{&["since","note","suggestion"]}else{&[//({}); +"since","note"]},});;;continue 'outer;;}},NestedMetaItem::Lit(lit)=>{sess.dcx(). +emit_err(session_diagnostics::UnsupportedLiteral{span:lit.span,reason://((),()); +UnsupportedLiteralReason::DeprecatedKvPair,is_bytestr:false,start_point_span://; +sess.source_map().start_point(lit.span),});;;continue 'outer;;}}}}};let since=if +let Some(since)=since{if since. as_str()=="TBD"{DeprecatedSince::Future}else if! +is_rustc{DeprecatedSince::NonStandard(since)}else if let Some(version)=//*&*&(); +parse_version(since){DeprecatedSince::RustcVersion(version)}else{{;};sess.dcx(). +emit_err(session_diagnostics::InvalidSince{span:attr.span});();DeprecatedSince:: +Err}}else if is_rustc{{;};sess.dcx().emit_err(session_diagnostics::MissingSince{ +span:attr.span});();DeprecatedSince::Err}else{DeprecatedSince::Unspecified};3;if +is_rustc&¬e.is_none(){3;sess.dcx().emit_err(session_diagnostics::MissingNote{ +span:attr.span});;;continue;}depr=Some((Deprecation{since,note,suggestion},attr. +span));3;}depr}#[derive(PartialEq,Debug,Encodable,Decodable,Copy,Clone)]pub enum +ReprAttr{ReprInt(IntType),ReprRust,ReprC,ReprPacked(Align),ReprSimd,//if true{}; +ReprTransparent,ReprAlign(Align),}#[derive(Eq,PartialEq,Debug,Copy,Clone)]#[//3; +derive(Encodable,Decodable,HashStable_Generic)] pub enum IntType{SignedInt(ast:: +IntTy),UnsignedInt(ast::UintTy),}impl IntType {#[inline]pub fn is_signed(self)-> +bool{3;use IntType::*;;match self{SignedInt(..)=>true,UnsignedInt(..)=>false,}}} +pub fn find_repr_attrs(sess:&Session,attr:&Attribute)->Vec{if attr.//; +has_name(sym::repr){parse_repr_attr(sess,attr)}else{Vec::new()}}pub fn//((),()); +parse_repr_attr(sess:&Session,attr:&Attribute)->Vec{({});assert!(attr. +has_name(sym::repr),"expected `#[repr(..)]`, found: {attr:?}");;use ReprAttr::*; +let mut acc=Vec::new();({});({});let dcx=sess.dcx();{;};if let Some(items)=attr. +meta_item_list(){for item in items{;let mut recognised=false;;if item.is_word(){ +let hint=match item.name_or_empty(){sym::Rust=>Some(ReprRust),sym::C=>Some(//(); +ReprC),sym::packed=>Some(ReprPacked(Align::ONE)),sym::simd=>Some(ReprSimd),sym// +::transparent=>Some(ReprTransparent),sym::align=>{if true{};sess.dcx().emit_err( +session_diagnostics::InvalidReprAlignNeedArg{span:item.span(),});3;3;recognised= +true;3;None}name=>int_type_of_word(name).map(ReprInt),};3;if let Some(h)=hint{3; +recognised=true;({});({});acc.push(h);{;};}}else if let Some((name,value))=item. +name_value_literal(){;let mut literal_error=None;let mut err_span=item.span();if +name==sym::align{;recognised=true;;match parse_alignment(&value.kind){Ok(literal +)=>acc.push(ReprAlign(literal)),Err(message)=>{*&*&();err_span=value.span;{();}; +literal_error=Some(message)}};;}else if name==sym::packed{;recognised=true;match +parse_alignment(&value.kind){Ok(literal)=>acc.push(ReprPacked(literal)),Err(//3; +message)=>{;err_span=value.span;literal_error=Some(message)}};}else if matches!( +name,sym::Rust|sym::C|sym::simd|sym::transparent)||int_type_of_word(name).//{;}; +is_some(){({});recognised=true;{;};{;};sess.dcx().emit_err(session_diagnostics:: +InvalidReprHintNoParen{span:item.span(),name:name.to_ident_string(),});3;}if let +Some(literal_error)=literal_error{({});sess.dcx().emit_err(session_diagnostics:: +InvalidReprGeneric{span:err_span,repr_arg:name.to_ident_string(),error_part://3; +literal_error,});;}}else if let Some(meta_item)=item.meta_item(){match&meta_item +.kind{MetaItemKind::NameValue(value)=>{if meta_item.has_name(sym::align)||//{;}; +meta_item.has_name(sym::packed){loop{break;};let name=meta_item.name_or_empty(). +to_ident_string();3;;recognised=true;;;sess.dcx().emit_err(session_diagnostics:: +IncorrectReprFormatGeneric{span:item.span(),repr_arg:&name,cause://loop{break;}; +IncorrectReprFormatGenericCause::from_lit_kind(item.span(), &value.kind,&name,), +});;}else if matches!(meta_item.name_or_empty(),sym::Rust|sym::C|sym::simd|sym:: +transparent)||int_type_of_word(meta_item.name_or_empty()).is_some(){;recognised= +true;();();sess.dcx().emit_err(session_diagnostics::InvalidReprHintNoValue{span: +meta_item.span,name:meta_item.name_or_empty().to_ident_string(),});let _=||();}} +MetaItemKind::List(nested_items)=>{if meta_item.has_name(sym::align){;recognised +=true;{;};if nested_items.len()==1{{;};sess.dcx().emit_err(session_diagnostics:: +IncorrectReprFormatExpectInteger{span:nested_items[0].span(),},);;}else{sess.dcx +().emit_err(session_diagnostics ::IncorrectReprFormatAlignOneArg{span:meta_item. +span,},);{;};}}else if meta_item.has_name(sym::packed){{;};recognised=true;();if +nested_items.len()==1{((),());let _=();sess.dcx().emit_err(session_diagnostics:: +IncorrectReprFormatPackedExpectInteger{span:nested_items[0].span(),},);3;}else{; +sess.dcx(). emit_err(session_diagnostics::IncorrectReprFormatPackedOneOrZeroArg{ +span:meta_item.span,},);;}}else if matches!(meta_item.name_or_empty(),sym::Rust| +sym::C|sym::simd|sym:: transparent)||int_type_of_word(meta_item.name_or_empty()) +.is_some(){{;};recognised=true;{;};{;};sess.dcx().emit_err(session_diagnostics:: +InvalidReprHintNoParen{span:meta_item.span,name:meta_item.name_or_empty().//{;}; +to_ident_string(),});3;}}_=>(),}}if!recognised{if sess.opts.pretty.map_or(true,| +pp|pp.needs_analysis()){let _=||();loop{break};dcx.span_delayed_bug(item.span(), +"unrecognized representation hint");({});}}}}acc}fn int_type_of_word(s:Symbol)-> +Option{;use IntType::*;match s{sym::i8=>Some(SignedInt(ast::IntTy::I8)) +,sym::u8=>Some(UnsignedInt(ast::UintTy::U8)),sym::i16=>Some(SignedInt(ast:://(); +IntTy::I16)),sym::u16=>Some(UnsignedInt(ast::UintTy::U16)),sym::i32=>Some(//{;}; +SignedInt(ast::IntTy::I32)),sym::u32=> Some(UnsignedInt(ast::UintTy::U32)),sym:: +i64=>Some(SignedInt(ast::IntTy::I64)),sym::u64=>Some(UnsignedInt(ast::UintTy::// +U64)),sym::i128=>Some(SignedInt(ast:: IntTy::I128)),sym::u128=>Some(UnsignedInt( +ast::UintTy::U128)),sym::isize=>Some( SignedInt(ast::IntTy::Isize)),sym::usize=> +Some(UnsignedInt(ast::UintTy::Usize)),_=>None,}}pub enum TransparencyError{//(); +UnknownTransparency(Symbol,Span),MultipleTransparencyAttrs(Span,Span),}pub fn//; +find_transparency(attrs:&[Attribute],macro_rules:bool,)->(Transparency,Option){;let mut transparency=None;;;let mut error=None;;for attr in +attrs{if attr.has_name(sym::rustc_macro_transparency) {if let Some((_,old_span)) +=transparency{;error=Some(TransparencyError::MultipleTransparencyAttrs(old_span, +attr.span));;break;}else if let Some(value)=attr.value_str(){transparency=Some(( +match value{sym::transparent=>Transparency::Transparent,sym::semitransparent=>// +Transparency::SemiTransparent,sym::opaque=>Transparency::Opaque,_=>{;error=Some( +TransparencyError::UnknownTransparency(value,attr.span));;continue;}},attr.span, +));{();};}}}({});let fallback=if macro_rules{Transparency::SemiTransparent}else{ +Transparency::Opaque};*&*&();(transparency.map_or(fallback,|t|t.0),error)}pub fn +allow_internal_unstable<'a>(sess:&'a Session,attrs:&'a[Attribute],)->impl//({}); +Iterator+'a{ allow_unstable(sess,attrs,sym::allow_internal_unstable +)}pub fn rustc_allow_const_fn_unstable<'a>(sess :&'a Session,attrs:&'a[Attribute +],)->impl Iterator+'a{allow_unstable(sess,attrs,sym:://loop{break}; +rustc_allow_const_fn_unstable)}fn allow_unstable<'a>( sess:&'a Session,attrs:&'a +[Attribute],symbol:Symbol,)->impl Iterator+'a{({});let attrs=attr:: +filter_by_name(attrs,symbol);({});{;};let list=attrs.filter_map(move|attr|{attr. +meta_item_list().or_else(||{let _=||();sess.dcx().emit_err(session_diagnostics:: +ExpectsFeatureList{span:attr.span,name:symbol.to_ident_string(),});{;};None})}). +flatten();;list.into_iter().filter_map(move|it|{;let name=it.ident().map(|ident| +ident.name);({});if name.is_none(){{;};sess.dcx().emit_err(session_diagnostics:: +ExpectsFeatures{span:it.span(),name:symbol.to_ident_string(),});3;}name})}pub fn +parse_alignment(node:&ast::LitKind)->Result{if let ast:://3; +LitKind::Int(literal,ast::LitIntType::Unsuffixed)=node{if literal.get().//{();}; +is_power_of_two(){literal.get().try_into(). ok().and_then(|v|Align::from_bytes(v +).ok()).ok_or("larger than 2^29")}else{Err("not a power of two")}}else{Err(//(); +"not an unsuffixed integer")}}pub fn parse_confusables(attr:&Attribute)->Option +>{3;let meta=attr.meta()?;;;let MetaItem{kind:MetaItemKind::List(ref +metas),..}=meta else{return None};3;3;let mut candidates=Vec::new();;for meta in +metas{;let NestedMetaItem::Lit(meta_lit)=meta else{return None;};candidates.push +(meta_lit.symbol);loop{break};}loop{break};return Some(candidates);loop{break};} diff --git a/compiler/rustc_attr/src/lib.rs b/compiler/rustc_attr/src/lib.rs index fada69c4e6df1..91b473739bd3f 100644 --- a/compiler/rustc_attr/src/lib.rs +++ b/compiler/rustc_attr/src/lib.rs @@ -1,28 +1,6 @@ -//! Functions and types dealing with attributes and meta items. -//! -//! FIXME(Centril): For now being, much of the logic is still in `rustc_ast::attr`. -//! The goal is to move the definition of `MetaItem` and things that don't need to be in `syntax` -//! to this crate. - -#![allow(internal_features)] -#![feature(rustdoc_internals)] -#![doc(rust_logo)] -#![feature(generic_nonzero)] -#![feature(let_chains)] - -#[macro_use] -extern crate rustc_macros; - -mod builtin; -mod session_diagnostics; - -pub use builtin::*; -pub use IntType::*; -pub use ReprAttr::*; -pub use StabilityLevel::*; - -pub use rustc_ast::attr::*; - -pub(crate) use rustc_session::HashStableContext; - -rustc_fluent_macro::fluent_messages! { "../messages.ftl" } +#![allow(internal_features)]#![feature( rustdoc_internals)]#![doc(rust_logo)]#![ +feature(generic_nonzero)]#![feature(let_chains)]#[macro_use]extern crate//{();}; +rustc_macros;mod builtin;mod session_diagnostics;pub use builtin::*;pub use//(); +IntType::*;pub use ReprAttr::*;pub use StabilityLevel::*;pub use rustc_ast:://3; +attr::*;pub(crate)use rustc_session::HashStableContext;rustc_fluent_macro:://(); +fluent_messages!{"../messages.ftl"}//if true{};let _=||();let _=||();let _=||(); diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs index 0ad7bd6e17e5a..31db5aaa528e0 100644 --- a/compiler/rustc_attr/src/session_diagnostics.rs +++ b/compiler/rustc_attr/src/session_diagnostics.rs @@ -1,402 +1,105 @@ -use std::num::IntErrorKind; - -use rustc_ast as ast; -use rustc_errors::{codes::*, Applicability, Diag, DiagCtxt, Diagnostic, EmissionGuarantee, Level}; -use rustc_macros::Diagnostic; -use rustc_span::{Span, Symbol}; - -use crate::fluent_generated as fluent; -use crate::UnsupportedLiteralReason; - -#[derive(Diagnostic)] -#[diag(attr_expected_one_cfg_pattern, code = E0536)] -pub(crate) struct ExpectedOneCfgPattern { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(attr_invalid_predicate, code = E0537)] -pub(crate) struct InvalidPredicate { - #[primary_span] - pub span: Span, - - pub predicate: String, -} - -#[derive(Diagnostic)] -#[diag(attr_multiple_item, code = E0538)] -pub(crate) struct MultipleItem { - #[primary_span] - pub span: Span, - - pub item: String, -} - -#[derive(Diagnostic)] -#[diag(attr_incorrect_meta_item, code = E0539)] -pub(crate) struct IncorrectMetaItem { - #[primary_span] - pub span: Span, -} - -/// Error code: E0541 -pub(crate) struct UnknownMetaItem<'a> { - pub span: Span, - pub item: String, - pub expected: &'a [&'a str], -} - -// Manual implementation to be able to format `expected` items correctly. -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnknownMetaItem<'_> { - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { - let expected = self.expected.iter().map(|name| format!("`{name}`")).collect::>(); - Diag::new(dcx, level, fluent::attr_unknown_meta_item) - .with_span(self.span) - .with_code(E0541) - .with_arg("item", self.item) - .with_arg("expected", expected.join(", ")) - .with_span_label(self.span, fluent::attr_label) - } -} - -#[derive(Diagnostic)] -#[diag(attr_missing_since, code = E0542)] -pub(crate) struct MissingSince { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(attr_missing_note, code = E0543)] -pub(crate) struct MissingNote { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(attr_multiple_stability_levels, code = E0544)] -pub(crate) struct MultipleStabilityLevels { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(attr_invalid_issue_string, code = E0545)] -pub(crate) struct InvalidIssueString { - #[primary_span] - pub span: Span, - - #[subdiagnostic] - pub cause: Option, -} - -// The error kinds of `IntErrorKind` are duplicated here in order to allow the messages to be -// translatable. -#[derive(Subdiagnostic)] -pub(crate) enum InvalidIssueStringCause { - #[label(attr_must_not_be_zero)] - MustNotBeZero { - #[primary_span] - span: Span, - }, - - #[label(attr_empty)] - Empty { - #[primary_span] - span: Span, - }, - - #[label(attr_invalid_digit)] - InvalidDigit { - #[primary_span] - span: Span, - }, - - #[label(attr_pos_overflow)] - PosOverflow { - #[primary_span] - span: Span, - }, - - #[label(attr_neg_overflow)] - NegOverflow { - #[primary_span] - span: Span, - }, -} - -impl InvalidIssueStringCause { - pub fn from_int_error_kind(span: Span, kind: &IntErrorKind) -> Option { - match kind { - IntErrorKind::Empty => Some(Self::Empty { span }), - IntErrorKind::InvalidDigit => Some(Self::InvalidDigit { span }), - IntErrorKind::PosOverflow => Some(Self::PosOverflow { span }), - IntErrorKind::NegOverflow => Some(Self::NegOverflow { span }), - IntErrorKind::Zero => Some(Self::MustNotBeZero { span }), - _ => None, - } - } -} - -#[derive(Diagnostic)] -#[diag(attr_missing_feature, code = E0546)] -pub(crate) struct MissingFeature { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(attr_non_ident_feature, code = E0546)] -pub(crate) struct NonIdentFeature { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(attr_missing_issue, code = E0547)] -pub(crate) struct MissingIssue { - #[primary_span] - pub span: Span, -} - -// FIXME: Why is this the same error code as `InvalidReprHintNoParen` and `InvalidReprHintNoValue`? -// It is more similar to `IncorrectReprFormatGeneric`. -#[derive(Diagnostic)] -#[diag(attr_incorrect_repr_format_packed_one_or_zero_arg, code = E0552)] -pub(crate) struct IncorrectReprFormatPackedOneOrZeroArg { - #[primary_span] - pub span: Span, -} -#[derive(Diagnostic)] -#[diag(attr_incorrect_repr_format_packed_expect_integer, code = E0552)] -pub(crate) struct IncorrectReprFormatPackedExpectInteger { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(attr_invalid_repr_hint_no_paren, code = E0552)] -pub(crate) struct InvalidReprHintNoParen { - #[primary_span] - pub span: Span, - - pub name: String, -} - -#[derive(Diagnostic)] -#[diag(attr_invalid_repr_hint_no_value, code = E0552)] -pub(crate) struct InvalidReprHintNoValue { - #[primary_span] - pub span: Span, - - pub name: String, -} - -/// Error code: E0565 -pub(crate) struct UnsupportedLiteral { - pub span: Span, - pub reason: UnsupportedLiteralReason, - pub is_bytestr: bool, - pub start_point_span: Span, -} - -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnsupportedLiteral { - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { - let mut diag = Diag::new( - dcx, - level, - match self.reason { - UnsupportedLiteralReason::Generic => fluent::attr_unsupported_literal_generic, - UnsupportedLiteralReason::CfgString => fluent::attr_unsupported_literal_cfg_string, - UnsupportedLiteralReason::DeprecatedString => { - fluent::attr_unsupported_literal_deprecated_string - } - UnsupportedLiteralReason::DeprecatedKvPair => { - fluent::attr_unsupported_literal_deprecated_kv_pair - } - }, - ); - diag.span(self.span); - diag.code(E0565); - if self.is_bytestr { - diag.span_suggestion( - self.start_point_span, - fluent::attr_unsupported_literal_suggestion, - "", - Applicability::MaybeIncorrect, - ); - } - diag - } -} - -#[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(Diagnostic)] -#[diag(attr_invalid_repr_generic, code = E0589)] -pub(crate) struct InvalidReprGeneric<'a> { - #[primary_span] - pub span: Span, - - pub repr_arg: String, - pub error_part: &'a str, -} - -#[derive(Diagnostic)] -#[diag(attr_incorrect_repr_format_align_one_arg, code = E0693)] -pub(crate) struct IncorrectReprFormatAlignOneArg { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(attr_incorrect_repr_format_expect_literal_integer, code = E0693)] -pub(crate) struct IncorrectReprFormatExpectInteger { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(attr_incorrect_repr_format_generic, code = E0693)] -pub(crate) struct IncorrectReprFormatGeneric<'a> { - #[primary_span] - pub span: Span, - - pub repr_arg: &'a str, - - #[subdiagnostic] - pub cause: Option>, -} - -#[derive(Subdiagnostic)] -pub(crate) enum IncorrectReprFormatGenericCause<'a> { - #[suggestion(attr_suggestion, code = "{name}({int})", applicability = "machine-applicable")] - Int { - #[primary_span] - span: Span, - - #[skip_arg] - name: &'a str, - - #[skip_arg] - int: u128, - }, - - #[suggestion(attr_suggestion, code = "{name}({symbol})", applicability = "machine-applicable")] - Symbol { - #[primary_span] - span: Span, - - #[skip_arg] - name: &'a str, - - #[skip_arg] - symbol: Symbol, - }, -} - -impl<'a> IncorrectReprFormatGenericCause<'a> { - pub fn from_lit_kind(span: Span, kind: &ast::LitKind, name: &'a str) -> Option { - match kind { - ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => { - Some(Self::Int { span, name, int: int.get() }) - } - ast::LitKind::Str(symbol, _) => Some(Self::Symbol { span, name, symbol: *symbol }), - _ => None, - } - } -} - -#[derive(Diagnostic)] -#[diag(attr_rustc_promotable_pairing, code = E0717)] -pub(crate) struct RustcPromotablePairing { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(attr_rustc_allowed_unstable_pairing, code = E0789)] -pub(crate) struct RustcAllowedUnstablePairing { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(attr_cfg_predicate_identifier)] -pub(crate) struct CfgPredicateIdentifier { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(attr_deprecated_item_suggestion)] -pub(crate) struct DeprecatedItemSuggestion { - #[primary_span] - pub span: Span, - - #[help] - pub is_nightly: Option<()>, - - #[note] - pub details: (), -} - -#[derive(Diagnostic)] -#[diag(attr_expected_single_version_literal)] -pub(crate) struct ExpectedSingleVersionLiteral { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(attr_expected_version_literal)] -pub(crate) struct ExpectedVersionLiteral { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(attr_expects_feature_list)] -pub(crate) struct ExpectsFeatureList { - #[primary_span] - pub span: Span, - - pub name: String, -} - -#[derive(Diagnostic)] -#[diag(attr_expects_features)] -pub(crate) struct ExpectsFeatures { - #[primary_span] - pub span: Span, - - pub name: String, -} - -#[derive(Diagnostic)] -#[diag(attr_invalid_since)] -pub(crate) struct InvalidSince { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(attr_soft_no_args)] -pub(crate) struct SoftNoArgs { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(attr_unknown_version_literal)] -pub(crate) struct UnknownVersionLiteral { - #[primary_span] - pub span: Span, -} +use std::num::IntErrorKind;use rustc_ast as ast;use rustc_errors::{codes::*,//3; +Applicability,Diag,DiagCtxt,Diagnostic,EmissionGuarantee,Level};use//let _=||(); +rustc_macros::Diagnostic;use rustc_span::{Span,Symbol};use crate:://loop{break}; +fluent_generated as fluent;use crate::UnsupportedLiteralReason;#[derive(//{();}; +Diagnostic)]#[diag(attr_expected_one_cfg_pattern,code=E0536)]pub(crate)struct//; +ExpectedOneCfgPattern{#[primary_span]pub span:Span ,}#[derive(Diagnostic)]#[diag +(attr_invalid_predicate,code=E0537)]pub(crate)struct InvalidPredicate{#[//{();}; +primary_span]pub span:Span,pub predicate:String,}#[derive(Diagnostic)]#[diag(//; +attr_multiple_item,code=E0538)]pub(crate )struct MultipleItem{#[primary_span]pub +span:Span,pub item:String,}#[derive(Diagnostic)]#[diag(//let _=||();loop{break}; +attr_incorrect_meta_item,code=E0539)]pub(crate)struct IncorrectMetaItem{#[//{;}; +primary_span]pub span:Span,}pub(crate) struct UnknownMetaItem<'a>{pub span:Span, +pub item:String,pub expected:&'a[&'a str],}impl<'a,G:EmissionGuarantee>//*&*&(); +Diagnostic<'a,G>for UnknownMetaItem<'_>{fn into_diag(self,dcx:&'a DiagCtxt,//(); +level:Level)->Diag<'a,G>{();let expected=self.expected.iter().map(|name|format!( +"`{name}`")).collect::>();let _=();if true{};Diag::new(dcx,level,fluent:: +attr_unknown_meta_item).with_span(self.span).with_code(E0541).with_arg(("item"), +self.item).with_arg(("expected"),expected.join(", ")).with_span_label(self.span, +fluent::attr_label)}}#[derive(Diagnostic )]#[diag(attr_missing_since,code=E0542) +]pub(crate)struct MissingSince{#[primary_span]pub span:Span,}#[derive(//((),()); +Diagnostic)]#[diag(attr_missing_note,code= E0543)]pub(crate)struct MissingNote{# +[primary_span]pub span:Span,}#[derive(Diagnostic)]#[diag(//if true{};let _=||(); +attr_multiple_stability_levels,code=E0544)]pub(crate)struct//let _=();if true{}; +MultipleStabilityLevels{#[primary_span]pub span:Span,}#[derive(Diagnostic)]#[//; +diag(attr_invalid_issue_string,code=E0545) ]pub(crate)struct InvalidIssueString{ +#[primary_span]pub span:Span,#[subdiagnostic]pub cause:Option,}#[derive(Subdiagnostic)]pub(crate)enum//if let _=(){}; +InvalidIssueStringCause{#[label(attr_must_not_be_zero)]MustNotBeZero{#[//*&*&(); +primary_span]span:Span,},#[label(attr_empty) ]Empty{#[primary_span]span:Span,},# +[label(attr_invalid_digit)]InvalidDigit{#[primary_span]span:Span,},#[label(//(); +attr_pos_overflow)]PosOverflow{#[primary_span]span:Span,},#[label(//loop{break}; +attr_neg_overflow)]NegOverflow{#[primary_span]span:Span,},}impl//*&*&();((),()); +InvalidIssueStringCause{pub fn from_int_error_kind( span:Span,kind:&IntErrorKind +)->Option{match kind{IntErrorKind::Empty=>((Some(((Self::Empty{span}))))), +IntErrorKind::InvalidDigit=>((Some((Self:: InvalidDigit{span})))),IntErrorKind:: +PosOverflow=>Some(Self::PosOverflow{span} ),IntErrorKind::NegOverflow=>Some(Self +::NegOverflow{span}),IntErrorKind::Zero=>(Some((Self::MustNotBeZero{span}))),_=> +None,}}}#[derive(Diagnostic)]# [diag(attr_missing_feature,code=E0546)]pub(crate) +struct MissingFeature{#[primary_span]pub span: Span,}#[derive(Diagnostic)]#[diag +(attr_non_ident_feature,code=E0546)]pub(crate)struct NonIdentFeature{#[//*&*&(); +primary_span]pub span:Span,}#[ derive(Diagnostic)]#[diag(attr_missing_issue,code +=E0547)]pub(crate)struct MissingIssue{#[primary_span]pub span:Span,}#[derive(//; +Diagnostic)]#[diag (attr_incorrect_repr_format_packed_one_or_zero_arg,code=E0552 +)]pub(crate)struct IncorrectReprFormatPackedOneOrZeroArg{#[primary_span]pub//(); +span:Span,}#[derive(Diagnostic)]#[diag(//let _=();if true{};if true{};if true{}; +attr_incorrect_repr_format_packed_expect_integer,code=E0552)]pub(crate)struct//; +IncorrectReprFormatPackedExpectInteger{#[primary_span]pub span:Span,}#[derive(// +Diagnostic)]#[diag(attr_invalid_repr_hint_no_paren, code=E0552)]pub(crate)struct +InvalidReprHintNoParen{#[primary_span]pub span:Span,pub name:String,}#[derive(// +Diagnostic)]#[diag(attr_invalid_repr_hint_no_value, code=E0552)]pub(crate)struct +InvalidReprHintNoValue{#[primary_span]pub span:Span,pub name:String,}pub(crate// +)struct UnsupportedLiteral{pub span:Span,pub reason:UnsupportedLiteralReason,//; +pub is_bytestr:bool,pub start_point_span:Span,}impl<'a,G:EmissionGuarantee>//(); +Diagnostic<'a,G>for UnsupportedLiteral{fn into_diag(self,dcx:&'a DiagCtxt,level +:Level)->Diag<'a,G>{let _=();let mut diag=Diag::new(dcx,level,match self.reason{ +UnsupportedLiteralReason::Generic=>fluent::attr_unsupported_literal_generic,//3; +UnsupportedLiteralReason::CfgString=>fluent:://((),());((),());((),());let _=(); +attr_unsupported_literal_cfg_string,UnsupportedLiteralReason::DeprecatedString// +=>{fluent::attr_unsupported_literal_deprecated_string}UnsupportedLiteralReason// +::DeprecatedKvPair=>{fluent::attr_unsupported_literal_deprecated_kv_pair}},);3;; +diag.span(self.span);;;diag.code(E0565);if self.is_bytestr{diag.span_suggestion( +self.start_point_span,fluent:: attr_unsupported_literal_suggestion,(((((""))))), +Applicability::MaybeIncorrect,);loop{break;};}diag}}#[derive(Diagnostic)]#[diag( +attr_invalid_repr_align_need_arg,code=E0589)]pub(crate)struct//((),());let _=(); +InvalidReprAlignNeedArg{#[primary_span]#[suggestion(code="align(...)",//((),()); +applicability="has-placeholders")]pub span:Span,}#[derive(Diagnostic)]#[diag(//; +attr_invalid_repr_generic,code=E0589)]pub( crate)struct InvalidReprGeneric<'a>{# +[primary_span]pub span:Span,pub repr_arg:String,pub error_part:&'a str,}#[//{;}; +derive(Diagnostic)]#[diag (attr_incorrect_repr_format_align_one_arg,code=E0693)] +pub(crate)struct IncorrectReprFormatAlignOneArg{#[ primary_span]pub span:Span,}# +[derive(Diagnostic)]#[diag(attr_incorrect_repr_format_expect_literal_integer,//; +code=E0693)]pub(crate)struct IncorrectReprFormatExpectInteger{#[primary_span]//; +pub span:Span,}#[derive(Diagnostic)]#[diag(attr_incorrect_repr_format_generic,// +code=E0693)]pub(crate)struct IncorrectReprFormatGeneric<'a>{#[primary_span]pub// +span:Span,pub repr_arg:&'a str,#[subdiagnostic]pub cause:Option>,}#[derive(Subdiagnostic)]pub(crate)enum//3; +IncorrectReprFormatGenericCause<'a>{#[suggestion(attr_suggestion,code=//((),()); +"{name}({int})",applicability="machine-applicable")]Int{#[primary_span]span://3; +Span,#[skip_arg]name:&'a str,# [skip_arg]int:u128,},#[suggestion(attr_suggestion +,code="{name}({symbol})",applicability="machine-applicable")]Symbol{#[//((),()); +primary_span]span:Span,#[skip_arg]name:&'a str,#[skip_arg]symbol:Symbol,},}impl +<'a>IncorrectReprFormatGenericCause<'a>{pub fn from_lit_kind(span:Span,kind:&//; +ast::LitKind,name:&'a str)->Option{match kind{ast::LitKind::Int(int,ast:: +LitIntType::Unsuffixed)=>{Some(Self::Int{span,name ,int:int.get()})}ast::LitKind +::Str(symbol,_)=>(Some((Self::Symbol{span,name, symbol:*symbol}))),_=>None,}}}#[ +derive(Diagnostic)]#[diag(attr_rustc_promotable_pairing,code=E0717)]pub(crate)// +struct RustcPromotablePairing{#[primary_span]pub span:Span,}#[derive(Diagnostic +)]#[diag(attr_rustc_allowed_unstable_pairing,code=E0789)]pub(crate)struct//({}); +RustcAllowedUnstablePairing{#[primary_span]pub span: Span,}#[derive(Diagnostic)] +#[diag(attr_cfg_predicate_identifier)]pub (crate)struct CfgPredicateIdentifier{# +[primary_span]pub span:Span,}#[derive(Diagnostic)]#[diag(//if true{};let _=||(); +attr_deprecated_item_suggestion)]pub(crate)struct DeprecatedItemSuggestion{#[//; +primary_span]pub span:Span,#[help]pub is_nightly :Option<()>,#[note]pub details: +(),}#[derive(Diagnostic) ]#[diag(attr_expected_single_version_literal)]pub(crate +)struct ExpectedSingleVersionLiteral{#[primary_span]pub span:Span,}#[derive(//3; +Diagnostic)]#[diag(attr_expected_version_literal)]pub(crate)struct//loop{break}; +ExpectedVersionLiteral{#[primary_span]pub span:Span,}#[derive(Diagnostic)]#[//3; +diag(attr_expects_feature_list)]pub(crate)struct ExpectsFeatureList{#[//((),()); +primary_span]pub span:Span,pub name:String,}#[derive(Diagnostic)]#[diag(//{();}; +attr_expects_features)]pub(crate)struct ExpectsFeatures{#[primary_span]pub span +:Span,pub name:String,}#[derive(Diagnostic)]#[diag(attr_invalid_since)]pub(//(); +crate)struct InvalidSince{#[primary_span]pub span :Span,}#[derive(Diagnostic)]#[ +diag(attr_soft_no_args)]pub(crate)struct SoftNoArgs{#[primary_span]pub span://3; +Span,}#[derive(Diagnostic)]#[diag(attr_unknown_version_literal)]pub(crate)//{;}; +struct UnknownVersionLiteral{#[primary_span]pub span:Span,}//let _=();if true{}; diff --git a/compiler/rustc_baked_icu_data/src/data/any.rs b/compiler/rustc_baked_icu_data/src/data/any.rs index 230288766764c..3537602241d71 100644 --- a/compiler/rustc_baked_icu_data/src/data/any.rs +++ b/compiler/rustc_baked_icu_data/src/data/any.rs @@ -1,2 +1 @@ -// @generated -impl_any_provider!(BakedDataProvider); +impl_any_provider!(BakedDataProvider);//if true{};if true{};if true{};if true{}; diff --git a/compiler/rustc_baked_icu_data/src/data/macros/fallback_likelysubtags_v1.data.rs b/compiler/rustc_baked_icu_data/src/data/macros/fallback_likelysubtags_v1.data.rs index 1adb58743f727..da30269ed255e 100644 --- a/compiler/rustc_baked_icu_data/src/data/macros/fallback_likelysubtags_v1.data.rs +++ b/compiler/rustc_baked_icu_data/src/data/macros/fallback_likelysubtags_v1.data.rs @@ -1,40 +1,44 @@ -// @generated -/// Implement `DataProvider` on the given struct using the data -/// hardcoded in this file. This allows the struct to be used with -/// `icu`'s `_unstable` constructors. -#[doc(hidden)] -#[macro_export] -macro_rules! __impl_fallback_likelysubtags_v1 { - ($ provider : ty) => { - #[clippy::msrv = "1.66"] - const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; - #[clippy::msrv = "1.66"] - impl $provider { - #[doc(hidden)] - pub const SINGLETON_FALLBACK_LIKELYSUBTAGS_V1: &'static ::Yokeable = &icu_locid_transform::provider::LocaleFallbackLikelySubtagsV1 { - l2s: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"am\0ar\0as\0be\0bg\0bgcbhobn\0brxchrcv\0doiel\0fa\0gu\0he\0hi\0hy\0ja\0ka\0kk\0km\0kn\0ko\0kokks\0ky\0lo\0maimk\0ml\0mn\0mnimr\0my\0ne\0or\0pa\0ps\0rajru\0sa\0satsd\0si\0sr\0ta\0te\0tg\0th\0ti\0tt\0uk\0ur\0yuezh\0") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"EthiArabBengCyrlCyrlDevaDevaBengDevaCherCyrlDevaGrekArabGujrHebrDevaArmnJpanGeorCyrlKhmrKndaKoreDevaArabCyrlLaooDevaCyrlMlymCyrlBengDevaMymrDevaOryaGuruArabDevaCyrlDevaOlckArabSinhCyrlTamlTeluCyrlThaiEthiCyrlCyrlArabHantHans") }) - }, - lr2s: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap2d::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"az\0ha\0kk\0ky\0mn\0ms\0pa\0sd\0sr\0tg\0uz\0yuezh\0") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x03\0\0\0\x05\0\0\0\t\0\0\0\x0B\0\0\0\x0C\0\0\0\r\0\0\0\x0E\0\0\0\x0F\0\0\0\x13\0\0\0\x14\0\0\0\x16\0\0\0\x17\0\0\0&\0\0\0") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"IQ\0IR\0RU\0CM\0SD\0AF\0CN\0IR\0MN\0CN\0TR\0CN\0CC\0PK\0IN\0ME\0RO\0RU\0TR\0PK\0AF\0CN\0CN\0AU\0BN\0GB\0GF\0HK\0ID\0MO\0PA\0PF\0PH\0SR\0TH\0TW\0US\0VN\0") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"ArabArabCyrlArabArabArabArabArabArabArabLatnMongArabArabDevaLatnLatnLatnLatnArabArabCyrlHansHantHantHantHantHantHantHantHantHantHantHantHantHantHantHant") }) - }, - l2r: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"af\0am\0ar\0as\0astaz\0be\0bg\0bgcbhobn\0br\0brxbs\0ca\0cebchrcs\0cv\0cy\0da\0de\0doidsbel\0en\0es\0et\0eu\0fa\0ff\0fi\0filfo\0fr\0ga\0gd\0gl\0gu\0ha\0he\0hi\0hr\0hsbhu\0hy\0ia\0id\0ig\0is\0it\0ja\0jv\0ka\0keakgpkk\0km\0kn\0ko\0kokks\0ky\0lo\0lt\0lv\0maimi\0mk\0ml\0mn\0mnimr\0ms\0my\0ne\0nl\0nn\0no\0or\0pa\0pcmpl\0ps\0pt\0qu\0rajrm\0ro\0ru\0sa\0satsc\0sd\0si\0sk\0sl\0so\0sq\0sr\0su\0sv\0sw\0ta\0te\0tg\0th\0ti\0tk\0to\0tr\0tt\0uk\0ur\0uz\0vi\0wo\0xh\0yo\0yrlyuezh\0zu\0") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"ZA\0ET\0EG\0IN\0ES\0AZ\0BY\0BG\0IN\0IN\0BD\0FR\0IN\0BA\0ES\0PH\0US\0CZ\0RU\0GB\0DK\0DE\0IN\0DE\0GR\0US\0ES\0EE\0ES\0IR\0SN\0FI\0PH\0FO\0FR\0IE\0GB\0ES\0IN\0NG\0IL\0IN\0HR\0DE\0HU\0AM\x00001ID\0NG\0IS\0IT\0JP\0ID\0GE\0CV\0BR\0KZ\0KH\0IN\0KR\0IN\0IN\0KG\0LA\0LT\0LV\0IN\0NZ\0MK\0IN\0MN\0IN\0IN\0MY\0MM\0NP\0NL\0NO\0NO\0IN\0IN\0NG\0PL\0AF\0BR\0PE\0IN\0CH\0RO\0RU\0IN\0IN\0IT\0PK\0LK\0SK\0SI\0SO\0AL\0RS\0ID\0SE\0TZ\0IN\0IN\0TJ\0TH\0ET\0TM\0TO\0TR\0RU\0UA\0PK\0UZ\0VN\0SN\0ZA\0NG\0BR\0HK\0CN\0ZA\0") }) - }, - ls2r: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap2d::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"az\0en\0ff\0kk\0ky\0mn\0pa\0sd\0tg\0uz\0yuezh\0") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x01\0\0\0\x02\0\0\0\x03\0\0\0\x04\0\0\0\x06\0\0\0\x07\0\0\0\x08\0\0\0\x0B\0\0\0\x0C\0\0\0\r\0\0\0\x0E\0\0\0\x11\0\0\0") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"ArabShawAdlmArabArabLatnMongArabDevaKhojSindArabArabHansBopoHanbHant") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"IR\0GB\0GN\0CN\0CN\0TR\0CN\0PK\0IN\0IN\0IN\0PK\0AF\0CN\0TW\0TW\0TW\0") }) - }, - }; - } - #[clippy::msrv = "1.66"] - impl icu_provider::DataProvider for $provider { - fn load(&self, req: icu_provider::DataRequest) -> Result, icu_provider::DataError> { - if req.locale.is_empty() { Ok(icu_provider::DataResponse { payload: Some(icu_provider::DataPayload::from_static_ref(Self::SINGLETON_FALLBACK_LIKELYSUBTAGS_V1)), metadata: Default::default() }) } else { Err(icu_provider::DataErrorKind::ExtraneousLocale.with_req(::KEY, req)) } - } - } - }; -} +#[doc(hidden)]#[macro_export]macro_rules!__impl_fallback_likelysubtags_v1{($//3; +provider:ty)=>{#[clippy::msrv="1.66"]const _:()=<$provider>:://((),());let _=(); +MUST_USE_MAKE_PROVIDER_MACRO;#[clippy::msrv="1.66"] impl$provider{#[doc(hidden)] +pub const SINGLETON_FALLBACK_LIKELYSUBTAGS_V1:&'static:://3; +Yokeable=&icu_locid_transform::provider::LocaleFallbackLikelySubtagsV1{l2s://(); +unsafe{#[allow(unused_unsafe)]zerovec::ZeroMap::from_parts_unchecked(unsafe{//3; +zerovec::ZeroVec::from_bytes_unchecked(//let _=();if true{};if true{};if true{}; +b"am\0ar\0as\0be\0bg\0bgcbhobn\0brxchrcv\0doiel\0fa\0gu\0he\0hi\0hy\0ja\0ka\0kk\0km\0kn\0ko\0kokks\0ky\0lo\0maimk\0ml\0mn\0mnimr\0my\0ne\0or\0pa\0ps\0rajru\0sa\0satsd\0si\0sr\0ta\0te\0tg\0th\0ti\0tt\0uk\0ur\0yuezh\0" +)},unsafe{zerovec::ZeroVec::from_bytes_unchecked(//if let _=(){};*&*&();((),()); +b"EthiArabBengCyrlCyrlDevaDevaBengDevaCherCyrlDevaGrekArabGujrHebrDevaArmnJpanGeorCyrlKhmrKndaKoreDevaArabCyrlLaooDevaCyrlMlymCyrlBengDevaMymrDevaOryaGuruArabDevaCyrlDevaOlckArabSinhCyrlTamlTeluCyrlThaiEthiCyrlCyrlArabHantHans" +)})},lr2s:unsafe{#[allow(unused_unsafe)]zerovec::ZeroMap2d:://let _=();let _=(); +from_parts_unchecked(unsafe{zerovec::ZeroVec::from_bytes_unchecked(//let _=||(); +b"az\0ha\0kk\0ky\0mn\0ms\0pa\0sd\0sr\0tg\0uz\0yuezh\0")},unsafe{zerovec:://({}); +ZeroVec::from_bytes_unchecked(//loop{break};loop{break};loop{break};loop{break}; +b"\x03\0\0\0\x05\0\0\0\t\0\0\0\x0B\0\0\0\x0C\0\0\0\r\0\0\0\x0E\0\0\0\x0F\0\0\0\x13\0\0\0\x14\0\0\0\x16\0\0\0\x17\0\0\0&\0\0\0" +)},unsafe{zerovec::ZeroVec::from_bytes_unchecked(//if let _=(){};*&*&();((),()); +b"IQ\0IR\0RU\0CM\0SD\0AF\0CN\0IR\0MN\0CN\0TR\0CN\0CC\0PK\0IN\0ME\0RO\0RU\0TR\0PK\0AF\0CN\0CN\0AU\0BN\0GB\0GF\0HK\0ID\0MO\0PA\0PF\0PH\0SR\0TH\0TW\0US\0VN\0" +)},unsafe{zerovec::ZeroVec::from_bytes_unchecked(//if let _=(){};*&*&();((),()); +b"ArabArabCyrlArabArabArabArabArabArabArabLatnMongArabArabDevaLatnLatnLatnLatnArabArabCyrlHansHantHantHantHantHantHantHantHantHantHantHantHantHantHantHant" +)})},l2r:unsafe{#[allow(unused_unsafe)]zerovec::ZeroMap::from_parts_unchecked(// +unsafe{zerovec::ZeroVec::from_bytes_unchecked(//((),());((),());((),());((),()); +b"af\0am\0ar\0as\0astaz\0be\0bg\0bgcbhobn\0br\0brxbs\0ca\0cebchrcs\0cv\0cy\0da\0de\0doidsbel\0en\0es\0et\0eu\0fa\0ff\0fi\0filfo\0fr\0ga\0gd\0gl\0gu\0ha\0he\0hi\0hr\0hsbhu\0hy\0ia\0id\0ig\0is\0it\0ja\0jv\0ka\0keakgpkk\0km\0kn\0ko\0kokks\0ky\0lo\0lt\0lv\0maimi\0mk\0ml\0mn\0mnimr\0ms\0my\0ne\0nl\0nn\0no\0or\0pa\0pcmpl\0ps\0pt\0qu\0rajrm\0ro\0ru\0sa\0satsc\0sd\0si\0sk\0sl\0so\0sq\0sr\0su\0sv\0sw\0ta\0te\0tg\0th\0ti\0tk\0to\0tr\0tt\0uk\0ur\0uz\0vi\0wo\0xh\0yo\0yrlyuezh\0zu\0" +)},unsafe{zerovec::ZeroVec::from_bytes_unchecked(//if let _=(){};*&*&();((),()); +b"ZA\0ET\0EG\0IN\0ES\0AZ\0BY\0BG\0IN\0IN\0BD\0FR\0IN\0BA\0ES\0PH\0US\0CZ\0RU\0GB\0DK\0DE\0IN\0DE\0GR\0US\0ES\0EE\0ES\0IR\0SN\0FI\0PH\0FO\0FR\0IE\0GB\0ES\0IN\0NG\0IL\0IN\0HR\0DE\0HU\0AM\x00001ID\0NG\0IS\0IT\0JP\0ID\0GE\0CV\0BR\0KZ\0KH\0IN\0KR\0IN\0IN\0KG\0LA\0LT\0LV\0IN\0NZ\0MK\0IN\0MN\0IN\0IN\0MY\0MM\0NP\0NL\0NO\0NO\0IN\0IN\0NG\0PL\0AF\0BR\0PE\0IN\0CH\0RO\0RU\0IN\0IN\0IT\0PK\0LK\0SK\0SI\0SO\0AL\0RS\0ID\0SE\0TZ\0IN\0IN\0TJ\0TH\0ET\0TM\0TO\0TR\0RU\0UA\0PK\0UZ\0VN\0SN\0ZA\0NG\0BR\0HK\0CN\0ZA\0" +)})},ls2r:unsafe{#[allow(unused_unsafe)]zerovec::ZeroMap2d:://let _=();let _=(); +from_parts_unchecked(unsafe{zerovec::ZeroVec::from_bytes_unchecked(//let _=||(); +b"az\0en\0ff\0kk\0ky\0mn\0pa\0sd\0tg\0uz\0yuezh\0")},unsafe{zerovec::ZeroVec::// +from_bytes_unchecked(//if let _=(){};if let _=(){};if let _=(){};*&*&();((),()); +b"\x01\0\0\0\x02\0\0\0\x03\0\0\0\x04\0\0\0\x06\0\0\0\x07\0\0\0\x08\0\0\0\x0B\0\0\0\x0C\0\0\0\r\0\0\0\x0E\0\0\0\x11\0\0\0" +)},unsafe{zerovec::ZeroVec::from_bytes_unchecked(//if let _=(){};*&*&();((),()); +b"ArabShawAdlmArabArabLatnMongArabDevaKhojSindArabArabHansBopoHanbHant")},//{;}; +unsafe{zerovec::ZeroVec::from_bytes_unchecked(//((),());((),());((),());((),()); +b"IR\0GB\0GN\0CN\0CN\0TR\0CN\0PK\0IN\0IN\0IN\0PK\0AF\0CN\0TW\0TW\0TW\0")}) },};} +#[clippy::msrv="1.66"]impl icu_provider::DataProviderfor$provider{fn load(&self,req://; +icu_provider::DataRequest)->Result,//if true{}; +icu_provider::DataError>{if req.locale .is_empty(){Ok(icu_provider::DataResponse +{payload:Some(icu_provider::DataPayload::from_static_ref(Self:://*&*&();((),()); +SINGLETON_FALLBACK_LIKELYSUBTAGS_V1)),metadata:Default::default()})}else{Err(//; +icu_provider::DataErrorKind::ExtraneousLocale.with_req( +::KEY,req))}}}};}//*&*&();((),());*&*&();((),());*&*&();((),());((),());((),()); diff --git a/compiler/rustc_baked_icu_data/src/data/macros/fallback_parents_v1.data.rs b/compiler/rustc_baked_icu_data/src/data/macros/fallback_parents_v1.data.rs index 6f8d6590b0857..7e598b4faa6d5 100644 --- a/compiler/rustc_baked_icu_data/src/data/macros/fallback_parents_v1.data.rs +++ b/compiler/rustc_baked_icu_data/src/data/macros/fallback_parents_v1.data.rs @@ -1,28 +1,21 @@ -// @generated -/// Implement `DataProvider` on the given struct using the data -/// hardcoded in this file. This allows the struct to be used with -/// `icu`'s `_unstable` constructors. -#[doc(hidden)] -#[macro_export] -macro_rules! __impl_fallback_parents_v1 { - ($ provider : ty) => { - #[clippy::msrv = "1.66"] - const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; - #[clippy::msrv = "1.66"] - impl $provider { - #[doc(hidden)] - pub const SINGLETON_FALLBACK_PARENTS_V1: &'static ::Yokeable = &icu_locid_transform::provider::LocaleFallbackParentsV1 { - parents: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::VarZeroVec::from_bytes_unchecked(b"\x84\0\0\0\0\0\x06\0\x0B\0\x10\0\x15\0\x1A\0\x1F\0$\0)\0.\x003\08\0=\0B\0G\0L\0Q\0V\0[\0`\0e\0j\0o\0t\0y\0~\0\x83\0\x88\0\x8D\0\x92\0\x97\0\x9C\0\xA1\0\xA6\0\xAB\0\xB0\0\xB5\0\xBA\0\xBF\0\xC4\0\xC9\0\xCE\0\xD3\0\xD8\0\xDD\0\xE2\0\xE7\0\xEC\0\xF1\0\xF6\0\xFB\0\0\x01\x05\x01\n\x01\x0F\x01\x14\x01\x19\x01\x1E\x01#\x01(\x01-\x012\x017\x01<\x01A\x01F\x01K\x01P\x01U\x01Z\x01_\x01d\x01i\x01n\x01s\x01x\x01}\x01\x82\x01\x87\x01\x8C\x01\x91\x01\x96\x01\x9B\x01\xA0\x01\xA5\x01\xAA\x01\xAF\x01\xB4\x01\xB9\x01\xBE\x01\xC3\x01\xC8\x01\xCD\x01\xD2\x01\xD7\x01\xDC\x01\xE1\x01\xE6\x01\xEB\x01\xF0\x01\xF5\x01\xFA\x01\xFF\x01\x04\x02\t\x02\x0E\x02\x13\x02\x18\x02\x1D\x02\"\x02'\x02,\x021\x026\x02;\x02@\x02G\x02I\x02K\x02M\x02R\x02W\x02\\\x02a\x02f\x02k\x02p\x02u\x02z\x02\x7F\x02\x84\x02\x89\x02en-150en-AGen-AIen-ATen-AUen-BBen-BEen-BMen-BSen-BWen-BZen-CCen-CHen-CKen-CMen-CXen-CYen-DEen-DGen-DKen-DMen-ERen-FIen-FJen-FKen-FMen-GBen-GDen-GGen-GHen-GIen-GMen-GYen-HKen-IEen-ILen-IMen-INen-IOen-JEen-JMen-KEen-KIen-KNen-KYen-LCen-LRen-LSen-MGen-MOen-MSen-MTen-MUen-MVen-MWen-MYen-NAen-NFen-NGen-NLen-NRen-NUen-NZen-PGen-PKen-PNen-PWen-RWen-SBen-SCen-SDen-SEen-SGen-SHen-SIen-SLen-SSen-SXen-SZen-TCen-TKen-TOen-TTen-TVen-TZen-UGen-VCen-VGen-VUen-WSen-ZAen-ZMen-ZWes-ARes-BOes-BRes-BZes-CLes-COes-CRes-CUes-DOes-ECes-GTes-HNes-MXes-NIes-PAes-PEes-PRes-PYes-SVes-USes-UYes-VEhi-Latnhtnbnnno-NOpt-AOpt-CHpt-CVpt-FRpt-GQpt-GWpt-LUpt-MOpt-MZpt-STpt-TLzh-Hant-MO") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419en\0\0\0\0\0\0\x01IN\0fr\0\0\0\0\0\0\x01HT\0no\0\0\0\0\0\0\0\0\0\0no\0\0\0\0\0\0\0\0\0\0no\0\0\0\0\0\0\0\0\0\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0zh\0\x01Hant\x01HK\0") }) - }, - }; - } - #[clippy::msrv = "1.66"] - impl icu_provider::DataProvider for $provider { - fn load(&self, req: icu_provider::DataRequest) -> Result, icu_provider::DataError> { - if req.locale.is_empty() { Ok(icu_provider::DataResponse { payload: Some(icu_provider::DataPayload::from_static_ref(Self::SINGLETON_FALLBACK_PARENTS_V1)), metadata: Default::default() }) } else { Err(icu_provider::DataErrorKind::ExtraneousLocale.with_req(::KEY, req)) } - } - } - }; -} +#[doc(hidden)]#[ macro_export]macro_rules!__impl_fallback_parents_v1{($provider: +ty)=>{#[clippy::msrv="1.66"]const _:()=<$provider>:://loop{break;};loop{break;}; +MUST_USE_MAKE_PROVIDER_MACRO;#[clippy::msrv="1.66"] impl$provider{#[doc(hidden)] +pub const SINGLETON_FALLBACK_PARENTS_V1:&'static::Yokeable=&//{();}; +icu_locid_transform::provider::LocaleFallbackParentsV1{parents:unsafe{#[allow(// +unused_unsafe)]zerovec::ZeroMap::from_parts_unchecked(unsafe{zerovec:://((),()); +VarZeroVec::from_bytes_unchecked(//let _=||();let _=||();let _=||();loop{break}; +b"\x84\0\0\0\0\0\x06\0\x0B\0\x10\0\x15\0\x1A\0\x1F\0$\0)\0.\x003\08\0=\0B\0G\0L\0Q\0V\0[\0`\0e\0j\0o\0t\0y\0~\0\x83\0\x88\0\x8D\0\x92\0\x97\0\x9C\0\xA1\0\xA6\0\xAB\0\xB0\0\xB5\0\xBA\0\xBF\0\xC4\0\xC9\0\xCE\0\xD3\0\xD8\0\xDD\0\xE2\0\xE7\0\xEC\0\xF1\0\xF6\0\xFB\0\0\x01\x05\x01\n\x01\x0F\x01\x14\x01\x19\x01\x1E\x01#\x01(\x01-\x012\x017\x01<\x01A\x01F\x01K\x01P\x01U\x01Z\x01_\x01d\x01i\x01n\x01s\x01x\x01}\x01\x82\x01\x87\x01\x8C\x01\x91\x01\x96\x01\x9B\x01\xA0\x01\xA5\x01\xAA\x01\xAF\x01\xB4\x01\xB9\x01\xBE\x01\xC3\x01\xC8\x01\xCD\x01\xD2\x01\xD7\x01\xDC\x01\xE1\x01\xE6\x01\xEB\x01\xF0\x01\xF5\x01\xFA\x01\xFF\x01\x04\x02\t\x02\x0E\x02\x13\x02\x18\x02\x1D\x02\"\x02'\x02,\x021\x026\x02;\x02@\x02G\x02I\x02K\x02M\x02R\x02W\x02\\\x02a\x02f\x02k\x02p\x02u\x02z\x02\x7F\x02\x84\x02\x89\x02en-150en-AGen-AIen-ATen-AUen-BBen-BEen-BMen-BSen-BWen-BZen-CCen-CHen-CKen-CMen-CXen-CYen-DEen-DGen-DKen-DMen-ERen-FIen-FJen-FKen-FMen-GBen-GDen-GGen-GHen-GIen-GMen-GYen-HKen-IEen-ILen-IMen-INen-IOen-JEen-JMen-KEen-KIen-KNen-KYen-LCen-LRen-LSen-MGen-MOen-MSen-MTen-MUen-MVen-MWen-MYen-NAen-NFen-NGen-NLen-NRen-NUen-NZen-PGen-PKen-PNen-PWen-RWen-SBen-SCen-SDen-SEen-SGen-SHen-SIen-SLen-SSen-SXen-SZen-TCen-TKen-TOen-TTen-TVen-TZen-UGen-VCen-VGen-VUen-WSen-ZAen-ZMen-ZWes-ARes-BOes-BRes-BZes-CLes-COes-CRes-CUes-DOes-ECes-GTes-HNes-MXes-NIes-PAes-PEes-PRes-PYes-SVes-USes-UYes-VEhi-Latnhtnbnnno-NOpt-AOpt-CHpt-CVpt-FRpt-GQpt-GWpt-LUpt-MOpt-MZpt-STpt-TLzh-Hant-MO" +)},unsafe{zerovec::ZeroVec::from_bytes_unchecked(//if let _=(){};*&*&();((),()); +b"en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419en\0\0\0\0\0\0\x01IN\0fr\0\0\0\0\0\0\x01HT\0no\0\0\0\0\0\0\0\0\0\0no\0\0\0\0\0\0\0\0\0\0no\0\0\0\0\0\0\0\0\0\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0zh\0\x01Hant\x01HK\0" +)})},};}#[clippy::msrv="1.66"]impl icu_provider::DataProviderfor$provider{fn//3; +load(&self,req:icu_provider::DataRequest)->Result,icu_provider:://3; +DataError>{if req.locale.is_empty( ){Ok(icu_provider::DataResponse{payload:Some( +icu_provider::DataPayload::from_static_ref (Self::SINGLETON_FALLBACK_PARENTS_V1) +),metadata:Default::default()})}else{Err(icu_provider::DataErrorKind:://((),()); +ExtraneousLocale.with_req(:: KEY,req))}}}}; +}//let _=();if true{};let _=();if true{};let _=();if true{};if true{};if true{}; diff --git a/compiler/rustc_baked_icu_data/src/data/macros/fallback_supplement_co_v1.data.rs b/compiler/rustc_baked_icu_data/src/data/macros/fallback_supplement_co_v1.data.rs index 02eec37ee09ff..38ae8604f55d0 100644 --- a/compiler/rustc_baked_icu_data/src/data/macros/fallback_supplement_co_v1.data.rs +++ b/compiler/rustc_baked_icu_data/src/data/macros/fallback_supplement_co_v1.data.rs @@ -1,32 +1,24 @@ -// @generated -/// Implement `DataProvider` on the given struct using the data -/// hardcoded in this file. This allows the struct to be used with -/// `icu`'s `_unstable` constructors. -#[doc(hidden)] -#[macro_export] -macro_rules! __impl_fallback_supplement_co_v1 { - ($ provider : ty) => { - #[clippy::msrv = "1.66"] - const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; - #[clippy::msrv = "1.66"] - impl $provider { - #[doc(hidden)] - pub const SINGLETON_FALLBACK_SUPPLEMENT_CO_V1: &'static ::Yokeable = &icu_locid_transform::provider::LocaleFallbackSupplementV1 { - parents: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::VarZeroVec::from_bytes_unchecked(b"\x01\0\0\0\0\0yue") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"zh\0\x01Hant\0\0\0\0") }) - }, - unicode_extension_defaults: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap2d::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"co") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x02\0\0\0") }, unsafe { zerovec::VarZeroVec::from_bytes_unchecked(b"\x02\0\0\0\0\0\x02\0zhzh-Hant") }, unsafe { zerovec::VarZeroVec::from_bytes_unchecked(b"\x02\0\0\0\0\0\x06\0pinyinstroke") }) - }, - }; - } - #[clippy::msrv = "1.66"] - impl icu_provider::DataProvider for $provider { - fn load(&self, req: icu_provider::DataRequest) -> Result, icu_provider::DataError> { - if req.locale.is_empty() { Ok(icu_provider::DataResponse { payload: Some(icu_provider::DataPayload::from_static_ref(Self::SINGLETON_FALLBACK_SUPPLEMENT_CO_V1)), metadata: Default::default() }) } else { Err(icu_provider::DataErrorKind::ExtraneousLocale.with_req(::KEY, req)) } - } - } - }; -} +#[doc(hidden)]#[macro_export]macro_rules!__impl_fallback_supplement_co_v1{($//3; +provider:ty)=>{#[clippy::msrv="1.66"]const _:()=<$provider>:://((),());let _=(); +MUST_USE_MAKE_PROVIDER_MACRO;#[clippy::msrv="1.66"] impl$provider{#[doc(hidden)] +pub const SINGLETON_FALLBACK_SUPPLEMENT_CO_V1:&'static:://3; +Yokeable=&icu_locid_transform::provider::LocaleFallbackSupplementV1{parents://3; +unsafe{#[allow(unused_unsafe)]zerovec::ZeroMap::from_parts_unchecked(unsafe{//3; +zerovec::VarZeroVec::from_bytes_unchecked( b"\x01\0\0\0\0\0yue")},unsafe{zerovec +::ZeroVec::from_bytes_unchecked(b"zh\0\x01Hant\0\0\0\0")})},//let _=();let _=(); +unicode_extension_defaults:unsafe{#[allow(unused_unsafe)]zerovec::ZeroMap2d:://; +from_parts_unchecked(unsafe{zerovec::ZeroVec::from_bytes_unchecked(b"co")},//(); +unsafe{zerovec::ZeroVec::from_bytes_unchecked(b"\x02\0\0\0")},unsafe{zerovec::// +VarZeroVec::from_bytes_unchecked(b"\x02\0\0\0\0\0\x02\0zhzh-Hant")},unsafe{//(); +zerovec::VarZeroVec:: from_bytes_unchecked(b"\x02\0\0\0\0\0\x06\0pinyinstroke")} +)},};}#[clippy:: msrv="1.66"]impl icu_provider::DataProviderfor$provider{ fn load(&self,req: +icu_provider::DataRequest)->Result,//if true{}; +icu_provider::DataError>{if req.locale .is_empty(){Ok(icu_provider::DataResponse +{payload:Some(icu_provider::DataPayload::from_static_ref(Self:://*&*&();((),()); +SINGLETON_FALLBACK_SUPPLEMENT_CO_V1)),metadata:Default::default()})}else{Err(//; +icu_provider::DataErrorKind::ExtraneousLocale.with_req( +::KEY,req))}}}};}//*&*&();((),());*&*&();((),());*&*&();((),());((),());((),()); diff --git a/compiler/rustc_baked_icu_data/src/data/macros/list_and_v1.data.rs b/compiler/rustc_baked_icu_data/src/data/macros/list_and_v1.data.rs index 186f706cdb285..8a2704d6165bc 100644 --- a/compiler/rustc_baked_icu_data/src/data/macros/list_and_v1.data.rs +++ b/compiler/rustc_baked_icu_data/src/data/macros/list_and_v1.data.rs @@ -1,35 +1,464 @@ -// @generated -/// Implement `DataProvider` on the given struct using the data -/// hardcoded in this file. This allows the struct to be used with -/// `icu`'s `_unstable` constructors. -#[doc(hidden)] -#[macro_export] -macro_rules! __impl_list_and_v1 { - ($ provider : ty) => { - #[clippy::msrv = "1.66"] - const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; - #[clippy::msrv = "1.66"] - impl icu_provider::DataProvider for $provider { - fn load(&self, req: icu_provider::DataRequest) -> Result, icu_provider::DataError> { - static EN_001: ::Yokeable = icu_list::provider::ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" and ", 5u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" and ", 5u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" and ", 5u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" and ", 5u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }]); - static EN_IN: ::Yokeable = icu_list::provider::ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" and ", 5u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" and ", 5u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" and ", 5u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" and ", 5u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", and ", 6u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }]); - static IT: ::Yokeable = icu_list::provider::ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8), special_case: None }]); - static PT: ::Yokeable = icu_list::provider::ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }]); - static FR: ::Yokeable = icu_list::provider::ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" et ", 4u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" et ", 4u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" et ", 4u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" et ", 4u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }]); - static TR: ::Yokeable = icu_list::provider::ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" ve ", 4u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" ve ", 4u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" ve ", 4u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" ve ", 4u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }]); - static ES: ::Yokeable = icu_list::provider::ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" y ", 3u8), special_case: Some(icu_list::provider::SpecialCasePattern { condition: unsafe { icu_list::provider::SerdeDFA::from_dfa_bytes_unchecked(if cfg!(target_endian = "little") { b"rust-regex-automata-dfa-sparse\0\0\xFF\xFE\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B(\x01\0\0\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\x04\0\0\0\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#\0\0\0" } else { b"rust-regex-automata-dfa-sparse\0\0\0\0\xFE\xFF\0\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\0\0\x01(\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\0\0\0\x04\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#" }) }, pattern: icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8) }) }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" y ", 3u8), special_case: Some(icu_list::provider::SpecialCasePattern { condition: unsafe { icu_list::provider::SerdeDFA::from_dfa_bytes_unchecked(if cfg!(target_endian = "little") { b"rust-regex-automata-dfa-sparse\0\0\xFF\xFE\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B(\x01\0\0\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\x04\0\0\0\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#\0\0\0" } else { b"rust-regex-automata-dfa-sparse\0\0\0\0\xFE\xFF\0\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\0\0\x01(\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\0\0\0\x04\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#" }) }, pattern: icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8) }) }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" y ", 3u8), special_case: Some(icu_list::provider::SpecialCasePattern { condition: unsafe { icu_list::provider::SerdeDFA::from_dfa_bytes_unchecked(if cfg!(target_endian = "little") { b"rust-regex-automata-dfa-sparse\0\0\xFF\xFE\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B(\x01\0\0\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\x04\0\0\0\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#\0\0\0" } else { b"rust-regex-automata-dfa-sparse\0\0\0\0\xFE\xFF\0\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\0\0\x01(\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\0\0\0\x04\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#" }) }, pattern: icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8) }) }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" y ", 3u8), special_case: Some(icu_list::provider::SpecialCasePattern { condition: unsafe { icu_list::provider::SerdeDFA::from_dfa_bytes_unchecked(if cfg!(target_endian = "little") { b"rust-regex-automata-dfa-sparse\0\0\xFF\xFE\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B(\x01\0\0\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\x04\0\0\0\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#\0\0\0" } else { b"rust-regex-automata-dfa-sparse\0\0\0\0\xFE\xFF\0\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\0\0\x01(\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\0\0\0\x04\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#" }) }, pattern: icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8) }) }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" y ", 3u8), special_case: Some(icu_list::provider::SpecialCasePattern { condition: unsafe { icu_list::provider::SerdeDFA::from_dfa_bytes_unchecked(if cfg!(target_endian = "little") { b"rust-regex-automata-dfa-sparse\0\0\xFF\xFE\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B(\x01\0\0\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\x04\0\0\0\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#\0\0\0" } else { b"rust-regex-automata-dfa-sparse\0\0\0\0\xFE\xFF\0\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\0\0\x01(\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\0\0\0\x04\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#" }) }, pattern: icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8) }) }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" y ", 3u8), special_case: Some(icu_list::provider::SpecialCasePattern { condition: unsafe { icu_list::provider::SerdeDFA::from_dfa_bytes_unchecked(if cfg!(target_endian = "little") { b"rust-regex-automata-dfa-sparse\0\0\xFF\xFE\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B(\x01\0\0\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\x04\0\0\0\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#\0\0\0" } else { b"rust-regex-automata-dfa-sparse\0\0\0\0\xFE\xFF\0\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\0\0\x01(\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\0\0\0\x04\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#" }) }, pattern: icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8) }) }]); - static RU: ::Yokeable = icu_list::provider::ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" и ", 4u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" и ", 4u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" и ", 4u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" и ", 4u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }]); - static UND: ::Yokeable = icu_list::provider::ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }]); - static EN: ::Yokeable = icu_list::provider::ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", and ", 6u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" and ", 5u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", & ", 4u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" & ", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }]); - static HI_LATN: ::Yokeable = icu_list::provider::ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", aur ", 6u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" aur ", 5u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", aur ", 6u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" aur ", 5u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts(" aur ", 5u8), special_case: None }]); - static JA: ::Yokeable = icu_list::provider::ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }]); - static ZH_HK: ::Yokeable = icu_list::provider::ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("及", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("及", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("及", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("及", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("及", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("及", 3u8), special_case: None }]); - static ZH: ::Yokeable = icu_list::provider::ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("和", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("和", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("和", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("和", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }]); - static ZH_HANT: ::Yokeable = icu_list::provider::ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("和", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("和", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("和", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("和", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("、", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("和", 3u8), special_case: None }, icu_list::provider::ConditionalListJoinerPattern { default: icu_list::provider::ListJoinerPattern::from_parts("和", 3u8), special_case: None }]); - static VALUES: [&::Yokeable; 215usize] = [&EN, &EN_001, &EN_001, &EN, &EN_001, &EN_001, &EN, &EN_001, &EN_001, &EN_001, &EN_001, &EN, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_IN, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN, &EN_001, &EN, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN, &EN_001, &EN_001, &EN, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &EN, &EN_001, &EN_001, &EN, &EN_001, &EN_001, &EN_001, &EN_001, &EN_001, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &ES, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &FR, &HI_LATN, &IT, &IT, &IT, &IT, &JA, &PT, &PT, &PT, &PT, &PT, &PT, &PT, &PT, &PT, &PT, &PT, &PT, &RU, &RU, &RU, &RU, &RU, &RU, &TR, &TR, &UND, &ZH, &ZH_HK, &ZH, &ZH, &ZH, &ZH_HANT, &ZH_HK, &ZH]; - static KEYS: [&str; 215usize] = ["en", "en-001", "en-150", "en-AE", "en-AG", "en-AI", "en-AS", "en-AT", "en-AU", "en-BB", "en-BE", "en-BI", "en-BM", "en-BS", "en-BW", "en-BZ", "en-CA", "en-CC", "en-CH", "en-CK", "en-CM", "en-CX", "en-CY", "en-DE", "en-DG", "en-DK", "en-DM", "en-ER", "en-FI", "en-FJ", "en-FK", "en-FM", "en-GB", "en-GD", "en-GG", "en-GH", "en-GI", "en-GM", "en-GU", "en-GY", "en-HK", "en-IE", "en-IL", "en-IM", "en-IN", "en-IO", "en-JE", "en-JM", "en-KE", "en-KI", "en-KN", "en-KY", "en-LC", "en-LR", "en-LS", "en-MG", "en-MH", "en-MO", "en-MP", "en-MS", "en-MT", "en-MU", "en-MV", "en-MW", "en-MY", "en-NA", "en-NF", "en-NG", "en-NL", "en-NR", "en-NU", "en-NZ", "en-PG", "en-PH", "en-PK", "en-PN", "en-PR", "en-PW", "en-RW", "en-SB", "en-SC", "en-SD", "en-SE", "en-SG", "en-SH", "en-SI", "en-SL", "en-SS", "en-SX", "en-SZ", "en-TC", "en-TK", "en-TO", "en-TT", "en-TV", "en-TZ", "en-UG", "en-UM", "en-VC", "en-VG", "en-VI", "en-VU", "en-WS", "en-ZA", "en-ZM", "en-ZW", "es", "es-419", "es-AR", "es-BO", "es-BR", "es-BZ", "es-CL", "es-CO", "es-CR", "es-CU", "es-DO", "es-EA", "es-EC", "es-GQ", "es-GT", "es-HN", "es-IC", "es-MX", "es-NI", "es-PA", "es-PE", "es-PH", "es-PR", "es-PY", "es-SV", "es-US", "es-UY", "es-VE", "fr", "fr-BE", "fr-BF", "fr-BI", "fr-BJ", "fr-BL", "fr-CA", "fr-CD", "fr-CF", "fr-CG", "fr-CH", "fr-CI", "fr-CM", "fr-DJ", "fr-DZ", "fr-GA", "fr-GF", "fr-GN", "fr-GP", "fr-GQ", "fr-HT", "fr-KM", "fr-LU", "fr-MA", "fr-MC", "fr-MF", "fr-MG", "fr-ML", "fr-MQ", "fr-MR", "fr-MU", "fr-NC", "fr-NE", "fr-PF", "fr-PM", "fr-RE", "fr-RW", "fr-SC", "fr-SN", "fr-SY", "fr-TD", "fr-TG", "fr-TN", "fr-VU", "fr-WF", "fr-YT", "hi-Latn", "it", "it-CH", "it-SM", "it-VA", "ja", "pt", "pt-AO", "pt-CH", "pt-CV", "pt-GQ", "pt-GW", "pt-LU", "pt-MO", "pt-MZ", "pt-PT", "pt-ST", "pt-TL", "ru", "ru-BY", "ru-KG", "ru-KZ", "ru-MD", "ru-UA", "tr", "tr-CY", "und", "zh", "zh-HK", "zh-Hans", "zh-Hans-HK", "zh-Hans-MO", "zh-Hant", "zh-MO", "zh-SG"]; - if let Ok(payload) = KEYS.binary_search_by(|k| req.locale.strict_cmp(k.as_bytes()).reverse()).map(|i| *unsafe { VALUES.get_unchecked(i) }) { Ok(icu_provider::DataResponse { payload: Some(icu_provider::DataPayload::from_static_ref(payload)), metadata: Default::default() }) } else { Err(icu_provider::DataErrorKind::MissingLocale.with_req(::KEY, req)) } - } - } - }; -} +#[doc(hidden)]#[macro_export]macro_rules !__impl_list_and_v1{($provider:ty)=>{#[ +clippy::msrv="1.66"]const _:()=<$provider>::MUST_USE_MAKE_PROVIDER_MACRO;#[//(); +clippy::msrv="1.66"]impl icu_provider::DataProviderfor$provider{fn load(&self,req:icu_provider::DataRequest)->//(); +Result,//*&*&(); +icu_provider::DataError>{static EN_001:::Yokeable =icu_list::provider::ListFormatterPatternsV1 +([icu_list::provider::ConditionalListJoinerPattern {default:icu_list::provider:: +ListJoinerPattern::from_parts(", ",2u8), special_case:None},icu_list::provider:: +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(" and ",5u8),special_case:None},icu_list::provider:://*&*&();((),()); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(" and ",5u8),special_case:None},icu_list::provider:://*&*&();((),()); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(" and ",5u8),special_case:None},icu_list::provider:://*&*&();((),()); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(" and ",5u8),special_case:None},icu_list::provider:://*&*&();((),()); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None}]);static EN_IN:::Yokeable=icu_list::provider:://(); +ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern{//{;}; +default:icu_list::provider::ListJoinerPattern::from_parts(", ",2u8),//if true{}; +special_case:None},icu_list::provider::ConditionalListJoinerPattern{default://3; +icu_list::provider::ListJoinerPattern::from_parts(", " ,2u8),special_case:None}, +icu_list::provider::ConditionalListJoinerPattern{default:icu_list::provider:://; +ListJoinerPattern::from_parts(" and ",5u8),special_case:None},icu_list:://{();}; +provider::ConditionalListJoinerPattern{default:icu_list::provider:://let _=||(); +ListJoinerPattern::from_parts(" and ",5u8),special_case:None},icu_list:://{();}; +provider::ConditionalListJoinerPattern{default:icu_list::provider:://let _=||(); +ListJoinerPattern::from_parts(", ",2u8), special_case:None},icu_list::provider:: +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(" and ",5u8),special_case:None},icu_list::provider:://*&*&();((),()); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(" and ",5u8),special_case:None},icu_list::provider:://*&*&();((),()); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", and ",6u8),special_case:None},icu_list::provider:://if let _=(){}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None}]);static IT:::Yokeable=icu_list::provider:://(); +ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern{//{;}; +default:icu_list::provider::ListJoinerPattern::from_parts(", ",2u8),//if true{}; +special_case:None},icu_list::provider::ConditionalListJoinerPattern{default://3; +icu_list::provider::ListJoinerPattern::from_parts(", " ,2u8),special_case:None}, +icu_list::provider::ConditionalListJoinerPattern{default:icu_list::provider:://; +ListJoinerPattern::from_parts(" e ",3u8),special_case:None},icu_list::provider// +::ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern::// +from_parts(" e ",3u8),special_case:None},icu_list::provider:://((),());let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(" e ",3u8),special_case:None},icu_list::provider:://((),());let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(" e ",3u8),special_case:None},icu_list::provider:://((),());let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(" e ",3u8),special_case:None},icu_list::provider:://((),());let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(" e ",3u8),special_case:None}]);static PT:::Yokeable=icu_list::provider:://(); +ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern{//{;}; +default:icu_list::provider::ListJoinerPattern::from_parts(", ",2u8),//if true{}; +special_case:None},icu_list::provider::ConditionalListJoinerPattern{default://3; +icu_list::provider::ListJoinerPattern::from_parts(", " ,2u8),special_case:None}, +icu_list::provider::ConditionalListJoinerPattern{default:icu_list::provider:://; +ListJoinerPattern::from_parts(" e ",3u8),special_case:None},icu_list::provider// +::ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern::// +from_parts(" e ",3u8),special_case:None},icu_list::provider:://((),());let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(" e ",3u8),special_case:None},icu_list::provider:://((),());let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(" e ",3u8),special_case:None},icu_list::provider:://((),());let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None}]);static FR:::Yokeable=icu_list::provider:://(); +ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern{//{;}; +default:icu_list::provider::ListJoinerPattern::from_parts(", ",2u8),//if true{}; +special_case:None},icu_list::provider::ConditionalListJoinerPattern{default://3; +icu_list::provider::ListJoinerPattern::from_parts(", " ,2u8),special_case:None}, +icu_list::provider::ConditionalListJoinerPattern{default:icu_list::provider:://; +ListJoinerPattern::from_parts(" et ",4u8) ,special_case:None},icu_list::provider +::ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern::// +from_parts(" et ",4u8),special_case:None},icu_list::provider:://((),());((),()); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(" et ",4u8),special_case:None},icu_list::provider:://((),());((),()); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(" et ",4u8),special_case:None},icu_list::provider:://((),());((),()); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None}]);static TR:::Yokeable=icu_list::provider:://(); +ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern{//{;}; +default:icu_list::provider::ListJoinerPattern::from_parts(", ",2u8),//if true{}; +special_case:None},icu_list::provider::ConditionalListJoinerPattern{default://3; +icu_list::provider::ListJoinerPattern::from_parts(", " ,2u8),special_case:None}, +icu_list::provider::ConditionalListJoinerPattern{default:icu_list::provider:://; +ListJoinerPattern::from_parts(" ve ",4u8) ,special_case:None},icu_list::provider +::ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern::// +from_parts(" ve ",4u8),special_case:None},icu_list::provider:://((),());((),()); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(" ve ",4u8),special_case:None},icu_list::provider:://((),());((),()); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(" ve ",4u8),special_case:None},icu_list::provider:://((),());((),()); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None}]);static ES:::Yokeable=icu_list::provider:://(); +ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern{//{;}; +default:icu_list::provider::ListJoinerPattern::from_parts(", ",2u8),//if true{}; +special_case:None},icu_list::provider::ConditionalListJoinerPattern{default://3; +icu_list::provider::ListJoinerPattern::from_parts(", " ,2u8),special_case:None}, +icu_list::provider::ConditionalListJoinerPattern{default:icu_list::provider:://; +ListJoinerPattern::from_parts(" y ",3u8) ,special_case:Some(icu_list::provider:: +SpecialCasePattern{condition:unsafe{icu_list::provider::SerdeDFA:://loop{break}; +from_dfa_bytes_unchecked(if cfg!(target_endian="little"){//if true{};let _=||(); +b"rust-regex-automata-dfa-sparse\0\0\xFF\xFE\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B(\x01\0\0\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\x04\0\0\0\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#\0\0\0" +}else{//let _=();let _=();let _=();let _=();let _=();let _=();let _=();let _=(); +b"rust-regex-automata-dfa-sparse\0\0\0\0\xFE\xFF\0\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\0\0\x01(\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\0\0\0\x04\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#" +})},pattern:icu_list::provider::ListJoinerPattern::from_parts(" e ",3u8)})},//3; +icu_list::provider::ConditionalListJoinerPattern{default:icu_list::provider:://; +ListJoinerPattern::from_parts(" y ",3u8) ,special_case:Some(icu_list::provider:: +SpecialCasePattern{condition:unsafe{icu_list::provider::SerdeDFA:://loop{break}; +from_dfa_bytes_unchecked(if cfg!(target_endian="little"){//if true{};let _=||(); +b"rust-regex-automata-dfa-sparse\0\0\xFF\xFE\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B(\x01\0\0\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\x04\0\0\0\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#\0\0\0" +}else{//let _=();let _=();let _=();let _=();let _=();let _=();let _=();let _=(); +b"rust-regex-automata-dfa-sparse\0\0\0\0\xFE\xFF\0\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\0\0\x01(\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\0\0\0\x04\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#" +})},pattern:icu_list::provider::ListJoinerPattern::from_parts(" e ",3u8)})},//3; +icu_list::provider::ConditionalListJoinerPattern{default:icu_list::provider:://; +ListJoinerPattern::from_parts(", ",2u8), special_case:None},icu_list::provider:: +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(" y ",3u8),special_case :Some(icu_list::provider::SpecialCasePattern{ +condition:unsafe{icu_list::provider:: SerdeDFA::from_dfa_bytes_unchecked(if cfg! +(target_endian="little"){//loop{break;};loop{break;};loop{break;};if let _=(){}; +b"rust-regex-automata-dfa-sparse\0\0\xFF\xFE\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B(\x01\0\0\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\x04\0\0\0\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#\0\0\0" +}else{//let _=();let _=();let _=();let _=();let _=();let _=();let _=();let _=(); +b"rust-regex-automata-dfa-sparse\0\0\0\0\xFE\xFF\0\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\0\0\x01(\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\0\0\0\x04\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#" +})},pattern:icu_list::provider::ListJoinerPattern::from_parts(" e ",3u8)})},//3; +icu_list::provider::ConditionalListJoinerPattern{default:icu_list::provider:://; +ListJoinerPattern::from_parts(" y ",3u8) ,special_case:Some(icu_list::provider:: +SpecialCasePattern{condition:unsafe{icu_list::provider::SerdeDFA:://loop{break}; +from_dfa_bytes_unchecked(if cfg!(target_endian="little"){//if true{};let _=||(); +b"rust-regex-automata-dfa-sparse\0\0\xFF\xFE\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B(\x01\0\0\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\x04\0\0\0\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#\0\0\0" +}else{//let _=();let _=();let _=();let _=();let _=();let _=();let _=();let _=(); +b"rust-regex-automata-dfa-sparse\0\0\0\0\xFE\xFF\0\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\0\0\x01(\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\0\0\0\x04\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#" +})},pattern:icu_list::provider::ListJoinerPattern::from_parts(" e ",3u8)})},//3; +icu_list::provider::ConditionalListJoinerPattern{default:icu_list::provider:://; +ListJoinerPattern::from_parts(", ",2u8), special_case:None},icu_list::provider:: +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(" y ",3u8),special_case :Some(icu_list::provider::SpecialCasePattern{ +condition:unsafe{icu_list::provider:: SerdeDFA::from_dfa_bytes_unchecked(if cfg! +(target_endian="little"){//loop{break;};loop{break;};loop{break;};if let _=(){}; +b"rust-regex-automata-dfa-sparse\0\0\xFF\xFE\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B(\x01\0\0\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\x04\0\0\0\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#\0\0\0" +}else{//let _=();let _=();let _=();let _=();let _=();let _=();let _=();let _=(); +b"rust-regex-automata-dfa-sparse\0\0\0\0\xFE\xFF\0\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\0\0\x01(\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\0\0\0\x04\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#" +})},pattern:icu_list::provider::ListJoinerPattern::from_parts(" e ",3u8)})},//3; +icu_list::provider::ConditionalListJoinerPattern{default:icu_list::provider:://; +ListJoinerPattern::from_parts(" y ",3u8) ,special_case:Some(icu_list::provider:: +SpecialCasePattern{condition:unsafe{icu_list::provider::SerdeDFA:://loop{break}; +from_dfa_bytes_unchecked(if cfg!(target_endian="little"){//if true{};let _=||(); +b"rust-regex-automata-dfa-sparse\0\0\xFF\xFE\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B(\x01\0\0\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\x04\0\0\0\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#\0\0\0" +}else{//let _=();let _=();let _=();let _=();let _=();let _=();let _=();let _=(); +b"rust-regex-automata-dfa-sparse\0\0\0\0\xFE\xFF\0\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\0\0\x01(\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\0\0\0\x04\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#" +})},pattern:icu_list::provider::ListJoinerPattern::from_parts(" e ",3u8)})}]);// +static RU::://; +Yokeable=icu_list::provider::ListFormatterPatternsV1([icu_list::provider:://{;}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(" и ",4u8),special_case:None},icu_list::provider:://((),());let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(" и ",4u8),special_case:None},icu_list::provider:://((),());let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(" и ",4u8),special_case:None},icu_list::provider:://((),());let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(" и ",4u8),special_case:None},icu_list::provider:://((),());let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None}]);static UND:::Yokeable=icu_list::provider:://(); +ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern{//{;}; +default:icu_list::provider::ListJoinerPattern::from_parts(", ",2u8),//if true{}; +special_case:None},icu_list::provider::ConditionalListJoinerPattern{default://3; +icu_list::provider::ListJoinerPattern::from_parts(", " ,2u8),special_case:None}, +icu_list::provider::ConditionalListJoinerPattern{default:icu_list::provider:://; +ListJoinerPattern::from_parts(", ",2u8), special_case:None},icu_list::provider:: +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None}]);static EN:::Yokeable=icu_list::provider:://(); +ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern{//{;}; +default:icu_list::provider::ListJoinerPattern::from_parts(", ",2u8),//if true{}; +special_case:None},icu_list::provider::ConditionalListJoinerPattern{default://3; +icu_list::provider::ListJoinerPattern::from_parts(", " ,2u8),special_case:None}, +icu_list::provider::ConditionalListJoinerPattern{default:icu_list::provider:://; +ListJoinerPattern::from_parts(", and ",6u8),special_case:None},icu_list:://({}); +provider::ConditionalListJoinerPattern{default:icu_list::provider:://let _=||(); +ListJoinerPattern::from_parts(" and ",5u8),special_case:None},icu_list:://{();}; +provider::ConditionalListJoinerPattern{default:icu_list::provider:://let _=||(); +ListJoinerPattern::from_parts(", ",2u8), special_case:None},icu_list::provider:: +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", & ",4u8),special_case:None},icu_list::provider:://((),());((),()); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(" & ",3u8),special_case:None},icu_list::provider:://((),());let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None}]);static HI_LATN:::Yokeable=icu_list::provider:://(); +ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern{//{;}; +default:icu_list::provider::ListJoinerPattern::from_parts(", ",2u8),//if true{}; +special_case:None},icu_list::provider::ConditionalListJoinerPattern{default://3; +icu_list::provider::ListJoinerPattern::from_parts(", " ,2u8),special_case:None}, +icu_list::provider::ConditionalListJoinerPattern{default:icu_list::provider:://; +ListJoinerPattern::from_parts(", aur ",6u8),special_case:None},icu_list:://({}); +provider::ConditionalListJoinerPattern{default:icu_list::provider:://let _=||(); +ListJoinerPattern::from_parts(" aur ",5u8),special_case:None},icu_list:://{();}; +provider::ConditionalListJoinerPattern{default:icu_list::provider:://let _=||(); +ListJoinerPattern::from_parts(", ",2u8), special_case:None},icu_list::provider:: +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", aur ",6u8),special_case:None},icu_list::provider:://if let _=(){}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(" aur ",5u8),special_case:None},icu_list::provider:://*&*&();((),()); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(", ",2u8),special_case:None},icu_list::provider:://let _=();let _=(); +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts(" aur ",5u8),special_case:None}]);static JA:::Yokeable=icu_list::provider:://(); +ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern{//{;}; +default:icu_list::provider::ListJoinerPattern:: from_parts("、",3u8),special_case +:None},icu_list::provider::ConditionalListJoinerPattern{default:icu_list:://{;}; +provider::ListJoinerPattern::from_parts("、",3u8),special_case:None},icu_list::// +provider::ConditionalListJoinerPattern{default:icu_list::provider:://let _=||(); +ListJoinerPattern::from_parts("、",3u8),special_case:None},icu_list::provider::// +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("、",3u8),special_case:None},icu_list::provider:://let _=();if true{}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("、",3u8),special_case:None},icu_list::provider:://let _=();if true{}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("、",3u8),special_case:None},icu_list::provider:://let _=();if true{}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("、",3u8),special_case:None},icu_list::provider:://let _=();if true{}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("、",3u8),special_case:None},icu_list::provider:://let _=();if true{}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("、",3u8),special_case:None},icu_list::provider:://let _=();if true{}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("、",3u8),special_case:None},icu_list::provider:://let _=();if true{}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("、",3u8),special_case:None},icu_list::provider:://let _=();if true{}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("、",3u8),special_case:None}]);static ZH_HK:::Yokeable=icu_list::provider:://(); +ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern{//{;}; +default:icu_list::provider::ListJoinerPattern:: from_parts("、",3u8),special_case +:None},icu_list::provider::ConditionalListJoinerPattern{default:icu_list:://{;}; +provider::ListJoinerPattern::from_parts("、",3u8),special_case:None},icu_list::// +provider::ConditionalListJoinerPattern{default:icu_list::provider:://let _=||(); +ListJoinerPattern::from_parts("及",3u8),special_case:None},icu_list::provider::// +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("及",3u8),special_case:None},icu_list::provider:://let _=();if true{}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("、",3u8),special_case:None},icu_list::provider:://let _=();if true{}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("、",3u8),special_case:None},icu_list::provider:://let _=();if true{}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("及",3u8),special_case:None},icu_list::provider:://let _=();if true{}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("及",3u8),special_case:None},icu_list::provider:://let _=();if true{}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("、",3u8),special_case:None},icu_list::provider:://let _=();if true{}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("、",3u8),special_case:None},icu_list::provider:://let _=();if true{}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("及",3u8),special_case:None},icu_list::provider:://let _=();if true{}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("及",3u8),special_case:None}]);static ZH:::Yokeable=icu_list::provider:://(); +ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern{//{;}; +default:icu_list::provider::ListJoinerPattern:: from_parts("、",3u8),special_case +:None},icu_list::provider::ConditionalListJoinerPattern{default:icu_list:://{;}; +provider::ListJoinerPattern::from_parts("、",3u8),special_case:None},icu_list::// +provider::ConditionalListJoinerPattern{default:icu_list::provider:://let _=||(); +ListJoinerPattern::from_parts("和",3u8),special_case:None},icu_list::provider::// +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("和",3u8),special_case:None},icu_list::provider:://let _=();if true{}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("、",3u8),special_case:None},icu_list::provider:://let _=();if true{}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("、",3u8),special_case:None},icu_list::provider:://let _=();if true{}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("和",3u8),special_case:None},icu_list::provider:://let _=();if true{}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("和",3u8),special_case:None},icu_list::provider:://let _=();if true{}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("、",3u8),special_case:None},icu_list::provider:://let _=();if true{}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("、",3u8),special_case:None},icu_list::provider:://let _=();if true{}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("、",3u8),special_case:None},icu_list::provider:://let _=();if true{}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("、",3u8),special_case:None}]);static ZH_HANT:::Yokeable=icu_list::provider:://(); +ListFormatterPatternsV1([icu_list::provider::ConditionalListJoinerPattern{//{;}; +default:icu_list::provider::ListJoinerPattern:: from_parts("、",3u8),special_case +:None},icu_list::provider::ConditionalListJoinerPattern{default:icu_list:://{;}; +provider::ListJoinerPattern::from_parts("、",3u8),special_case:None},icu_list::// +provider::ConditionalListJoinerPattern{default:icu_list::provider:://let _=||(); +ListJoinerPattern::from_parts("和",3u8),special_case:None},icu_list::provider::// +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("和",3u8),special_case:None},icu_list::provider:://let _=();if true{}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("、",3u8),special_case:None},icu_list::provider:://let _=();if true{}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("、",3u8),special_case:None},icu_list::provider:://let _=();if true{}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("和",3u8),special_case:None},icu_list::provider:://let _=();if true{}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("和",3u8),special_case:None},icu_list::provider:://let _=();if true{}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("、",3u8),special_case:None},icu_list::provider:://let _=();if true{}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("、",3u8),special_case:None},icu_list::provider:://let _=();if true{}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("和",3u8),special_case:None},icu_list::provider:://let _=();if true{}; +ConditionalListJoinerPattern{default:icu_list::provider::ListJoinerPattern:://3; +from_parts("和",3u8),special_case:None}]);static VALUES:[&::Yokeable; 215usize]=[&EN,&EN_001,& +EN_001,&EN,&EN_001,&EN_001,&EN,&EN_001,&EN_001,&EN_001,&EN_001,&EN,&EN_001,&//3; +EN_001,&EN_001,&EN_001,&EN_001,&EN_001, &EN_001,&EN_001,&EN_001,&EN_001,&EN_001, +&EN_001,&EN_001,&EN_001,&EN_001,&EN_001 ,&EN_001,&EN_001,&EN_001,&EN_001,&EN_001 +,&EN_001,&EN_001,&EN_001,&EN_001,&EN_001,&EN,&EN_001,&EN_001,&EN_001,&EN_001,&// +EN_001,&EN_IN,&EN_001,&EN_001,&EN_001,& EN_001,&EN_001,&EN_001,&EN_001,&EN_001,& +EN_001,&EN_001,&EN_001,&EN,&EN_001,&EN ,&EN_001,&EN_001,&EN_001,&EN_001,&EN_001, +&EN_001,&EN_001,&EN_001,&EN_001,&EN_001,&EN_001,&EN_001,&EN_001,&EN_001,&EN,&//; +EN_001,&EN_001,&EN,&EN_001,&EN_001,&EN_001,&EN_001,&EN_001,&EN_001,&EN_001,&//3; +EN_001,&EN_001,&EN_001,&EN_001,&EN_001, &EN_001,&EN_001,&EN_001,&EN_001,&EN_001, +&EN_001,&EN_001,&EN_001,&EN,&EN_001,& EN_001,&EN,&EN_001,&EN_001,&EN_001,&EN_001 +,&EN_001,&ES,&ES,&ES,&ES,&ES,&ES,&ES,&ES,&ES,&ES,&ES,&ES,&ES,&ES,&ES,&ES,&ES,&// +ES,&ES,&ES,&ES,&ES,&ES,&ES,&ES,&ES,&ES, &ES,&FR,&FR,&FR,&FR,&FR,&FR,&FR,&FR,&FR, +&FR,&FR,&FR,&FR,&FR,&FR,&FR,&FR,&FR,&FR ,&FR,&FR,&FR,&FR,&FR,&FR,&FR,&FR,&FR,&FR +,&FR,&FR,&FR,&FR,&FR,&FR,&FR,&FR,&FR, &FR,&FR,&FR,&FR,&FR,&FR,&FR,&FR,&HI_LATN,& +IT,&IT,&IT,&IT,&JA,&PT,&PT,&PT,&PT,&PT, &PT,&PT,&PT,&PT,&PT,&PT,&PT,&RU,&RU,&RU, +&RU,&RU,&RU,&TR,&TR,&UND,&ZH,&ZH_HK,&ZH,&ZH,&ZH,&ZH_HANT,&ZH_HK,&ZH];static//(); +KEYS:[&str;215usize]=["en","en-001","en-150","en-AE","en-AG","en-AI","en-AS",//; +"en-AT","en-AU","en-BB","en-BE","en-BI" ,"en-BM","en-BS","en-BW","en-BZ","en-CA" +,"en-CC","en-CH","en-CK","en-CM","en-CX","en-CY","en-DE","en-DG","en-DK",//({}); +"en-DM","en-ER","en-FI","en-FJ","en-FK" ,"en-FM","en-GB","en-GD","en-GG","en-GH" +,"en-GI","en-GM","en-GU","en-GY","en-HK","en-IE","en-IL","en-IM","en-IN",//({}); +"en-IO","en-JE","en-JM","en-KE","en-KI" ,"en-KN","en-KY","en-LC","en-LR","en-LS" +,"en-MG","en-MH","en-MO","en-MP","en-MS","en-MT","en-MU","en-MV","en-MW",//({}); +"en-MY","en-NA","en-NF","en-NG","en-NL" ,"en-NR","en-NU","en-NZ","en-PG","en-PH" +,"en-PK","en-PN","en-PR","en-PW","en-RW","en-SB","en-SC","en-SD","en-SE",//({}); +"en-SG","en-SH","en-SI","en-SL","en-SS" ,"en-SX","en-SZ","en-TC","en-TK","en-TO" +,"en-TT","en-TV","en-TZ","en-UG","en-UM","en-VC","en-VG","en-VI","en-VU",//({}); +"en-WS","en-ZA","en-ZM","en-ZW","es","es-419","es-AR","es-BO","es-BR","es-BZ",// +"es-CL","es-CO","es-CR","es-CU","es-DO" ,"es-EA","es-EC","es-GQ","es-GT","es-HN" +,"es-IC","es-MX","es-NI","es-PA","es-PE","es-PH","es-PR","es-PY","es-SV",//({}); +"es-US","es-UY","es-VE","fr","fr-BE","fr-BF","fr-BI","fr-BJ","fr-BL","fr-CA",//; +"fr-CD","fr-CF","fr-CG","fr-CH","fr-CI" ,"fr-CM","fr-DJ","fr-DZ","fr-GA","fr-GF" +,"fr-GN","fr-GP","fr-GQ","fr-HT","fr-KM","fr-LU","fr-MA","fr-MC","fr-MF",//({}); +"fr-MG","fr-ML","fr-MQ","fr-MR","fr-MU" ,"fr-NC","fr-NE","fr-PF","fr-PM","fr-RE" +,"fr-RW","fr-SC","fr-SN","fr-SY","fr-TD","fr-TG","fr-TN","fr-VU","fr-WF",//({}); +"fr-YT","hi-Latn","it","it-CH","it-SM","it-VA","ja","pt","pt-AO","pt-CH",//({}); +"pt-CV","pt-GQ","pt-GW","pt-LU","pt-MO","pt-MZ","pt-PT","pt-ST","pt-TL","ru",//; +"ru-BY","ru-KG","ru-KZ","ru-MD","ru-UA","tr","tr-CY","und","zh","zh-HK",//{();}; +"zh-Hans","zh-Hans-HK","zh-Hans-MO","zh-Hant","zh-MO","zh-SG"];if let Ok(//({}); +payload)=KEYS.binary_search_by(|k|req.locale .strict_cmp(k.as_bytes()).reverse() +).map(|i|*unsafe{VALUES.get_unchecked(i)}){Ok(icu_provider::DataResponse{//({}); +payload:Some(icu_provider::DataPayload::from_static_ref(payload)),metadata://(); +Default::default()})}else{Err(icu_provider::DataErrorKind::MissingLocale.//({}); +with_req( +::KEY,req))}}}};}//*&*&();((),());*&*&();((),());*&*&();((),());((),());((),()); diff --git a/compiler/rustc_baked_icu_data/src/data/mod.rs b/compiler/rustc_baked_icu_data/src/data/mod.rs index 465689f0cb8d7..b09918f4b2c97 100644 --- a/compiler/rustc_baked_icu_data/src/data/mod.rs +++ b/compiler/rustc_baked_icu_data/src/data/mod.rs @@ -1,31 +1,25 @@ -// @generated -include!("macros.rs"); -macro_rules! impl_data_provider { - ($ provider : ty) => { - make_provider!($provider); - impl_fallback_likelysubtags_v1!($provider); - impl_fallback_parents_v1!($provider); - impl_fallback_supplement_co_v1!($provider); - impl_list_and_v1!($provider); - }; -} -#[allow(unused_macros)] -macro_rules! impl_any_provider { - ($ provider : ty) => { - #[clippy::msrv = "1.66"] - impl icu_provider::AnyProvider for $provider { - fn load_any(&self, key: icu_provider::DataKey, req: icu_provider::DataRequest) -> Result { - match key.hashed() { - h if h == ::KEY.hashed() => icu_provider::DataProvider::::load(self, req).map(icu_provider::DataResponse::wrap_into_any_response), - h if h == ::KEY.hashed() => icu_provider::DataProvider::::load(self, req).map(icu_provider::DataResponse::wrap_into_any_response), - h if h == ::KEY.hashed() => icu_provider::DataProvider::::load(self, req).map(icu_provider::DataResponse::wrap_into_any_response), - h if h == ::KEY.hashed() => icu_provider::DataProvider::::load(self, req).map(icu_provider::DataResponse::wrap_into_any_response), - _ => Err(icu_provider::DataErrorKind::MissingDataKey.with_req(key, req)), - } - } - } - }; -} -#[clippy::msrv = "1.66"] -pub struct BakedDataProvider; -impl_data_provider!(BakedDataProvider); +include!("macros.rs");macro_rules!impl_data_provider{($provider:ty)=>{//((),()); +make_provider!($provider);impl_fallback_likelysubtags_v1!($provider);//let _=(); +impl_fallback_parents_v1!($provider) ;impl_fallback_supplement_co_v1!($provider) +;impl_list_and_v1!($provider);};}#[allow(unused_macros)]macro_rules!//if true{}; +impl_any_provider{($provider:ty)=>{#[clippy::msrv="1.66"]impl icu_provider:://3; +AnyProvider for$provider{fn load_any(&self,key:icu_provider::DataKey,req://({}); +icu_provider::DataRequest)->Result{match key.hashed(){h if h==::KEY.//(); +hashed()=>icu_provider::DataProvider::::load(self,req).map(icu_provider:://*&*&(); +DataResponse::wrap_into_any_response),h if h==::KEY.hashed()=> +icu_provider::DataProvider::::load(self,req ).map(icu_provider::DataResponse:: +wrap_into_any_response),h if h==::KEY.//(); +hashed()=>icu_provider::DataProvider::::load(self,req).map(icu_provider:://*&*&(); +DataResponse::wrap_into_any_response),h if h== ::KEY.hashed()=>icu_provider:: +DataProvider::::load(self,req).map(//{();}; +icu_provider::DataResponse::wrap_into_any_response),_=>Err(icu_provider:://({}); +DataErrorKind::MissingDataKey.with_req(key,req)),}} }};}#[clippy::msrv="1.66"]// +pub struct BakedDataProvider;impl_data_provider!(BakedDataProvider);//if true{}; diff --git a/compiler/rustc_baked_icu_data/src/lib.rs b/compiler/rustc_baked_icu_data/src/lib.rs index ffcb290685a19..9897ccc5331b1 100644 --- a/compiler/rustc_baked_icu_data/src/lib.rs +++ b/compiler/rustc_baked_icu_data/src/lib.rs @@ -1,50 +1,12 @@ -//! This crate contains pre-baked ICU4X data, generated by `icu4x-datagen`. The tool -//! fetches locale data from CLDR and transforms them into const code in statics that -//! ICU4X can load, via databake. `lib.rs` in this crate is manually written, but all -//! other code is generated. -//! -//! This crate can be regenerated when there's a new CLDR version, though that is unlikely -//! to result in changes in most cases (currently this only covers list formatting data, which -//! is rather stable). It may need to be regenerated when updating ICU4X versions, especially -//! across major versions, in case it fails to compile after an update. -//! -//! It must be regenerated when adding new locales to Rust, or if Rust's usage of ICU4X -//! grows to need more kinds of data. -//! -//! To regenerate the data, run this command: -//! -//! ```text -//! icu4x-datagen -W --pretty --fingerprint --use-separate-crates \ -//! --format mod -l en es fr it ja pt ru tr zh zh-Hans zh-Hant \ -//! -k list/and@1 fallback/likelysubtags@1 fallback/parents@1 fallback/supplement/co@1 \ -//! --cldr-tag latest --icuexport-tag latest -o src/data -//! ``` - -#![allow(internal_features)] -#![feature(rustdoc_internals)] -#![doc(rust_logo)] -#![allow(elided_lifetimes_in_paths)] - -mod data { - include!("data/mod.rs"); - include!("data/any.rs"); -} - -pub use data::BakedDataProvider; - -pub const fn baked_data_provider() -> BakedDataProvider { - data::BakedDataProvider -} - -pub mod supported_locales { - pub const EN: icu_locid::Locale = icu_locid::locale!("en"); - pub const ES: icu_locid::Locale = icu_locid::locale!("es"); - pub const FR: icu_locid::Locale = icu_locid::locale!("fr"); - pub const IT: icu_locid::Locale = icu_locid::locale!("it"); - pub const JA: icu_locid::Locale = icu_locid::locale!("ja"); - pub const PT: icu_locid::Locale = icu_locid::locale!("pt"); - pub const RU: icu_locid::Locale = icu_locid::locale!("ru"); - pub const TR: icu_locid::Locale = icu_locid::locale!("tr"); - pub const ZH_HANS: icu_locid::Locale = icu_locid::locale!("zh-Hans"); - pub const ZH_HANT: icu_locid::Locale = icu_locid::locale!("zh-Hant"); -} +#![allow(internal_features)]#![feature( rustdoc_internals)]#![doc(rust_logo)]#![ +allow(elided_lifetimes_in_paths)]mod data{include!("data/mod.rs");include!(//(); +"data/any.rs");}pub use data::BakedDataProvider;pub const fn//let _=();let _=(); +baked_data_provider()->BakedDataProvider{data::BakedDataProvider}pub mod//{();}; +supported_locales{pub const EN:icu_locid::Locale =(icu_locid::locale!("en"));pub +const ES:icu_locid::Locale=((icu_locid::locale!("es")));pub const FR:icu_locid:: +Locale=(((icu_locid::locale!("fr"))));pub const IT:icu_locid::Locale=icu_locid:: +locale!("it");pub const JA:icu_locid:: Locale=icu_locid::locale!("ja");pub const +PT:icu_locid::Locale=(icu_locid::locale!("pt" ));pub const RU:icu_locid::Locale= +icu_locid::locale!("ru");pub const TR:icu_locid::Locale=icu_locid::locale!("tr" +);pub const ZH_HANS:icu_locid::Locale= (icu_locid::locale!("zh-Hans"));pub const +ZH_HANT:icu_locid::Locale=(((((((((((icu_locid ::locale!("zh-Hant"))))))))))));} diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs index 6a683d129ded1..059a50be15fd5 100644 --- a/compiler/rustc_borrowck/src/borrow_set.rs +++ b/compiler/rustc_borrowck/src/borrow_set.rs @@ -1,347 +1,99 @@ -use crate::path_utils::allow_two_phase_borrow; -use crate::place_ext::PlaceExt; -use crate::BorrowIndex; -use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; -use rustc_index::bit_set::BitSet; -use rustc_middle::mir::traversal; -use rustc_middle::mir::visit::{MutatingUseContext, NonUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::{self, Body, Local, Location}; -use rustc_middle::ty::{RegionVid, TyCtxt}; -use rustc_mir_dataflow::move_paths::MoveData; -use std::fmt; -use std::ops::Index; - -pub struct BorrowSet<'tcx> { - /// The fundamental map relating bitvector indexes to the borrows - /// in the MIR. Each borrow is also uniquely identified in the MIR - /// by the `Location` of the assignment statement in which it - /// appears on the right hand side. Thus the location is the map - /// key, and its position in the map corresponds to `BorrowIndex`. - pub location_map: FxIndexMap>, - - /// Locations which activate borrows. - /// NOTE: a given location may activate more than one borrow in the future - /// when more general two-phase borrow support is introduced, but for now we - /// only need to store one borrow index. - pub activation_map: FxIndexMap>, - - /// Map from local to all the borrows on that local. - pub local_map: FxIndexMap>, - - pub locals_state_at_exit: LocalsStateAtExit, -} - -impl<'tcx> Index for BorrowSet<'tcx> { - type Output = BorrowData<'tcx>; - - fn index(&self, index: BorrowIndex) -> &BorrowData<'tcx> { - &self.location_map[index.as_usize()] - } -} - -/// Location where a two-phase borrow is activated, if a borrow -/// is in fact a two-phase borrow. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum TwoPhaseActivation { - NotTwoPhase, - NotActivated, - ActivatedAt(Location), -} - -#[derive(Debug, Clone)] -pub struct BorrowData<'tcx> { - /// Location where the borrow reservation starts. - /// In many cases, this will be equal to the activation location but not always. - pub reserve_location: Location, - /// Location where the borrow is activated. - pub activation_location: TwoPhaseActivation, - /// What kind of borrow this is - pub kind: mir::BorrowKind, - /// The region for which this borrow is live - pub region: RegionVid, - /// Place from which we are borrowing - pub borrowed_place: mir::Place<'tcx>, - /// Place to which the borrow was stored - pub assigned_place: mir::Place<'tcx>, -} - -impl<'tcx> fmt::Display for BorrowData<'tcx> { - fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result { - let kind = match self.kind { - mir::BorrowKind::Shared => "", - mir::BorrowKind::Fake => "fake ", - mir::BorrowKind::Mut { kind: mir::MutBorrowKind::ClosureCapture } => "uniq ", - // FIXME: differentiate `TwoPhaseBorrow` - mir::BorrowKind::Mut { - kind: mir::MutBorrowKind::Default | mir::MutBorrowKind::TwoPhaseBorrow, - } => "mut ", - }; - write!(w, "&{:?} {}{:?}", self.region, kind, self.borrowed_place) - } -} - -pub enum LocalsStateAtExit { - AllAreInvalidated, - SomeAreInvalidated { has_storage_dead_or_moved: BitSet }, -} - -impl LocalsStateAtExit { - fn build<'tcx>( - locals_are_invalidated_at_exit: bool, - body: &Body<'tcx>, - move_data: &MoveData<'tcx>, - ) -> Self { - struct HasStorageDead(BitSet); - - impl<'tcx> Visitor<'tcx> for HasStorageDead { - fn visit_local(&mut self, local: Local, ctx: PlaceContext, _: Location) { - if ctx == PlaceContext::NonUse(NonUseContext::StorageDead) { - self.0.insert(local); - } - } - } - - if locals_are_invalidated_at_exit { - LocalsStateAtExit::AllAreInvalidated - } else { - let mut has_storage_dead = HasStorageDead(BitSet::new_empty(body.local_decls.len())); - has_storage_dead.visit_body(body); - let mut has_storage_dead_or_moved = has_storage_dead.0; - for move_out in &move_data.moves { - if let Some(index) = move_data.base_local(move_out.path) { - has_storage_dead_or_moved.insert(index); - } - } - LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } - } - } -} - -impl<'tcx> BorrowSet<'tcx> { - pub fn build( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - locals_are_invalidated_at_exit: bool, - move_data: &MoveData<'tcx>, - ) -> Self { - let mut visitor = GatherBorrows { - tcx, - body: body, - location_map: Default::default(), - activation_map: Default::default(), - local_map: Default::default(), - pending_activations: Default::default(), - locals_state_at_exit: LocalsStateAtExit::build( - locals_are_invalidated_at_exit, - body, - move_data, - ), - }; - - for (block, block_data) in traversal::preorder(body) { - visitor.visit_basic_block_data(block, block_data); - } - - BorrowSet { - location_map: visitor.location_map, - activation_map: visitor.activation_map, - local_map: visitor.local_map, - locals_state_at_exit: visitor.locals_state_at_exit, - } - } - - pub(crate) fn activations_at_location(&self, location: Location) -> &[BorrowIndex] { - self.activation_map.get(&location).map_or(&[], |activations| &activations[..]) - } - - pub fn len(&self) -> usize { - self.location_map.len() - } - - pub(crate) fn indices(&self) -> impl Iterator { - BorrowIndex::from_usize(0)..BorrowIndex::from_usize(self.len()) - } - - pub(crate) fn iter_enumerated(&self) -> impl Iterator)> { - self.indices().zip(self.location_map.values()) - } - - pub(crate) fn get_index_of(&self, location: &Location) -> Option { - self.location_map.get_index_of(location).map(BorrowIndex::from) - } -} - -struct GatherBorrows<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - body: &'a Body<'tcx>, - location_map: FxIndexMap>, - activation_map: FxIndexMap>, - local_map: FxIndexMap>, - - /// When we encounter a 2-phase borrow statement, it will always - /// be assigning into a temporary TEMP: - /// - /// TEMP = &foo - /// - /// We add TEMP into this map with `b`, where `b` is the index of - /// the borrow. When we find a later use of this activation, we - /// remove from the map (and add to the "tombstone" set below). - pending_activations: FxIndexMap, - - locals_state_at_exit: LocalsStateAtExit, -} - -impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> { - fn visit_assign( - &mut self, - assigned_place: &mir::Place<'tcx>, - rvalue: &mir::Rvalue<'tcx>, - location: mir::Location, - ) { - if let &mir::Rvalue::Ref(region, kind, borrowed_place) = rvalue { - if borrowed_place.ignore_borrow(self.tcx, self.body, &self.locals_state_at_exit) { - debug!("ignoring_borrow of {:?}", borrowed_place); - return; - } - - let region = region.as_var(); - - let borrow = BorrowData { - kind, - region, - reserve_location: location, - activation_location: TwoPhaseActivation::NotTwoPhase, - borrowed_place, - assigned_place: *assigned_place, - }; - let (idx, _) = self.location_map.insert_full(location, borrow); - let idx = BorrowIndex::from(idx); - - self.insert_as_pending_if_two_phase(location, assigned_place, kind, idx); - - self.local_map.entry(borrowed_place.local).or_default().insert(idx); - } - - self.super_assign(assigned_place, rvalue, location) - } - - fn visit_local(&mut self, temp: Local, context: PlaceContext, location: Location) { - if !context.is_use() { - return; - } - - // We found a use of some temporary TMP - // check whether we (earlier) saw a 2-phase borrow like - // - // TMP = &mut place - if let Some(&borrow_index) = self.pending_activations.get(&temp) { - let borrow_data = &mut self.location_map[borrow_index.as_usize()]; - - // Watch out: the use of TMP in the borrow itself - // doesn't count as an activation. =) - if borrow_data.reserve_location == location - && context == PlaceContext::MutatingUse(MutatingUseContext::Store) - { - return; - } - - if let TwoPhaseActivation::ActivatedAt(other_location) = borrow_data.activation_location - { - span_bug!( - self.body.source_info(location).span, - "found two uses for 2-phase borrow temporary {:?}: \ - {:?} and {:?}", - temp, - location, - other_location, - ); - } - - // Otherwise, this is the unique later use that we expect. - // Double check: This borrow is indeed a two-phase borrow (that is, - // we are 'transitioning' from `NotActivated` to `ActivatedAt`) and - // we've not found any other activations (checked above). - assert_eq!( - borrow_data.activation_location, - TwoPhaseActivation::NotActivated, - "never found an activation for this borrow!", - ); - self.activation_map.entry(location).or_default().push(borrow_index); - - borrow_data.activation_location = TwoPhaseActivation::ActivatedAt(location); - } - } - - fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: mir::Location) { - if let &mir::Rvalue::Ref(region, kind, place) = rvalue { - // double-check that we already registered a BorrowData for this - - let borrow_data = &self.location_map[&location]; - assert_eq!(borrow_data.reserve_location, location); - assert_eq!(borrow_data.kind, kind); - assert_eq!(borrow_data.region, region.as_var()); - assert_eq!(borrow_data.borrowed_place, place); - } - - self.super_rvalue(rvalue, location) - } -} - -impl<'a, 'tcx> GatherBorrows<'a, 'tcx> { - /// If this is a two-phase borrow, then we will record it - /// as "pending" until we find the activating use. - fn insert_as_pending_if_two_phase( - &mut self, - start_location: Location, - assigned_place: &mir::Place<'tcx>, - kind: mir::BorrowKind, - borrow_index: BorrowIndex, - ) { - debug!( - "Borrows::insert_as_pending_if_two_phase({:?}, {:?}, {:?})", - start_location, assigned_place, borrow_index, - ); - - if !allow_two_phase_borrow(kind) { - debug!(" -> {:?}", start_location); - return; - } - - // When we encounter a 2-phase borrow statement, it will always - // be assigning into a temporary TEMP: - // - // TEMP = &foo - // - // so extract `temp`. - let Some(temp) = assigned_place.as_local() else { - span_bug!( - self.body.source_info(start_location).span, - "expected 2-phase borrow to assign to a local, not `{:?}`", - assigned_place, - ); - }; - - // Consider the borrow not activated to start. When we find an activation, we'll update - // this field. - { - let borrow_data = &mut self.location_map[borrow_index.as_usize()]; - borrow_data.activation_location = TwoPhaseActivation::NotActivated; - } - - // Insert `temp` into the list of pending activations. From - // now on, we'll be on the lookout for a use of it. Note that - // we are guaranteed that this use will come after the - // assignment. - let old_value = self.pending_activations.insert(temp, borrow_index); - if let Some(old_index) = old_value { - span_bug!( - self.body.source_info(start_location).span, - "found already pending activation for temp: {:?} \ - at borrow_index: {:?} with associated data {:?}", - temp, - old_index, - self.location_map[old_index.as_usize()] - ); - } - } -} +use crate::path_utils::allow_two_phase_borrow;use crate::place_ext::PlaceExt;//; +use crate::BorrowIndex;use rustc_data_structures::fx::{FxIndexMap,FxIndexSet};// +use rustc_index::bit_set::BitSet;use rustc_middle::mir::traversal;use//let _=(); +rustc_middle::mir::visit::{MutatingUseContext,NonUseContext,PlaceContext,//({}); +Visitor};use rustc_middle::mir::{self, Body,Local,Location};use rustc_middle::ty +::{RegionVid,TyCtxt};use rustc_mir_dataflow ::move_paths::MoveData;use std::fmt; +use std::ops::Index;pub struct BorrowSet<'tcx>{pub location_map:FxIndexMap>,pub activation_map:FxIndexMap>,pub local_map:FxIndexMap>,pub// +locals_state_at_exit:LocalsStateAtExit,}impl<'tcx>Indexfor//*&*&(); +BorrowSet<'tcx>{type Output=BorrowData<'tcx>;fn index(&self,index:BorrowIndex)// +->&BorrowData<'tcx>{(&self.location_map[index.as_usize()])}}#[derive(Copy,Clone, +PartialEq,Eq,Debug)]pub enum TwoPhaseActivation{NotTwoPhase,NotActivated,//({}); +ActivatedAt(Location),}#[derive(Debug,Clone)]pub struct BorrowData<'tcx>{pub//3; +reserve_location:Location,pub activation_location:TwoPhaseActivation,pub kind:// +mir::BorrowKind,pub region:RegionVid,pub borrowed_place:mir::Place<'tcx>,pub//3; +assigned_place:mir::Place<'tcx>,}impl<'tcx >fmt::Display for BorrowData<'tcx>{fn +fmt(&self,w:&mut fmt::Formatter<'_>)->fmt::Result{3;let kind=match self.kind{mir +::BorrowKind::Shared=>(""),mir::BorrowKind ::Fake=>"fake ",mir::BorrowKind::Mut{ +kind:mir::MutBorrowKind::ClosureCapture}=>"uniq " ,mir::BorrowKind::Mut{kind:mir +::MutBorrowKind::Default|mir::MutBorrowKind::TwoPhaseBorrow,}=>"mut ",};;write!( +w,"&{:?} {}{:?}",self.region,kind,self.borrowed_place)}}pub enum//if let _=(){}; +LocalsStateAtExit{AllAreInvalidated,SomeAreInvalidated{//let _=||();loop{break}; +has_storage_dead_or_moved:BitSet},} impl LocalsStateAtExit{fn build<'tcx> +(locals_are_invalidated_at_exit:bool,body:&Body< 'tcx>,move_data:&MoveData<'tcx> +,)->Self{();struct HasStorageDead(BitSet);();3;impl<'tcx>Visitor<'tcx>for +HasStorageDead{fn visit_local(&mut self, local:Local,ctx:PlaceContext,_:Location +){if ctx==PlaceContext::NonUse(NonUseContext::StorageDead){;self.0.insert(local) +;;}}}if locals_are_invalidated_at_exit{LocalsStateAtExit::AllAreInvalidated}else +{;let mut has_storage_dead=HasStorageDead(BitSet::new_empty(body.local_decls.len +()));3;3;has_storage_dead.visit_body(body);3;;let mut has_storage_dead_or_moved= +has_storage_dead.0;;for move_out in&move_data.moves{if let Some(index)=move_data +.base_local(move_out.path){{();};has_storage_dead_or_moved.insert(index);({});}} +LocalsStateAtExit::SomeAreInvalidated{has_storage_dead_or_moved}}}}impl<'tcx>//; +BorrowSet<'tcx>{pub fn build(tcx:TyCtxt<'tcx>,body:&Body<'tcx>,//*&*&();((),()); +locals_are_invalidated_at_exit:bool,move_data:&MoveData<'tcx>,)->Self{();let mut +visitor=GatherBorrows{tcx,body:body,location_map:((((((Default::default())))))), +activation_map:((((Default::default())))), local_map:((((Default::default())))), +pending_activations:Default::default( ),locals_state_at_exit:LocalsStateAtExit:: +build(locals_are_invalidated_at_exit,body,move_data,),};;for(block,block_data)in +traversal::preorder(body){3;visitor.visit_basic_block_data(block,block_data);3;} +BorrowSet{location_map:visitor.location_map,activation_map:visitor.//let _=||(); +activation_map,local_map:visitor.local_map,locals_state_at_exit:visitor.//{();}; +locals_state_at_exit,}}pub(crate)fn activations_at_location(&self,location://(); +Location)->&[BorrowIndex]{(self.activation_map.get(( &location))).map_or((&[]),| +activations|&activations[..])}pub fn len(&self)->usize{self.location_map.len()} +pub(crate)fn indices(&self)->impl Iterator{BorrowIndex:://{;}; +from_usize(0)..BorrowIndex::from_usize(self .len())}pub(crate)fn iter_enumerated +(&self)->impl Iterator)>{self.indices().zip +(self.location_map.values())}pub (crate)fn get_index_of(&self,location:&Location +)->Option{self. location_map.get_index_of(location).map(BorrowIndex +::from)}}struct GatherBorrows<'a,'tcx>{tcx:TyCtxt<'tcx>,body:&'a Body<'tcx>,//3; +location_map:FxIndexMap>,activation_map:FxIndexMap>,local_map:FxIndexMap>,pending_activations:FxIndexMap,//let _=(); +locals_state_at_exit:LocalsStateAtExit,}impl<'a,'tcx>Visitor<'tcx>for//let _=(); +GatherBorrows<'a,'tcx>{fn visit_assign(&mut self,assigned_place:&mir::Place,rvalue:&mir::Rvalue<'tcx>,location:mir::Location,){if let&mir::Rvalue:://; +Ref(region,kind,borrowed_place)=rvalue {if borrowed_place.ignore_borrow(self.tcx +,self.body,&self.locals_state_at_exit){((),());debug!("ignoring_borrow of {:?}", +borrowed_place);;;return;}let region=region.as_var();let borrow=BorrowData{kind, +region,reserve_location:location,activation_location:TwoPhaseActivation:://({}); +NotTwoPhase,borrowed_place,assigned_place:*assigned_place,};3;3;let(idx,_)=self. +location_map.insert_full(location,borrow);;;let idx=BorrowIndex::from(idx);self. +insert_as_pending_if_two_phase(location,assigned_place,kind,idx);;self.local_map +.entry(borrowed_place.local).or_default().insert(idx);*&*&();}self.super_assign( +assigned_place,rvalue,location)}fn visit_local(&mut self,temp:Local,context://3; +PlaceContext,location:Location){if!context.is_use(){{;};return;();}if let Some(& +borrow_index)=self.pending_activations.get(&temp){{;};let borrow_data=&mut self. +location_map[borrow_index.as_usize()];;if borrow_data.reserve_location==location +&&context==PlaceContext::MutatingUse(MutatingUseContext::Store){;return;;}if let +TwoPhaseActivation::ActivatedAt(other_location )=borrow_data.activation_location +{((),());((),());((),());((),());span_bug!(self.body.source_info(location).span, +"found two uses for 2-phase borrow temporary {:?}: \ + {:?} and {:?}" +,temp,location,other_location,);3;}3;assert_eq!(borrow_data.activation_location, +TwoPhaseActivation::NotActivated ,"never found an activation for this borrow!",) +;();();self.activation_map.entry(location).or_default().push(borrow_index);();3; +borrow_data.activation_location=TwoPhaseActivation::ActivatedAt(location);3;}}fn +visit_rvalue(&mut self,rvalue:&mir::Rvalue <'tcx>,location:mir::Location){if let +&mir::Rvalue::Ref(region,kind,place)=rvalue{;let borrow_data=&self.location_map[ +&location];3;3;assert_eq!(borrow_data.reserve_location,location);3;3;assert_eq!( +borrow_data.kind,kind);;assert_eq!(borrow_data.region,region.as_var());assert_eq +!(borrow_data.borrowed_place,place);3;}self.super_rvalue(rvalue,location)}}impl< +'a,'tcx>GatherBorrows<'a,'tcx>{fn insert_as_pending_if_two_phase(&mut self,//(); +start_location:Location,assigned_place:&mir::Place<'tcx>,kind:mir::BorrowKind,// +borrow_index:BorrowIndex,){let _=||();loop{break};let _=||();loop{break};debug!( +"Borrows::insert_as_pending_if_two_phase({:?}, {:?}, {:?})",start_location,//(); +assigned_place,borrow_index,);{();};if!allow_two_phase_borrow(kind){({});debug!( +" -> {:?}",start_location);;;return;;};let Some(temp)=assigned_place.as_local() +else{let _=||();let _=||();span_bug!(self.body.source_info(start_location).span, +"expected 2-phase borrow to assign to a local, not `{:?}`",assigned_place,);;};{ +let borrow_data=&mut self.location_map[borrow_index.as_usize()];3;3;borrow_data. +activation_location=TwoPhaseActivation::NotActivated;{;};}();let old_value=self. +pending_activations.insert(temp,borrow_index);;if let Some(old_index)=old_value{ +span_bug!(self.body.source_info(start_location).span,//loop{break};loop{break;}; +"found already pending activation for temp: {:?} \ + at borrow_index: {:?} with associated data {:?}" +,temp,old_index,self.location_map[old_index.as_usize()]);if true{};if true{};}}} diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index 6b576ba3c4cc6..063d18d0a5185 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -1,473 +1,140 @@ -#![allow(rustc::diagnostic_outside_of_impl)] -#![allow(rustc::untranslatable_diagnostic)] - -use rustc_errors::{codes::*, struct_span_code_err, Diag, DiagCtxt}; -use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::Span; - -impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { - pub fn dcx(&self) -> &'tcx DiagCtxt { - self.infcx.dcx() - } - - pub(crate) fn cannot_move_when_borrowed( - &self, - span: Span, - borrow_span: Span, - place: &str, - borrow_place: &str, - value_place: &str, - ) -> Diag<'tcx> { - self.dcx().create_err(crate::session_diagnostics::MoveBorrow { - place, - span, - borrow_place, - value_place, - borrow_span, - }) - } - - pub(crate) fn cannot_use_when_mutably_borrowed( - &self, - span: Span, - desc: &str, - borrow_span: Span, - borrow_desc: &str, - ) -> Diag<'tcx> { - struct_span_code_err!( - self.dcx(), - span, - E0503, - "cannot use {} because it was mutably borrowed", - desc, - ) - .with_span_label(borrow_span, format!("{borrow_desc} is borrowed here")) - .with_span_label(span, format!("use of borrowed {borrow_desc}")) - } - - pub(crate) fn cannot_mutably_borrow_multiply( - &self, - new_loan_span: Span, - desc: &str, - opt_via: &str, - old_loan_span: Span, - old_opt_via: &str, - old_load_end_span: Option, - ) -> Diag<'tcx> { - let via = |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {msg})") }; - let mut err = struct_span_code_err!( - self.dcx(), - new_loan_span, - E0499, - "cannot borrow {}{} as mutable more than once at a time", - desc, - via(opt_via), - ); - if old_loan_span == new_loan_span { - // Both borrows are happening in the same place - // Meaning the borrow is occurring in a loop - err.span_label( - new_loan_span, - format!( - "{}{} was mutably borrowed here in the previous iteration of the loop{}", - desc, - via(opt_via), - opt_via, - ), - ); - if let Some(old_load_end_span) = old_load_end_span { - err.span_label(old_load_end_span, "mutable borrow ends here"); - } - } else { - err.span_label( - old_loan_span, - format!("first mutable borrow occurs here{}", via(old_opt_via)), - ); - err.span_label( - new_loan_span, - format!("second mutable borrow occurs here{}", via(opt_via)), - ); - if let Some(old_load_end_span) = old_load_end_span { - err.span_label(old_load_end_span, "first borrow ends here"); - } - } - err - } - - pub(crate) fn cannot_uniquely_borrow_by_two_closures( - &self, - new_loan_span: Span, - desc: &str, - old_loan_span: Span, - old_load_end_span: Option, - ) -> Diag<'tcx> { - let mut err = struct_span_code_err!( - self.dcx(), - new_loan_span, - E0524, - "two closures require unique access to {} at the same time", - desc, - ); - if old_loan_span == new_loan_span { - err.span_label( - old_loan_span, - "closures are constructed here in different iterations of loop", - ); - } else { - err.span_label(old_loan_span, "first closure is constructed here"); - err.span_label(new_loan_span, "second closure is constructed here"); - } - if let Some(old_load_end_span) = old_load_end_span { - err.span_label(old_load_end_span, "borrow from first closure ends here"); - } - err - } - - pub(crate) fn cannot_uniquely_borrow_by_one_closure( - &self, - new_loan_span: Span, - container_name: &str, - desc_new: &str, - opt_via: &str, - old_loan_span: Span, - noun_old: &str, - old_opt_via: &str, - previous_end_span: Option, - ) -> Diag<'tcx> { - let mut err = struct_span_code_err!( - self.dcx(), - new_loan_span, - E0500, - "closure requires unique access to {} but {} is already borrowed{}", - desc_new, - noun_old, - old_opt_via, - ); - err.span_label( - new_loan_span, - format!("{container_name} construction occurs here{opt_via}"), - ); - err.span_label(old_loan_span, format!("borrow occurs here{old_opt_via}")); - if let Some(previous_end_span) = previous_end_span { - err.span_label(previous_end_span, "borrow ends here"); - } - err - } - - pub(crate) fn cannot_reborrow_already_uniquely_borrowed( - &self, - new_loan_span: Span, - container_name: &str, - desc_new: &str, - opt_via: &str, - kind_new: &str, - old_loan_span: Span, - old_opt_via: &str, - previous_end_span: Option, - second_borrow_desc: &str, - ) -> Diag<'tcx> { - let mut err = struct_span_code_err!( - self.dcx(), - new_loan_span, - E0501, - "cannot borrow {}{} as {} because previous closure requires unique access", - desc_new, - opt_via, - kind_new, - ); - err.span_label(new_loan_span, format!("{second_borrow_desc}borrow occurs here{opt_via}")); - err.span_label( - old_loan_span, - format!("{container_name} construction occurs here{old_opt_via}"), - ); - if let Some(previous_end_span) = previous_end_span { - err.span_label(previous_end_span, "borrow from closure ends here"); - } - err - } - - pub(crate) fn cannot_reborrow_already_borrowed( - &self, - span: Span, - desc_new: &str, - msg_new: &str, - kind_new: &str, - old_span: Span, - noun_old: &str, - kind_old: &str, - msg_old: &str, - old_load_end_span: Option, - ) -> Diag<'tcx> { - let via = |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {msg})") }; - let mut err = struct_span_code_err!( - self.dcx(), - span, - E0502, - "cannot borrow {}{} as {} because {} is also borrowed as {}{}", - desc_new, - via(msg_new), - kind_new, - noun_old, - kind_old, - via(msg_old), - ); - - if msg_new == "" { - // If `msg_new` is empty, then this isn't a borrow of a union field. - err.span_label(span, format!("{kind_new} borrow occurs here")); - err.span_label(old_span, format!("{kind_old} borrow occurs here")); - } else { - // If `msg_new` isn't empty, then this a borrow of a union field. - err.span_label( - span, - format!( - "{kind_new} borrow of {msg_new} -- which overlaps with {msg_old} -- occurs here", - ), - ); - err.span_label(old_span, format!("{} borrow occurs here{}", kind_old, via(msg_old))); - } - - if let Some(old_load_end_span) = old_load_end_span { - err.span_label(old_load_end_span, format!("{kind_old} borrow ends here")); - } - err - } - - pub(crate) fn cannot_assign_to_borrowed( - &self, - span: Span, - borrow_span: Span, - desc: &str, - ) -> Diag<'tcx> { - struct_span_code_err!( - self.dcx(), - span, - E0506, - "cannot assign to {} because it is borrowed", - desc, - ) - .with_span_label(borrow_span, format!("{desc} is borrowed here")) - .with_span_label(span, format!("{desc} is assigned to here but it was already borrowed")) - } - - pub(crate) fn cannot_reassign_immutable( - &self, - span: Span, - desc: &str, - is_arg: bool, - ) -> Diag<'tcx> { - let msg = if is_arg { "to immutable argument" } else { "twice to immutable variable" }; - struct_span_code_err!(self.dcx(), span, E0384, "cannot assign {} {}", msg, desc) - } - - pub(crate) fn cannot_assign(&self, span: Span, desc: &str) -> Diag<'tcx> { - struct_span_code_err!(self.dcx(), span, E0594, "cannot assign to {}", desc) - } - - pub(crate) fn cannot_move_out_of( - &self, - move_from_span: Span, - move_from_desc: &str, - ) -> Diag<'tcx> { - struct_span_code_err!( - self.dcx(), - move_from_span, - E0507, - "cannot move out of {}", - move_from_desc - ) - } - - /// Signal an error due to an attempt to move out of the interior - /// of an array or slice. `is_index` is None when error origin - /// didn't capture whether there was an indexing operation or not. - pub(crate) fn cannot_move_out_of_interior_noncopy( - &self, - move_from_span: Span, - ty: Ty<'_>, - is_index: Option, - ) -> Diag<'tcx> { - let type_name = match (&ty.kind(), is_index) { - (&ty::Array(_, _), Some(true)) | (&ty::Array(_, _), None) => "array", - (&ty::Slice(_), _) => "slice", - _ => span_bug!(move_from_span, "this path should not cause illegal move"), - }; - struct_span_code_err!( - self.dcx(), - move_from_span, - E0508, - "cannot move out of type `{}`, a non-copy {}", - ty, - type_name, - ) - .with_span_label(move_from_span, "cannot move out of here") - } - - pub(crate) fn cannot_move_out_of_interior_of_drop( - &self, - move_from_span: Span, - container_ty: Ty<'_>, - ) -> Diag<'tcx> { - struct_span_code_err!( - self.dcx(), - move_from_span, - E0509, - "cannot move out of type `{}`, which implements the `Drop` trait", - container_ty, - ) - .with_span_label(move_from_span, "cannot move out of here") - } - - pub(crate) fn cannot_act_on_moved_value( - &self, - use_span: Span, - verb: &str, - optional_adverb_for_moved: &str, - moved_path: Option, - ) -> Diag<'tcx> { - let moved_path = moved_path.map(|mp| format!(": `{mp}`")).unwrap_or_default(); - - struct_span_code_err!( - self.dcx(), - use_span, - E0382, - "{} of {}moved value{}", - verb, - optional_adverb_for_moved, - moved_path, - ) - } - - pub(crate) fn cannot_borrow_path_as_mutable_because( - &self, - span: Span, - path: &str, - reason: &str, - ) -> Diag<'tcx> { - struct_span_code_err!( - self.dcx(), - span, - E0596, - "cannot borrow {} as mutable{}", - path, - reason - ) - } - - pub(crate) fn cannot_mutate_in_immutable_section( - &self, - mutate_span: Span, - immutable_span: Span, - immutable_place: &str, - immutable_section: &str, - action: &str, - ) -> Diag<'tcx> { - struct_span_code_err!( - self.dcx(), - mutate_span, - E0510, - "cannot {} {} in {}", - action, - immutable_place, - immutable_section, - ) - .with_span_label(mutate_span, format!("cannot {action}")) - .with_span_label(immutable_span, format!("value is immutable in {immutable_section}")) - } - - pub(crate) fn cannot_borrow_across_coroutine_yield( - &self, - span: Span, - yield_span: Span, - ) -> Diag<'tcx> { - let coroutine_kind = self.body.coroutine.as_ref().unwrap().coroutine_kind; - struct_span_code_err!( - self.dcx(), - span, - E0626, - "borrow may still be in use when {coroutine_kind:#} yields", - ) - .with_span_label(yield_span, "possible yield occurs here") - } - - pub(crate) fn cannot_borrow_across_destructor(&self, borrow_span: Span) -> Diag<'tcx> { - struct_span_code_err!( - self.dcx(), - borrow_span, - E0713, - "borrow may still be in use when destructor runs", - ) - } - - pub(crate) fn path_does_not_live_long_enough(&self, span: Span, path: &str) -> Diag<'tcx> { - struct_span_code_err!(self.dcx(), span, E0597, "{} does not live long enough", path,) - } - - pub(crate) fn cannot_return_reference_to_local( - &self, - span: Span, - return_kind: &str, - reference_desc: &str, - path_desc: &str, - ) -> Diag<'tcx> { - struct_span_code_err!( - self.dcx(), - span, - E0515, - "cannot {RETURN} {REFERENCE} {LOCAL}", - RETURN = return_kind, - REFERENCE = reference_desc, - LOCAL = path_desc, - ) - .with_span_label( - span, - format!("{return_kind}s a {reference_desc} data owned by the current function"), - ) - } - - pub(crate) fn cannot_capture_in_long_lived_closure( - &self, - closure_span: Span, - closure_kind: &str, - borrowed_path: &str, - capture_span: Span, - scope: &str, - ) -> Diag<'tcx> { - struct_span_code_err!( - self.dcx(), - closure_span, - E0373, - "{closure_kind} may outlive the current {scope}, but it borrows {borrowed_path}, \ - which is owned by the current {scope}", - ) - .with_span_label(capture_span, format!("{borrowed_path} is borrowed here")) - .with_span_label(closure_span, format!("may outlive borrowed value {borrowed_path}")) - } - - pub(crate) fn thread_local_value_does_not_live_long_enough(&self, span: Span) -> Diag<'tcx> { - struct_span_code_err!( - self.dcx(), - span, - E0712, - "thread-local variable borrowed past end of function", - ) - } - - pub(crate) fn temporary_value_borrowed_for_too_long(&self, span: Span) -> Diag<'tcx> { - struct_span_code_err!(self.dcx(), span, E0716, "temporary value dropped while borrowed",) - } -} - -pub(crate) fn borrowed_data_escapes_closure<'tcx>( - tcx: TyCtxt<'tcx>, - escape_span: Span, - escapes_from: &str, -) -> Diag<'tcx> { - struct_span_code_err!( - tcx.dcx(), - escape_span, - E0521, - "borrowed data escapes outside of {}", - escapes_from, - ) -} +#![allow(rustc::diagnostic_outside_of_impl)]#![allow(rustc:://let _=();let _=(); +untranslatable_diagnostic)]use rustc_errors::{codes::*,struct_span_code_err,//3; +Diag,DiagCtxt};use rustc_middle::ty::{self ,Ty,TyCtxt};use rustc_span::Span;impl +<'cx,'tcx>crate::MirBorrowckCtxt<'cx,'tcx>{pub fn dcx(&self)->&'tcx DiagCtxt{//; +self.infcx.dcx()}pub(crate)fn cannot_move_when_borrowed(&self,span:Span,//{();}; +borrow_span:Span,place:&str,borrow_place:&str,value_place:&str,)->Diag<'tcx>{//; +self.dcx().create_err(crate::session_diagnostics::MoveBorrow{place,span,//{();}; +borrow_place,value_place,borrow_span,})}pub(crate)fn//loop{break;};loop{break;}; +cannot_use_when_mutably_borrowed(&self,span:Span,desc:&str,borrow_span:Span,//3; +borrow_desc:&str,)->Diag<'tcx>{struct_span_code_err!(self.dcx(),span,E0503,//(); +"cannot use {} because it was mutably borrowed",desc,).with_span_label(//*&*&(); +borrow_span,((format!("{borrow_desc} is borrowed here")))).with_span_label(span, +format!("use of borrowed {borrow_desc}"))}pub(crate)fn//loop{break};loop{break}; +cannot_mutably_borrow_multiply(&self,new_loan_span:Span, desc:&str,opt_via:&str, +old_loan_span:Span,old_opt_via:&str,old_load_end_span :Option,)->Diag<'tcx +>{if let _=(){};let via=|msg:&str|if msg.is_empty(){"".to_string()}else{format!( +" (via {msg})")};3;3;let mut err=struct_span_code_err!(self.dcx(),new_loan_span, +E0499,"cannot borrow {}{} as mutable more than once at a time", desc,via(opt_via +),);{;};if old_loan_span==new_loan_span{();err.span_label(new_loan_span,format!( +"{}{} was mutably borrowed here in the previous iteration of the loop{}",desc,// +via(opt_via),opt_via,),);;if let Some(old_load_end_span)=old_load_end_span{;err. +span_label(old_load_end_span,"mutable borrow ends here");;}}else{err.span_label( +old_loan_span,format!("first mutable borrow occurs here{}",via(old_opt_via)),);; +err.span_label(new_loan_span, format!("second mutable borrow occurs here{}",via( +opt_via)),);3;if let Some(old_load_end_span)=old_load_end_span{3;err.span_label( +old_load_end_span,"first borrow ends here");let _=();let _=();}}err}pub(crate)fn +cannot_uniquely_borrow_by_two_closures(&self,new_loan_span:Span,desc:&str,//{;}; +old_loan_span:Span,old_load_end_span:Option,)->Diag<'tcx>{{;};let mut err= +struct_span_code_err!(self.dcx(),new_loan_span,E0524,//loop{break};loop{break;}; +"two closures require unique access to {} at the same time",desc,);if true{};if +old_loan_span==new_loan_span{let _=||();let _=||();err.span_label(old_loan_span, +"closures are constructed here in different iterations of loop",);3;}else{3;err. +span_label(old_loan_span,"first closure is constructed here");3;;err.span_label( +new_loan_span,"second closure is constructed here");*&*&();((),());}if let Some( +old_load_end_span)=old_load_end_span{if true{};err.span_label(old_load_end_span, +"borrow from first closure ends here");loop{break};loop{break};}err}pub(crate)fn +cannot_uniquely_borrow_by_one_closure(&self,new_loan_span :Span,container_name:& +str,desc_new:&str,opt_via:&str,old_loan_span:Span,noun_old:&str,old_opt_via:&//; +str,previous_end_span:Option,)->Diag<'tcx>{let _=();if true{};let mut err= +struct_span_code_err!(self.dcx(),new_loan_span,E0500,//loop{break};loop{break;}; +"closure requires unique access to {} but {} is already borrowed{}",desc_new,//; +noun_old,old_opt_via,);if true{};if true{};err.span_label(new_loan_span,format!( +"{container_name} construction occurs here{opt_via}"),);({});{;};err.span_label( +old_loan_span,format!("borrow occurs here{old_opt_via}"));if true{};if let Some( +previous_end_span)=previous_end_span{if true{};err.span_label(previous_end_span, +"borrow ends here");;}err}pub(crate)fn cannot_reborrow_already_uniquely_borrowed +(&self,new_loan_span:Span,container_name:&str,desc_new:&str,opt_via:&str,//({}); +kind_new:&str,old_loan_span:Span, old_opt_via:&str,previous_end_span:Option,second_borrow_desc:&str,)->Diag<'tcx>{;let mut err=struct_span_code_err!(self. +dcx(),new_loan_span,E0501,//loop{break;};loop{break;};loop{break;};loop{break;}; +"cannot borrow {}{} as {} because previous closure requires unique access",//(); +desc_new,opt_via,kind_new,);((),());*&*&();err.span_label(new_loan_span,format!( +"{second_borrow_desc}borrow occurs here{opt_via}"));*&*&();{();};err.span_label( +old_loan_span,format !("{container_name} construction occurs here{old_opt_via}") +,);*&*&();if let Some(previous_end_span)=previous_end_span{{();};err.span_label( +previous_end_span,"borrow from closure ends here");loop{break};}err}pub(crate)fn +cannot_reborrow_already_borrowed(&self,span:Span,desc_new:&str,msg_new:&str,//3; +kind_new:&str,old_span:Span,noun_old:&str,kind_old:&str,msg_old:&str,//let _=(); +old_load_end_span:Option,)->Diag<'tcx>{;let via=|msg:&str|if msg.is_empty( +){"".to_string()}else{format!(" (via {msg})")};;let mut err=struct_span_code_err +!(self.dcx(),span,E0502,//loop{break;};if let _=(){};loop{break;};if let _=(){}; +"cannot borrow {}{} as {} because {} is also borrowed as {}{}",desc_new,via(//3; +msg_new),kind_new,noun_old,kind_old,via(msg_old),);({});if msg_new==""{({});err. +span_label(span,format!("{kind_new} borrow occurs here"));{;};();err.span_label( +old_span,format!("{kind_old} borrow occurs here"));3;}else{;err.span_label(span, +format!(//((),());let _=();let _=();let _=();((),());let _=();let _=();let _=(); +"{kind_new} borrow of {msg_new} -- which overlaps with {msg_old} -- occurs here" +,),);3;3;err.span_label(old_span,format!("{} borrow occurs here{}",kind_old,via( +msg_old)));3;}if let Some(old_load_end_span)=old_load_end_span{3;err.span_label( +old_load_end_span,format!("{kind_old} borrow ends here"));({});}err}pub(crate)fn +cannot_assign_to_borrowed(&self,span:Span,borrow_span:Span,desc:&str,)->Diag{struct_span_code_err!(self.dcx(),span,E0506,//if let _=(){};if let _=(){}; +"cannot assign to {} because it is borrowed",desc,) .with_span_label(borrow_span +,(((((((format!("{desc} is borrowed here"))))))))).with_span_label(span,format!( +"{desc} is assigned to here but it was already borrowed"))}pub(crate)fn//*&*&(); +cannot_reassign_immutable(&self,span:Span,desc:&str,is_arg:bool,)->Diag<'tcx>{3; +let msg=if is_arg{"to immutable argument"}else{"twice to immutable variable"};3; +struct_span_code_err!(self.dcx(),span, E0384,"cannot assign {} {}",msg,desc)}pub +(crate)fn cannot_assign(&self,span:Span,desc:&str)->Diag<'tcx>{//*&*&();((),()); +struct_span_code_err!(self.dcx(),span,E0594,"cannot assign to {}",desc)}pub(//3; +crate)fn cannot_move_out_of(&self,move_from_span:Span,move_from_desc:&str,)->//; +Diag<'tcx>{struct_span_code_err!(self.dcx(),move_from_span,E0507,//loop{break;}; +"cannot move out of {}",move_from_desc)}pub(crate)fn//loop{break;};loop{break;}; +cannot_move_out_of_interior_noncopy(&self,move_from_span:Span,ty:Ty<'_>,//{();}; +is_index:Option,)->Diag<'tcx>{;let type_name=match(&ty.kind(),is_index){(& +ty::Array(_,_),Some(true))|(&ty::Array(_,_),None)=>("array"),(&ty::Slice(_),_)=> +"slice",_=>span_bug !(move_from_span,"this path should not cause illegal move"), +};loop{break};loop{break};struct_span_code_err!(self.dcx(),move_from_span,E0508, +"cannot move out of type `{}`, a non-copy {}",ty,type_name,).with_span_label(//; +move_from_span,((((((((((((("cannot move out of here"))))))))))))))}pub(crate)fn +cannot_move_out_of_interior_of_drop(&self,move_from_span:Span,container_ty:Ty,)->Diag<'tcx>{struct_span_code_err!(self.dcx(),move_from_span,E0509,//{();}; +"cannot move out of type `{}`, which implements the `Drop` trait", container_ty, +).with_span_label(move_from_span,(((("cannot move out of here")))))}pub(crate)fn +cannot_act_on_moved_value(&self,use_span:Span,verb:&str,//let _=||();let _=||(); +optional_adverb_for_moved:&str,moved_path:Option,)->Diag<'tcx>{{();};let +moved_path=moved_path.map(|mp|format!(": `{mp}`")).unwrap_or_default();let _=(); +struct_span_code_err!(self.dcx(),use_span,E0382,"{} of {}moved value{}",verb,//; +optional_adverb_for_moved,moved_path,)}pub(crate)fn//loop{break;};if let _=(){}; +cannot_borrow_path_as_mutable_because(&self,span:Span,path :&str,reason:&str,)-> +Diag<'tcx>{struct_span_code_err!(self.dcx(),span,E0596,//let _=||();loop{break}; +"cannot borrow {} as mutable{}",path,reason)}pub(crate)fn//if true{};let _=||(); +cannot_mutate_in_immutable_section(&self,mutate_span:Span,immutable_span:Span,// +immutable_place:&str,immutable_section:&str,action:&str,)->Diag<'tcx>{//((),()); +struct_span_code_err!(self.dcx() ,mutate_span,E0510,"cannot {} {} in {}",action, +immutable_place,immutable_section,).with_span_label(mutate_span,format!(//{();}; +"cannot {action}")).with_span_label(immutable_span,format!(//let _=();if true{}; +"value is immutable in {immutable_section}"))}pub(crate)fn//if true{};if true{}; +cannot_borrow_across_coroutine_yield(&self,span:Span,yield_span:Span,)->Diag{;let coroutine_kind=self.body.coroutine.as_ref().unwrap().coroutine_kind;; +struct_span_code_err!(self.dcx(),span,E0626,//((),());let _=();((),());let _=(); +"borrow may still be in use when {coroutine_kind:#} yields",).with_span_label(// +yield_span,((((((((((((("possible yield occurs here")))))))))))))) }pub(crate)fn +cannot_borrow_across_destructor(&self,borrow_span:Span)->Diag<'tcx>{//if true{}; +struct_span_code_err!(self.dcx(),borrow_span,E0713,//loop{break;};if let _=(){}; +"borrow may still be in use when destructor runs",)}pub(crate)fn//if let _=(){}; +path_does_not_live_long_enough(&self,span:Span,path:&str)->Diag<'tcx>{//((),()); +struct_span_code_err!(self.dcx() ,span,E0597,"{} does not live long enough",path +,)}pub(crate)fn cannot_return_reference_to_local(&self,span:Span,return_kind:&// +str,reference_desc:&str,path_desc:&str, )->Diag<'tcx>{struct_span_code_err!(self +.dcx(),span,E0515,"cannot {RETURN} {REFERENCE} {LOCAL}",RETURN=return_kind,//(); +REFERENCE=reference_desc,LOCAL=path_desc,).with_span_label(span,format!(//{();}; +"{return_kind}s a {reference_desc} data owned by the current function"),)}pub(// +crate)fn cannot_capture_in_long_lived_closure(&self,closure_span:Span,//((),()); +closure_kind:&str,borrowed_path:&str,capture_span: Span,scope:&str,)->Diag<'tcx> +{struct_span_code_err!(self.dcx(),closure_span,E0373,//loop{break};loop{break;}; +"{closure_kind} may outlive the current {scope}, but it borrows {borrowed_path}, \ + which is owned by the current {scope}" +,).with_span_label(capture_span,( format!("{borrowed_path} is borrowed here"))). +with_span_label(closure_span,format!(//if true{};if true{};if true{};let _=||(); +"may outlive borrowed value {borrowed_path}"))}pub(crate)fn//let _=();if true{}; +thread_local_value_does_not_live_long_enough(&self,span:Span)->Diag<'tcx>{//{;}; +struct_span_code_err!(self.dcx(),span,E0712,//((),());let _=();((),());let _=(); +"thread-local variable borrowed past end of function",)}pub(crate)fn//if true{}; +temporary_value_borrowed_for_too_long(&self,span:Span)->Diag<'tcx>{//let _=||(); +struct_span_code_err!(self.dcx(),span,E0716,//((),());let _=();((),());let _=(); +"temporary value dropped while borrowed",)}}pub(crate)fn//let _=||();let _=||(); +borrowed_data_escapes_closure<'tcx>(tcx:TyCtxt<'tcx>,escape_span:Span,//((),()); +escapes_from:&str,)->Diag<'tcx>{struct_span_code_err!(tcx.dcx(),escape_span,//3; +E0521,"borrowed data escapes outside of {}",escapes_from,)}//let _=();if true{}; diff --git a/compiler/rustc_borrowck/src/constraints/graph.rs b/compiler/rustc_borrowck/src/constraints/graph.rs index 8b7d9ec2cd671..d542463e5b7f3 100644 --- a/compiler/rustc_borrowck/src/constraints/graph.rs +++ b/compiler/rustc_borrowck/src/constraints/graph.rs @@ -1,238 +1,66 @@ -use rustc_data_structures::graph; -use rustc_index::IndexVec; -use rustc_middle::mir::ConstraintCategory; -use rustc_middle::ty::{RegionVid, VarianceDiagInfo}; -use rustc_span::DUMMY_SP; - -use crate::{ - constraints::OutlivesConstraintIndex, - constraints::{OutlivesConstraint, OutlivesConstraintSet}, - type_check::Locations, -}; - -/// The construct graph organizes the constraints by their end-points. -/// It can be used to view a `R1: R2` constraint as either an edge `R1 -/// -> R2` or `R2 -> R1` depending on the direction type `D`. -pub(crate) struct ConstraintGraph { - _direction: D, - first_constraints: IndexVec>, - next_constraints: IndexVec>, -} - -pub(crate) type NormalConstraintGraph = ConstraintGraph; - -pub(crate) type ReverseConstraintGraph = ConstraintGraph; - -/// Marker trait that controls whether a `R1: R2` constraint -/// represents an edge `R1 -> R2` or `R2 -> R1`. -pub(crate) trait ConstraintGraphDirection: Copy + 'static { - fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid; - fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid; - fn is_normal() -> bool; -} - -/// In normal mode, a `R1: R2` constraint results in an edge `R1 -> -/// R2`. This is what we use when constructing the SCCs for -/// inference. This is because we compute the value of R1 by union'ing -/// all the things that it relies on. -#[derive(Copy, Clone, Debug)] -pub(crate) struct Normal; - -impl ConstraintGraphDirection for Normal { - fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid { - c.sup - } - - fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid { - c.sub - } - - fn is_normal() -> bool { - true - } -} - -/// In reverse mode, a `R1: R2` constraint results in an edge `R2 -> -/// R1`. We use this for optimizing liveness computation, because then -/// we wish to iterate from a region (e.g., R2) to all the regions -/// that will outlive it (e.g., R1). -#[derive(Copy, Clone, Debug)] -pub(crate) struct Reverse; - -impl ConstraintGraphDirection for Reverse { - fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid { - c.sub - } - - fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid { - c.sup - } - - fn is_normal() -> bool { - false - } -} - -impl ConstraintGraph { - /// Creates a "dependency graph" where each region constraint `R1: - /// R2` is treated as an edge `R1 -> R2`. We use this graph to - /// construct SCCs for region inference but also for error - /// reporting. - pub(crate) fn new( - direction: D, - set: &OutlivesConstraintSet<'_>, - num_region_vars: usize, - ) -> Self { - let mut first_constraints = IndexVec::from_elem_n(None, num_region_vars); - let mut next_constraints = IndexVec::from_elem(None, &set.outlives); - - for (idx, constraint) in set.outlives.iter_enumerated().rev() { - let head = &mut first_constraints[D::start_region(constraint)]; - let next = &mut next_constraints[idx]; - debug_assert!(next.is_none()); - *next = *head; - *head = Some(idx); - } - - Self { _direction: direction, first_constraints, next_constraints } - } - - /// Given the constraint set from which this graph was built - /// creates a region graph so that you can iterate over *regions* - /// and not constraints. - pub(crate) fn region_graph<'rg, 'tcx>( - &'rg self, - set: &'rg OutlivesConstraintSet<'tcx>, - static_region: RegionVid, - ) -> RegionGraph<'rg, 'tcx, D> { - RegionGraph::new(set, self, static_region) - } - - /// Given a region `R`, iterate over all constraints `R: R1`. - pub(crate) fn outgoing_edges<'a, 'tcx>( - &'a self, - region_sup: RegionVid, - constraints: &'a OutlivesConstraintSet<'tcx>, - static_region: RegionVid, - ) -> Edges<'a, 'tcx, D> { - //if this is the `'static` region and the graph's direction is normal, - //then setup the Edges iterator to return all regions #53178 - if region_sup == static_region && D::is_normal() { - Edges { - graph: self, - constraints, - pointer: None, - next_static_idx: Some(0), - static_region, - } - } else { - //otherwise, just setup the iterator as normal - let first = self.first_constraints[region_sup]; - Edges { graph: self, constraints, pointer: first, next_static_idx: None, static_region } - } - } -} - -pub(crate) struct Edges<'s, 'tcx, D: ConstraintGraphDirection> { - graph: &'s ConstraintGraph, - constraints: &'s OutlivesConstraintSet<'tcx>, - pointer: Option, - next_static_idx: Option, - static_region: RegionVid, -} - -impl<'s, 'tcx, D: ConstraintGraphDirection> Iterator for Edges<'s, 'tcx, D> { - type Item = OutlivesConstraint<'tcx>; - - fn next(&mut self) -> Option { - if let Some(p) = self.pointer { - self.pointer = self.graph.next_constraints[p]; - - Some(self.constraints[p]) - } else if let Some(next_static_idx) = self.next_static_idx { - self.next_static_idx = if next_static_idx == (self.graph.first_constraints.len() - 1) { - None - } else { - Some(next_static_idx + 1) - }; - - Some(OutlivesConstraint { - sup: self.static_region, - sub: next_static_idx.into(), - locations: Locations::All(DUMMY_SP), - span: DUMMY_SP, - category: ConstraintCategory::Internal, - variance_info: VarianceDiagInfo::default(), - from_closure: false, - }) - } else { - None - } - } -} - -/// This struct brings together a constraint set and a (normal, not -/// reverse) constraint graph. It implements the graph traits and is -/// usd for doing the SCC computation. -pub(crate) struct RegionGraph<'s, 'tcx, D: ConstraintGraphDirection> { - set: &'s OutlivesConstraintSet<'tcx>, - constraint_graph: &'s ConstraintGraph, - static_region: RegionVid, -} - -impl<'s, 'tcx, D: ConstraintGraphDirection> RegionGraph<'s, 'tcx, D> { - /// Creates a "dependency graph" where each region constraint `R1: - /// R2` is treated as an edge `R1 -> R2`. We use this graph to - /// construct SCCs for region inference but also for error - /// reporting. - pub(crate) fn new( - set: &'s OutlivesConstraintSet<'tcx>, - constraint_graph: &'s ConstraintGraph, - static_region: RegionVid, - ) -> Self { - Self { set, constraint_graph, static_region } - } - - /// Given a region `R`, iterate over all regions `R1` such that - /// there exists a constraint `R: R1`. - pub(crate) fn outgoing_regions(&self, region_sup: RegionVid) -> Successors<'s, 'tcx, D> { - Successors { - edges: self.constraint_graph.outgoing_edges(region_sup, self.set, self.static_region), - } - } -} - -pub(crate) struct Successors<'s, 'tcx, D: ConstraintGraphDirection> { - edges: Edges<'s, 'tcx, D>, -} - -impl<'s, 'tcx, D: ConstraintGraphDirection> Iterator for Successors<'s, 'tcx, D> { - type Item = RegionVid; - - fn next(&mut self) -> Option { - self.edges.next().map(|c| D::end_region(&c)) - } -} - -impl<'s, 'tcx, D: ConstraintGraphDirection> graph::DirectedGraph for RegionGraph<'s, 'tcx, D> { - type Node = RegionVid; -} - -impl<'s, 'tcx, D: ConstraintGraphDirection> graph::WithNumNodes for RegionGraph<'s, 'tcx, D> { - fn num_nodes(&self) -> usize { - self.constraint_graph.first_constraints.len() - } -} - -impl<'s, 'tcx, D: ConstraintGraphDirection> graph::WithSuccessors for RegionGraph<'s, 'tcx, D> { - fn successors(&self, node: Self::Node) -> >::Iter { - self.outgoing_regions(node) - } -} - -impl<'s, 'tcx, D: ConstraintGraphDirection> graph::GraphSuccessors<'_> - for RegionGraph<'s, 'tcx, D> -{ - type Item = RegionVid; - type Iter = Successors<'s, 'tcx, D>; -} +use rustc_data_structures::graph;use rustc_index::IndexVec;use rustc_middle:://; +mir::ConstraintCategory;use rustc_middle::ty::{RegionVid,VarianceDiagInfo};use// +rustc_span::DUMMY_SP;use crate::{constraints::OutlivesConstraintIndex,//((),()); +constraints::{OutlivesConstraint,OutlivesConstraintSet },type_check::Locations,} +;pub(crate)struct ConstraintGraph{_direction:D,//(); +first_constraints:IndexVec>,//((),()); +next_constraints:IndexVec>,}pub( crate)type NormalConstraintGraph=ConstraintGraph +;pub(crate)type ReverseConstraintGraph=ConstraintGraph;pub(//3; +crate)trait ConstraintGraphDirection:Copy+'static{fn start_region(c:&//let _=(); +OutlivesConstraint<'_>)->RegionVid;fn end_region(c:&OutlivesConstraint<'_>)->//; +RegionVid;fn is_normal()->bool;}#[derive(Copy,Clone,Debug)]pub(crate)struct//(); +Normal;impl ConstraintGraphDirection for Normal{fn start_region(c:&//let _=||(); +OutlivesConstraint<'_>)->RegionVid{c.sup }fn end_region(c:&OutlivesConstraint<'_ +>)->RegionVid{c.sub}fn is_normal()->bool{(true)}}#[derive(Copy,Clone,Debug)]pub( +crate)struct Reverse;impl ConstraintGraphDirection for Reverse{fn start_region( +c:&OutlivesConstraint<'_>)->RegionVid{ c.sub}fn end_region(c:&OutlivesConstraint +<'_>)->RegionVid{c.sup}fn is_normal()->bool{(((((((((((false)))))))))))}}implConstraintGraph{pub(crate)fn new(direction:D,set:&// +OutlivesConstraintSet<'_>,num_region_vars:usize,)->Self{((),());let _=();let mut +first_constraints=IndexVec::from_elem_n(None,num_region_vars);{();};({});let mut +next_constraints=IndexVec::from_elem(None,&set.outlives);;for(idx,constraint)in +set.outlives.iter_enumerated().rev(){((),());let head=&mut first_constraints[D:: +start_region(constraint)];;;let next=&mut next_constraints[idx];;;debug_assert!( +next.is_none());3;3;*next=*head;3;3;*head=Some(idx);;}Self{_direction:direction, +first_constraints,next_constraints}}pub(crate)fn region_graph<'rg,'tcx>(&'rg//3; +self,set:&'rg OutlivesConstraintSet<'tcx>,static_region:RegionVid,)->//let _=(); +RegionGraph<'rg,'tcx,D>{(RegionGraph::new (set,self,static_region))}pub(crate)fn +outgoing_edges<'a,'tcx>(&'a self,region_sup:RegionVid,constraints:&'a//let _=(); +OutlivesConstraintSet<'tcx>,static_region:RegionVid,)->Edges<'a,'tcx,D>{if //(); +region_sup==static_region&&D::is_normal() {Edges{graph:self,constraints,pointer: +None,next_static_idx:Some(0),static_region,}}else{*&*&();((),());let first=self. +first_constraints[region_sup];*&*&();Edges{graph:self,constraints,pointer:first, +next_static_idx:None,static_region}}}}pub(crate)struct Edges<'s,'tcx,D://*&*&(); +ConstraintGraphDirection>{graph:&'s ConstraintGraph,constraints:&'s//((),()); +OutlivesConstraintSet<'tcx>,pointer:Option,//if true{}; +next_static_idx:Option,static_region:RegionVid,}impl<'s,'tcx,D://((),()); +ConstraintGraphDirection>Iterator for Edges<'s,'tcx,D>{type Item=//loop{break;}; +OutlivesConstraint<'tcx>;fn next(&mut self)-> Option{if let Some(p)= +self.pointer{;self.pointer=self.graph.next_constraints[p];Some(self.constraints[ +p])}else if let Some(next_static_idx)=self.next_static_idx{;self.next_static_idx +=if (next_static_idx==((self.graph.first_constraints.len( )-1))){None}else{Some( +next_static_idx+1)};let _=();Some(OutlivesConstraint{sup:self.static_region,sub: +next_static_idx.into(),locations:((((Locations::All(DUMMY_SP))))),span:DUMMY_SP, +category:ConstraintCategory::Internal,variance_info :VarianceDiagInfo::default() +,from_closure:(((false))),})}else{None}}}pub(crate)struct RegionGraph<'s,'tcx,D: +ConstraintGraphDirection>{set:&'s OutlivesConstraintSet<'tcx>,constraint_graph: +&'s ConstraintGraph,static_region:RegionVid,}impl<'s,'tcx,D://*&*&();((),()); +ConstraintGraphDirection>RegionGraph<'s,'tcx,D>{pub(crate)fn new(set:&'s//{();}; +OutlivesConstraintSet<'tcx>,constraint_graph:&'s ConstraintGraph,//if true{}; +static_region:RegionVid,)->Self{(Self {set,constraint_graph,static_region})}pub( +crate)fn outgoing_regions(&self,region_sup:RegionVid)->Successors<'s,'tcx,D>{//; +Successors{edges:self.constraint_graph. outgoing_edges(region_sup,self.set,self. +static_region),}}}pub(crate)struct Successors<'s,'tcx,D://let _=||();let _=||(); +ConstraintGraphDirection>{edges:Edges<'s,'tcx,D>,}impl<'s,'tcx,D://loop{break;}; +ConstraintGraphDirection>Iterator for Successors<'s, 'tcx,D>{type Item=RegionVid +;fn next(&mut self)->Option{ self.edges.next().map(|c|D::end_region( +&c))}}impl<'s,'tcx,D:ConstraintGraphDirection>graph::DirectedGraph for//((),()); +RegionGraph<'s,'tcx,D>{type Node=RegionVid;}impl<'s,'tcx,D://let _=();if true{}; +ConstraintGraphDirection>graph::WithNumNodes for RegionGraph<'s,'tcx,D>{fn//{;}; +num_nodes(&self)->usize{self.constraint_graph .first_constraints.len()}}impl<'s, +'tcx,D:ConstraintGraphDirection>graph::WithSuccessors for RegionGraph<'s,'tcx,D +>{fn successors(&self,node:Self::Node)->>::// +Iter{self.outgoing_regions(node)} }impl<'s,'tcx,D:ConstraintGraphDirection>graph +::GraphSuccessors<'_>for RegionGraph<'s,'tcx,D>{type Item=RegionVid;type Iter=// +Successors<'s,'tcx,D>;}//loop{break;};if let _=(){};if let _=(){};if let _=(){}; diff --git a/compiler/rustc_borrowck/src/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs index ff11e4db12133..b7138b374f56e 100644 --- a/compiler/rustc_borrowck/src/constraints/mod.rs +++ b/compiler/rustc_borrowck/src/constraints/mod.rs @@ -1,125 +1,30 @@ -use rustc_data_structures::graph::scc::Sccs; -use rustc_index::{IndexSlice, IndexVec}; -use rustc_middle::mir::ConstraintCategory; -use rustc_middle::ty::{RegionVid, VarianceDiagInfo}; -use rustc_span::Span; -use std::fmt; -use std::ops::Index; - -use crate::type_check::Locations; - -pub(crate) mod graph; - -/// A set of NLL region constraints. These include "outlives" -/// constraints of the form `R1: R2`. Each constraint is identified by -/// a unique `OutlivesConstraintIndex` and you can index into the set -/// (`constraint_set[i]`) to access the constraint details. -#[derive(Clone, Debug, Default)] -pub(crate) struct OutlivesConstraintSet<'tcx> { - outlives: IndexVec>, -} - -impl<'tcx> OutlivesConstraintSet<'tcx> { - pub(crate) fn push(&mut self, constraint: OutlivesConstraint<'tcx>) { - debug!("OutlivesConstraintSet::push({:?})", constraint); - if constraint.sup == constraint.sub { - // 'a: 'a is pretty uninteresting - return; - } - self.outlives.push(constraint); - } - - /// Constructs a "normal" graph from the constraint set; the graph makes it - /// easy to find the constraints affecting a particular region. - /// - /// N.B., this graph contains a "frozen" view of the current - /// constraints. Any new constraints added to the `OutlivesConstraintSet` - /// after the graph is built will not be present in the graph. - pub(crate) fn graph(&self, num_region_vars: usize) -> graph::NormalConstraintGraph { - graph::ConstraintGraph::new(graph::Normal, self, num_region_vars) - } - - /// Like `graph`, but constraints a reverse graph where `R1: R2` - /// represents an edge `R2 -> R1`. - pub(crate) fn reverse_graph(&self, num_region_vars: usize) -> graph::ReverseConstraintGraph { - graph::ConstraintGraph::new(graph::Reverse, self, num_region_vars) - } - - /// Computes cycles (SCCs) in the graph of regions. In particular, - /// find all regions R1, R2 such that R1: R2 and R2: R1 and group - /// them into an SCC, and find the relationships between SCCs. - pub(crate) fn compute_sccs( - &self, - constraint_graph: &graph::NormalConstraintGraph, - static_region: RegionVid, - ) -> Sccs { - let region_graph = &constraint_graph.region_graph(self, static_region); - Sccs::new(region_graph) - } - - pub(crate) fn outlives( - &self, - ) -> &IndexSlice> { - &self.outlives - } -} - -impl<'tcx> Index for OutlivesConstraintSet<'tcx> { - type Output = OutlivesConstraint<'tcx>; - - fn index(&self, i: OutlivesConstraintIndex) -> &Self::Output { - &self.outlives[i] - } -} - -#[derive(Copy, Clone, PartialEq, Eq)] -pub struct OutlivesConstraint<'tcx> { - // NB. The ordering here is not significant for correctness, but - // it is for convenience. Before we dump the constraints in the - // debugging logs, we sort them, and we'd like the "super region" - // to be first, etc. (In particular, span should remain last.) - /// The region SUP must outlive SUB... - pub sup: RegionVid, - - /// Region that must be outlived. - pub sub: RegionVid, - - /// Where did this constraint arise? - pub locations: Locations, - - /// The `Span` associated with the creation of this constraint. - /// This should be used in preference to obtaining the span from - /// `locations`, since the `locations` may give a poor span - /// in some cases (e.g. converting a constraint from a promoted). - pub span: Span, - - /// What caused this constraint? - pub category: ConstraintCategory<'tcx>, - - /// Variance diagnostic information - pub variance_info: VarianceDiagInfo<'tcx>, - - /// If this constraint is promoted from closure requirements. - pub from_closure: bool, -} - -impl<'tcx> fmt::Debug for OutlivesConstraint<'tcx> { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - formatter, - "({:?}: {:?}) due to {:?} ({:?}) ({:?})", - self.sup, self.sub, self.locations, self.variance_info, self.category, - ) - } -} - -rustc_index::newtype_index! { - #[debug_format = "OutlivesConstraintIndex({})"] - pub struct OutlivesConstraintIndex {} -} - -rustc_index::newtype_index! { - #[orderable] - #[debug_format = "ConstraintSccIndex({})"] - pub struct ConstraintSccIndex {} -} +use rustc_data_structures::graph::scc::Sccs;use rustc_index::{IndexSlice,//({}); +IndexVec};use rustc_middle::mir::ConstraintCategory;use rustc_middle::ty::{//(); +RegionVid,VarianceDiagInfo};use rustc_span::Span;use std::fmt;use std::ops:://3; +Index;use crate::type_check::Locations;pub( crate)mod graph;#[derive(Clone,Debug +,Default)]pub(crate)struct OutlivesConstraintSet<'tcx>{outlives:IndexVec>,}impl<'tcx>//((),());let _=(); +OutlivesConstraintSet<'tcx>{pub(crate)fn push(&mut self,constraint://let _=||(); +OutlivesConstraint<'tcx>){;debug!("OutlivesConstraintSet::push({:?})",constraint +);;if constraint.sup==constraint.sub{return;}self.outlives.push(constraint);}pub +(crate)fn graph(&self,num_region_vars:usize)->graph::NormalConstraintGraph{//(); +graph::ConstraintGraph::new(graph::Normal,self,num_region_vars)}pub(crate)fn//3; +reverse_graph(&self,num_region_vars:usize )->graph::ReverseConstraintGraph{graph +::ConstraintGraph::new(graph::Reverse,self,num_region_vars)}pub(crate)fn//{();}; +compute_sccs(&self,constraint_graph :&graph::NormalConstraintGraph,static_region +:RegionVid,)->Sccs{loop{break;};let region_graph=& +constraint_graph.region_graph(self,static_region);3;Sccs::new(region_graph)}pub( +crate)fn outlives(&self,)->&IndexSlice>{(((((((((((&self.outlives)))))))))))}}impl<'tcx>Index< +OutlivesConstraintIndex>for OutlivesConstraintSet<'tcx>{type Output=//if true{}; +OutlivesConstraint<'tcx>;fn index(&self,i:OutlivesConstraintIndex)->&Self:://(); +Output{(((&((self.outlives[i])))))}}#[derive(Copy,Clone,PartialEq,Eq)]pub struct +OutlivesConstraint<'tcx>{pub sup:RegionVid,pub sub:RegionVid,pub locations://(); +Locations,pub span:Span,pub category:ConstraintCategory<'tcx>,pub variance_info +:VarianceDiagInfo<'tcx>,pub from_closure:bool,}impl<'tcx>fmt::Debug for//*&*&(); +OutlivesConstraint<'tcx>{fn fmt(&self,formatter :&mut fmt::Formatter<'_>)->fmt:: +Result{write!(formatter, "({:?}: {:?}) due to {:?} ({:?}) ({:?})",self.sup,self. +sub,self.locations,self.variance_info,self.category,)}}rustc_index:://if true{}; +newtype_index!{#[debug_format="OutlivesConstraintIndex({})"]pub struct//((),()); +OutlivesConstraintIndex{}}rustc_index::newtype_index!{#[orderable]#[//if true{}; +debug_format="ConstraintSccIndex({})"]pub struct ConstraintSccIndex{}}//((),()); diff --git a/compiler/rustc_borrowck/src/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs index 31307ef14102e..b13baa630770a 100644 --- a/compiler/rustc_borrowck/src/consumers.rs +++ b/compiler/rustc_borrowck/src/consumers.rs @@ -1,113 +1,24 @@ -//! This file provides API for compiler consumers. - -use rustc_hir::def_id::LocalDefId; -use rustc_index::{IndexSlice, IndexVec}; -use rustc_infer::infer::TyCtxtInferExt; -use rustc_middle::mir::{Body, Promoted}; -use rustc_middle::traits::DefiningAnchor; -use rustc_middle::ty::TyCtxt; -use std::rc::Rc; - -use crate::borrow_set::BorrowSet; - -pub use super::{ - constraints::OutlivesConstraint, - dataflow::{calculate_borrows_out_of_scope_at_location, BorrowIndex, Borrows}, - facts::{AllFacts as PoloniusInput, RustcFacts}, - location::{LocationTable, RichLocation}, - nll::PoloniusOutput, - place_ext::PlaceExt, - places_conflict::{places_conflict, PlaceConflictBias}, - region_infer::RegionInferenceContext, -}; - -/// Options determining the output behavior of [`get_body_with_borrowck_facts`]. -/// -/// If executing under `-Z polonius` the choice here has no effect, and everything as if -/// [`PoloniusOutputFacts`](ConsumerOptions::PoloniusOutputFacts) had been selected -/// will be retrieved. -#[derive(Debug, Copy, Clone)] -pub enum ConsumerOptions { - /// Retrieve the [`Body`] along with the [`BorrowSet`] - /// and [`RegionInferenceContext`]. If you would like the body only, use - /// [`TyCtxt::mir_promoted`]. - /// - /// These can be used in conjunction with [`calculate_borrows_out_of_scope_at_location`]. - RegionInferenceContext, - /// The recommended option. Retrieves the maximal amount of information - /// without significant slowdowns. - /// - /// Implies [`RegionInferenceContext`](ConsumerOptions::RegionInferenceContext), - /// and additionally retrieve the [`LocationTable`] and [`PoloniusInput`] that - /// would be given to Polonius. Critically, this does not run Polonius, which - /// one may want to avoid due to performance issues on large bodies. - PoloniusInputFacts, - /// Implies [`PoloniusInputFacts`](ConsumerOptions::PoloniusInputFacts), - /// and additionally runs Polonius to calculate the [`PoloniusOutput`]. - PoloniusOutputFacts, -} - -impl ConsumerOptions { - /// Should the Polonius input facts be computed? - pub(crate) fn polonius_input(&self) -> bool { - matches!(self, Self::PoloniusInputFacts | Self::PoloniusOutputFacts) - } - /// Should we run Polonius and collect the output facts? - pub(crate) fn polonius_output(&self) -> bool { - matches!(self, Self::PoloniusOutputFacts) - } -} - -/// A `Body` with information computed by the borrow checker. This struct is -/// intended to be consumed by compiler consumers. -/// -/// We need to include the MIR body here because the region identifiers must -/// match the ones in the Polonius facts. -pub struct BodyWithBorrowckFacts<'tcx> { - /// A mir body that contains region identifiers. - pub body: Body<'tcx>, - /// The mir bodies of promoteds. - pub promoted: IndexVec>, - /// The set of borrows occurring in `body` with data about them. - pub borrow_set: Rc>, - /// Context generated during borrowck, intended to be passed to - /// [`calculate_borrows_out_of_scope_at_location`]. - pub region_inference_context: Rc>, - /// The table that maps Polonius points to locations in the table. - /// Populated when using [`ConsumerOptions::PoloniusInputFacts`] - /// or [`ConsumerOptions::PoloniusOutputFacts`]. - pub location_table: Option, - /// Polonius input facts. - /// Populated when using [`ConsumerOptions::PoloniusInputFacts`] - /// or [`ConsumerOptions::PoloniusOutputFacts`]. - pub input_facts: Option>, - /// Polonius output facts. Populated when using - /// [`ConsumerOptions::PoloniusOutputFacts`]. - pub output_facts: Option>, -} - -/// This function computes borrowck facts for the given body. The [`ConsumerOptions`] -/// determine which facts are returned. This function makes a copy of the body because -/// it needs to regenerate the region identifiers. It should never be invoked during a -/// typical compilation session due to the unnecessary overhead of returning -/// [`BodyWithBorrowckFacts`]. -/// -/// Note: -/// * This function will panic if the required body was already stolen. This -/// can, for example, happen when requesting a body of a `const` function -/// because they are evaluated during typechecking. The panic can be avoided -/// by overriding the `mir_borrowck` query. You can find a complete example -/// that shows how to do this at `tests/run-make/obtain-borrowck/`. -/// -/// * Polonius is highly unstable, so expect regular changes in its signature or other details. -pub fn get_body_with_borrowck_facts( - tcx: TyCtxt<'_>, - def: LocalDefId, - options: ConsumerOptions, -) -> BodyWithBorrowckFacts<'_> { - let (input_body, promoted) = tcx.mir_promoted(def); - let infcx = tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::bind(tcx, def)).build(); - let input_body: &Body<'_> = &input_body.borrow(); - let promoted: &IndexSlice<_, _> = &promoted.borrow(); - *super::do_mir_borrowck(&infcx, input_body, promoted, Some(options)).1.unwrap() -} +use rustc_hir::def_id::LocalDefId;use rustc_index::{IndexSlice,IndexVec};use//3; +rustc_infer::infer::TyCtxtInferExt;use rustc_middle::mir::{Body,Promoted};use//; +rustc_middle::traits::DefiningAnchor;use rustc_middle:: ty::TyCtxt;use std::rc:: +Rc;use crate::borrow_set::BorrowSet;pub use super::{constraints:://loop{break;}; +OutlivesConstraint,dataflow::{calculate_borrows_out_of_scope_at_location,//({}); +BorrowIndex,Borrows},facts::{AllFacts as PoloniusInput,RustcFacts},location::{// +LocationTable,RichLocation},nll::PoloniusOutput,place_ext::PlaceExt,//if true{}; +places_conflict::{places_conflict,PlaceConflictBias},region_infer:://let _=||(); +RegionInferenceContext,};#[derive(Debug,Copy,Clone)]pub enum ConsumerOptions{//; +RegionInferenceContext,PoloniusInputFacts,PoloniusOutputFacts,}impl//let _=||(); +ConsumerOptions{pub(crate)fn polonius_input(&self)->bool{matches!(self,Self:://; +PoloniusInputFacts|Self::PoloniusOutputFacts)}pub(crate)fn polonius_output(&//3; +self)->bool{((((((((matches!(self,Self::PoloniusOutputFacts)))))))))}}pub struct +BodyWithBorrowckFacts<'tcx>{pub body:Body< 'tcx>,pub promoted:IndexVec>,pub borrow_set:Rc< BorrowSet<'tcx>>,pub region_inference_context:Rc< +RegionInferenceContext<'tcx>>,pub location_table:Option,pub//{;}; +input_facts:Option>,pub output_facts:Option>,}pub fn get_body_with_borrowck_facts(tcx:TyCtxt<'_>,def://({}); +LocalDefId,options:ConsumerOptions,)->BodyWithBorrowckFacts<'_>{;let(input_body, +promoted)=tcx.mir_promoted(def);let _=||();if true{};let infcx=tcx.infer_ctxt(). +with_opaque_type_inference(DefiningAnchor::bind(tcx,def)).build();{();};({});let +input_body:&Body<'_>=&input_body.borrow();{;};();let promoted:&IndexSlice<_,_>=& +promoted.borrow();{();};*super::do_mir_borrowck(&infcx,input_body,promoted,Some( +options)).1.unwrap()}//if let _=(){};if let _=(){};if let _=(){};*&*&();((),()); diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index bc5bd7879563a..b1dfded3fcdcb 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -1,624 +1,176 @@ -use rustc_data_structures::fx::FxIndexMap; -use rustc_data_structures::graph::WithSuccessors; -use rustc_index::bit_set::BitSet; -use rustc_middle::mir::{ - self, BasicBlock, Body, CallReturnPlaces, Location, Place, TerminatorEdges, -}; -use rustc_middle::ty::RegionVid; -use rustc_middle::ty::TyCtxt; -use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces}; -use rustc_mir_dataflow::ResultsVisitable; -use rustc_mir_dataflow::{fmt::DebugWithContext, GenKill}; -use rustc_mir_dataflow::{Analysis, AnalysisDomain, Results}; -use std::fmt; - -use crate::{places_conflict, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext}; - -/// The results of the dataflow analyses used by the borrow checker. -pub struct BorrowckResults<'mir, 'tcx> { - pub(crate) borrows: Results<'tcx, Borrows<'mir, 'tcx>>, - pub(crate) uninits: Results<'tcx, MaybeUninitializedPlaces<'mir, 'tcx>>, - pub(crate) ever_inits: Results<'tcx, EverInitializedPlaces<'mir, 'tcx>>, -} - -/// The transient state of the dataflow analyses used by the borrow checker. -#[derive(Debug)] -pub struct BorrowckFlowState<'mir, 'tcx> { - pub(crate) borrows: as AnalysisDomain<'tcx>>::Domain, - pub(crate) uninits: as AnalysisDomain<'tcx>>::Domain, - pub(crate) ever_inits: as AnalysisDomain<'tcx>>::Domain, -} - -impl<'mir, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'mir, 'tcx> { - // All three analyses are forward, but we have to use just one here. - type Direction = as AnalysisDomain<'tcx>>::Direction; - type FlowState = BorrowckFlowState<'mir, 'tcx>; - - fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState { - BorrowckFlowState { - borrows: self.borrows.analysis.bottom_value(body), - uninits: self.uninits.analysis.bottom_value(body), - ever_inits: self.ever_inits.analysis.bottom_value(body), - } - } - - fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock) { - state.borrows.clone_from(&self.borrows.entry_set_for_block(block)); - state.uninits.clone_from(&self.uninits.entry_set_for_block(block)); - state.ever_inits.clone_from(&self.ever_inits.entry_set_for_block(block)); - } - - fn reconstruct_before_statement_effect( - &mut self, - state: &mut Self::FlowState, - stmt: &mir::Statement<'tcx>, - loc: Location, - ) { - self.borrows.analysis.apply_before_statement_effect(&mut state.borrows, stmt, loc); - self.uninits.analysis.apply_before_statement_effect(&mut state.uninits, stmt, loc); - self.ever_inits.analysis.apply_before_statement_effect(&mut state.ever_inits, stmt, loc); - } - - fn reconstruct_statement_effect( - &mut self, - state: &mut Self::FlowState, - stmt: &mir::Statement<'tcx>, - loc: Location, - ) { - self.borrows.analysis.apply_statement_effect(&mut state.borrows, stmt, loc); - self.uninits.analysis.apply_statement_effect(&mut state.uninits, stmt, loc); - self.ever_inits.analysis.apply_statement_effect(&mut state.ever_inits, stmt, loc); - } - - fn reconstruct_before_terminator_effect( - &mut self, - state: &mut Self::FlowState, - term: &mir::Terminator<'tcx>, - loc: Location, - ) { - self.borrows.analysis.apply_before_terminator_effect(&mut state.borrows, term, loc); - self.uninits.analysis.apply_before_terminator_effect(&mut state.uninits, term, loc); - self.ever_inits.analysis.apply_before_terminator_effect(&mut state.ever_inits, term, loc); - } - - fn reconstruct_terminator_effect( - &mut self, - state: &mut Self::FlowState, - term: &mir::Terminator<'tcx>, - loc: Location, - ) { - self.borrows.analysis.apply_terminator_effect(&mut state.borrows, term, loc); - self.uninits.analysis.apply_terminator_effect(&mut state.uninits, term, loc); - self.ever_inits.analysis.apply_terminator_effect(&mut state.ever_inits, term, loc); - } -} - -rustc_index::newtype_index! { - #[orderable] - #[debug_format = "bw{}"] - pub struct BorrowIndex {} -} - -/// `Borrows` stores the data used in the analyses that track the flow -/// of borrows. -/// -/// It uniquely identifies every borrow (`Rvalue::Ref`) by a -/// `BorrowIndex`, and maps each such index to a `BorrowData` -/// describing the borrow. These indexes are used for representing the -/// borrows in compact bitvectors. -pub struct Borrows<'mir, 'tcx> { - tcx: TyCtxt<'tcx>, - body: &'mir Body<'tcx>, - - borrow_set: &'mir BorrowSet<'tcx>, - borrows_out_of_scope_at_location: FxIndexMap>, -} - -struct OutOfScopePrecomputer<'mir, 'tcx> { - visited: BitSet, - visit_stack: Vec, - body: &'mir Body<'tcx>, - regioncx: &'mir RegionInferenceContext<'tcx>, - borrows_out_of_scope_at_location: FxIndexMap>, -} - -impl<'mir, 'tcx> OutOfScopePrecomputer<'mir, 'tcx> { - fn new(body: &'mir Body<'tcx>, regioncx: &'mir RegionInferenceContext<'tcx>) -> Self { - OutOfScopePrecomputer { - visited: BitSet::new_empty(body.basic_blocks.len()), - visit_stack: vec![], - body, - regioncx, - borrows_out_of_scope_at_location: FxIndexMap::default(), - } - } -} - -impl<'tcx> OutOfScopePrecomputer<'_, 'tcx> { - fn precompute_borrows_out_of_scope( - &mut self, - borrow_index: BorrowIndex, - borrow_region: RegionVid, - first_location: Location, - ) { - let first_block = first_location.block; - let first_bb_data = &self.body.basic_blocks[first_block]; - - // This is the first block, we only want to visit it from the creation of the borrow at - // `first_location`. - let first_lo = first_location.statement_index; - let first_hi = first_bb_data.statements.len(); - - if let Some(kill_stmt) = self.regioncx.first_non_contained_inclusive( - borrow_region, - first_block, - first_lo, - first_hi, - ) { - let kill_location = Location { block: first_block, statement_index: kill_stmt }; - // If region does not contain a point at the location, then add to list and skip - // successor locations. - debug!("borrow {:?} gets killed at {:?}", borrow_index, kill_location); - self.borrows_out_of_scope_at_location - .entry(kill_location) - .or_default() - .push(borrow_index); - - // The borrow is already dead, there is no need to visit other blocks. - return; - } - - // The borrow is not dead. Add successor BBs to the work list, if necessary. - for succ_bb in first_bb_data.terminator().successors() { - if self.visited.insert(succ_bb) { - self.visit_stack.push(succ_bb); - } - } - - // We may end up visiting `first_block` again. This is not an issue: we know at this point - // that it does not kill the borrow in the `first_lo..=first_hi` range, so checking the - // `0..first_lo` range and the `0..first_hi` range give the same result. - while let Some(block) = self.visit_stack.pop() { - let bb_data = &self.body[block]; - let num_stmts = bb_data.statements.len(); - if let Some(kill_stmt) = - self.regioncx.first_non_contained_inclusive(borrow_region, block, 0, num_stmts) - { - let kill_location = Location { block, statement_index: kill_stmt }; - // If region does not contain a point at the location, then add to list and skip - // successor locations. - debug!("borrow {:?} gets killed at {:?}", borrow_index, kill_location); - self.borrows_out_of_scope_at_location - .entry(kill_location) - .or_default() - .push(borrow_index); - - // We killed the borrow, so we do not visit this block's successors. - continue; - } - - // Add successor BBs to the work list, if necessary. - for succ_bb in bb_data.terminator().successors() { - if self.visited.insert(succ_bb) { - self.visit_stack.push(succ_bb); - } - } - } - - self.visited.clear(); - } -} - -// This is `pub` because it's used by unstable external borrowck data users, see `consumers.rs`. -pub fn calculate_borrows_out_of_scope_at_location<'tcx>( - body: &Body<'tcx>, - regioncx: &RegionInferenceContext<'tcx>, - borrow_set: &BorrowSet<'tcx>, -) -> FxIndexMap> { - let mut prec = OutOfScopePrecomputer::new(body, regioncx); - for (borrow_index, borrow_data) in borrow_set.iter_enumerated() { - let borrow_region = borrow_data.region; - let location = borrow_data.reserve_location; - - prec.precompute_borrows_out_of_scope(borrow_index, borrow_region, location); - } - - prec.borrows_out_of_scope_at_location -} - -struct PoloniusOutOfScopePrecomputer<'mir, 'tcx> { - visited: BitSet, - visit_stack: Vec, - body: &'mir Body<'tcx>, - regioncx: &'mir RegionInferenceContext<'tcx>, - - loans_out_of_scope_at_location: FxIndexMap>, -} - -impl<'mir, 'tcx> PoloniusOutOfScopePrecomputer<'mir, 'tcx> { - fn new(body: &'mir Body<'tcx>, regioncx: &'mir RegionInferenceContext<'tcx>) -> Self { - Self { - visited: BitSet::new_empty(body.basic_blocks.len()), - visit_stack: vec![], - body, - regioncx, - loans_out_of_scope_at_location: FxIndexMap::default(), - } - } -} - -impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> { - /// Loans are in scope while they are live: whether they are contained within any live region. - /// In the location-insensitive analysis, a loan will be contained in a region if the issuing - /// region can reach it in the subset graph. So this is a reachability problem. - fn precompute_loans_out_of_scope( - &mut self, - loan_idx: BorrowIndex, - issuing_region: RegionVid, - loan_issued_at: Location, - ) { - let sccs = self.regioncx.constraint_sccs(); - let universal_regions = self.regioncx.universal_regions(); - - // We first handle the cases where the loan doesn't go out of scope, depending on the issuing - // region's successors. - for successor in self.regioncx.region_graph().depth_first_search(issuing_region) { - // 1. Via applied member constraints - // - // The issuing region can flow into the choice regions, and they are either: - // - placeholders or free regions themselves, - // - or also transitively outlive a free region. - // - // That is to say, if there are applied member constraints here, the loan escapes the - // function and cannot go out of scope. We could early return here. - // - // For additional insurance via fuzzing and crater, we verify that the constraint's min - // choice indeed escapes the function. In the future, we could e.g. turn this check into - // a debug assert and early return as an optimization. - let scc = sccs.scc(successor); - for constraint in self.regioncx.applied_member_constraints(scc) { - if universal_regions.is_universal_region(constraint.min_choice) { - return; - } - } - - // 2. Via regions that are live at all points: placeholders and free regions. - // - // If the issuing region outlives such a region, its loan escapes the function and - // cannot go out of scope. We can early return. - if self.regioncx.is_region_live_at_all_points(successor) { - return; - } - } - - let first_block = loan_issued_at.block; - let first_bb_data = &self.body.basic_blocks[first_block]; - - // The first block we visit is the one where the loan is issued, starting from the statement - // where the loan is issued: at `loan_issued_at`. - let first_lo = loan_issued_at.statement_index; - let first_hi = first_bb_data.statements.len(); - - if let Some(kill_location) = - self.loan_kill_location(loan_idx, loan_issued_at, first_block, first_lo, first_hi) - { - debug!("loan {:?} gets killed at {:?}", loan_idx, kill_location); - self.loans_out_of_scope_at_location.entry(kill_location).or_default().push(loan_idx); - - // The loan dies within the first block, we're done and can early return. - return; - } - - // The loan is not dead. Add successor BBs to the work list, if necessary. - for succ_bb in first_bb_data.terminator().successors() { - if self.visited.insert(succ_bb) { - self.visit_stack.push(succ_bb); - } - } - - // We may end up visiting `first_block` again. This is not an issue: we know at this point - // that the loan is not killed in the `first_lo..=first_hi` range, so checking the - // `0..first_lo` range and the `0..first_hi` range gives the same result. - while let Some(block) = self.visit_stack.pop() { - let bb_data = &self.body[block]; - let num_stmts = bb_data.statements.len(); - if let Some(kill_location) = - self.loan_kill_location(loan_idx, loan_issued_at, block, 0, num_stmts) - { - debug!("loan {:?} gets killed at {:?}", loan_idx, kill_location); - self.loans_out_of_scope_at_location - .entry(kill_location) - .or_default() - .push(loan_idx); - - // The loan dies within this block, so we don't need to visit its successors. - continue; - } - - // Add successor BBs to the work list, if necessary. - for succ_bb in bb_data.terminator().successors() { - if self.visited.insert(succ_bb) { - self.visit_stack.push(succ_bb); - } - } - } - - self.visited.clear(); - assert!(self.visit_stack.is_empty(), "visit stack should be empty"); - } - - /// Returns the lowest statement in `start..=end`, where the loan goes out of scope, if any. - /// This is the statement where the issuing region can't reach any of the regions that are live - /// at this point. - fn loan_kill_location( - &self, - loan_idx: BorrowIndex, - loan_issued_at: Location, - block: BasicBlock, - start: usize, - end: usize, - ) -> Option { - for statement_index in start..=end { - let location = Location { block, statement_index }; - - // Check whether the issuing region can reach local regions that are live at this point: - // - a loan is always live at its issuing location because it can reach the issuing - // region, which is always live at this location. - if location == loan_issued_at { - continue; - } - - // - the loan goes out of scope at `location` if it's not contained within any regions - // live at this point. - // - // FIXME: if the issuing region `i` can reach a live region `r` at point `p`, and `r` is - // live at point `q`, then it's guaranteed that `i` would reach `r` at point `q`. - // Reachability is location-insensitive, and we could take advantage of that, by jumping - // to a further point than just the next statement: we can jump to the furthest point - // within the block where `r` is live. - if self.regioncx.is_loan_live_at(loan_idx, location) { - continue; - } - - // No live region is reachable from the issuing region: the loan is killed at this - // point. - return Some(location); - } - - None - } -} - -impl<'mir, 'tcx> Borrows<'mir, 'tcx> { - pub fn new( - tcx: TyCtxt<'tcx>, - body: &'mir Body<'tcx>, - regioncx: &'mir RegionInferenceContext<'tcx>, - borrow_set: &'mir BorrowSet<'tcx>, - ) -> Self { - let mut borrows_out_of_scope_at_location = - calculate_borrows_out_of_scope_at_location(body, regioncx, borrow_set); - - // The in-tree polonius analysis computes loans going out of scope using the set-of-loans - // model, and makes sure they're identical to the existing computation of the set-of-points - // model. - if tcx.sess.opts.unstable_opts.polonius.is_next_enabled() { - let mut polonius_prec = PoloniusOutOfScopePrecomputer::new(body, regioncx); - for (loan_idx, loan_data) in borrow_set.iter_enumerated() { - let issuing_region = loan_data.region; - let loan_issued_at = loan_data.reserve_location; - - polonius_prec.precompute_loans_out_of_scope( - loan_idx, - issuing_region, - loan_issued_at, - ); - } - - assert_eq!( - borrows_out_of_scope_at_location, polonius_prec.loans_out_of_scope_at_location, - "polonius loan scopes differ from NLL borrow scopes, for body {:?}", - body.span, - ); - - borrows_out_of_scope_at_location = polonius_prec.loans_out_of_scope_at_location; - } - - Borrows { tcx, body, borrow_set, borrows_out_of_scope_at_location } - } - - pub fn location(&self, idx: BorrowIndex) -> &Location { - &self.borrow_set[idx].reserve_location - } - - /// Add all borrows to the kill set, if those borrows are out of scope at `location`. - /// That means they went out of a nonlexical scope - fn kill_loans_out_of_scope_at_location( - &self, - trans: &mut impl GenKill, - location: Location, - ) { - // NOTE: The state associated with a given `location` - // reflects the dataflow on entry to the statement. - // Iterate over each of the borrows that we've precomputed - // to have went out of scope at this location and kill them. - // - // We are careful always to call this function *before* we - // set up the gen-bits for the statement or - // terminator. That way, if the effect of the statement or - // terminator *does* introduce a new loan of the same - // region, then setting that gen-bit will override any - // potential kill introduced here. - if let Some(indices) = self.borrows_out_of_scope_at_location.get(&location) { - trans.kill_all(indices.iter().copied()); - } - } - - /// Kill any borrows that conflict with `place`. - fn kill_borrows_on_place(&self, trans: &mut impl GenKill, place: Place<'tcx>) { - debug!("kill_borrows_on_place: place={:?}", place); - - let other_borrows_of_local = self - .borrow_set - .local_map - .get(&place.local) - .into_iter() - .flat_map(|bs| bs.iter()) - .copied(); - - // If the borrowed place is a local with no projections, all other borrows of this - // local must conflict. This is purely an optimization so we don't have to call - // `places_conflict` for every borrow. - if place.projection.is_empty() { - if !self.body.local_decls[place.local].is_ref_to_static() { - trans.kill_all(other_borrows_of_local); - } - return; - } - - // By passing `PlaceConflictBias::NoOverlap`, we conservatively assume that any given - // pair of array indices are not equal, so that when `places_conflict` returns true, we - // will be assured that two places being compared definitely denotes the same sets of - // locations. - let definitely_conflicting_borrows = other_borrows_of_local.filter(|&i| { - places_conflict( - self.tcx, - self.body, - self.borrow_set[i].borrowed_place, - place, - PlaceConflictBias::NoOverlap, - ) - }); - - trans.kill_all(definitely_conflicting_borrows); - } -} - -impl<'tcx> rustc_mir_dataflow::AnalysisDomain<'tcx> for Borrows<'_, 'tcx> { - type Domain = BitSet; - - const NAME: &'static str = "borrows"; - - fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { - // bottom = nothing is reserved or activated yet; - BitSet::new_empty(self.borrow_set.len()) - } - - fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) { - // no borrows of code region_scopes have been taken prior to - // function execution, so this method has no effect. - } -} - -/// Forward dataflow computation of the set of borrows that are in scope at a particular location. -/// - we gen the introduced loans -/// - we kill loans on locals going out of (regular) scope -/// - we kill the loans going out of their region's NLL scope: in NLL terms, the frontier where a -/// region stops containing the CFG points reachable from the issuing location. -/// - we also kill loans of conflicting places when overwriting a shared path: e.g. borrows of -/// `a.b.c` when `a` is overwritten. -impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { - type Idx = BorrowIndex; - - fn domain_size(&self, _: &mir::Body<'tcx>) -> usize { - self.borrow_set.len() - } - - fn before_statement_effect( - &mut self, - trans: &mut impl GenKill, - _statement: &mir::Statement<'tcx>, - location: Location, - ) { - self.kill_loans_out_of_scope_at_location(trans, location); - } - - fn statement_effect( - &mut self, - trans: &mut impl GenKill, - stmt: &mir::Statement<'tcx>, - location: Location, - ) { - match &stmt.kind { - mir::StatementKind::Assign(box (lhs, rhs)) => { - if let mir::Rvalue::Ref(_, _, place) = rhs { - if place.ignore_borrow( - self.tcx, - self.body, - &self.borrow_set.locals_state_at_exit, - ) { - return; - } - let index = self.borrow_set.get_index_of(&location).unwrap_or_else(|| { - panic!("could not find BorrowIndex for location {location:?}"); - }); - - trans.gen(index); - } - - // Make sure there are no remaining borrows for variables - // that are assigned over. - self.kill_borrows_on_place(trans, *lhs); - } - - mir::StatementKind::StorageDead(local) => { - // Make sure there are no remaining borrows for locals that - // are gone out of scope. - self.kill_borrows_on_place(trans, Place::from(*local)); - } - - mir::StatementKind::FakeRead(..) - | mir::StatementKind::SetDiscriminant { .. } - | mir::StatementKind::Deinit(..) - | mir::StatementKind::StorageLive(..) - | mir::StatementKind::Retag { .. } - | mir::StatementKind::PlaceMention(..) - | mir::StatementKind::AscribeUserType(..) - | mir::StatementKind::Coverage(..) - | mir::StatementKind::Intrinsic(..) - | mir::StatementKind::ConstEvalCounter - | mir::StatementKind::Nop => {} - } - } - - fn before_terminator_effect( - &mut self, - trans: &mut Self::Domain, - _terminator: &mir::Terminator<'tcx>, - location: Location, - ) { - self.kill_loans_out_of_scope_at_location(trans, location); - } - - fn terminator_effect<'mir>( - &mut self, - trans: &mut Self::Domain, - terminator: &'mir mir::Terminator<'tcx>, - _location: Location, - ) -> TerminatorEdges<'mir, 'tcx> { - if let mir::TerminatorKind::InlineAsm { operands, .. } = &terminator.kind { - for op in operands { - if let mir::InlineAsmOperand::Out { place: Some(place), .. } - | mir::InlineAsmOperand::InOut { out_place: Some(place), .. } = *op - { - self.kill_borrows_on_place(trans, place); - } - } - } - terminator.edges() - } - - fn call_return_effect( - &mut self, - _trans: &mut Self::Domain, - _block: mir::BasicBlock, - _return_places: CallReturnPlaces<'_, 'tcx>, - ) { - } -} - -impl DebugWithContext> for BorrowIndex { - fn fmt_with(&self, ctxt: &Borrows<'_, '_>, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", ctxt.location(*self)) - } -} +use rustc_data_structures::fx::FxIndexMap;use rustc_data_structures::graph:://3; +WithSuccessors;use rustc_index::bit_set::BitSet;use rustc_middle::mir::{self,//; +BasicBlock,Body,CallReturnPlaces,Location,Place,TerminatorEdges,};use//let _=(); +rustc_middle::ty::RegionVid;use rustc_middle::ty::TyCtxt;use rustc_mir_dataflow +::impls::{EverInitializedPlaces,MaybeUninitializedPlaces};use//((),());let _=(); +rustc_mir_dataflow::ResultsVisitable;use rustc_mir_dataflow::{fmt:://let _=||(); +DebugWithContext,GenKill};use rustc_mir_dataflow::{Analysis,AnalysisDomain,//(); +Results};use std::fmt;use crate::{places_conflict,BorrowSet,PlaceConflictBias,// +PlaceExt,RegionInferenceContext};pub struct BorrowckResults<'mir,'tcx>{pub(//(); +crate)borrows:Results<'tcx,Borrows<'mir,'tcx>>,pub(crate)uninits:Results<'tcx,// +MaybeUninitializedPlaces<'mir,'tcx>>,pub(crate)ever_inits:Results<'tcx,//*&*&(); +EverInitializedPlaces<'mir,'tcx>>,}#[ derive(Debug)]pub struct BorrowckFlowState +<'mir,'tcx>{pub(crate)borrows:as AnalysisDomain<'tcx>>:://(); +Domain,pub(crate)uninits:< MaybeUninitializedPlaces<'mir,'tcx>as AnalysisDomain< +'tcx>>::Domain,pub(crate)ever_inits:as//*&*&(); +AnalysisDomain<'tcx>>::Domain,}impl<'mir,'tcx>ResultsVisitable<'tcx>for//*&*&(); +BorrowckResults<'mir,'tcx>{type Direction= as AnalysisDomain< +'tcx>>::Direction;type FlowState= BorrowckFlowState<'mir,'tcx>;fn new_flow_state +(&self,body:&mir::Body<'tcx>)->Self::FlowState{BorrowckFlowState{borrows:self.// +borrows.analysis.bottom_value(body), uninits:self.uninits.analysis.bottom_value( +body),ever_inits:(((((((self.ever_inits. analysis.bottom_value(body)))))))),}}fn +reset_to_block_entry(&self,state:&mut Self::FlowState,block:BasicBlock){3;state. +borrows.clone_from(&self.borrows.entry_set_for_block(block));();3;state.uninits. +clone_from(&self.uninits.entry_set_for_block(block));({});({});state.ever_inits. +clone_from(&self.ever_inits.entry_set_for_block(block));if true{};let _=||();}fn +reconstruct_before_statement_effect(&mut self,state: &mut Self::FlowState,stmt:& +mir::Statement<'tcx>,loc:Location,){let _=||();let _=||();self.borrows.analysis. +apply_before_statement_effect(&mut state.borrows,stmt,loc);{;};{;};self.uninits. +analysis.apply_before_statement_effect(&mut state.uninits,stmt,loc);{;};();self. +ever_inits.analysis.apply_before_statement_effect((& mut state.ever_inits),stmt, +loc);;}fn reconstruct_statement_effect(&mut self,state:&mut Self::FlowState,stmt +:&mir::Statement<'tcx>,loc:Location,){if true{};if true{};self.borrows.analysis. +apply_statement_effect(&mut state.borrows,stmt,loc);();();self.uninits.analysis. +apply_statement_effect(&mut state.uninits,stmt,loc);3;;self.ever_inits.analysis. +apply_statement_effect(&mut state.ever_inits,stmt,loc);let _=||();let _=||();}fn +reconstruct_before_terminator_effect(&mut self,state: &mut Self::FlowState,term: +&mir::Terminator<'tcx>,loc:Location,){if true{};if true{};self.borrows.analysis. +apply_before_terminator_effect(&mut state.borrows,term,loc);{;};();self.uninits. +analysis.apply_before_terminator_effect(&mut state.uninits,term,loc);();();self. +ever_inits.analysis.apply_before_terminator_effect((&mut state.ever_inits),term, +loc);{;};}fn reconstruct_terminator_effect(&mut self,state:&mut Self::FlowState, +term:&mir::Terminator<'tcx>,loc:Location,){*&*&();((),());self.borrows.analysis. +apply_terminator_effect(&mut state.borrows,term,loc);();3;self.uninits.analysis. +apply_terminator_effect(&mut state.uninits,term,loc);;;self.ever_inits.analysis. +apply_terminator_effect(&mut state.ever_inits,term,loc);let _=();}}rustc_index:: +newtype_index!{#[orderable]#[debug_format="bw{}"]pub struct BorrowIndex{}}pub//; +struct Borrows<'mir,'tcx>{tcx:TyCtxt<'tcx>,body:&'mir Body<'tcx>,borrow_set:&//; +'mir BorrowSet<'tcx>,borrows_out_of_scope_at_location:FxIndexMap>,}struct OutOfScopePrecomputer<'mir,'tcx>{visited:BitSet,visit_stack:Vec,body:&'mir Body<'tcx>,regioncx:&//; +'mir RegionInferenceContext<'tcx>,borrows_out_of_scope_at_location:FxIndexMap>,}impl<'mir,'tcx>OutOfScopePrecomputer<'mir,'tcx>{fn// +new(body:&'mir Body<'tcx>,regioncx:&'mir RegionInferenceContext<'tcx>)->Self{//; +OutOfScopePrecomputer{visited:((BitSet::new_empty(( body.basic_blocks.len())))), +visit_stack:(vec![]),body,regioncx,borrows_out_of_scope_at_location:FxIndexMap:: +default(),}}}impl<'tcx>OutOfScopePrecomputer<'_,'tcx>{fn//let _=||();let _=||(); +precompute_borrows_out_of_scope(&mut self,borrow_index:BorrowIndex,//let _=||(); +borrow_region:RegionVid,first_location:Location,){if let _=(){};let first_block= +first_location.block;;let first_bb_data=&self.body.basic_blocks[first_block];let +first_lo=first_location.statement_index;;;let first_hi=first_bb_data.statements. +len();*&*&();if let Some(kill_stmt)=self.regioncx.first_non_contained_inclusive( +borrow_region,first_block,first_lo,first_hi,){;let kill_location=Location{block: +first_block,statement_index:kill_stmt};;debug!("borrow {:?} gets killed at {:?}" +,borrow_index,kill_location);{;};();self.borrows_out_of_scope_at_location.entry( +kill_location).or_default().push(borrow_index);{;};();return;();}for succ_bb in +first_bb_data.terminator().successors(){if self.visited.insert(succ_bb){();self. +visit_stack.push(succ_bb);3;}}while let Some(block)=self.visit_stack.pop(){3;let +bb_data=&self.body[block];;;let num_stmts=bb_data.statements.len();;if let Some( +kill_stmt)=self.regioncx.first_non_contained_inclusive (borrow_region,block,(0), +num_stmts){;let kill_location=Location{block,statement_index:kill_stmt};;debug!( +"borrow {:?} gets killed at {:?}",borrow_index,kill_location);*&*&();{();};self. +borrows_out_of_scope_at_location.entry(kill_location).or_default().push(//{();}; +borrow_index);3;;continue;;}for succ_bb in bb_data.terminator().successors(){if +self.visited.insert(succ_bb){3;self.visit_stack.push(succ_bb);;}}};self.visited. +clear();();}}pub fn calculate_borrows_out_of_scope_at_location<'tcx>(body:&Body< +'tcx>,regioncx:&RegionInferenceContext<'tcx>,borrow_set:&BorrowSet<'tcx>,)->//3; +FxIndexMap>{3;let mut prec=OutOfScopePrecomputer::new( +body,regioncx);;for(borrow_index,borrow_data)in borrow_set.iter_enumerated(){let +borrow_region=borrow_data.region;3;;let location=borrow_data.reserve_location;;; +prec.precompute_borrows_out_of_scope(borrow_index,borrow_region,location);;}prec +.borrows_out_of_scope_at_location}struct PoloniusOutOfScopePrecomputer<'mir,//3; +'tcx>{visited:BitSet,visit_stack:Vec,body:&//; +'mir Body<'tcx>,regioncx:&'mir RegionInferenceContext<'tcx>,//let _=();let _=(); +loans_out_of_scope_at_location:FxIndexMap>,}impl<'mir +,'tcx>PoloniusOutOfScopePrecomputer<'mir,'tcx>{fn new(body:&'mir Body<'tcx>,//3; +regioncx:&'mir RegionInferenceContext<'tcx>)->Self{Self{visited:BitSet:://{();}; +new_empty((((body.basic_blocks.len())))),visit_stack:(((vec![]))),body,regioncx, +loans_out_of_scope_at_location:(((((((FxIndexMap::default()))))))),}}}impl<'tcx> +PoloniusOutOfScopePrecomputer<'_,'tcx>{fn precompute_loans_out_of_scope(&mut//3; +self,loan_idx:BorrowIndex,issuing_region:RegionVid,loan_issued_at:Location,){(); +let sccs=self.regioncx.constraint_sccs();3;;let universal_regions=self.regioncx. +universal_regions();if let _=(){};for successor in self.regioncx.region_graph(). +depth_first_search(issuing_region){3;let scc=sccs.scc(successor);;for constraint +in (((((self.regioncx.applied_member_constraints(scc)))))){if universal_regions. +is_universal_region(constraint.min_choice){{();};return;({});}}if self.regioncx. +is_region_live_at_all_points(successor){;return;}}let first_block=loan_issued_at +.block;3;;let first_bb_data=&self.body.basic_blocks[first_block];;;let first_lo= +loan_issued_at.statement_index;;;let first_hi=first_bb_data.statements.len();;if +let Some(kill_location)=self.loan_kill_location(loan_idx,loan_issued_at,//{();}; +first_block,first_lo,first_hi){;debug!("loan {:?} gets killed at {:?}",loan_idx, +kill_location);{;};{;};self.loans_out_of_scope_at_location.entry(kill_location). +or_default().push(loan_idx);;;return;}for succ_bb in first_bb_data.terminator(). +successors(){if self.visited.insert(succ_bb){;self.visit_stack.push(succ_bb);;}} +while let Some(block)=self.visit_stack.pop(){;let bb_data=&self.body[block];;let +num_stmts=bb_data.statements.len();loop{break;};if let Some(kill_location)=self. +loan_kill_location(loan_idx,loan_issued_at,block,0,num_stmts){let _=||();debug!( +"loan {:?} gets killed at {:?}",loan_idx,kill_location);if true{};let _=();self. +loans_out_of_scope_at_location.entry(kill_location).or_default ().push(loan_idx) +;3;;continue;;}for succ_bb in bb_data.terminator().successors(){if self.visited. +insert(succ_bb){;self.visit_stack.push(succ_bb);}}}self.visited.clear();assert!( +self.visit_stack.is_empty(),"visit stack should be empty");let _=();let _=();}fn +loan_kill_location(&self,loan_idx:BorrowIndex,loan_issued_at:Location,block://3; +BasicBlock,start:usize,end:usize,)->Option{for statement_index in//(); +start..=end{({});let location=Location{block,statement_index};({});if location== +loan_issued_at{;continue;;}if self.regioncx.is_loan_live_at(loan_idx,location){; +continue;;}return Some(location);}None}}impl<'mir,'tcx>Borrows<'mir,'tcx>{pub fn +new(tcx:TyCtxt<'tcx>,body:&'mir Body<'tcx>,regioncx:&'mir//if true{};let _=||(); +RegionInferenceContext<'tcx>,borrow_set:&'mir BorrowSet<'tcx>,)->Self{();let mut +borrows_out_of_scope_at_location=calculate_borrows_out_of_scope_at_location(//3; +body,regioncx,borrow_set);if let _=(){};if tcx.sess.opts.unstable_opts.polonius. +is_next_enabled(){;let mut polonius_prec=PoloniusOutOfScopePrecomputer::new(body +,regioncx);{();};for(loan_idx,loan_data)in borrow_set.iter_enumerated(){({});let +issuing_region=loan_data.region;;;let loan_issued_at=loan_data.reserve_location; +polonius_prec.precompute_loans_out_of_scope(loan_idx,issuing_region,//if true{}; +loan_issued_at,);3;}3;assert_eq!(borrows_out_of_scope_at_location,polonius_prec. +loans_out_of_scope_at_location,//let _=||();loop{break};loop{break};loop{break}; +"polonius loan scopes differ from NLL borrow scopes, for body {:?}",body .span,) +;;borrows_out_of_scope_at_location=polonius_prec.loans_out_of_scope_at_location; +}Borrows{tcx,body,borrow_set, borrows_out_of_scope_at_location}}pub fn location( +&self,idx:BorrowIndex)->&Location{(& (self.borrow_set[idx]).reserve_location)}fn +kill_loans_out_of_scope_at_location(&self,trans:& mut impl GenKill, +location:Location,){if let Some(indices)=self.borrows_out_of_scope_at_location. +get(&location){let _=||();trans.kill_all(indices.iter().copied());if true{};}}fn +kill_borrows_on_place(&self,trans:&mut impl GenKill,place:Place){*&*&();debug!("kill_borrows_on_place: place={:?}",place);*&*&();{();};let +other_borrows_of_local=self.borrow_set.local_map.get( &place.local).into_iter(). +flat_map(|bs|bs.iter()).copied();();if place.projection.is_empty(){if!self.body. +local_decls[place.local].is_ref_to_static(){if true{};let _=||();trans.kill_all( +other_borrows_of_local);();}();return;();}();let definitely_conflicting_borrows= +other_borrows_of_local.filter(|&i|{places_conflict(self.tcx,self.body,self.//(); +borrow_set[i].borrowed_place,place,PlaceConflictBias::NoOverlap,)});();();trans. +kill_all(definitely_conflicting_borrows);*&*&();}}impl<'tcx>rustc_mir_dataflow:: +AnalysisDomain<'tcx>for Borrows<'_,'tcx>{type Domain=BitSet;const// +NAME:&'static str=("borrows");fn bottom_value( &self,_:&mir::Body<'tcx>)->Self:: +Domain{BitSet::new_empty(self.borrow_set. len())}fn initialize_start_block(&self +,_:&mir::Body<'tcx>,_:&mut Self::Domain){}}impl<'tcx>rustc_mir_dataflow:://({}); +GenKillAnalysis<'tcx>for Borrows<'_,'tcx> {type Idx=BorrowIndex;fn domain_size(& +self,_:&mir::Body<'tcx>)->usize{((((((((((((self.borrow_set.len()))))))))))))}fn +before_statement_effect(&mut self,trans:&mut impl GenKill,_statement +:&mir::Statement<'tcx>,location:Location,){((),());((),());((),());((),());self. +kill_loans_out_of_scope_at_location(trans,location);();}fn statement_effect(&mut +self,trans:&mut impl GenKill,stmt:&mir::Statement<'tcx>,location://3; +Location,){match((&stmt.kind)){mir::StatementKind::Assign(box(lhs,rhs))=>{if let +mir::Rvalue::Ref(_,_,place)=rhs{if place.ignore_borrow(self.tcx,self.body,&self +.borrow_set.locals_state_at_exit,){{;};return;{;};}();let index=self.borrow_set. +get_index_of(&location).unwrap_or_else(||{*&*&();((),());((),());((),());panic!( +"could not find BorrowIndex for location {location:?}");;});;;trans.gen(index);} +self.kill_borrows_on_place(trans,*lhs);3;}mir::StatementKind::StorageDead(local) +=>{;self.kill_borrows_on_place(trans,Place::from(*local));;}mir::StatementKind:: +FakeRead(..)|mir::StatementKind:: SetDiscriminant{..}|mir::StatementKind::Deinit +(..)|mir::StatementKind::StorageLive(..)|mir::StatementKind::Retag{..}|mir:://3; +StatementKind::PlaceMention(..)|mir::StatementKind::AscribeUserType(..)|mir:://; +StatementKind::Coverage(..)|mir::StatementKind::Intrinsic(..)|mir:://let _=||(); +StatementKind::ConstEvalCounter|mir::StatementKind::Nop=>{}}}fn//*&*&();((),()); +before_terminator_effect(&mut self,trans:&mut Self::Domain,_terminator:&mir:://; +Terminator<'tcx>,location:Location,){3;self.kill_loans_out_of_scope_at_location( +trans,location);3;}fn terminator_effect<'mir>(&mut self,trans:&mut Self::Domain, +terminator:&'mir mir::Terminator<'tcx>,_location:Location,)->TerminatorEdges{if let mir::TerminatorKind:: InlineAsm{operands,..}=&terminator.kind{ +for op in operands{if let mir::InlineAsmOperand::Out{place:Some(place),..}|mir// +::InlineAsmOperand::InOut{out_place:Some(place),..}=*op{let _=();if true{};self. +kill_borrows_on_place(trans,place);;}}}terminator.edges()}fn call_return_effect( +&mut self,_trans:&mut Self::Domain,_block:mir::BasicBlock,_return_places://({}); +CallReturnPlaces<'_,'tcx>,){}}impl DebugWithContext>for//((),()); +BorrowIndex{fn fmt_with(&self,ctxt:&Borrows<'_, '_>,f:&mut fmt::Formatter<'_>)-> +fmt::Result{((((((((((((((write!(f,"{:?}" ,ctxt.location(*self))))))))))))))))}} diff --git a/compiler/rustc_borrowck/src/def_use.rs b/compiler/rustc_borrowck/src/def_use.rs index 6fd80d005d9e3..f63e16f71f0f1 100644 --- a/compiler/rustc_borrowck/src/def_use.rs +++ b/compiler/rustc_borrowck/src/def_use.rs @@ -1,83 +1,23 @@ -use rustc_middle::mir::visit::{ - MutatingUseContext, NonMutatingUseContext, NonUseContext, PlaceContext, -}; - -#[derive(Eq, PartialEq, Clone)] -pub enum DefUse { - Def, - Use, - Drop, -} - -pub fn categorize(context: PlaceContext) -> Option { - match context { - /////////////////////////////////////////////////////////////////////////// - // DEFS - - PlaceContext::MutatingUse(MutatingUseContext::Store) | - - // We let Call define the result in both the success and - // unwind cases. This is not really correct, however it - // does not seem to be observable due to the way that we - // generate MIR. To do things properly, we would apply - // the def in call only to the input from the success - // path and not the unwind path. -nmatsakis - PlaceContext::MutatingUse(MutatingUseContext::Call) | - PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) | - PlaceContext::MutatingUse(MutatingUseContext::Yield) | - - // Storage live and storage dead aren't proper defines, but we can ignore - // values that come before them. - PlaceContext::NonUse(NonUseContext::StorageLive) | - PlaceContext::NonUse(NonUseContext::StorageDead) => Some(DefUse::Def), - - /////////////////////////////////////////////////////////////////////////// - // REGULAR USES - // - // These are uses that occur *outside* of a drop. For the - // purposes of NLL, these are special in that **all** the - // lifetimes appearing in the variable must be live for each regular use. - - PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) | - PlaceContext::MutatingUse(MutatingUseContext::Projection) | - - // Borrows only consider their local used at the point of the borrow. - // This won't affect the results since we use this analysis for coroutines - // and we only care about the result at suspension points. Borrows cannot - // cross suspension points so this behavior is unproblematic. - PlaceContext::MutatingUse(MutatingUseContext::Borrow) | - PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) | - PlaceContext::NonMutatingUse(NonMutatingUseContext::FakeBorrow) | - - // `PlaceMention` and `AscribeUserType` both evaluate the place, which must not - // contain dangling references. - PlaceContext::NonMutatingUse(NonMutatingUseContext::PlaceMention) | - PlaceContext::NonUse(NonUseContext::AscribeUserTy(_)) | - - PlaceContext::MutatingUse(MutatingUseContext::AddressOf) | - PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) | - PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect) | - PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) | - PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) | - PlaceContext::MutatingUse(MutatingUseContext::Retag) => - Some(DefUse::Use), - - /////////////////////////////////////////////////////////////////////////// - // DROP USES - // - // These are uses that occur in a DROP (a MIR drop, not a - // call to `std::mem::drop()`). For the purposes of NLL, - // uses in drop are special because `#[may_dangle]` - // attributes can affect whether lifetimes must be live. - - PlaceContext::MutatingUse(MutatingUseContext::Drop) => - Some(DefUse::Drop), - - // Debug info is neither def nor use. - PlaceContext::NonUse(NonUseContext::VarDebugInfo) => None, - - PlaceContext::MutatingUse(MutatingUseContext::Deinit | MutatingUseContext::SetDiscriminant) => { - bug!("These statements are not allowed in this MIR phase") - } - } -} +use rustc_middle::mir::visit::{MutatingUseContext,NonMutatingUseContext,//{();}; +NonUseContext,PlaceContext,};#[derive(Eq,PartialEq,Clone)]pub enum DefUse{Def,// +Use,Drop,}pub fn categorize(context :PlaceContext)->Option{match context +{PlaceContext::MutatingUse(MutatingUseContext ::Store)|PlaceContext::MutatingUse +(MutatingUseContext::Call)|PlaceContext::MutatingUse(MutatingUseContext:://({}); +AsmOutput)|PlaceContext::MutatingUse(MutatingUseContext::Yield)|PlaceContext::// +NonUse(NonUseContext::StorageLive)|PlaceContext::NonUse(NonUseContext:://*&*&(); +StorageDead)=>(((((((((Some(DefUse:: Def)))))))))),PlaceContext::NonMutatingUse( +NonMutatingUseContext::Projection)| PlaceContext::MutatingUse(MutatingUseContext +::Projection)|PlaceContext::MutatingUse(MutatingUseContext::Borrow)|//if true{}; +PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow)|PlaceContext// +::NonMutatingUse(NonMutatingUseContext::FakeBorrow)|PlaceContext:://loop{break}; +NonMutatingUse(NonMutatingUseContext::PlaceMention)|PlaceContext::NonUse(//({}); +NonUseContext::AscribeUserTy(_)) |PlaceContext::MutatingUse(MutatingUseContext:: +AddressOf)|PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf)|//{;}; +PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect)|PlaceContext:://(); +NonMutatingUse(NonMutatingUseContext::Copy)|PlaceContext::NonMutatingUse(//({}); +NonMutatingUseContext::Move)|PlaceContext::MutatingUse(MutatingUseContext:://(); +Retag)=>Some(DefUse::Use) ,PlaceContext::MutatingUse(MutatingUseContext::Drop)=> +Some(DefUse::Drop),PlaceContext::NonUse(NonUseContext::VarDebugInfo)=>None,//(); +PlaceContext::MutatingUse(MutatingUseContext::Deinit|MutatingUseContext:://({}); +SetDiscriminant)=>{bug !("These statements are not allowed in this MIR phase")}} +}//let _=();if true{};let _=();if true{};let _=();if true{};if true{};if true{}; diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 9b8b7e8ddda6b..ed603c6c018f0 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -1,466 +1,158 @@ -use rustc_errors::Diag; -use rustc_infer::infer::canonical::Canonical; -use rustc_infer::infer::error_reporting::nice_region_error::NiceRegionError; -use rustc_infer::infer::region_constraints::Constraint; -use rustc_infer::infer::region_constraints::RegionConstraintData; -use rustc_infer::infer::RegionVariableOrigin; -use rustc_infer::infer::{InferCtxt, RegionResolutionError, SubregionOrigin, TyCtxtInferExt as _}; -use rustc_infer::traits::ObligationCause; -use rustc_middle::ty::error::TypeError; -use rustc_middle::ty::RePlaceholder; -use rustc_middle::ty::Region; -use rustc_middle::ty::RegionVid; -use rustc_middle::ty::UniverseIndex; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc_span::Span; -use rustc_trait_selection::traits::query::type_op; -use rustc_trait_selection::traits::ObligationCtxt; -use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause}; - -use std::fmt; -use std::rc::Rc; - -use crate::region_infer::values::RegionElement; -use crate::session_diagnostics::HigherRankedErrorCause; -use crate::session_diagnostics::HigherRankedLifetimeError; -use crate::session_diagnostics::HigherRankedSubtypeError; -use crate::MirBorrowckCtxt; - -#[derive(Clone)] -pub(crate) struct UniverseInfo<'tcx>(UniverseInfoInner<'tcx>); - -/// What operation a universe was created for. -#[derive(Clone)] -enum UniverseInfoInner<'tcx> { - /// Relating two types which have binders. - RelateTys { expected: Ty<'tcx>, found: Ty<'tcx> }, - /// Created from performing a `TypeOp`. - TypeOp(Rc + 'tcx>), - /// Any other reason. - Other, -} - -impl<'tcx> UniverseInfo<'tcx> { - pub(crate) fn other() -> UniverseInfo<'tcx> { - UniverseInfo(UniverseInfoInner::Other) - } - - pub(crate) fn relate(expected: Ty<'tcx>, found: Ty<'tcx>) -> UniverseInfo<'tcx> { - UniverseInfo(UniverseInfoInner::RelateTys { expected, found }) - } - - pub(crate) fn report_error( - &self, - mbcx: &mut MirBorrowckCtxt<'_, 'tcx>, - placeholder: ty::PlaceholderRegion, - error_element: RegionElement, - cause: ObligationCause<'tcx>, - ) { - match self.0 { - UniverseInfoInner::RelateTys { expected, found } => { - let err = mbcx.infcx.err_ctxt().report_mismatched_types( - &cause, - expected, - found, - TypeError::RegionsPlaceholderMismatch, - ); - mbcx.buffer_error(err); - } - UniverseInfoInner::TypeOp(ref type_op_info) => { - type_op_info.report_error(mbcx, placeholder, error_element, cause); - } - UniverseInfoInner::Other => { - // FIXME: This error message isn't great, but it doesn't show - // up in the existing UI tests. Consider investigating this - // some more. - mbcx.buffer_error( - mbcx.dcx().create_err(HigherRankedSubtypeError { span: cause.span }), - ); - } - } - } -} - -pub(crate) trait ToUniverseInfo<'tcx> { - fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx>; -} - -impl<'tcx> ToUniverseInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> { - fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { - UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(crate::type_check::InstantiateOpaqueType { - base_universe: Some(base_universe), - ..self - }))) - } -} - -impl<'tcx> ToUniverseInfo<'tcx> - for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>> -{ - fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { - UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(PredicateQuery { - canonical_query: self, - base_universe, - }))) - } -} - -impl<'tcx, T: Copy + fmt::Display + TypeFoldable> + 'tcx> ToUniverseInfo<'tcx> - for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize>> -{ - fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { - UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(NormalizeQuery { - canonical_query: self, - base_universe, - }))) - } -} - -impl<'tcx> ToUniverseInfo<'tcx> - for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>> -{ - fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { - UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(AscribeUserTypeQuery { - canonical_query: self, - base_universe, - }))) - } -} - -impl<'tcx, F> ToUniverseInfo<'tcx> for Canonical<'tcx, type_op::custom::CustomTypeOp> { - fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { - // We can't rerun custom type ops. - UniverseInfo::other() - } -} - -impl<'tcx> ToUniverseInfo<'tcx> for ! { - fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { - self - } -} - -#[allow(unused_lifetimes)] -trait TypeOpInfo<'tcx> { - /// Returns an error to be reported if rerunning the type op fails to - /// recover the error's cause. - fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> Diag<'tcx>; - - fn base_universe(&self) -> ty::UniverseIndex; - - fn nice_error( - &self, - mbcx: &mut MirBorrowckCtxt<'_, 'tcx>, - cause: ObligationCause<'tcx>, - placeholder_region: ty::Region<'tcx>, - error_region: Option>, - ) -> Option>; - - #[instrument(level = "debug", skip(self, mbcx))] - fn report_error( - &self, - mbcx: &mut MirBorrowckCtxt<'_, 'tcx>, - placeholder: ty::PlaceholderRegion, - error_element: RegionElement, - cause: ObligationCause<'tcx>, - ) { - let tcx = mbcx.infcx.tcx; - let base_universe = self.base_universe(); - debug!(?base_universe); - - let Some(adjusted_universe) = - placeholder.universe.as_u32().checked_sub(base_universe.as_u32()) - else { - mbcx.buffer_error(self.fallback_error(tcx, cause.span)); - return; - }; - - let placeholder_region = ty::Region::new_placeholder( - tcx, - ty::Placeholder { universe: adjusted_universe.into(), bound: placeholder.bound }, - ); - - let error_region = if let RegionElement::PlaceholderRegion(error_placeholder) = - error_element - { - let adjusted_universe = - error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32()); - adjusted_universe.map(|adjusted| { - ty::Region::new_placeholder( - tcx, - ty::Placeholder { universe: adjusted.into(), bound: error_placeholder.bound }, - ) - }) - } else { - None - }; - - debug!(?placeholder_region); - - let span = cause.span; - let nice_error = self.nice_error(mbcx, cause, placeholder_region, error_region); - - debug!(?nice_error); - - if let Some(nice_error) = nice_error { - mbcx.buffer_error(nice_error); - } else { - mbcx.buffer_error(self.fallback_error(tcx, span)); - } - } -} - -struct PredicateQuery<'tcx> { - canonical_query: - Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>, - base_universe: ty::UniverseIndex, -} - -impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> { - fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> Diag<'tcx> { - tcx.dcx().create_err(HigherRankedLifetimeError { - cause: Some(HigherRankedErrorCause::CouldNotProve { - predicate: self.canonical_query.value.value.predicate.to_string(), - }), - span, - }) - } - - fn base_universe(&self) -> ty::UniverseIndex { - self.base_universe - } - - fn nice_error( - &self, - mbcx: &mut MirBorrowckCtxt<'_, 'tcx>, - cause: ObligationCause<'tcx>, - placeholder_region: ty::Region<'tcx>, - error_region: Option>, - ) -> Option> { - let (infcx, key, _) = - mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query); - let ocx = ObligationCtxt::new(&infcx); - type_op_prove_predicate_with_cause(&ocx, key, cause); - try_extract_error_from_fulfill_cx(&ocx, placeholder_region, error_region) - } -} - -struct NormalizeQuery<'tcx, T> { - canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize>>, - base_universe: ty::UniverseIndex, -} - -impl<'tcx, T> TypeOpInfo<'tcx> for NormalizeQuery<'tcx, T> -where - T: Copy + fmt::Display + TypeFoldable> + 'tcx, -{ - fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> Diag<'tcx> { - tcx.dcx().create_err(HigherRankedLifetimeError { - cause: Some(HigherRankedErrorCause::CouldNotNormalize { - value: self.canonical_query.value.value.value.to_string(), - }), - span, - }) - } - - fn base_universe(&self) -> ty::UniverseIndex { - self.base_universe - } - - fn nice_error( - &self, - mbcx: &mut MirBorrowckCtxt<'_, 'tcx>, - cause: ObligationCause<'tcx>, - placeholder_region: ty::Region<'tcx>, - error_region: Option>, - ) -> Option> { - let (infcx, key, _) = - mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query); - let ocx = ObligationCtxt::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 - // `QueryNormalizeExt::query_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 _ = ocx.normalize(&cause, param_env, value.value); - - try_extract_error_from_fulfill_cx(&ocx, placeholder_region, error_region) - } -} - -struct AscribeUserTypeQuery<'tcx> { - canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>, - base_universe: ty::UniverseIndex, -} - -impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> { - fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> Diag<'tcx> { - // FIXME: This error message isn't great, but it doesn't show up in the existing UI tests, - // and is only the fallback when the nice error fails. Consider improving this some more. - tcx.dcx().create_err(HigherRankedLifetimeError { cause: None, span }) - } - - fn base_universe(&self) -> ty::UniverseIndex { - self.base_universe - } - - fn nice_error( - &self, - mbcx: &mut MirBorrowckCtxt<'_, 'tcx>, - cause: ObligationCause<'tcx>, - placeholder_region: ty::Region<'tcx>, - error_region: Option>, - ) -> Option> { - let (infcx, key, _) = - mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query); - let ocx = ObligationCtxt::new(&infcx); - type_op_ascribe_user_type_with_span(&ocx, key, Some(cause.span)).ok()?; - try_extract_error_from_fulfill_cx(&ocx, placeholder_region, error_region) - } -} - -impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> { - fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> Diag<'tcx> { - // FIXME: This error message isn't great, but it doesn't show up in the existing UI tests, - // and is only the fallback when the nice error fails. Consider improving this some more. - tcx.dcx().create_err(HigherRankedLifetimeError { cause: None, span }) - } - - fn base_universe(&self) -> ty::UniverseIndex { - self.base_universe.unwrap() - } - - fn nice_error( - &self, - mbcx: &mut MirBorrowckCtxt<'_, 'tcx>, - _cause: ObligationCause<'tcx>, - placeholder_region: ty::Region<'tcx>, - error_region: Option>, - ) -> Option> { - try_extract_error_from_region_constraints( - mbcx.infcx, - placeholder_region, - error_region, - self.region_constraints.as_ref().unwrap(), - // We're using the original `InferCtxt` that we - // started MIR borrowchecking with, so the region - // constraints have already been taken. Use the data from - // our `mbcx` instead. - |vid| mbcx.regioncx.var_infos[vid].origin, - |vid| mbcx.regioncx.var_infos[vid].universe, - ) - } -} - -#[instrument(skip(ocx), level = "debug")] -fn try_extract_error_from_fulfill_cx<'tcx>( - ocx: &ObligationCtxt<'_, 'tcx>, - placeholder_region: ty::Region<'tcx>, - error_region: Option>, -) -> Option> { - // We generally shouldn't have errors here because the query was - // already run, but there's no point using `span_delayed_bug` - // when we're going to emit an error here anyway. - let _errors = ocx.select_all_or_error(); - let region_constraints = ocx.infcx.with_region_constraints(|r| r.clone()); - try_extract_error_from_region_constraints( - ocx.infcx, - placeholder_region, - error_region, - ®ion_constraints, - |vid| ocx.infcx.region_var_origin(vid), - |vid| ocx.infcx.universe_of_region(ty::Region::new_var(ocx.infcx.tcx, vid)), - ) -} - -#[instrument(level = "debug", skip(infcx, region_var_origin, universe_of_region))] -fn try_extract_error_from_region_constraints<'tcx>( - infcx: &InferCtxt<'tcx>, - placeholder_region: ty::Region<'tcx>, - error_region: Option>, - region_constraints: &RegionConstraintData<'tcx>, - mut region_var_origin: impl FnMut(RegionVid) -> RegionVariableOrigin, - mut universe_of_region: impl FnMut(RegionVid) -> UniverseIndex, -) -> Option> { - let placeholder_universe = match placeholder_region.kind() { - ty::RePlaceholder(p) => p.universe, - ty::ReVar(vid) => universe_of_region(vid), - _ => ty::UniverseIndex::ROOT, - }; - let matches = - |a_region: Region<'tcx>, b_region: Region<'tcx>| match (a_region.kind(), b_region.kind()) { - (RePlaceholder(a_p), RePlaceholder(b_p)) => a_p.bound == b_p.bound, - _ => a_region == b_region, - }; - let mut check = - |constraint: &Constraint<'tcx>, cause: &SubregionOrigin<'tcx>, exact| match *constraint { - Constraint::RegSubReg(sub, sup) - if ((exact && sup == placeholder_region) - || (!exact && matches(sup, placeholder_region))) - && sup != sub => - { - Some((sub, cause.clone())) - } - Constraint::VarSubReg(vid, sup) - if (exact - && sup == placeholder_region - && !universe_of_region(vid).can_name(placeholder_universe)) - || (!exact && matches(sup, placeholder_region)) => - { - Some((ty::Region::new_var(infcx.tcx, vid), cause.clone())) - } - _ => None, - }; - let mut info = region_constraints - .constraints - .iter() - .find_map(|(constraint, cause)| check(constraint, cause, true)); - if info.is_none() { - info = region_constraints - .constraints - .iter() - .find_map(|(constraint, cause)| check(constraint, cause, false)); - } - let (sub_region, cause) = info?; - - debug!(?sub_region, "cause = {:#?}", cause); - 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)) => RegionResolutionError::UpperBoundUniverseConflict( - vid, - region_var_origin(vid), - universe_of_region(vid), - cause.clone(), - placeholder_region, - ), - (None, _) => { - RegionResolutionError::ConcreteFailure(cause.clone(), sub_region, placeholder_region) - } - }; - NiceRegionError::new(&infcx.err_ctxt(), error).try_report_from_nll().or_else(|| { - if let SubregionOrigin::Subtype(trace) = cause { - Some( - infcx - .err_ctxt() - .report_and_explain_type_error(*trace, TypeError::RegionsPlaceholderMismatch), - ) - } else { - None - } - }) -} +use rustc_errors::Diag;use rustc_infer::infer::canonical::Canonical;use//*&*&(); +rustc_infer::infer::error_reporting::nice_region_error::NiceRegionError;use//(); +rustc_infer::infer::region_constraints::Constraint;use rustc_infer::infer:://(); +region_constraints::RegionConstraintData;use rustc_infer::infer:://loop{break;}; +RegionVariableOrigin;use rustc_infer::infer::{InferCtxt,RegionResolutionError,// +SubregionOrigin,TyCtxtInferExt as _};use rustc_infer::traits::ObligationCause;// +use rustc_middle::ty::error::TypeError;use rustc_middle::ty::RePlaceholder;use// +rustc_middle::ty::Region;use rustc_middle:: ty::RegionVid;use rustc_middle::ty:: +UniverseIndex;use rustc_middle::ty::{self,Ty,TyCtxt,TypeFoldable};use//let _=(); +rustc_span::Span;use rustc_trait_selection::traits::query::type_op;use//((),()); +rustc_trait_selection::traits::ObligationCtxt;use rustc_traits::{//loop{break;}; +type_op_ascribe_user_type_with_span,type_op_prove_predicate_with_cause} ;use std +::fmt;use std::rc::Rc;use crate::region_infer::values::RegionElement;use crate// +::session_diagnostics::HigherRankedErrorCause;use crate::session_diagnostics::// +HigherRankedLifetimeError;use crate::session_diagnostics:://if true{};if true{}; +HigherRankedSubtypeError;use crate::MirBorrowckCtxt;#[derive(Clone)]pub(crate)// +struct UniverseInfo<'tcx>(UniverseInfoInner<'tcx>);#[derive(Clone)]enum//*&*&(); +UniverseInfoInner<'tcx>{RelateTys{expected:Ty<'tcx>,found:Ty<'tcx>},TypeOp(Rc+'tcx>),Other,}impl<'tcx>UniverseInfo<'tcx>{pub(crate)fn//3; +other()->UniverseInfo<'tcx>{UniverseInfo (UniverseInfoInner::Other)}pub(crate)fn +relate(expected:Ty<'tcx>,found:Ty<'tcx>)->UniverseInfo<'tcx>{UniverseInfo(//{;}; +UniverseInfoInner::RelateTys{expected,found})}pub(crate)fn report_error(&self,// +mbcx:&mut MirBorrowckCtxt<'_,'tcx>,placeholder:ty::PlaceholderRegion,//let _=(); +error_element:RegionElement,cause:ObligationCause<'tcx>,){match self.0{//*&*&(); +UniverseInfoInner::RelateTys{expected,found}=>{();let err=mbcx.infcx.err_ctxt(). +report_mismatched_types((((((((((((&cause))))))))))) ,expected,found,TypeError:: +RegionsPlaceholderMismatch,);;mbcx.buffer_error(err);}UniverseInfoInner::TypeOp( +ref type_op_info)=>{();type_op_info.report_error(mbcx,placeholder,error_element, +cause);();}UniverseInfoInner::Other=>{3;mbcx.buffer_error(mbcx.dcx().create_err( +HigherRankedSubtypeError{span:cause.span}),);;}}}}pub(crate)trait ToUniverseInfo +<'tcx>{fn to_universe_info(self ,base_universe:ty::UniverseIndex)->UniverseInfo< +'tcx>;}impl<'tcx>ToUniverseInfo<'tcx>for crate::type_check:://let _=();let _=(); +InstantiateOpaqueType<'tcx>{fn to_universe_info(self,base_universe:ty:://*&*&(); +UniverseIndex)->UniverseInfo<'tcx>{UniverseInfo(UniverseInfoInner::TypeOp(Rc::// +new(crate::type_check::InstantiateOpaqueType{ base_universe:Some(base_universe), +..self})))}}impl<'tcx>ToUniverseInfo<'tcx>for Canonical<'tcx,ty::ParamEnvAnd>>{fn to_universe_info(self, +base_universe:ty::UniverseIndex)->UniverseInfo<'tcx>{UniverseInfo(//loop{break}; +UniverseInfoInner::TypeOp(Rc::new(PredicateQuery{canonical_query:self,//((),()); +base_universe,})))}}impl<'tcx,T:Copy+fmt::Display+TypeFoldable>+//; +'tcx>ToUniverseInfo<'tcx>for Canonical<'tcx,ty::ParamEnvAnd<'tcx,type_op:://{;}; +Normalize>>{fn to_universe_info(self,base_universe:ty::UniverseIndex)->//{;}; +UniverseInfo<'tcx>{UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(//loop{break}; +NormalizeQuery{canonical_query:self,base_universe,})))}}impl<'tcx>//loop{break}; +ToUniverseInfo<'tcx>for Canonical<'tcx,ty::ParamEnvAnd<'tcx,type_op:://let _=(); +AscribeUserType<'tcx>>>{fn to_universe_info(self,base_universe:ty:://let _=||(); +UniverseIndex)->UniverseInfo<'tcx>{UniverseInfo(UniverseInfoInner::TypeOp(Rc::// +new((AscribeUserTypeQuery{canonical_query:self,base_universe,}))))}}impl<'tcx,F> +ToUniverseInfo<'tcx>for Canonical<'tcx,type_op::custom::CustomTypeOp>{fn//(); +to_universe_info(self,_base_universe:ty::UniverseIndex)->UniverseInfo<'tcx>{//3; +UniverseInfo::other()}}impl<'tcx>ToUniverseInfo<'tcx>for!{fn to_universe_info(// +self,_base_universe:ty::UniverseIndex)->UniverseInfo<'tcx>{self}}#[allow(//({}); +unused_lifetimes)]trait TypeOpInfo<'tcx>{fn fallback_error(&self,tcx:TyCtxt,span:Span)->Diag<'tcx>;fn base_universe(&self)->ty::UniverseIndex;fn//{;}; +nice_error(&self,mbcx:&mut MirBorrowckCtxt <'_,'tcx>,cause:ObligationCause<'tcx> +,placeholder_region:ty::Region<'tcx>,error_region:Option>,)->// +Option>;#[instrument(level= "debug",skip(self,mbcx))]fn report_error( +&self,mbcx:&mut MirBorrowckCtxt<'_,'tcx>,placeholder:ty::PlaceholderRegion,//(); +error_element:RegionElement,cause:ObligationCause<'tcx>,){();let tcx=mbcx.infcx. +tcx;;;let base_universe=self.base_universe();;;debug!(?base_universe);;let Some( +adjusted_universe)=((placeholder.universe. as_u32())).checked_sub(base_universe. +as_u32())else{;mbcx.buffer_error(self.fallback_error(tcx,cause.span));;return;}; +let placeholder_region=ty::Region:: new_placeholder(tcx,ty::Placeholder{universe +:adjusted_universe.into(),bound:placeholder.bound},);3;3;let error_region=if let +RegionElement::PlaceholderRegion(error_placeholder)=error_element{let _=||();let +adjusted_universe=error_placeholder.universe. as_u32().checked_sub(base_universe +.as_u32());3;adjusted_universe.map(|adjusted|{ty::Region::new_placeholder(tcx,ty +::Placeholder{universe:adjusted.into(),bound: error_placeholder.bound},)})}else{ +None};;;debug!(?placeholder_region);;;let span=cause.span;;;let nice_error=self. +nice_error(mbcx,cause,placeholder_region,error_region);;;debug!(?nice_error);;if +let Some(nice_error)=nice_error{();mbcx.buffer_error(nice_error);3;}else{3;mbcx. +buffer_error(self.fallback_error(tcx,span));({});}}}struct PredicateQuery<'tcx>{ +canonical_query:Canonical<'tcx,ty::ParamEnvAnd<'tcx,type_op::prove_predicate::// +ProvePredicate<'tcx>>>,base_universe:ty::UniverseIndex,}impl<'tcx>TypeOpInfofor PredicateQuery<'tcx>{fn fallback_error(&self,tcx:TyCtxt<'tcx>,span://3; +Span)->Diag<'tcx>{((tcx.dcx())).create_err(HigherRankedLifetimeError{cause:Some( +HigherRankedErrorCause::CouldNotProve{predicate:self.canonical_query.value.//(); +value.predicate.to_string(),}),span,})}fn base_universe(&self)->ty:://if true{}; +UniverseIndex{self.base_universe}fn nice_error( &self,mbcx:&mut MirBorrowckCtxt< +'_,'tcx>,cause:ObligationCause<'tcx>,placeholder_region:ty::Region<'tcx>,//({}); +error_region:Option>,)->Option>{();let(infcx,key,_)= +mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span,&self.//loop{break}; +canonical_query);*&*&();*&*&();let ocx=ObligationCtxt::new(&infcx);*&*&();{();}; +type_op_prove_predicate_with_cause(&ocx,key,cause);if let _=(){};*&*&();((),()); +try_extract_error_from_fulfill_cx(&ocx, placeholder_region,error_region)}}struct +NormalizeQuery<'tcx,T>{canonical_query:Canonical<'tcx,ty::ParamEnvAnd<'tcx,//(); +type_op::Normalize>>,base_universe:ty ::UniverseIndex,}impl<'tcx,T>TypeOpInfo +<'tcx>for NormalizeQuery<'tcx,T>where T:Copy+fmt::Display+TypeFoldable>+'tcx,{fn fallback_error(&self,tcx:TyCtxt<'tcx>,span:Span)->Diag<'tcx>{//; +tcx.dcx().create_err(HigherRankedLifetimeError{cause:Some(//if true{};if true{}; +HigherRankedErrorCause::CouldNotNormalize{value:self.canonical_query.value.//(); +value.value.to_string(),}),span,})}fn base_universe(&self)->ty::UniverseIndex{// +self.base_universe}fn nice_error(&self,mbcx :&mut MirBorrowckCtxt<'_,'tcx>,cause +:ObligationCause<'tcx>,placeholder_region:ty ::Region<'tcx>,error_region:Option< +ty::Region<'tcx>>,)->Option>{((),());let(infcx,key,_)=mbcx.infcx.tcx. +infer_ctxt().build_with_canonical(cause.span,&self.canonical_query);3;3;let ocx= +ObligationCtxt::new(&infcx);;;let(param_env,value)=key.into_parts();;;let _=ocx. +normalize(&cause,param_env,value.value);;try_extract_error_from_fulfill_cx(&ocx, +placeholder_region,error_region)}}struct AscribeUserTypeQuery<'tcx>{//if true{}; +canonical_query:Canonical<'tcx,ty::ParamEnvAnd<'tcx,type_op::AscribeUserType>>,base_universe:ty::UniverseIndex,}impl<'tcx>TypeOpInfo<'tcx>for//((),()); +AscribeUserTypeQuery<'tcx>{fn fallback_error(&self,tcx:TyCtxt<'tcx>,span:Span)// +->Diag<'tcx>{(tcx.dcx().create_err(HigherRankedLifetimeError{cause:None,span}))} +fn base_universe(&self)->ty::UniverseIndex{self.base_universe}fn nice_error(&//; +self,mbcx:&mut MirBorrowckCtxt<'_,'tcx>,cause:ObligationCause<'tcx>,//if true{}; +placeholder_region:ty::Region<'tcx>,error_region:Option>,)->//; +Option>{((),());((),());let(infcx,key,_)=mbcx.infcx.tcx.infer_ctxt(). +build_with_canonical(cause.span,&self.canonical_query);;let ocx=ObligationCtxt:: +new(&infcx);;type_op_ascribe_user_type_with_span(&ocx,key,Some(cause.span)).ok() +?;;try_extract_error_from_fulfill_cx(&ocx,placeholder_region,error_region)}}impl +<'tcx>TypeOpInfo<'tcx>for crate::type_check::InstantiateOpaqueType<'tcx>{fn//(); +fallback_error(&self,tcx:TyCtxt<'tcx>,span:Span )->Diag<'tcx>{((((tcx.dcx())))). +create_err((HigherRankedLifetimeError{cause:None,span}))}fn base_universe(&self) +->ty::UniverseIndex{(self.base_universe.unwrap() )}fn nice_error(&self,mbcx:&mut +MirBorrowckCtxt<'_,'tcx>,_cause:ObligationCause<'tcx>,placeholder_region:ty:://; +Region<'tcx>,error_region:Option>,)->Option>{//({}); +try_extract_error_from_region_constraints(mbcx.infcx,placeholder_region,//{();}; +error_region,(((self.region_constraints.as_ref()).unwrap())),|vid|mbcx.regioncx. +var_infos[vid].origin,(((|vid|((mbcx.regioncx.var_infos[vid])).universe))),)}}#[ +instrument(skip(ocx),level= "debug")]fn try_extract_error_from_fulfill_cx<'tcx>( +ocx:&ObligationCtxt<'_,'tcx>,placeholder_region:ty::Region<'tcx>,error_region:// +Option>,)->Option>{((),());let _=();let _errors=ocx. +select_all_or_error();;let region_constraints=ocx.infcx.with_region_constraints( +|r|r.clone());if let _=(){};try_extract_error_from_region_constraints(ocx.infcx, +placeholder_region,error_region,((((((®ion_constraints)))))), |vid|ocx.infcx. +region_var_origin(vid),|vid|ocx.infcx.universe_of_region(ty::Region::new_var(//; +ocx.infcx.tcx,vid)),)}#[instrument(level="debug",skip(infcx,region_var_origin,// +universe_of_region))]fn try_extract_error_from_region_constraints <'tcx>(infcx:& +InferCtxt<'tcx>,placeholder_region:ty::Region<'tcx>,error_region:Option>,region_constraints:&RegionConstraintData<'tcx>,mut//if let _=(){}; +region_var_origin:impl FnMut(RegionVid)->RegionVariableOrigin,mut//loop{break;}; +universe_of_region:impl FnMut(RegionVid)->UniverseIndex,)->Option>{3; +let placeholder_universe=match placeholder_region.kind (){ty::RePlaceholder(p)=> +p.universe,ty::ReVar(vid)=>universe_of_region (vid),_=>ty::UniverseIndex::ROOT,} +;;let matches=|a_region:Region<'tcx>,b_region:Region<'tcx>|match(a_region.kind() +,b_region.kind()){(RePlaceholder(a_p) ,RePlaceholder(b_p))=>a_p.bound==b_p.bound +,_=>a_region==b_region,};3;3;let mut check=|constraint:&Constraint<'tcx>,cause:& +SubregionOrigin<'tcx>,exact|match*constraint{Constraint ::RegSubReg(sub,sup)if(( +exact&&(sup==placeholder_region))||(!exact &&matches(sup,placeholder_region)))&& +sup!=sub=>{(Some((sub,cause.clone() )))}Constraint::VarSubReg(vid,sup)if(exact&& +sup==placeholder_region&&! universe_of_region(vid).can_name(placeholder_universe +))||(!exact&&matches(sup,placeholder_region ))=>{Some((ty::Region::new_var(infcx +.tcx,vid),cause.clone()))}_=>None,};;let mut info=region_constraints.constraints +.iter().find_map(|(constraint,cause)|check(constraint,cause,true));({});if info. +is_none(){({});info=region_constraints.constraints.iter().find_map(|(constraint, +cause)|check(constraint,cause,false));3;};let(sub_region,cause)=info?;;;debug!(? +sub_region,"cause = {:#?}",cause);3;;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)}(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)}};loop{break};NiceRegionError::new(&infcx.err_ctxt(),error). +try_report_from_nll().or_else(||{if let SubregionOrigin::Subtype(trace)=cause{// +Some((((infcx.err_ctxt()))).report_and_explain_type_error(((*trace)),TypeError:: +RegionsPlaceholderMismatch),)}else{None}})}//((),());let _=();let _=();let _=(); diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 62e16d445c63f..cacf1c85a7b97 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1,4076 +1,1177 @@ -// ignore-tidy-filelength - -#![allow(rustc::diagnostic_outside_of_impl)] -#![allow(rustc::untranslatable_diagnostic)] - -use either::Either; -use hir::ClosureKind; -use rustc_data_structures::captures::Captures; -use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag, MultiSpan}; -use rustc_hir as hir; -use rustc_hir::def::{DefKind, Res}; -use rustc_hir::intravisit::{walk_block, walk_expr, Map, Visitor}; -use rustc_hir::{CoroutineDesugaring, PatField}; -use rustc_hir::{CoroutineKind, CoroutineSource, LangItem}; -use rustc_middle::hir::nested_filter::OnlyBodies; -use rustc_middle::mir::tcx::PlaceTy; -use rustc_middle::mir::{ - self, AggregateKind, BindingForm, BorrowKind, CallSource, ClearCrossCrate, ConstraintCategory, - FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind, Operand, Place, - PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, - VarBindingForm, -}; -use rustc_middle::ty::{ - self, suggest_constraining_type_params, PredicateKind, ToPredicate, Ty, TyCtxt, - TypeSuperVisitable, TypeVisitor, -}; -use rustc_middle::util::CallKind; -use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex}; -use rustc_span::def_id::DefId; -use rustc_span::def_id::LocalDefId; -use rustc_span::hygiene::DesugaringKind; -use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::{BytePos, Span, Symbol}; -use rustc_trait_selection::infer::InferCtxtExt; -use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt; -use rustc_trait_selection::traits::error_reporting::FindExprBySpan; -use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt}; -use std::iter; - -use crate::borrow_set::TwoPhaseActivation; -use crate::borrowck_errors; -use crate::diagnostics::conflict_errors::StorageDeadOrDrop::LocalStorageDead; -use crate::diagnostics::{find_all_local_uses, CapturedMessageOpt}; -use crate::{ - borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf, - InitializationRequiringAction, MirBorrowckCtxt, WriteKind, -}; - -use super::{ - explain_borrow::{BorrowExplanation, LaterUseKind}, - DescribePlaceOpt, RegionName, RegionNameSource, UseSpans, -}; - -#[derive(Debug)] -struct MoveSite { - /// Index of the "move out" that we found. The `MoveData` can - /// then tell us where the move occurred. - moi: MoveOutIndex, - - /// `true` if we traversed a back edge while walking from the point - /// of error to the move site. - traversed_back_edge: bool, -} - -/// Which case a StorageDeadOrDrop is for. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum StorageDeadOrDrop<'tcx> { - LocalStorageDead, - BoxedStorageDead, - Destructor(Ty<'tcx>), -} - -impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { - pub(crate) fn report_use_of_moved_or_uninitialized( - &mut self, - location: Location, - desired_action: InitializationRequiringAction, - (moved_place, used_place, span): (PlaceRef<'tcx>, PlaceRef<'tcx>, Span), - mpi: MovePathIndex, - ) { - debug!( - "report_use_of_moved_or_uninitialized: location={:?} desired_action={:?} \ - moved_place={:?} used_place={:?} span={:?} mpi={:?}", - location, desired_action, moved_place, used_place, span, mpi - ); - - let use_spans = - self.move_spans(moved_place, location).or_else(|| self.borrow_spans(span, location)); - let span = use_spans.args_or_use(); - - let (move_site_vec, maybe_reinitialized_locations) = self.get_moved_indexes(location, mpi); - debug!( - "report_use_of_moved_or_uninitialized: move_site_vec={:?} use_spans={:?}", - move_site_vec, use_spans - ); - let move_out_indices: Vec<_> = - move_site_vec.iter().map(|move_site| move_site.moi).collect(); - - if move_out_indices.is_empty() { - let root_place = PlaceRef { projection: &[], ..used_place }; - - if !self.uninitialized_error_reported.insert(root_place) { - debug!( - "report_use_of_moved_or_uninitialized place: error about {:?} suppressed", - root_place - ); - return; - } - - let err = self.report_use_of_uninitialized( - mpi, - used_place, - moved_place, - desired_action, - span, - use_spans, - ); - self.buffer_error(err); - } else { - if let Some((reported_place, _)) = self.has_move_error(&move_out_indices) { - if used_place.is_prefix_of(*reported_place) { - debug!( - "report_use_of_moved_or_uninitialized place: error suppressed mois={:?}", - move_out_indices - ); - return; - } - } - - let is_partial_move = move_site_vec.iter().any(|move_site| { - let move_out = self.move_data.moves[(*move_site).moi]; - let moved_place = &self.move_data.move_paths[move_out.path].place; - // `*(_1)` where `_1` is a `Box` is actually a move out. - let is_box_move = moved_place.as_ref().projection == [ProjectionElem::Deref] - && self.body.local_decls[moved_place.local].ty.is_box(); - - !is_box_move - && used_place != moved_place.as_ref() - && used_place.is_prefix_of(moved_place.as_ref()) - }); - - let partial_str = if is_partial_move { "partial " } else { "" }; - let partially_str = if is_partial_move { "partially " } else { "" }; - - let mut err = self.cannot_act_on_moved_value( - span, - desired_action.as_noun(), - partially_str, - self.describe_place_with_options( - moved_place, - DescribePlaceOpt { including_downcast: true, including_tuple_field: true }, - ), - ); - - let reinit_spans = maybe_reinitialized_locations - .iter() - .take(3) - .map(|loc| { - self.move_spans(self.move_data.move_paths[mpi].place.as_ref(), *loc) - .args_or_use() - }) - .collect::>(); - - let reinits = maybe_reinitialized_locations.len(); - if reinits == 1 { - err.span_label(reinit_spans[0], "this reinitialization might get skipped"); - } else if reinits > 1 { - err.span_note( - MultiSpan::from_spans(reinit_spans), - if reinits <= 3 { - format!("these {reinits} reinitializations might get skipped") - } else { - format!( - "these 3 reinitializations and {} other{} might get skipped", - reinits - 3, - if reinits == 4 { "" } else { "s" } - ) - }, - ); - } - - let closure = self.add_moved_or_invoked_closure_note(location, used_place, &mut err); - - let mut is_loop_move = false; - let mut in_pattern = false; - let mut seen_spans = FxIndexSet::default(); - - for move_site in &move_site_vec { - let move_out = self.move_data.moves[(*move_site).moi]; - let moved_place = &self.move_data.move_paths[move_out.path].place; - - let move_spans = self.move_spans(moved_place.as_ref(), move_out.source); - let move_span = move_spans.args_or_use(); - - let is_move_msg = move_spans.for_closure(); - - let is_loop_message = location == move_out.source || move_site.traversed_back_edge; - - if location == move_out.source { - is_loop_move = true; - } - - if !seen_spans.contains(&move_span) { - if !closure { - self.suggest_ref_or_clone( - mpi, - move_span, - &mut err, - &mut in_pattern, - move_spans, - ); - } - - let msg_opt = CapturedMessageOpt { - is_partial_move, - is_loop_message, - is_move_msg, - is_loop_move, - maybe_reinitialized_locations_is_empty: maybe_reinitialized_locations - .is_empty(), - }; - self.explain_captures( - &mut err, - span, - move_span, - move_spans, - *moved_place, - msg_opt, - ); - } - seen_spans.insert(move_span); - } - - use_spans.var_path_only_subdiag(self.dcx(), &mut err, desired_action); - - if !is_loop_move { - err.span_label( - span, - format!( - "value {} here after {partial_str}move", - desired_action.as_verb_in_past_tense(), - ), - ); - } - - let ty = used_place.ty(self.body, self.infcx.tcx).ty; - let needs_note = match ty.kind() { - ty::Closure(id, _) => { - self.infcx.tcx.closure_kind_origin(id.expect_local()).is_none() - } - _ => true, - }; - - let mpi = self.move_data.moves[move_out_indices[0]].path; - let place = &self.move_data.move_paths[mpi].place; - let ty = place.ty(self.body, self.infcx.tcx).ty; - - // If we're in pattern, we do nothing in favor of the previous suggestion (#80913). - // Same for if we're in a loop, see #101119. - if is_loop_move & !in_pattern && !matches!(use_spans, UseSpans::ClosureUse { .. }) { - if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() { - // We have a `&mut` ref, we need to reborrow on each iteration (#62112). - err.span_suggestion_verbose( - span.shrink_to_lo(), - format!( - "consider creating a fresh reborrow of {} here", - self.describe_place(moved_place) - .map(|n| format!("`{n}`")) - .unwrap_or_else(|| "the mutable reference".to_string()), - ), - "&mut *", - Applicability::MachineApplicable, - ); - } - } - - let opt_name = self.describe_place_with_options( - place.as_ref(), - DescribePlaceOpt { including_downcast: true, including_tuple_field: true }, - ); - let note_msg = match opt_name { - Some(name) => format!("`{name}`"), - None => "value".to_owned(), - }; - if self.suggest_borrow_fn_like(&mut err, ty, &move_site_vec, ¬e_msg) { - // Suppress the next suggestion since we don't want to put more bounds onto - // something that already has `Fn`-like bounds (or is a closure), so we can't - // restrict anyways. - } else { - let copy_did = self.infcx.tcx.require_lang_item(LangItem::Copy, Some(span)); - self.suggest_adding_bounds(&mut err, ty, copy_did, span); - } - - if needs_note { - if let Some(local) = place.as_local() { - let span = self.body.local_decls[local].source_info.span; - err.subdiagnostic( - self.dcx(), - crate::session_diagnostics::TypeNoCopy::Label { - is_partial_move, - ty, - place: ¬e_msg, - span, - }, - ); - } else { - err.subdiagnostic( - self.dcx(), - crate::session_diagnostics::TypeNoCopy::Note { - is_partial_move, - ty, - place: ¬e_msg, - }, - ); - }; - } - - if let UseSpans::FnSelfUse { - kind: CallKind::DerefCoercion { deref_target, deref_target_ty, .. }, - .. - } = use_spans - { - err.note(format!( - "{} occurs due to deref coercion to `{deref_target_ty}`", - desired_action.as_noun(), - )); - - // Check first whether the source is accessible (issue #87060) - if self.infcx.tcx.sess.source_map().is_span_accessible(deref_target) { - err.span_note(deref_target, "deref defined here"); - } - } - - self.buffer_move_error(move_out_indices, (used_place, err)); - } - } - - fn suggest_ref_or_clone( - &self, - mpi: MovePathIndex, - move_span: Span, - err: &mut Diag<'tcx>, - in_pattern: &mut bool, - move_spans: UseSpans<'_>, - ) { - struct ExpressionFinder<'hir> { - expr_span: Span, - expr: Option<&'hir hir::Expr<'hir>>, - pat: Option<&'hir hir::Pat<'hir>>, - parent_pat: Option<&'hir hir::Pat<'hir>>, - } - impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> { - fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) { - if e.span == self.expr_span { - self.expr = Some(e); - } - hir::intravisit::walk_expr(self, e); - } - fn visit_pat(&mut self, p: &'hir hir::Pat<'hir>) { - if p.span == self.expr_span { - self.pat = Some(p); - } - if let hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, i, sub) = p.kind { - if i.span == self.expr_span || p.span == self.expr_span { - self.pat = Some(p); - } - // Check if we are in a situation of `ident @ ident` where we want to suggest - // `ref ident @ ref ident` or `ref ident @ Struct { ref ident }`. - if let Some(subpat) = sub - && self.pat.is_none() - { - self.visit_pat(subpat); - if self.pat.is_some() { - self.parent_pat = Some(p); - } - return; - } - } - hir::intravisit::walk_pat(self, p); - } - } - let hir = self.infcx.tcx.hir(); - if let Some(body_id) = hir.maybe_body_owned_by(self.mir_def_id()) { - let expr = hir.body(body_id).value; - let place = &self.move_data.move_paths[mpi].place; - let span = place.as_local().map(|local| self.body.local_decls[local].source_info.span); - let mut finder = - ExpressionFinder { expr_span: move_span, expr: None, pat: None, parent_pat: None }; - finder.visit_expr(expr); - if let Some(span) = span - && let Some(expr) = finder.expr - { - for (_, expr) in hir.parent_iter(expr.hir_id) { - if let hir::Node::Expr(expr) = expr { - if expr.span.contains(span) { - // If the let binding occurs within the same loop, then that - // loop isn't relevant, like in the following, the outermost `loop` - // doesn't play into `x` being moved. - // ``` - // loop { - // let x = String::new(); - // loop { - // foo(x); - // } - // } - // ``` - break; - } - if let hir::ExprKind::Loop(.., loop_span) = expr.kind { - err.span_label(loop_span, "inside of this loop"); - } - } - } - let typeck = self.infcx.tcx.typeck(self.mir_def_id()); - let parent = self.infcx.tcx.parent_hir_node(expr.hir_id); - let (def_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent - && let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind - && let Some(def_id) = typeck.type_dependent_def_id(parent_expr.hir_id) - { - (def_id.as_local(), args, 1) - } else if let hir::Node::Expr(parent_expr) = parent - && let hir::ExprKind::Call(call, args) = parent_expr.kind - && let ty::FnDef(def_id, _) = typeck.node_type(call.hir_id).kind() - { - (def_id.as_local(), args, 0) - } else { - (None, &[][..], 0) - }; - if let Some(def_id) = def_id - && let node = self.infcx.tcx.hir_node_by_def_id(def_id) - && let Some(fn_sig) = node.fn_sig() - && let Some(ident) = node.ident() - && let Some(pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id) - && let Some(arg) = fn_sig.decl.inputs.get(pos + offset) - { - let mut span: MultiSpan = arg.span.into(); - span.push_span_label( - arg.span, - "this parameter takes ownership of the value".to_string(), - ); - let descr = match node.fn_kind() { - Some(hir::intravisit::FnKind::ItemFn(..)) | None => "function", - Some(hir::intravisit::FnKind::Method(..)) => "method", - Some(hir::intravisit::FnKind::Closure) => "closure", - }; - span.push_span_label(ident.span, format!("in this {descr}")); - err.span_note( - span, - format!( - "consider changing this parameter type in {descr} `{ident}` to borrow \ - instead if owning the value isn't necessary", - ), - ); - } - let place = &self.move_data.move_paths[mpi].place; - let ty = place.ty(self.body, self.infcx.tcx).ty; - if let hir::Node::Expr(parent_expr) = parent - && let hir::ExprKind::Call(call_expr, _) = parent_expr.kind - && let hir::ExprKind::Path(hir::QPath::LangItem(LangItem::IntoIterIntoIter, _)) = - call_expr.kind - { - // Do not suggest `.clone()` in a `for` loop, we already suggest borrowing. - } else if let UseSpans::FnSelfUse { kind: CallKind::Normal { .. }, .. } = move_spans - { - // We already suggest cloning for these cases in `explain_captures`. - } else if let UseSpans::ClosureUse { - closure_kind: - ClosureKind::Coroutine(CoroutineKind::Desugared(_, CoroutineSource::Block)), - args_span: _, - capture_kind_span: _, - path_span, - } = move_spans - { - self.suggest_cloning(err, ty, expr, path_span); - } else if self.suggest_hoisting_call_outside_loop(err, expr) { - // The place where the the type moves would be misleading to suggest clone. - // #121466 - self.suggest_cloning(err, ty, expr, move_span); - } - } - if let Some(pat) = finder.pat { - *in_pattern = true; - let mut sugg = vec![(pat.span.shrink_to_lo(), "ref ".to_string())]; - if let Some(pat) = finder.parent_pat { - sugg.insert(0, (pat.span.shrink_to_lo(), "ref ".to_string())); - } - err.multipart_suggestion_verbose( - "borrow this binding in the pattern to avoid moving the value", - sugg, - Applicability::MachineApplicable, - ); - } - } - } - - fn report_use_of_uninitialized( - &self, - mpi: MovePathIndex, - used_place: PlaceRef<'tcx>, - moved_place: PlaceRef<'tcx>, - desired_action: InitializationRequiringAction, - span: Span, - use_spans: UseSpans<'tcx>, - ) -> Diag<'tcx> { - // We need all statements in the body where the binding was assigned to later find all - // the branching code paths where the binding *wasn't* assigned to. - let inits = &self.move_data.init_path_map[mpi]; - let move_path = &self.move_data.move_paths[mpi]; - let decl_span = self.body.local_decls[move_path.place.local].source_info.span; - let mut spans = vec![]; - for init_idx in inits { - let init = &self.move_data.inits[*init_idx]; - let span = init.span(self.body); - if !span.is_dummy() { - spans.push(span); - } - } - - let (name, desc) = match self.describe_place_with_options( - moved_place, - DescribePlaceOpt { including_downcast: true, including_tuple_field: true }, - ) { - Some(name) => (format!("`{name}`"), format!("`{name}` ")), - None => ("the variable".to_string(), String::new()), - }; - let path = match self.describe_place_with_options( - used_place, - DescribePlaceOpt { including_downcast: true, including_tuple_field: true }, - ) { - Some(name) => format!("`{name}`"), - None => "value".to_string(), - }; - - // We use the statements were the binding was initialized, and inspect the HIR to look - // for the branching codepaths that aren't covered, to point at them. - let map = self.infcx.tcx.hir(); - let body_id = map.body_owned_by(self.mir_def_id()); - let body = map.body(body_id); - - 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 - { - // The same error is emitted for bindings that are *sometimes* initialized and the ones - // that are *partially* initialized by assigning to a field of an uninitialized - // binding. We differentiate between them for more accurate wording here. - "isn't fully initialized" - } else if !spans.iter().any(|i| { - // We filter these to avoid misleading wording in cases like the following, - // where `x` has an `init`, but it is in the same place we're looking at: - // ``` - // let x; - // x += 1; - // ``` - !i.contains(span) - // We filter these to avoid incorrect main message on `match-cfg-fake-edges.rs` - && !visitor - .errors - .iter() - .map(|(sp, _)| *sp) - .any(|sp| span < sp && !sp.contains(span)) - }) { - show_assign_sugg = true; - "isn't initialized" - } else { - "is possibly-uninitialized" - }; - - let used = desired_action.as_general_verb_in_past_tense(); - let mut err = struct_span_code_err!( - self.dcx(), - span, - E0381, - "{used} binding {desc}{isnt_initialized}" - ); - use_spans.var_path_only_subdiag(self.dcx(), &mut err, desired_action); - - if let InitializationRequiringAction::PartialAssignment - | InitializationRequiringAction::Assignment = desired_action - { - err.help( - "partial initialization isn't supported, fully initialize the binding with a \ - default value and mutate it, or use `std::mem::MaybeUninit`", - ); - } - err.span_label(span, format!("{path} {used} here but it {isnt_initialized}")); - - let mut shown = false; - for (sp, label) in visitor.errors { - if sp < span && !sp.overlaps(span) { - // When we have a case like `match-cfg-fake-edges.rs`, we don't want to mention - // match arms coming after the primary span because they aren't relevant: - // ``` - // let x; - // match y { - // _ if { x = 2; true } => {} - // _ if { - // x; //~ ERROR - // false - // } => {} - // _ => {} // We don't want to point to this. - // }; - // ``` - err.span_label(sp, label); - shown = true; - } - } - if !shown { - for sp in &spans { - if *sp < span && !sp.overlaps(span) { - err.span_label(*sp, "binding initialized here in some conditions"); - } - } - } - - err.span_label(decl_span, "binding declared here but left uninitialized"); - if show_assign_sugg { - struct LetVisitor { - decl_span: Span, - sugg_span: Option, - } - - impl<'v> Visitor<'v> for LetVisitor { - fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) { - if self.sugg_span.is_some() { - return; - } - - // FIXME: We make sure that this is a normal top-level binding, - // but we could suggest `todo!()` for all uninitialized bindings in the pattern pattern - if let hir::StmtKind::Let(hir::LetStmt { span, ty, init: None, pat, .. }) = - &ex.kind - && let hir::PatKind::Binding(..) = pat.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 Diag<'_>, - 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; - }; - self.infcx - .type_implements_trait(default_trait, [ty], 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(), - "consider assigning a value", - format!(" = {assign_value}"), - Applicability::MaybeIncorrect, - ); - } - } - - fn suggest_borrow_fn_like( - &self, - err: &mut Diag<'_>, - ty: Ty<'tcx>, - move_sites: &[MoveSite], - value_name: &str, - ) -> bool { - let tcx = self.infcx.tcx; - - // Find out if the predicates show that the type is a Fn or FnMut - let find_fn_kind_from_did = |(pred, _): (ty::Clause<'tcx>, _)| { - if let ty::ClauseKind::Trait(pred) = pred.kind().skip_binder() - && pred.self_ty() == ty - { - if Some(pred.def_id()) == tcx.lang_items().fn_trait() { - return Some(hir::Mutability::Not); - } else if Some(pred.def_id()) == tcx.lang_items().fn_mut_trait() { - return Some(hir::Mutability::Mut); - } - } - None - }; - - // If the type is opaque/param/closure, and it is Fn or FnMut, let's suggest (mutably) - // borrowing the type, since `&mut F: FnMut` iff `F: FnMut` and similarly for `Fn`. - // These types seem reasonably opaque enough that they could be instantiated with their - // borrowed variants in a function body when we see a move error. - let borrow_level = match *ty.kind() { - ty::Param(_) => tcx - .explicit_predicates_of(self.mir_def_id().to_def_id()) - .predicates - .iter() - .copied() - .find_map(find_fn_kind_from_did), - ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => tcx - .explicit_item_super_predicates(def_id) - .iter_instantiated_copied(tcx, args) - .find_map(|(clause, span)| find_fn_kind_from_did((clause, span))), - ty::Closure(_, args) => match args.as_closure().kind() { - ty::ClosureKind::Fn => Some(hir::Mutability::Not), - ty::ClosureKind::FnMut => Some(hir::Mutability::Mut), - _ => None, - }, - _ => None, - }; - - let Some(borrow_level) = borrow_level else { - return false; - }; - let sugg = move_sites - .iter() - .map(|move_site| { - let move_out = self.move_data.moves[(*move_site).moi]; - let moved_place = &self.move_data.move_paths[move_out.path].place; - let move_spans = self.move_spans(moved_place.as_ref(), move_out.source); - let move_span = move_spans.args_or_use(); - let suggestion = borrow_level.ref_prefix_str().to_owned(); - (move_span.shrink_to_lo(), suggestion) - }) - .collect(); - err.multipart_suggestion_verbose( - format!("consider {}borrowing {value_name}", borrow_level.mutably_str()), - sugg, - Applicability::MaybeIncorrect, - ); - true - } - - /// In a move error that occurs on a call within a loop, we try to identify cases where cloning - /// the value would lead to a logic error. We infer these cases by seeing if the moved value is - /// part of the logic to break the loop, either through an explicit `break` or if the expression - /// is part of a `while let`. - fn suggest_hoisting_call_outside_loop(&self, err: &mut Diag<'_>, expr: &hir::Expr<'_>) -> bool { - let tcx = self.infcx.tcx; - let mut can_suggest_clone = true; - - // If the moved value is a locally declared binding, we'll look upwards on the expression - // tree until the scope where it is defined, and no further, as suggesting to move the - // expression beyond that point would be illogical. - let local_hir_id = if let hir::ExprKind::Path(hir::QPath::Resolved( - _, - hir::Path { res: hir::def::Res::Local(local_hir_id), .. }, - )) = expr.kind - { - Some(local_hir_id) - } else { - // This case would be if the moved value comes from an argument binding, we'll just - // look within the entire item, that's fine. - None - }; - - /// This will allow us to look for a specific `HirId`, in our case `local_hir_id` where the - /// binding was declared, within any other expression. We'll use it to search for the - /// binding declaration within every scope we inspect. - struct Finder { - hir_id: hir::HirId, - found: bool, - } - impl<'hir> Visitor<'hir> for Finder { - fn visit_pat(&mut self, pat: &'hir hir::Pat<'hir>) { - if pat.hir_id == self.hir_id { - self.found = true; - } - hir::intravisit::walk_pat(self, pat); - } - fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) { - if ex.hir_id == self.hir_id { - self.found = true; - } - hir::intravisit::walk_expr(self, ex); - } - } - // The immediate HIR parent of the moved expression. We'll look for it to be a call. - let mut parent = None; - // The top-most loop where the moved expression could be moved to a new binding. - let mut outer_most_loop: Option<&hir::Expr<'_>> = None; - for (_, node) in tcx.hir().parent_iter(expr.hir_id) { - let e = match node { - hir::Node::Expr(e) => e, - hir::Node::LetStmt(hir::LetStmt { els: Some(els), .. }) => { - let mut finder = BreakFinder { found_breaks: vec![], found_continues: vec![] }; - finder.visit_block(els); - if !finder.found_breaks.is_empty() { - // Don't suggest clone as it could be will likely end in an infinite - // loop. - // let Some(_) = foo(non_copy.clone()) else { break; } - // --- ^^^^^^^^ ----- - can_suggest_clone = false; - } - continue; - } - _ => continue, - }; - if let Some(&hir_id) = local_hir_id { - let mut finder = Finder { hir_id, found: false }; - finder.visit_expr(e); - if finder.found { - // The current scope includes the declaration of the binding we're accessing, we - // can't look up any further for loops. - break; - } - } - if parent.is_none() { - parent = Some(e); - } - match e.kind { - hir::ExprKind::Let(_) => { - match tcx.parent_hir_node(e.hir_id) { - hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::If(cond, ..), .. - }) => { - let mut finder = Finder { hir_id: expr.hir_id, found: false }; - finder.visit_expr(cond); - if finder.found { - // The expression where the move error happened is in a `while let` - // condition Don't suggest clone as it will likely end in an - // infinite loop. - // while let Some(_) = foo(non_copy.clone()) { } - // --------- ^^^^^^^^ - can_suggest_clone = false; - } - } - _ => {} - } - } - hir::ExprKind::Loop(..) => { - outer_most_loop = Some(e); - } - _ => {} - } - } - let loop_count: usize = tcx - .hir() - .parent_iter(expr.hir_id) - .map(|(_, node)| match node { - hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Loop(..), .. }) => 1, - _ => 0, - }) - .sum(); - - let sm = tcx.sess.source_map(); - if let Some(in_loop) = outer_most_loop { - let mut finder = BreakFinder { found_breaks: vec![], found_continues: vec![] }; - finder.visit_expr(in_loop); - // All of the spans for `break` and `continue` expressions. - let spans = finder - .found_breaks - .iter() - .chain(finder.found_continues.iter()) - .map(|(_, span)| *span) - .filter(|span| { - !matches!( - span.desugaring_kind(), - Some(DesugaringKind::ForLoop | DesugaringKind::WhileLoop) - ) - }) - .collect::>(); - // All of the spans for the loops above the expression with the move error. - let loop_spans: Vec<_> = tcx - .hir() - .parent_iter(expr.hir_id) - .filter_map(|(_, node)| match node { - hir::Node::Expr(hir::Expr { span, kind: hir::ExprKind::Loop(..), .. }) => { - Some(*span) - } - _ => None, - }) - .collect(); - // It is possible that a user written `break` or `continue` is in the wrong place. We - // point them out at the user for them to make a determination. (#92531) - if !spans.is_empty() && loop_count > 1 { - // Getting fancy: if the spans of the loops *do not* overlap, we only use the line - // number when referring to them. If there *are* overlaps (multiple loops on the - // same line) then we use the more verbose span output (`file.rs:col:ll`). - let mut lines: Vec<_> = - loop_spans.iter().map(|sp| sm.lookup_char_pos(sp.lo()).line).collect(); - lines.sort(); - lines.dedup(); - let fmt_span = |span: Span| { - if lines.len() == loop_spans.len() { - format!("line {}", sm.lookup_char_pos(span.lo()).line) - } else { - sm.span_to_diagnostic_string(span) - } - }; - let mut spans: MultiSpan = spans.clone().into(); - // Point at all the `continue`s and explicit `break`s in the relevant loops. - for (desc, elements) in [ - ("`break` exits", &finder.found_breaks), - ("`continue` advances", &finder.found_continues), - ] { - for (destination, sp) in elements { - if let Ok(hir_id) = destination.target_id - && let hir::Node::Expr(expr) = tcx.hir().hir_node(hir_id) - && !matches!( - sp.desugaring_kind(), - Some(DesugaringKind::ForLoop | DesugaringKind::WhileLoop) - ) - { - spans.push_span_label( - *sp, - format!("this {desc} the loop at {}", fmt_span(expr.span)), - ); - } - } - } - // Point at all the loops that are between this move and the parent item. - for span in loop_spans { - spans.push_span_label(sm.guess_head_span(span), ""); - } - - // note: verify that your loop breaking logic is correct - // --> $DIR/nested-loop-moved-value-wrong-continue.rs:41:17 - // | - // 28 | for foo in foos { - // | --------------- - // ... - // 33 | for bar in &bars { - // | ---------------- - // ... - // 41 | continue; - // | ^^^^^^^^ this `continue` advances the loop at line 33 - err.span_note(spans, "verify that your loop breaking logic is correct"); - } - if let Some(parent) = parent - && let hir::ExprKind::MethodCall(..) | hir::ExprKind::Call(..) = parent.kind - { - // FIXME: We could check that the call's *parent* takes `&mut val` to make the - // suggestion more targeted to the `mk_iter(val).next()` case. Maybe do that only to - // check for whether to suggest `let value` or `let mut value`. - - let span = in_loop.span; - if !finder.found_breaks.is_empty() - && let Ok(value) = sm.span_to_snippet(parent.span) - { - // We know with high certainty that this move would affect the early return of a - // loop, so we suggest moving the expression with the move out of the loop. - let indent = if let Some(indent) = sm.indentation_before(span) { - format!("\n{indent}") - } else { - " ".to_string() - }; - err.multipart_suggestion( - "consider moving the expression out of the loop so it is only moved once", - vec![ - (parent.span, "value".to_string()), - (span.shrink_to_lo(), format!("let mut value = {value};{indent}")), - ], - Applicability::MaybeIncorrect, - ); - } - } - } - can_suggest_clone - } - - fn suggest_cloning(&self, err: &mut Diag<'_>, ty: Ty<'tcx>, expr: &hir::Expr<'_>, span: Span) { - let tcx = self.infcx.tcx; - // Try to find predicates on *generic params* that would allow copying `ty` - let suggestion = - if let Some(symbol) = tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) { - format!(": {symbol}.clone()") - } else { - ".clone()".to_owned() - }; - if let Some(clone_trait_def) = tcx.lang_items().clone_trait() - && self - .infcx - .type_implements_trait(clone_trait_def, [ty], self.param_env) - .must_apply_modulo_regions() - { - let msg = if let ty::Adt(def, _) = ty.kind() - && [tcx.get_diagnostic_item(sym::Arc), tcx.get_diagnostic_item(sym::Rc)] - .contains(&Some(def.did())) - { - "clone the value to increment its reference count" - } else { - "consider cloning the value if the performance cost is acceptable" - }; - err.span_suggestion_verbose( - span.shrink_to_hi(), - msg, - suggestion, - Applicability::MachineApplicable, - ); - } - } - - fn suggest_adding_bounds(&self, err: &mut Diag<'_>, ty: Ty<'tcx>, def_id: DefId, span: Span) { - let tcx = self.infcx.tcx; - let generics = tcx.generics_of(self.mir_def_id()); - - let Some(hir_generics) = tcx - .typeck_root_def_id(self.mir_def_id().to_def_id()) - .as_local() - .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 ocx = ObligationCtxt::new(self.infcx); - let cause = ObligationCause::misc(span, self.mir_def_id()); - - ocx.register_bound(cause, self.param_env, ty, def_id); - let errors = ocx.select_all_or_error(); - - // Only emit suggestion if all required predicates are on generic - let predicates: Result, _> = errors - .into_iter() - .map(|err| match err.obligation.predicate.kind().skip_binder() { - PredicateKind::Clause(ty::ClauseKind::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(()), - } - } - _ => Err(()), - }) - .collect(); - - if let Ok(predicates) = predicates { - suggest_constraining_type_params( - tcx, - hir_generics, - err, - predicates - .iter() - .map(|(param, constraint)| (param.name.as_str(), &**constraint, None)), - None, - ); - } - } - - pub(crate) fn report_move_out_while_borrowed( - &mut self, - location: Location, - (place, span): (Place<'tcx>, Span), - borrow: &BorrowData<'tcx>, - ) { - debug!( - "report_move_out_while_borrowed: location={:?} place={:?} span={:?} borrow={:?}", - location, place, span, borrow - ); - let value_msg = self.describe_any_place(place.as_ref()); - let borrow_msg = self.describe_any_place(borrow.borrowed_place.as_ref()); - - let borrow_spans = self.retrieve_borrow_spans(borrow); - let borrow_span = borrow_spans.args_or_use(); - - let move_spans = self.move_spans(place.as_ref(), location); - let span = move_spans.args_or_use(); - - let mut err = self.cannot_move_when_borrowed( - span, - borrow_span, - &self.describe_any_place(place.as_ref()), - &borrow_msg, - &value_msg, - ); - - borrow_spans.var_path_only_subdiag( - self.dcx(), - &mut err, - crate::InitializationRequiringAction::Borrow, - ); - - move_spans.var_subdiag(self.dcx(), &mut err, None, |kind, var_span| { - use crate::session_diagnostics::CaptureVarCause::*; - match kind { - hir::ClosureKind::Coroutine(_) => MoveUseInCoroutine { var_span }, - hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { - MoveUseInClosure { var_span } - } - } - }); - - self.explain_why_borrow_contains_point(location, borrow, None) - .add_explanation_to_diagnostic( - self.infcx.tcx, - self.body, - &self.local_names, - &mut err, - "", - Some(borrow_span), - None, - ); - self.suggest_copy_for_type_in_cloned_ref(&mut err, place); - self.buffer_error(err); - } - - pub(crate) fn report_use_while_mutably_borrowed( - &self, - location: Location, - (place, _span): (Place<'tcx>, Span), - borrow: &BorrowData<'tcx>, - ) -> Diag<'tcx> { - let borrow_spans = self.retrieve_borrow_spans(borrow); - let borrow_span = borrow_spans.args_or_use(); - - // Conflicting borrows are reported separately, so only check for move - // captures. - let use_spans = self.move_spans(place.as_ref(), location); - let span = use_spans.var_or_use(); - - // If the attempted use is in a closure then we do not care about the path span of the place we are currently trying to use - // we call `var_span_label` on `borrow_spans` to annotate if the existing borrow was in a closure - let mut err = self.cannot_use_when_mutably_borrowed( - span, - &self.describe_any_place(place.as_ref()), - borrow_span, - &self.describe_any_place(borrow.borrowed_place.as_ref()), - ); - borrow_spans.var_subdiag(self.dcx(), &mut err, Some(borrow.kind), |kind, var_span| { - use crate::session_diagnostics::CaptureVarCause::*; - let place = &borrow.borrowed_place; - let desc_place = self.describe_any_place(place.as_ref()); - match kind { - hir::ClosureKind::Coroutine(_) => { - BorrowUsePlaceCoroutine { place: desc_place, var_span, is_single_var: true } - } - hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { - BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: true } - } - } - }); - - self.explain_why_borrow_contains_point(location, borrow, None) - .add_explanation_to_diagnostic( - self.infcx.tcx, - self.body, - &self.local_names, - &mut err, - "", - None, - None, - ); - err - } - - pub(crate) fn report_conflicting_borrow( - &self, - location: Location, - (place, span): (Place<'tcx>, Span), - gen_borrow_kind: BorrowKind, - issued_borrow: &BorrowData<'tcx>, - ) -> Diag<'tcx> { - let issued_spans = self.retrieve_borrow_spans(issued_borrow); - let issued_span = issued_spans.args_or_use(); - - let borrow_spans = self.borrow_spans(span, location); - let span = borrow_spans.args_or_use(); - - let container_name = if issued_spans.for_coroutine() || borrow_spans.for_coroutine() { - "coroutine" - } else { - "closure" - }; - - let (desc_place, msg_place, msg_borrow, union_type_name) = - self.describe_place_for_conflicting_borrow(place, issued_borrow.borrowed_place); - - let explanation = self.explain_why_borrow_contains_point(location, issued_borrow, None); - let second_borrow_desc = if explanation.is_explained() { "second " } else { "" }; - - // FIXME: supply non-"" `opt_via` when appropriate - let first_borrow_desc; - let mut err = match (gen_borrow_kind, issued_borrow.kind) { - ( - BorrowKind::Shared, - BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow }, - ) => { - first_borrow_desc = "mutable "; - self.cannot_reborrow_already_borrowed( - span, - &desc_place, - &msg_place, - "immutable", - issued_span, - "it", - "mutable", - &msg_borrow, - None, - ) - } - ( - BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow }, - BorrowKind::Shared, - ) => { - first_borrow_desc = "immutable "; - let mut err = self.cannot_reborrow_already_borrowed( - span, - &desc_place, - &msg_place, - "mutable", - issued_span, - "it", - "immutable", - &msg_borrow, - None, - ); - self.suggest_binding_for_closure_capture_self(&mut err, &issued_spans); - self.suggest_using_closure_argument_instead_of_capture( - &mut err, - issued_borrow.borrowed_place, - &issued_spans, - ); - err - } - - ( - BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow }, - BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow }, - ) => { - first_borrow_desc = "first "; - let mut err = self.cannot_mutably_borrow_multiply( - span, - &desc_place, - &msg_place, - issued_span, - &msg_borrow, - None, - ); - self.suggest_slice_method_if_applicable( - &mut err, - place, - issued_borrow.borrowed_place, - ); - self.suggest_using_closure_argument_instead_of_capture( - &mut err, - issued_borrow.borrowed_place, - &issued_spans, - ); - self.explain_iterator_advancement_in_for_loop_if_applicable( - &mut err, - span, - &issued_spans, - ); - err - } - - ( - BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }, - BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }, - ) => { - first_borrow_desc = "first "; - self.cannot_uniquely_borrow_by_two_closures(span, &desc_place, issued_span, None) - } - - (BorrowKind::Mut { .. }, BorrowKind::Fake) => { - if let Some(immutable_section_description) = - self.classify_immutable_section(issued_borrow.assigned_place) - { - let mut err = self.cannot_mutate_in_immutable_section( - span, - issued_span, - &desc_place, - immutable_section_description, - "mutably borrow", - ); - borrow_spans.var_subdiag( - self.dcx(), - &mut err, - Some(BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }), - |kind, var_span| { - use crate::session_diagnostics::CaptureVarCause::*; - match kind { - hir::ClosureKind::Coroutine(_) => BorrowUsePlaceCoroutine { - place: desc_place, - var_span, - is_single_var: true, - }, - hir::ClosureKind::Closure - | hir::ClosureKind::CoroutineClosure(_) => BorrowUsePlaceClosure { - place: desc_place, - var_span, - is_single_var: true, - }, - } - }, - ); - return err; - } else { - first_borrow_desc = "immutable "; - self.cannot_reborrow_already_borrowed( - span, - &desc_place, - &msg_place, - "mutable", - issued_span, - "it", - "immutable", - &msg_borrow, - None, - ) - } - } - - (BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }, _) => { - first_borrow_desc = "first "; - self.cannot_uniquely_borrow_by_one_closure( - span, - container_name, - &desc_place, - "", - issued_span, - "it", - "", - None, - ) - } - - (BorrowKind::Shared, BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }) => { - first_borrow_desc = "first "; - self.cannot_reborrow_already_uniquely_borrowed( - span, - container_name, - &desc_place, - "", - "immutable", - issued_span, - "", - None, - second_borrow_desc, - ) - } - - (BorrowKind::Mut { .. }, BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }) => { - first_borrow_desc = "first "; - self.cannot_reborrow_already_uniquely_borrowed( - span, - container_name, - &desc_place, - "", - "mutable", - issued_span, - "", - None, - second_borrow_desc, - ) - } - - (BorrowKind::Shared, BorrowKind::Shared | BorrowKind::Fake) - | (BorrowKind::Fake, BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake) => { - unreachable!() - } - }; - - if issued_spans == borrow_spans { - borrow_spans.var_subdiag( - self.dcx(), - &mut err, - Some(gen_borrow_kind), - |kind, var_span| { - use crate::session_diagnostics::CaptureVarCause::*; - match kind { - hir::ClosureKind::Coroutine(_) => BorrowUsePlaceCoroutine { - place: desc_place, - var_span, - is_single_var: false, - }, - hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { - BorrowUsePlaceClosure { - place: desc_place, - var_span, - is_single_var: false, - } - } - } - }, - ); - } else { - issued_spans.var_subdiag( - self.dcx(), - &mut err, - Some(issued_borrow.kind), - |kind, var_span| { - use crate::session_diagnostics::CaptureVarCause::*; - let borrow_place = &issued_borrow.borrowed_place; - let borrow_place_desc = self.describe_any_place(borrow_place.as_ref()); - match kind { - hir::ClosureKind::Coroutine(_) => { - FirstBorrowUsePlaceCoroutine { place: borrow_place_desc, var_span } - } - hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { - FirstBorrowUsePlaceClosure { place: borrow_place_desc, var_span } - } - } - }, - ); - - borrow_spans.var_subdiag( - self.dcx(), - &mut err, - Some(gen_borrow_kind), - |kind, var_span| { - use crate::session_diagnostics::CaptureVarCause::*; - match kind { - hir::ClosureKind::Coroutine(_) => { - SecondBorrowUsePlaceCoroutine { place: desc_place, var_span } - } - hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { - SecondBorrowUsePlaceClosure { place: desc_place, var_span } - } - } - }, - ); - } - - if union_type_name != "" { - err.note(format!( - "{msg_place} is a field of the union `{union_type_name}`, so it overlaps the field {msg_borrow}", - )); - } - - explanation.add_explanation_to_diagnostic( - self.infcx.tcx, - self.body, - &self.local_names, - &mut err, - first_borrow_desc, - None, - Some((issued_span, span)), - ); - - self.suggest_using_local_if_applicable(&mut err, location, issued_borrow, explanation); - self.suggest_copy_for_type_in_cloned_ref(&mut err, place); - - err - } - - fn suggest_copy_for_type_in_cloned_ref(&self, err: &mut Diag<'tcx>, place: Place<'tcx>) { - let tcx = self.infcx.tcx; - let hir = tcx.hir(); - let Some(body_id) = tcx.hir_node(self.mir_hir_id()).body_id() else { return }; - struct FindUselessClone<'hir> { - pub clones: Vec<&'hir hir::Expr<'hir>>, - } - impl<'hir> FindUselessClone<'hir> { - pub fn new() -> Self { - Self { clones: vec![] } - } - } - - impl<'v> Visitor<'v> for FindUselessClone<'v> { - fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { - // FIXME: use `lookup_method_for_diagnostic`? - if let hir::ExprKind::MethodCall(segment, _rcvr, args, _span) = ex.kind - && segment.ident.name == sym::clone - && args.len() == 0 - { - self.clones.push(ex); - } - hir::intravisit::walk_expr(self, ex); - } - } - let mut expr_finder = FindUselessClone::new(); - - let body = hir.body(body_id).value; - expr_finder.visit_expr(body); - - pub struct Holds<'tcx> { - ty: Ty<'tcx>, - holds: bool, - } - - impl<'tcx> TypeVisitor> for Holds<'tcx> { - type Result = std::ops::ControlFlow<()>; - - fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result { - if t == self.ty { - self.holds = true; - } - t.super_visit_with(self) - } - } - - let mut types_to_constrain = FxIndexSet::default(); - - let local_ty = self.body.local_decls[place.local].ty; - let typeck_results = tcx.typeck(self.mir_def_id()); - let clone = tcx.require_lang_item(LangItem::Clone, Some(body.span)); - for expr in expr_finder.clones { - if let hir::ExprKind::MethodCall(_, rcvr, _, span) = expr.kind - && let Some(rcvr_ty) = typeck_results.node_type_opt(rcvr.hir_id) - && let Some(ty) = typeck_results.node_type_opt(expr.hir_id) - && rcvr_ty == ty - && let ty::Ref(_, inner, _) = rcvr_ty.kind() - && let inner = inner.peel_refs() - && let mut v = (Holds { ty: inner, holds: false }) - && let _ = v.visit_ty(local_ty) - && v.holds - && let None = self.infcx.type_implements_trait_shallow(clone, inner, self.param_env) - { - err.span_label( - span, - format!( - "this call doesn't do anything, the result is still `{rcvr_ty}` \ - because `{inner}` doesn't implement `Clone`", - ), - ); - types_to_constrain.insert(inner); - } - } - for ty in types_to_constrain { - self.suggest_adding_bounds(err, ty, clone, body.span); - if let ty::Adt(..) = ty.kind() { - // The type doesn't implement Clone. - let trait_ref = ty::Binder::dummy(ty::TraitRef::new(self.infcx.tcx, clone, [ty])); - let obligation = Obligation::new( - self.infcx.tcx, - ObligationCause::dummy(), - self.param_env, - trait_ref, - ); - self.infcx.err_ctxt().suggest_derive( - &obligation, - err, - trait_ref.to_predicate(self.infcx.tcx), - ); - } - } - } - - #[instrument(level = "debug", skip(self, err))] - fn suggest_using_local_if_applicable( - &self, - err: &mut Diag<'_>, - location: Location, - issued_borrow: &BorrowData<'tcx>, - explanation: BorrowExplanation<'tcx>, - ) { - let used_in_call = matches!( - explanation, - BorrowExplanation::UsedLater(LaterUseKind::Call | LaterUseKind::Other, _call_span, _) - ); - if !used_in_call { - debug!("not later used in call"); - return; - } - - let use_span = - if let BorrowExplanation::UsedLater(LaterUseKind::Other, use_span, _) = explanation { - Some(use_span) - } else { - None - }; - - let outer_call_loc = - if let TwoPhaseActivation::ActivatedAt(loc) = issued_borrow.activation_location { - loc - } else { - issued_borrow.reserve_location - }; - let outer_call_stmt = self.body.stmt_at(outer_call_loc); - - let inner_param_location = location; - let Some(inner_param_stmt) = self.body.stmt_at(inner_param_location).left() else { - debug!("`inner_param_location` {:?} is not for a statement", inner_param_location); - return; - }; - let Some(&inner_param) = inner_param_stmt.kind.as_assign().map(|(p, _)| p) else { - debug!( - "`inner_param_location` {:?} is not for an assignment: {:?}", - inner_param_location, inner_param_stmt - ); - return; - }; - let inner_param_uses = find_all_local_uses::find(self.body, inner_param.local); - let Some((inner_call_loc, inner_call_term)) = - inner_param_uses.into_iter().find_map(|loc| { - let Either::Right(term) = self.body.stmt_at(loc) else { - debug!("{:?} is a statement, so it can't be a call", loc); - return None; - }; - let TerminatorKind::Call { args, .. } = &term.kind else { - debug!("not a call: {:?}", term); - return None; - }; - debug!("checking call args for uses of inner_param: {:?}", args); - args.iter() - .map(|a| &a.node) - .any(|a| a == &Operand::Move(inner_param)) - .then_some((loc, term)) - }) - else { - debug!("no uses of inner_param found as a by-move call arg"); - return; - }; - debug!("===> outer_call_loc = {:?}, inner_call_loc = {:?}", outer_call_loc, inner_call_loc); - - let inner_call_span = inner_call_term.source_info.span; - let outer_call_span = match use_span { - Some(span) => span, - None => outer_call_stmt.either(|s| s.source_info, |t| t.source_info).span, - }; - if outer_call_span == inner_call_span || !outer_call_span.contains(inner_call_span) { - // FIXME: This stops the suggestion in some cases where it should be emitted. - // Fix the spans for those cases so it's emitted correctly. - debug!( - "outer span {:?} does not strictly contain inner span {:?}", - outer_call_span, inner_call_span - ); - return; - } - err.span_help( - inner_call_span, - format!( - "try adding a local storing this{}...", - if use_span.is_some() { "" } else { " argument" } - ), - ); - err.span_help( - outer_call_span, - format!( - "...and then using that local {}", - if use_span.is_some() { "here" } else { "as the argument to this call" } - ), - ); - } - - fn suggest_slice_method_if_applicable( - &self, - err: &mut Diag<'_>, - place: Place<'tcx>, - borrowed_place: Place<'tcx>, - ) { - let tcx = self.infcx.tcx; - let hir = tcx.hir(); - - if let ([ProjectionElem::Index(index1)], [ProjectionElem::Index(index2)]) - | ( - [ProjectionElem::Deref, ProjectionElem::Index(index1)], - [ProjectionElem::Deref, ProjectionElem::Index(index2)], - ) = (&place.projection[..], &borrowed_place.projection[..]) - { - let mut note_default_suggestion = || { - err.help( - "consider using `.split_at_mut(position)` or similar method to obtain \ - two mutable non-overlapping sub-slices", - ) - .help("consider using `.swap(index_1, index_2)` to swap elements at the specified indices"); - }; - - let Some(body_id) = tcx.hir_node(self.mir_hir_id()).body_id() else { - note_default_suggestion(); - return; - }; - - let mut expr_finder = - FindExprBySpan::new(self.body.local_decls[*index1].source_info.span); - expr_finder.visit_expr(hir.body(body_id).value); - let Some(index1) = expr_finder.result else { - note_default_suggestion(); - return; - }; - - expr_finder = FindExprBySpan::new(self.body.local_decls[*index2].source_info.span); - expr_finder.visit_expr(hir.body(body_id).value); - let Some(index2) = expr_finder.result else { - note_default_suggestion(); - return; - }; - - let sm = tcx.sess.source_map(); - - let Ok(index1_str) = sm.span_to_snippet(index1.span) else { - note_default_suggestion(); - return; - }; - - let Ok(index2_str) = sm.span_to_snippet(index2.span) else { - note_default_suggestion(); - return; - }; - - let Some(object) = hir.parent_id_iter(index1.hir_id).find_map(|id| { - if let hir::Node::Expr(expr) = tcx.hir_node(id) - && let hir::ExprKind::Index(obj, ..) = expr.kind - { - Some(obj) - } else { - None - } - }) else { - note_default_suggestion(); - return; - }; - - let Ok(obj_str) = sm.span_to_snippet(object.span) else { - note_default_suggestion(); - return; - }; - - let Some(swap_call) = hir.parent_id_iter(object.hir_id).find_map(|id| { - if let hir::Node::Expr(call) = tcx.hir_node(id) - && let hir::ExprKind::Call(callee, ..) = call.kind - && let hir::ExprKind::Path(qpath) = callee.kind - && let hir::QPath::Resolved(None, res) = qpath - && let hir::def::Res::Def(_, did) = res.res - && tcx.is_diagnostic_item(sym::mem_swap, did) - { - Some(call) - } else { - None - } - }) else { - note_default_suggestion(); - return; - }; - - err.span_suggestion( - swap_call.span, - "use `.swap()` to swap elements at the specified indices instead", - format!("{obj_str}.swap({index1_str}, {index2_str})"), - Applicability::MachineApplicable, - ); - } - } - - /// Suggest using `while let` for call `next` on an iterator in a for loop. - /// - /// For example: - /// ```ignore (illustrative) - /// - /// for x in iter { - /// ... - /// iter.next() - /// } - /// ``` - pub(crate) fn explain_iterator_advancement_in_for_loop_if_applicable( - &self, - err: &mut Diag<'_>, - span: Span, - issued_spans: &UseSpans<'tcx>, - ) { - let issue_span = issued_spans.args_or_use(); - let tcx = self.infcx.tcx; - let hir = tcx.hir(); - - let Some(body_id) = tcx.hir_node(self.mir_hir_id()).body_id() else { return }; - let typeck_results = tcx.typeck(self.mir_def_id()); - - struct ExprFinder<'hir> { - issue_span: Span, - expr_span: Span, - body_expr: Option<&'hir hir::Expr<'hir>>, - loop_bind: Option<&'hir Ident>, - loop_span: Option, - head_span: Option, - pat_span: Option, - head: Option<&'hir hir::Expr<'hir>>, - } - impl<'hir> Visitor<'hir> for ExprFinder<'hir> { - fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) { - // Try to find - // let result = match IntoIterator::into_iter() { - // mut iter => { - // [opt_ident]: loop { - // match Iterator::next(&mut iter) { - // None => break, - // Some() => , - // }; - // } - // } - // }; - // corresponding to the desugaring of a for loop `for in { }`. - if let hir::ExprKind::Call(path, [arg]) = ex.kind - && let hir::ExprKind::Path(hir::QPath::LangItem(LangItem::IntoIterIntoIter, _)) = - path.kind - && arg.span.contains(self.issue_span) - { - // Find `IntoIterator::into_iter()` - self.head = Some(arg); - } - if let hir::ExprKind::Loop( - hir::Block { stmts: [stmt, ..], .. }, - _, - hir::LoopSource::ForLoop, - _, - ) = ex.kind - && let hir::StmtKind::Expr(hir::Expr { - kind: hir::ExprKind::Match(call, [_, bind, ..], _), - span: head_span, - .. - }) = stmt.kind - && let hir::ExprKind::Call(path, _args) = call.kind - && let hir::ExprKind::Path(hir::QPath::LangItem(LangItem::IteratorNext, _)) = - path.kind - && let hir::PatKind::Struct(path, [field, ..], _) = bind.pat.kind - && let hir::QPath::LangItem(LangItem::OptionSome, pat_span) = path - && call.span.contains(self.issue_span) - { - // Find `` and the span for the whole `for` loop. - if let PatField { - pat: hir::Pat { kind: hir::PatKind::Binding(_, _, ident, ..), .. }, - .. - } = field - { - self.loop_bind = Some(ident); - } - self.head_span = Some(*head_span); - self.pat_span = Some(pat_span); - self.loop_span = Some(stmt.span); - } - - if let hir::ExprKind::MethodCall(body_call, recv, ..) = ex.kind - && body_call.ident.name == sym::next - && recv.span.source_equal(self.expr_span) - { - self.body_expr = Some(ex); - } - - hir::intravisit::walk_expr(self, ex); - } - } - let mut finder = ExprFinder { - expr_span: span, - issue_span, - loop_bind: None, - body_expr: None, - head_span: None, - loop_span: None, - pat_span: None, - head: None, - }; - finder.visit_expr(hir.body(body_id).value); - - if let Some(body_expr) = finder.body_expr - && let Some(loop_span) = finder.loop_span - && let Some(def_id) = typeck_results.type_dependent_def_id(body_expr.hir_id) - && let Some(trait_did) = tcx.trait_of_item(def_id) - && tcx.is_diagnostic_item(sym::Iterator, trait_did) - { - if let Some(loop_bind) = finder.loop_bind { - err.note(format!( - "a for loop advances the iterator for you, the result is stored in `{}`", - loop_bind.name, - )); - } else { - err.note( - "a for loop advances the iterator for you, the result is stored in its pattern", - ); - } - let msg = "if you want to call `next` on a iterator within the loop, consider using \ - `while let`"; - if let Some(head) = finder.head - && let Some(pat_span) = finder.pat_span - && loop_span.contains(body_expr.span) - && loop_span.contains(head.span) - { - let sm = self.infcx.tcx.sess.source_map(); - - let mut sugg = vec![]; - if let hir::ExprKind::Path(hir::QPath::Resolved(None, _)) = head.kind { - // A bare path doesn't need a `let` assignment, it's already a simple - // binding access. - // As a new binding wasn't added, we don't need to modify the advancing call. - sugg.push((loop_span.with_hi(pat_span.lo()), "while let Some(".to_string())); - sugg.push(( - pat_span.shrink_to_hi().with_hi(head.span.lo()), - ") = ".to_string(), - )); - sugg.push((head.span.shrink_to_hi(), ".next()".to_string())); - } else { - // Needs a new a `let` binding. - let indent = if let Some(indent) = sm.indentation_before(loop_span) { - format!("\n{indent}") - } else { - " ".to_string() - }; - let Ok(head_str) = sm.span_to_snippet(head.span) else { - err.help(msg); - return; - }; - sugg.push(( - loop_span.with_hi(pat_span.lo()), - format!("let iter = {head_str};{indent}while let Some("), - )); - sugg.push(( - pat_span.shrink_to_hi().with_hi(head.span.hi()), - ") = iter.next()".to_string(), - )); - // As a new binding was added, we should change how the iterator is advanced to - // use the newly introduced binding. - if let hir::ExprKind::MethodCall(_, recv, ..) = body_expr.kind - && let hir::ExprKind::Path(hir::QPath::Resolved(None, ..)) = recv.kind - { - // As we introduced a `let iter = ;`, we need to change where the - // already borrowed value was accessed from `.next()` to - // `iter.next()`. - sugg.push((recv.span, "iter".to_string())); - } - } - err.multipart_suggestion(msg, sugg, Applicability::MaybeIncorrect); - } else { - err.help(msg); - } - } - } - - /// Suggest using closure argument instead of capture. - /// - /// For example: - /// ```ignore (illustrative) - /// struct S; - /// - /// impl S { - /// fn call(&mut self, f: impl Fn(&mut Self)) { /* ... */ } - /// fn x(&self) {} - /// } - /// - /// let mut v = S; - /// v.call(|this: &mut S| v.x()); - /// // ^\ ^-- help: try using the closure argument: `this` - /// // *-- error: cannot borrow `v` as mutable because it is also borrowed as immutable - /// ``` - fn suggest_using_closure_argument_instead_of_capture( - &self, - err: &mut Diag<'_>, - borrowed_place: Place<'tcx>, - issued_spans: &UseSpans<'tcx>, - ) { - let &UseSpans::ClosureUse { capture_kind_span, .. } = issued_spans else { return }; - let tcx = self.infcx.tcx; - let hir = tcx.hir(); - - // Get the type of the local that we are trying to borrow - let local = borrowed_place.local; - let local_ty = self.body.local_decls[local].ty; - - // Get the body the error happens in - let Some(body_id) = tcx.hir_node(self.mir_hir_id()).body_id() else { return }; - - let body_expr = hir.body(body_id).value; - - struct ClosureFinder<'hir> { - hir: rustc_middle::hir::map::Map<'hir>, - borrow_span: Span, - res: Option<(&'hir hir::Expr<'hir>, &'hir hir::Closure<'hir>)>, - /// The path expression with the `borrow_span` span - error_path: Option<(&'hir hir::Expr<'hir>, &'hir hir::QPath<'hir>)>, - } - impl<'hir> Visitor<'hir> for ClosureFinder<'hir> { - type NestedFilter = OnlyBodies; - - fn nested_visit_map(&mut self) -> Self::Map { - self.hir - } - - fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) { - if let hir::ExprKind::Path(qpath) = &ex.kind - && ex.span == self.borrow_span - { - self.error_path = Some((ex, qpath)); - } - - if let hir::ExprKind::Closure(closure) = ex.kind - && ex.span.contains(self.borrow_span) - // To support cases like `|| { v.call(|this| v.get()) }` - // FIXME: actually support such cases (need to figure out how to move from the capture place to original local) - && self.res.as_ref().map_or(true, |(prev_res, _)| prev_res.span.contains(ex.span)) - { - self.res = Some((ex, closure)); - } - - hir::intravisit::walk_expr(self, ex); - } - } - - // Find the closure that most tightly wraps `capture_kind_span` - let mut finder = - ClosureFinder { hir, borrow_span: capture_kind_span, res: None, error_path: None }; - finder.visit_expr(body_expr); - let Some((closure_expr, closure)) = finder.res else { return }; - - let typeck_results = tcx.typeck(self.mir_def_id()); - - // Check that the parent of the closure is a method call, - // with receiver matching with local's type (modulo refs) - if let hir::Node::Expr(parent) = tcx.parent_hir_node(closure_expr.hir_id) { - if let hir::ExprKind::MethodCall(_, recv, ..) = parent.kind { - let recv_ty = typeck_results.expr_ty(recv); - - if recv_ty.peel_refs() != local_ty { - return; - } - } - } - - // Get closure's arguments - let ty::Closure(_, args) = typeck_results.expr_ty(closure_expr).kind() else { - /* hir::Closure can be a coroutine too */ - return; - }; - let sig = args.as_closure().sig(); - let tupled_params = tcx.instantiate_bound_regions_with_erased( - sig.inputs().iter().next().unwrap().map_bound(|&b| b), - ); - let ty::Tuple(params) = tupled_params.kind() else { return }; - - // Find the first argument with a matching type, get its name - let Some((_, this_name)) = - params.iter().zip(hir.body_param_names(closure.body)).find(|(param_ty, name)| { - // FIXME: also support deref for stuff like `Rc` arguments - param_ty.peel_refs() == local_ty && name != &Ident::empty() - }) - else { - return; - }; - - let spans; - if let Some((_path_expr, qpath)) = finder.error_path - && let hir::QPath::Resolved(_, path) = qpath - && let hir::def::Res::Local(local_id) = path.res - { - // Find all references to the problematic variable in this closure body - - struct VariableUseFinder { - local_id: hir::HirId, - spans: Vec, - } - impl<'hir> Visitor<'hir> for VariableUseFinder { - fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) { - if let hir::ExprKind::Path(qpath) = &ex.kind - && let hir::QPath::Resolved(_, path) = qpath - && let hir::def::Res::Local(local_id) = path.res - && local_id == self.local_id - { - self.spans.push(ex.span); - } - - hir::intravisit::walk_expr(self, ex); - } - } - - let mut finder = VariableUseFinder { local_id, spans: Vec::new() }; - finder.visit_expr(hir.body(closure.body).value); - - spans = finder.spans; - } else { - spans = vec![capture_kind_span]; - } - - err.multipart_suggestion( - "try using the closure argument", - iter::zip(spans, iter::repeat(this_name.to_string())).collect(), - Applicability::MaybeIncorrect, - ); - } - - fn suggest_binding_for_closure_capture_self( - &self, - err: &mut Diag<'_>, - issued_spans: &UseSpans<'tcx>, - ) { - let UseSpans::ClosureUse { capture_kind_span, .. } = issued_spans else { return }; - - struct ExpressionFinder<'tcx> { - capture_span: Span, - closure_change_spans: Vec, - closure_arg_span: Option, - in_closure: bool, - suggest_arg: String, - tcx: TyCtxt<'tcx>, - closure_local_id: Option, - closure_call_changes: Vec<(Span, String)>, - } - impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> { - fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) { - if e.span.contains(self.capture_span) { - if let hir::ExprKind::Closure(&hir::Closure { - kind: hir::ClosureKind::Closure, - body, - fn_arg_span, - fn_decl: hir::FnDecl { inputs, .. }, - .. - }) = e.kind - && let hir::Node::Expr(body) = self.tcx.hir_node(body.hir_id) - { - self.suggest_arg = "this: &Self".to_string(); - if inputs.len() > 0 { - self.suggest_arg.push_str(", "); - } - self.in_closure = true; - self.closure_arg_span = fn_arg_span; - self.visit_expr(body); - self.in_closure = false; - } - } - if let hir::Expr { kind: hir::ExprKind::Path(path), .. } = e { - if let hir::QPath::Resolved(_, hir::Path { segments: [seg], .. }) = path - && seg.ident.name == kw::SelfLower - && self.in_closure - { - self.closure_change_spans.push(e.span); - } - } - hir::intravisit::walk_expr(self, e); - } - - fn visit_local(&mut self, local: &'hir hir::LetStmt<'hir>) { - if let hir::Pat { kind: hir::PatKind::Binding(_, hir_id, _ident, _), .. } = - local.pat - && let Some(init) = local.init - { - if let hir::Expr { - kind: - hir::ExprKind::Closure(&hir::Closure { - kind: hir::ClosureKind::Closure, - .. - }), - .. - } = init - && init.span.contains(self.capture_span) - { - self.closure_local_id = Some(*hir_id); - } - } - hir::intravisit::walk_local(self, local); - } - - fn visit_stmt(&mut self, s: &'hir hir::Stmt<'hir>) { - if let hir::StmtKind::Semi(e) = s.kind - && let hir::ExprKind::Call( - hir::Expr { kind: hir::ExprKind::Path(path), .. }, - args, - ) = e.kind - && let hir::QPath::Resolved(_, hir::Path { segments: [seg], .. }) = path - && let Res::Local(hir_id) = seg.res - && Some(hir_id) == self.closure_local_id - { - let (span, arg_str) = if args.len() > 0 { - (args[0].span.shrink_to_lo(), "self, ".to_string()) - } else { - let span = e.span.trim_start(seg.ident.span).unwrap_or(e.span); - (span, "(self)".to_string()) - }; - self.closure_call_changes.push((span, arg_str)); - } - hir::intravisit::walk_stmt(self, s); - } - } - - if let hir::Node::ImplItem(hir::ImplItem { - kind: hir::ImplItemKind::Fn(_fn_sig, body_id), - .. - }) = self.infcx.tcx.hir_node(self.mir_hir_id()) - && let hir::Node::Expr(expr) = self.infcx.tcx.hir_node(body_id.hir_id) - { - let mut finder = ExpressionFinder { - capture_span: *capture_kind_span, - closure_change_spans: vec![], - closure_arg_span: None, - in_closure: false, - suggest_arg: String::new(), - closure_local_id: None, - closure_call_changes: vec![], - tcx: self.infcx.tcx, - }; - finder.visit_expr(expr); - - if finder.closure_change_spans.is_empty() || finder.closure_call_changes.is_empty() { - return; - } - - let mut sugg = vec![]; - let sm = self.infcx.tcx.sess.source_map(); - - if let Some(span) = finder.closure_arg_span { - sugg.push((sm.next_point(span.shrink_to_lo()).shrink_to_hi(), finder.suggest_arg)); - } - for span in finder.closure_change_spans { - sugg.push((span, "this".to_string())); - } - - for (span, suggest) in finder.closure_call_changes { - sugg.push((span, suggest)); - } - - err.multipart_suggestion_verbose( - "try explicitly pass `&Self` into the Closure as an argument", - sugg, - Applicability::MachineApplicable, - ); - } - } - - /// Returns the description of the root place for a conflicting borrow and the full - /// descriptions of the places that caused the conflict. - /// - /// In the simplest case, where there are no unions involved, if a mutable borrow of `x` is - /// attempted while a shared borrow is live, then this function will return: - /// ``` - /// ("x", "", "") - /// # ; - /// ``` - /// In the simple union case, if a mutable borrow of a union field `x.z` is attempted while - /// a shared borrow of another field `x.y`, then this function will return: - /// ``` - /// ("x", "x.z", "x.y") - /// # ; - /// ``` - /// In the more complex union case, where the union is a field of a struct, then if a mutable - /// borrow of a union field in a struct `x.u.z` is attempted while a shared borrow of - /// another field `x.u.y`, then this function will return: - /// ``` - /// ("x.u", "x.u.z", "x.u.y") - /// # ; - /// ``` - /// This is used when creating error messages like below: - /// - /// ```text - /// cannot borrow `a.u` (via `a.u.z.c`) as immutable because it is also borrowed as - /// mutable (via `a.u.s.b`) [E0502] - /// ``` - pub(crate) fn describe_place_for_conflicting_borrow( - &self, - first_borrowed_place: Place<'tcx>, - second_borrowed_place: Place<'tcx>, - ) -> (String, String, String, String) { - // Define a small closure that we can use to check if the type of a place - // is a union. - let union_ty = |place_base| { - // Need to use fn call syntax `PlaceRef::ty` to determine the type of `place_base`; - // using a type annotation in the closure argument instead leads to a lifetime error. - let ty = PlaceRef::ty(&place_base, self.body, self.infcx.tcx).ty; - ty.ty_adt_def().filter(|adt| adt.is_union()).map(|_| ty) - }; - - // Start with an empty tuple, so we can use the functions on `Option` to reduce some - // code duplication (particularly around returning an empty description in the failure - // case). - Some(()) - .filter(|_| { - // If we have a conflicting borrow of the same place, then we don't want to add - // an extraneous "via x.y" to our diagnostics, so filter out this case. - first_borrowed_place != second_borrowed_place - }) - .and_then(|_| { - // We're going to want to traverse the first borrowed place to see if we can find - // field access to a union. If we find that, then we will keep the place of the - // union being accessed and the field that was being accessed so we can check the - // second borrowed place for the same union and an access to a different field. - for (place_base, elem) in first_borrowed_place.iter_projections().rev() { - match elem { - ProjectionElem::Field(field, _) if union_ty(place_base).is_some() => { - return Some((place_base, field)); - } - _ => {} - } - } - None - }) - .and_then(|(target_base, target_field)| { - // With the place of a union and a field access into it, we traverse the second - // borrowed place and look for an access to a different field of the same union. - for (place_base, elem) in second_borrowed_place.iter_projections().rev() { - if let ProjectionElem::Field(field, _) = elem { - if let Some(union_ty) = union_ty(place_base) { - if field != target_field && place_base == target_base { - return Some(( - self.describe_any_place(place_base), - self.describe_any_place(first_borrowed_place.as_ref()), - self.describe_any_place(second_borrowed_place.as_ref()), - union_ty.to_string(), - )); - } - } - } - } - None - }) - .unwrap_or_else(|| { - // If we didn't find a field access into a union, or both places match, then - // only return the description of the first place. - ( - self.describe_any_place(first_borrowed_place.as_ref()), - "".to_string(), - "".to_string(), - "".to_string(), - ) - }) - } - - /// This means that some data referenced by `borrow` needs to live - /// past the point where the StorageDeadOrDrop of `place` occurs. - /// This is usually interpreted as meaning that `place` has too - /// short a lifetime. (But sometimes it is more useful to report - /// it as a more direct conflict between the execution of a - /// `Drop::drop` with an aliasing borrow.) - #[instrument(level = "debug", skip(self))] - pub(crate) fn report_borrowed_value_does_not_live_long_enough( - &mut self, - location: Location, - borrow: &BorrowData<'tcx>, - place_span: (Place<'tcx>, Span), - kind: Option, - ) { - let drop_span = place_span.1; - let borrowed_local = borrow.borrowed_place.local; - - let borrow_spans = self.retrieve_borrow_spans(borrow); - let borrow_span = borrow_spans.var_or_use_path_span(); - - let proper_span = self.body.local_decls[borrowed_local].source_info.span; - - if self.access_place_error_reported.contains(&(Place::from(borrowed_local), borrow_span)) { - debug!( - "suppressing access_place error when borrow doesn't live long enough for {:?}", - borrow_span - ); - return; - } - - self.access_place_error_reported.insert((Place::from(borrowed_local), borrow_span)); - - if self.body.local_decls[borrowed_local].is_ref_to_thread_local() { - let err = - self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span); - self.buffer_error(err); - return; - } - - if let StorageDeadOrDrop::Destructor(dropped_ty) = - self.classify_drop_access_kind(borrow.borrowed_place.as_ref()) - { - // If a borrow of path `B` conflicts with drop of `D` (and - // we're not in the uninteresting case where `B` is a - // prefix of `D`), then report this as a more interesting - // destructor conflict. - if !borrow.borrowed_place.as_ref().is_prefix_of(place_span.0.as_ref()) { - self.report_borrow_conflicts_with_destructor( - location, borrow, place_span, kind, dropped_ty, - ); - return; - } - } - - let place_desc = self.describe_place(borrow.borrowed_place.as_ref()); - - let kind_place = kind.filter(|_| place_desc.is_some()).map(|k| (k, place_span.0)); - let explanation = self.explain_why_borrow_contains_point(location, borrow, kind_place); - - debug!(?place_desc, ?explanation); - - let err = match (place_desc, explanation) { - // If the outlives constraint comes from inside the closure, - // for example: - // - // let x = 0; - // let y = &x; - // Box::new(|| y) as Box &'static i32> - // - // then just use the normal error. The closure isn't escaping - // and `move` will not help here. - ( - Some(name), - BorrowExplanation::UsedLater(LaterUseKind::ClosureCapture, var_or_use_span, _), - ) if borrow_spans.for_coroutine() || borrow_spans.for_closure() => self - .report_escaping_closure_capture( - borrow_spans, - borrow_span, - &RegionName { - name: self.synthesize_region_name(), - source: RegionNameSource::Static, - }, - ConstraintCategory::CallArgument(None), - var_or_use_span, - &format!("`{name}`"), - "block", - ), - ( - Some(name), - BorrowExplanation::MustBeValidFor { - category: - category @ (ConstraintCategory::Return(_) - | ConstraintCategory::CallArgument(_) - | ConstraintCategory::OpaqueType), - from_closure: false, - ref region_name, - span, - .. - }, - ) if borrow_spans.for_coroutine() || borrow_spans.for_closure() => self - .report_escaping_closure_capture( - borrow_spans, - borrow_span, - region_name, - category, - span, - &format!("`{name}`"), - "function", - ), - ( - name, - BorrowExplanation::MustBeValidFor { - category: ConstraintCategory::Assignment, - from_closure: false, - region_name: - RegionName { - source: RegionNameSource::AnonRegionFromUpvar(upvar_span, upvar_name), - .. - }, - span, - .. - }, - ) => self.report_escaping_data(borrow_span, &name, upvar_span, upvar_name, span), - (Some(name), explanation) => self.report_local_value_does_not_live_long_enough( - location, - &name, - borrow, - drop_span, - borrow_spans, - explanation, - ), - (None, explanation) => self.report_temporary_value_does_not_live_long_enough( - location, - borrow, - drop_span, - borrow_spans, - proper_span, - explanation, - ), - }; - - self.buffer_error(err); - } - - fn report_local_value_does_not_live_long_enough( - &self, - location: Location, - name: &str, - borrow: &BorrowData<'tcx>, - drop_span: Span, - borrow_spans: UseSpans<'tcx>, - explanation: BorrowExplanation<'tcx>, - ) -> Diag<'tcx> { - debug!( - "report_local_value_does_not_live_long_enough(\ +#![allow(rustc::diagnostic_outside_of_impl)]#![allow(rustc:://let _=();let _=(); +untranslatable_diagnostic)]use either::Either;use hir::ClosureKind;use//((),()); +rustc_data_structures::captures::Captures;use rustc_data_structures::fx:://({}); +FxIndexSet;use rustc_errors::{codes ::*,struct_span_code_err,Applicability,Diag, +MultiSpan};use rustc_hir as hir;use rustc_hir::def::{DefKind,Res};use rustc_hir +::intravisit::{walk_block,walk_expr,Map,Visitor};use rustc_hir::{//loop{break;}; +CoroutineDesugaring,PatField};use rustc_hir::{CoroutineKind,CoroutineSource,//3; +LangItem};use rustc_middle::hir::nested_filter::OnlyBodies;use rustc_middle:://; +mir::tcx::PlaceTy;use rustc_middle::mir::{self,AggregateKind,BindingForm,//({}); +BorrowKind,CallSource,ClearCrossCrate,ConstraintCategory,FakeReadCause,//*&*&(); +LocalDecl,LocalInfo,LocalKind,Location,MutBorrowKind,Operand,Place,PlaceRef,//3; +ProjectionElem,Rvalue,Statement,StatementKind,Terminator,TerminatorKind,//{();}; +VarBindingForm,};use rustc_middle::ty::{self,suggest_constraining_type_params,// +PredicateKind,ToPredicate,Ty,TyCtxt,TypeSuperVisitable,TypeVisitor,};use//{();}; +rustc_middle::util::CallKind;use rustc_mir_dataflow::move_paths::{InitKind,//(); +MoveOutIndex,MovePathIndex};use rustc_span::def_id::DefId;use rustc_span:://{;}; +def_id::LocalDefId;use rustc_span::hygiene::DesugaringKind;use rustc_span:://(); +symbol::{kw,sym,Ident};use rustc_span::{BytePos,Span,Symbol};use//if let _=(){}; +rustc_trait_selection::infer::InferCtxtExt;use rustc_trait_selection::traits::// +error_reporting::suggestions::TypeErrCtxtExt;use rustc_trait_selection::traits// +::error_reporting::FindExprBySpan;use rustc_trait_selection::traits::{//((),()); +Obligation,ObligationCause,ObligationCtxt};use std::iter;use crate::borrow_set// +::TwoPhaseActivation;use crate::borrowck_errors;use crate::diagnostics:://{();}; +conflict_errors::StorageDeadOrDrop::LocalStorageDead;use crate::diagnostics::{// +find_all_local_uses,CapturedMessageOpt};use crate::{borrow_set::BorrowData,//(); +diagnostics::Instance,prefixes::IsPrefixOf,InitializationRequiringAction,//({}); +MirBorrowckCtxt,WriteKind,};use super::{explain_borrow::{BorrowExplanation,//(); +LaterUseKind},DescribePlaceOpt,RegionName,RegionNameSource ,UseSpans,};#[derive( +Debug)]struct MoveSite{moi:MoveOutIndex ,traversed_back_edge:bool,}#[derive(Copy +,Clone,PartialEq,Eq,Debug)]enum StorageDeadOrDrop<'tcx>{LocalStorageDead,//({}); +BoxedStorageDead,Destructor(Ty<'tcx>),}impl <'cx,'tcx>MirBorrowckCtxt<'cx,'tcx>{ +pub(crate)fn report_use_of_moved_or_uninitialized(&mut self,location:Location,// +desired_action:InitializationRequiringAction,(moved_place,used_place,span):(//3; +PlaceRef<'tcx>,PlaceRef<'tcx>,Span),mpi:MovePathIndex,){((),());let _=();debug!( +"report_use_of_moved_or_uninitialized: location={:?} desired_action={:?} \ + moved_place={:?} used_place={:?} span={:?} mpi={:?}" +,location,desired_action,moved_place,used_place,span,mpi);3;;let use_spans=self. +move_spans(moved_place,location).or_else(||self.borrow_spans(span,location));3;; +let span=use_spans.args_or_use();*&*&();((),());if let _=(){};let(move_site_vec, +maybe_reinitialized_locations)=self.get_moved_indexes(location,mpi);();3;debug!( +"report_use_of_moved_or_uninitialized: move_site_vec={:?} use_spans={:?}",//{;}; +move_site_vec,use_spans);;let move_out_indices:Vec<_>=move_site_vec.iter().map(| +move_site|move_site.moi).collect();{();};if move_out_indices.is_empty(){({});let +root_place=PlaceRef{projection:&[],..used_place};let _=||();loop{break};if!self. +uninitialized_error_reported.insert(root_place){loop{break};loop{break;};debug!( +"report_use_of_moved_or_uninitialized place: error about {:?} suppressed",//{;}; +root_place);;;return;;};let err=self.report_use_of_uninitialized(mpi,used_place, +moved_place,desired_action,span,use_spans,);;self.buffer_error(err);}else{if let +Some((reported_place,_))=(self.has_move_error(&move_out_indices)){if used_place. +is_prefix_of(*reported_place){if true{};let _=||();let _=||();let _=||();debug!( +"report_use_of_moved_or_uninitialized place: error suppressed mois={:?}",//({}); +move_out_indices);3;3;return;3;}};let is_partial_move=move_site_vec.iter().any(| +move_site|{;let move_out=self.move_data.moves[(*move_site).moi];let moved_place= +&self.move_data.move_paths[move_out.path].place;3;3;let is_box_move=moved_place. +as_ref().projection==[ProjectionElem::Deref ]&&self.body.local_decls[moved_place +.local].ty.is_box();;!is_box_move&&used_place!=moved_place.as_ref()&&used_place. +is_prefix_of(moved_place.as_ref())});{;};{;};let partial_str=if is_partial_move{ +"partial "}else{""};;let partially_str=if is_partial_move{"partially "}else{""}; +let mut err=self.cannot_act_on_moved_value (span,(((desired_action.as_noun()))), +partially_str,self.describe_place_with_options(moved_place,DescribePlaceOpt{//3; +including_downcast:true,including_tuple_field:true},),);{;};();let reinit_spans= +maybe_reinitialized_locations.iter().take(((3))).map(|loc|{self.move_spans(self. +move_data.move_paths[mpi].place.as_ref(),(*loc )).args_or_use()}).collect::>();3;;let reinits=maybe_reinitialized_locations.len();;if reinits==1{;err. +span_label(reinit_spans[0],"this reinitialization might get skipped");;}else if +reinits>1{{();};err.span_note(MultiSpan::from_spans(reinit_spans),if reinits<=3{ +format!("these {reinits} reinitializations might get skipped")}else{format!(//3; +"these 3 reinitializations and {} other{} might get skipped",reinits-3,if//({}); +reinits==4{""}else{"s"})},);;}let closure=self.add_moved_or_invoked_closure_note +(location,used_place,&mut err);;;let mut is_loop_move=false;;let mut in_pattern= +false;;;let mut seen_spans=FxIndexSet::default();for move_site in&move_site_vec{ +let move_out=self.move_data.moves[(*move_site).moi];();();let moved_place=&self. +move_data.move_paths[move_out.path].place;{;};();let move_spans=self.move_spans( +moved_place.as_ref(),move_out.source);;;let move_span=move_spans.args_or_use();; +let is_move_msg=move_spans.for_closure();;let is_loop_message=location==move_out +.source||move_site.traversed_back_edge;{();};if location==move_out.source{{();}; +is_loop_move=true;({});}if!seen_spans.contains(&move_span){if!closure{({});self. +suggest_ref_or_clone(mpi,move_span,&mut err,&mut in_pattern,move_spans,);3;};let +msg_opt=CapturedMessageOpt{is_partial_move,is_loop_message,is_move_msg,//*&*&(); +is_loop_move,maybe_reinitialized_locations_is_empty://loop{break;};loop{break;}; +maybe_reinitialized_locations.is_empty(),};;self.explain_captures(&mut err,span, +move_span,move_spans,*moved_place,msg_opt,);3;};seen_spans.insert(move_span);;}; +use_spans.var_path_only_subdiag(self.dcx(),&mut err,desired_action);let _=();if! +is_loop_move{let _=();if true{};if true{};if true{};err.span_label(span,format!( +"value {} here after {partial_str}move",desired_action. as_verb_in_past_tense(), +),);;}let ty=used_place.ty(self.body,self.infcx.tcx).ty;let needs_note=match ty. +kind(){ty::Closure(id,_)=>{ self.infcx.tcx.closure_kind_origin(id.expect_local() +).is_none()}_=>true,};;;let mpi=self.move_data.moves[move_out_indices[0]].path;; +let place=&self.move_data.move_paths[mpi].place;;let ty=place.ty(self.body,self. +infcx.tcx).ty;*&*&();if is_loop_move&!in_pattern&&!matches!(use_spans,UseSpans:: +ClosureUse{..}){if let ty::Ref(_,_,hir::Mutability::Mut)=ty.kind(){let _=();err. +span_suggestion_verbose(((((((((((((((span.shrink_to_lo())))))))))))))),format!( +"consider creating a fresh reborrow of {} here",self .describe_place(moved_place +).map(|n|format!("`{n}`" )).unwrap_or_else(||"the mutable reference".to_string() +),),"&mut *",Applicability::MachineApplicable,);{();};}}{();};let opt_name=self. +describe_place_with_options(place.as_ref() ,DescribePlaceOpt{including_downcast: +true,including_tuple_field:true},);();3;let note_msg=match opt_name{Some(name)=> +format!("`{name}`"),None=>"value".to_owned(),};;if self.suggest_borrow_fn_like(& +mut err,ty,&move_site_vec,¬e_msg){}else{let _=();let copy_did=self.infcx.tcx. +require_lang_item(LangItem::Copy,Some(span));3;3;self.suggest_adding_bounds(&mut +err,ty,copy_did,span);3;}if needs_note{;if let Some(local)=place.as_local(){;let +span=self.body.local_decls[local].source_info.span;;err.subdiagnostic(self.dcx() +,crate::session_diagnostics::TypeNoCopy::Label{is_partial_move,ty,place:&//({}); +note_msg,span,},);;}else{err.subdiagnostic(self.dcx(),crate::session_diagnostics +::TypeNoCopy::Note{is_partial_move,ty,place:¬e_msg,},);;};;}if let UseSpans:: +FnSelfUse{kind:CallKind::DerefCoercion{deref_target,deref_target_ty,..},..}=//3; +use_spans{loop{break;};loop{break;};loop{break;};if let _=(){};err.note(format!( +"{} occurs due to deref coercion to `{deref_target_ty}`", desired_action.as_noun +(),));;if self.infcx.tcx.sess.source_map().is_span_accessible(deref_target){err. +span_note(deref_target,"deref defined here");({});}}({});self.buffer_move_error( +move_out_indices,(used_place,err));let _=();}}fn suggest_ref_or_clone(&self,mpi: +MovePathIndex,move_span:Span,err:&mut Diag<'tcx>,in_pattern:&mut bool,//((),()); +move_spans:UseSpans<'_>,){{;};struct ExpressionFinder<'hir>{expr_span:Span,expr: +Option<&'hir hir::Expr<'hir>>,pat:Option<&'hir hir::Pat<'hir>>,parent_pat://{;}; +Option<&'hir hir::Pat<'hir>>,};impl<'hir>Visitor<'hir>for ExpressionFinder<'hir> +{fn visit_expr(&mut self,e:&'hir hir::Expr<'hir>){if e.span==self.expr_span{{;}; +self.expr=Some(e);;}hir::intravisit::walk_expr(self,e);}fn visit_pat(&mut self,p +:&'hir hir::Pat<'hir>){if p.span==self.expr_span{;self.pat=Some(p);}if let hir:: +PatKind::Binding(hir::BindingAnnotation::NONE,_,i,sub)=p.kind{if i.span==self.// +expr_span||p.span==self.expr_span{3;self.pat=Some(p);;}if let Some(subpat)=sub&& +self.pat.is_none(){;self.visit_pat(subpat);if self.pat.is_some(){self.parent_pat +=Some(p);;};return;}}hir::intravisit::walk_pat(self,p);}}let hir=self.infcx.tcx. +hir();;if let Some(body_id)=hir.maybe_body_owned_by(self.mir_def_id()){let expr= +hir.body(body_id).value;3;;let place=&self.move_data.move_paths[mpi].place;;;let +span=place.as_local().map(|local| self.body.local_decls[local].source_info.span) +;{;};{;};let mut finder=ExpressionFinder{expr_span:move_span,expr:None,pat:None, +parent_pat:None};;finder.visit_expr(expr);if let Some(span)=span&&let Some(expr) +=finder.expr{for(_,expr)in hir. parent_iter(expr.hir_id){if let hir::Node::Expr( +expr)=expr{if expr.span.contains(span){3;break;3;}if let hir::ExprKind::Loop(.., +loop_span)=expr.kind{3;err.span_label(loop_span,"inside of this loop");3;}}};let +typeck=self.infcx.tcx.typeck(self.mir_def_id());();();let parent=self.infcx.tcx. +parent_hir_node(expr.hir_id);3;3;let(def_id,args,offset)=if let hir::Node::Expr( +parent_expr)=parent&&let hir::ExprKind::MethodCall( _,_,args,_)=parent_expr.kind +&&let Some(def_id)=((typeck.type_dependent_def_id(parent_expr.hir_id))){(def_id. +as_local(),args,(1))}else if let hir::Node::Expr(parent_expr)=parent&&let hir:: +ExprKind::Call(call,args)=parent_expr.kind&&let ty::FnDef(def_id,_)=typeck.//(); +node_type(call.hir_id).kind(){(def_id.as_local(),args,0 )}else{(None,&[][..],0)} +;;if let Some(def_id)=def_id&&let node=self.infcx.tcx.hir_node_by_def_id(def_id) +&&let Some(fn_sig)=(node.fn_sig())&&let Some(ident)=node.ident()&&let Some(pos)= +args.iter().position((|arg|arg.hir_id==expr.hir_id))&&let Some(arg)=fn_sig.decl. +inputs.get(pos+offset){({});let mut span:MultiSpan=arg.span.into();{;};{;};span. +push_span_label(arg.span ,(((("this parameter takes ownership of the value")))). +to_string(),);();3;let descr=match node.fn_kind(){Some(hir::intravisit::FnKind:: +ItemFn(..))|None=>(((("function")))),Some(hir::intravisit::FnKind::Method(..))=> +"method",Some(hir::intravisit::FnKind::Closure)=>"closure",};*&*&();*&*&();span. +push_span_label(ident.span,format!("in this {descr}"));();();err.span_note(span, +format!(//((),());let _=();let _=();let _=();((),());let _=();let _=();let _=(); +"consider changing this parameter type in {descr} `{ident}` to borrow \ + instead if owning the value isn't necessary" +,),);;}let place=&self.move_data.move_paths[mpi].place;let ty=place.ty(self.body +,self.infcx.tcx).ty;*&*&();if let hir::Node::Expr(parent_expr)=parent&&let hir:: +ExprKind::Call(call_expr,_)=parent_expr.kind&&let hir::ExprKind::Path(hir:://(); +QPath::LangItem(LangItem::IntoIterIntoIter,_))=call_expr.kind{}else if let//{;}; +UseSpans::FnSelfUse{kind:CallKind::Normal{..},..}=move_spans{}else if let//({}); +UseSpans::ClosureUse{closure_kind:ClosureKind::Coroutine(CoroutineKind:://{();}; +Desugared(_,CoroutineSource::Block)), args_span:_,capture_kind_span:_,path_span, +}=move_spans{({});self.suggest_cloning(err,ty,expr,path_span);{;};}else if self. +suggest_hoisting_call_outside_loop(err,expr){3;self.suggest_cloning(err,ty,expr, +move_span);;}}if let Some(pat)=finder.pat{;*in_pattern=true;;let mut sugg=vec![( +pat.span.shrink_to_lo(),"ref ".to_string())];;if let Some(pat)=finder.parent_pat +{({});sugg.insert(0,(pat.span.shrink_to_lo(),"ref ".to_string()));({});}{;};err. +multipart_suggestion_verbose(//loop{break};loop{break};loop{break};loop{break;}; +"borrow this binding in the pattern to avoid moving the value",sugg,//if true{}; +Applicability::MachineApplicable,);;}}}fn report_use_of_uninitialized(&self,mpi: +MovePathIndex,used_place:PlaceRef<'tcx>,moved_place:PlaceRef<'tcx>,//let _=||(); +desired_action:InitializationRequiringAction,span:Span ,use_spans:UseSpans<'tcx> +,)->Diag<'tcx>{;let inits=&self.move_data.init_path_map[mpi];let move_path=&self +.move_data.move_paths[mpi];;let decl_span=self.body.local_decls[move_path.place. +local].source_info.span;;;let mut spans=vec![];;for init_idx in inits{let init=& +self.move_data.inits[*init_idx];;let span=init.span(self.body);if!span.is_dummy( +){3;spans.push(span);3;}};let(name,desc)=match self.describe_place_with_options( +moved_place,DescribePlaceOpt{including_downcast: true,including_tuple_field:true +},){Some(name)=>((((((format!("`{name}`"))),((format!("`{name}` "))))))),None=>( +"the variable".to_string(),String::new()),};((),());((),());let path=match self. +describe_place_with_options(used_place,DescribePlaceOpt {including_downcast:true +,including_tuple_field:(true)},){Some(name) =>format!("`{name}`"),None=>"value". +to_string(),};;;let map=self.infcx.tcx.hir();let body_id=map.body_owned_by(self. +mir_def_id());;let body=map.body(body_id);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{"isn't fully initialized"}else if !spans.iter().any( +|i|{(!i.contains(span))&&!visitor.errors.iter().map(|(sp,_)|*sp).any(|sp|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::Let(hir::LetStmt{span,ty,init:None,pat, +..})=(((&ex.kind)))&&let hir::PatKind::Binding(..)=pat.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);3;}}3;;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);let _=();if true{};}}err}fn +suggest_assign_value(&self,err:&mut Diag<'_>,moved_place:PlaceRef<'tcx>,//{();}; +sugg_span:Span,){3;let ty=moved_place.ty(self.body,self.infcx.tcx).ty;3;;debug!( +"ty: {:?}, kind: {:?}",ty,ty.kind());({});{;};let tcx=self.infcx.tcx;{;};{;};let +implements_default=|ty,param_env|{let _=();let _=();let Some(default_trait)=tcx. +get_diagnostic_item(sym::Default)else{{();};return false;({});};({});self.infcx. +type_implements_trait(default_trait,[ty] ,param_env).must_apply_modulo_regions() +};3;;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!()",};3;if! +assign_value.is_empty(){();err.span_suggestion_verbose(sugg_span.shrink_to_hi(), +"consider assigning a value",(((format! (" = {assign_value}")))),Applicability:: +MaybeIncorrect,);;}}fn suggest_borrow_fn_like(&self,err:&mut Diag<'_>,ty:Ty<'tcx +>,move_sites:&[MoveSite],value_name:&str,)->bool{3;let tcx=self.infcx.tcx;3;;let +find_fn_kind_from_did=|(pred,_):(ty::Clause<'tcx>,_)|{if let ty::ClauseKind:://; +Trait(pred)=pred.kind().skip_binder()&&pred .self_ty()==ty{if Some(pred.def_id() +)==tcx.lang_items().fn_trait(){;return Some(hir::Mutability::Not);}else if Some( +pred.def_id())==tcx.lang_items().fn_mut_trait(){();return Some(hir::Mutability:: +Mut);{();};}}None};({});({});let borrow_level=match*ty.kind(){ty::Param(_)=>tcx. +explicit_predicates_of(self.mir_def_id().to_def_id( )).predicates.iter().copied( +).find_map(find_fn_kind_from_did),ty::Alias (ty::Opaque,ty::AliasTy{def_id,args, +..})=>(tcx.explicit_item_super_predicates(def_id)).iter_instantiated_copied(tcx, +args).find_map(|(clause,span)|find_fn_kind_from_did ((clause,span))),ty::Closure +(_,args)=>match ((((args.as_closure())).kind())){ty::ClosureKind::Fn=>Some(hir:: +Mutability::Not),ty::ClosureKind::FnMut=>Some( hir::Mutability::Mut),_=>None,},_ +=>None,};;;let Some(borrow_level)=borrow_level else{;return false;;};;;let sugg= +move_sites.iter().map(|move_site|{;let move_out=self.move_data.moves[(*move_site +).moi];3;3;let moved_place=&self.move_data.move_paths[move_out.path].place;;;let +move_spans=self.move_spans(moved_place.as_ref(),move_out.source);;let move_span= +move_spans.args_or_use();;let suggestion=borrow_level.ref_prefix_str().to_owned( +);((),());(move_span.shrink_to_lo(),suggestion)}).collect();((),());((),());err. +multipart_suggestion_verbose(format!("consider {}borrowing {value_name}",//({}); +borrow_level.mutably_str()),sugg,Applicability::MaybeIncorrect,);((),());true}fn +suggest_hoisting_call_outside_loop(&self,err:&mut Diag< '_>,expr:&hir::Expr<'_>) +->bool{;let tcx=self.infcx.tcx;;let mut can_suggest_clone=true;let local_hir_id= +if let hir::ExprKind::Path(hir::QPath::Resolved (_,hir::Path{res:hir::def::Res:: +Local(local_hir_id),..},))=expr.kind{Some(local_hir_id)}else{None};{;};();struct +Finder{hir_id:hir::HirId,found:bool,}{;};();impl<'hir>Visitor<'hir>for Finder{fn +visit_pat(&mut self,pat:&'hir hir::Pat<'hir>){if pat.hir_id==self.hir_id{3;self. +found=true;;};hir::intravisit::walk_pat(self,pat);;}fn visit_expr(&mut self,ex:& +'hir hir::Expr<'hir>){if ex.hir_id==self.hir_id{{;};self.found=true;();}();hir:: +intravisit::walk_expr(self,ex);;}};;let mut parent=None;let mut outer_most_loop: +Option<&hir::Expr<'_>>=None;3;for(_,node)in tcx.hir().parent_iter(expr.hir_id){; +let e=match node{hir::Node::Expr(e) =>e,hir::Node::LetStmt(hir::LetStmt{els:Some +(els),..})=>{;let mut finder=BreakFinder{found_breaks:vec![],found_continues:vec +![]};({});{;};finder.visit_block(els);{;};if!finder.found_breaks.is_empty(){{;}; +can_suggest_clone=false;();}();continue;3;}_=>continue,};3;if let Some(&hir_id)= +local_hir_id{;let mut finder=Finder{hir_id,found:false};;finder.visit_expr(e);if +finder.found{3;break;;}}if parent.is_none(){;parent=Some(e);;}match e.kind{hir:: +ExprKind::Let(_)=>{match ((tcx.parent_hir_node(e.hir_id))){hir::Node::Expr(hir:: +Expr{kind:hir::ExprKind::If(cond,..),..})=>{3;let mut finder=Finder{hir_id:expr. +hir_id,found:false};;;finder.visit_expr(cond);if finder.found{can_suggest_clone= +false;;}}_=>{}}}hir::ExprKind::Loop(..)=>{;outer_most_loop=Some(e);;}_=>{}}};let +loop_count:usize=(tcx.hir().parent_iter(expr .hir_id)).map(|(_,node)|match node{ +hir::Node::Expr(hir::Expr{kind:hir::ExprKind::Loop(..),..})=>1,_=>0,}).sum();3;; +let sm=tcx.sess.source_map();{;};if let Some(in_loop)=outer_most_loop{();let mut +finder=BreakFinder{found_breaks:vec![],found_continues:vec![]};({});({});finder. +visit_expr(in_loop);({});({});let spans=finder.found_breaks.iter().chain(finder. +found_continues.iter()).map(((|(_,span)|(*span)))).filter(|span|{!matches!(span. +desugaring_kind(),Some(DesugaringKind::ForLoop|DesugaringKind::WhileLoop))}).//; +collect::>();;let loop_spans:Vec<_>=tcx.hir().parent_iter(expr.hir_id) +.filter_map(|(_,node)|match node{hir::Node::Expr(hir::Expr{span,kind:hir:://{;}; +ExprKind::Loop(..),..})=>{Some(*span)}_=>None,}).collect();3;if!spans.is_empty() +&&loop_count>1{*&*&();((),());let mut lines:Vec<_>=loop_spans.iter().map(|sp|sm. +lookup_char_pos(sp.lo()).line).collect();3;3;lines.sort();3;;lines.dedup();;;let +fmt_span=|span:Span|{if ((lines.len() )==loop_spans.len()){format!("line {}",sm. +lookup_char_pos(span.lo()).line)}else{sm.span_to_diagnostic_string(span)}};;;let +mut spans:MultiSpan=spans.clone().into();;for(desc,elements)in[("`break` exits", +&finder.found_breaks),((("`continue` advances"),&finder.found_continues)),]{for( +destination,sp)in elements{if let Ok(hir_id)=destination.target_id&&let hir:://; +Node::Expr(expr)=((tcx.hir()).hir_node(hir_id))&&!matches!(sp.desugaring_kind(), +Some(DesugaringKind::ForLoop|DesugaringKind::WhileLoop)){;spans.push_span_label( +*sp,format!("this {desc} the loop at {}",fmt_span(expr.span)),);3;}}}for span in +loop_spans{;spans.push_span_label(sm.guess_head_span(span),"");;};err.span_note( +spans,"verify that your loop breaking logic is correct");3;}if let Some(parent)= +parent&&let hir::ExprKind::MethodCall(..)|hir::ExprKind::Call(..)=parent.kind{3; +let span=in_loop.span;{();};if!finder.found_breaks.is_empty()&&let Ok(value)=sm. +span_to_snippet(parent.span){((),());let _=();let indent=if let Some(indent)=sm. +indentation_before(span){format!("\n{indent}")}else{" ".to_string()};{;};();err. +multipart_suggestion(//if let _=(){};if let _=(){};if let _=(){};*&*&();((),()); +"consider moving the expression out of the loop so it is only moved once", vec![ +(parent.span,"value".to_string()),(span.shrink_to_lo(),format!(//*&*&();((),()); +"let mut value = {value};{indent}")),],Applicability::MaybeIncorrect,);{();};}}} +can_suggest_clone}fn suggest_cloning(&self,err:&mut Diag<'_>,ty:Ty<'tcx>,expr:& +hir::Expr<'_>,span:Span){3;let tcx=self.infcx.tcx;3;;let suggestion=if let Some( +symbol)=(((tcx.hir()) .maybe_get_struct_pattern_shorthand_field(expr))){format!( +": {symbol}.clone()")}else{".clone()".to_owned()};;if let Some(clone_trait_def)= +tcx.lang_items().clone_trait()&&self.infcx.type_implements_trait(//loop{break;}; +clone_trait_def,[ty],self.param_env).must_apply_modulo_regions(){;let msg=if let +ty::Adt(def,_)=((((ty.kind()))))&& [(((tcx.get_diagnostic_item(sym::Arc)))),tcx. +get_diagnostic_item(sym::Rc)].contains(((((&((((Some ((((def.did()))))))))))))){ +"clone the value to increment its reference count"}else{//let _=||();let _=||(); +"consider cloning the value if the performance cost is acceptable"};{;};{;};err. +span_suggestion_verbose((((span.shrink_to_hi()))),msg,suggestion,Applicability:: +MachineApplicable,);();}}fn suggest_adding_bounds(&self,err:&mut Diag<'_>,ty:Ty< +'tcx>,def_id:DefId,span:Span){{;};let tcx=self.infcx.tcx;();();let generics=tcx. +generics_of(self.mir_def_id());3;;let Some(hir_generics)=tcx.typeck_root_def_id( +self.mir_def_id().to_def_id()).as_local() .and_then(|def_id|(((((tcx.hir()))))). +get_generics(def_id))else{;return;;};let ocx=ObligationCtxt::new(self.infcx);let +cause=ObligationCause::misc(span,self.mir_def_id());3;;ocx.register_bound(cause, +self.param_env,ty,def_id);;;let errors=ocx.select_all_or_error();let predicates: +Result,_>=((errors.into_iter())).map(|err|match err.obligation.predicate. +kind().skip_binder(){PredicateKind:: Clause(ty::ClauseKind::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 +(()),}}_=>Err(()),}).collect();((),());if let Ok(predicates)=predicates{((),()); +suggest_constraining_type_params(tcx,hir_generics,err,(predicates.iter()).map(|( +param,constraint)|(param.name.as_str(),&**constraint,None)),None,);;}}pub(crate) +fn report_move_out_while_borrowed(&mut self,location:Location,(place,span):(//3; +Place<'tcx>,Span),borrow:&BorrowData<'tcx>,){if let _=(){};if let _=(){};debug!( +"report_move_out_while_borrowed: location={:?} place={:?} span={:?} borrow={:?}" +,location,place,span,borrow);;let value_msg=self.describe_any_place(place.as_ref +());;;let borrow_msg=self.describe_any_place(borrow.borrowed_place.as_ref());let +borrow_spans=self.retrieve_borrow_spans(borrow);3;;let borrow_span=borrow_spans. +args_or_use();;let move_spans=self.move_spans(place.as_ref(),location);let span= +move_spans.args_or_use();{;};();let mut err=self.cannot_move_when_borrowed(span, +borrow_span,&self.describe_any_place(place.as_ref()),&borrow_msg,&value_msg,);;; +borrow_spans.var_path_only_subdiag((((((self.dcx()))))),((((&mut err)))),crate:: +InitializationRequiringAction::Borrow,);;;move_spans.var_subdiag(self.dcx(),&mut +err,None,|kind,var_span|{3;use crate::session_diagnostics::CaptureVarCause::*;3; +match kind{hir::ClosureKind::Coroutine(_ )=>(MoveUseInCoroutine{var_span}),hir:: +ClosureKind::Closure|hir::ClosureKind::CoroutineClosure(_)=>{MoveUseInClosure{// +var_span}}}});();3;self.explain_why_borrow_contains_point(location,borrow,None). +add_explanation_to_diagnostic(self.infcx.tcx,self.body ,(&self.local_names),&mut +err,"",Some(borrow_span),None,);3;;self.suggest_copy_for_type_in_cloned_ref(&mut +err,place);let _=||();let _=||();self.buffer_error(err);let _=||();}pub(crate)fn +report_use_while_mutably_borrowed(&self,location:Location, (place,_span):(Place< +'tcx>,Span),borrow:&BorrowData<'tcx>,)->Diag<'tcx>{*&*&();let borrow_spans=self. +retrieve_borrow_spans(borrow);;;let borrow_span=borrow_spans.args_or_use();;;let +use_spans=self.move_spans(place.as_ref(),location);({});({});let span=use_spans. +var_or_use();();();let mut err=self.cannot_use_when_mutably_borrowed(span,&self. +describe_any_place(place.as_ref()) ,borrow_span,&self.describe_any_place(borrow. +borrowed_place.as_ref()),);3;;borrow_spans.var_subdiag(self.dcx(),&mut err,Some( +borrow.kind),|kind,var_span|{;use crate::session_diagnostics::CaptureVarCause::* +;;let place=&borrow.borrowed_place;let desc_place=self.describe_any_place(place. +as_ref());3;match kind{hir::ClosureKind::Coroutine(_)=>{BorrowUsePlaceCoroutine{ +place:desc_place,var_span,is_single_var:(true) }}hir::ClosureKind::Closure|hir:: +ClosureKind::CoroutineClosure(_)=>{BorrowUsePlaceClosure{place:desc_place,//{;}; +var_span,is_single_var:true}}}});{;};{;};self.explain_why_borrow_contains_point( +location,borrow,None).add_explanation_to_diagnostic(self.infcx.tcx,self.body,&// +self.local_names,&mut err,"",None,None,);let _=||();loop{break};err}pub(crate)fn +report_conflicting_borrow(&self,location:Location,(place,span):(Place<'tcx>,//3; +Span),gen_borrow_kind:BorrowKind,issued_borrow:&BorrowData<'tcx>,)->Diag<'tcx>{; +let issued_spans=self.retrieve_borrow_spans(issued_borrow);();3;let issued_span= +issued_spans.args_or_use();;;let borrow_spans=self.borrow_spans(span,location);; +let span=borrow_spans.args_or_use();({});{;};let container_name=if issued_spans. +for_coroutine()||borrow_spans.for_coroutine(){"coroutine"}else{"closure"};;;let( +desc_place,msg_place,msg_borrow,union_type_name)=self.//loop{break};loop{break}; +describe_place_for_conflicting_borrow(place,issued_borrow.borrowed_place);3;;let +explanation=self.explain_why_borrow_contains_point( location,issued_borrow,None) +;;;let second_borrow_desc=if explanation.is_explained(){"second "}else{""};;;let +first_borrow_desc;{;};();let mut err=match(gen_borrow_kind,issued_borrow.kind){( +BorrowKind::Shared,BorrowKind::Mut{kind:MutBorrowKind::Default|MutBorrowKind::// +TwoPhaseBorrow},)=>{loop{break;};first_borrow_desc="mutable ";loop{break;};self. +cannot_reborrow_already_borrowed(span,(&desc_place), (&msg_place),("immutable"), +issued_span,(("it")),(("mutable")),((&msg_borrow)),None,)}(BorrowKind::Mut{kind: +MutBorrowKind::Default|MutBorrowKind::TwoPhaseBorrow},BorrowKind::Shared,)=>{(); +first_borrow_desc="immutable ";((),());((),());((),());((),());let mut err=self. +cannot_reborrow_already_borrowed(span,((&desc_place)), (&msg_place),("mutable"), +issued_span,"it","immutable",&msg_borrow,None,);if let _=(){};loop{break;};self. +suggest_binding_for_closure_capture_self(&mut err,&issued_spans);({});({});self. +suggest_using_closure_argument_instead_of_capture((((&mut err))),issued_borrow. +borrowed_place,&issued_spans,);;err}(BorrowKind::Mut{kind:MutBorrowKind::Default +|MutBorrowKind::TwoPhaseBorrow},BorrowKind::Mut{kind:MutBorrowKind::Default|//3; +MutBorrowKind::TwoPhaseBorrow},)=>{;first_borrow_desc="first ";let mut err=self. +cannot_mutably_borrow_multiply(span,((&desc_place)),((&msg_place)),issued_span,& +msg_borrow,None,);{;};();self.suggest_slice_method_if_applicable(&mut err,place, +issued_borrow.borrowed_place,);let _=||();let _=||();let _=||();let _=||();self. +suggest_using_closure_argument_instead_of_capture((((&mut err))),issued_borrow. +borrowed_place,&issued_spans,);let _=||();let _=||();let _=||();let _=||();self. +explain_iterator_advancement_in_for_loop_if_applicable((((((&mut err))))),span,& +issued_spans,);((),());err}(BorrowKind::Mut{kind:MutBorrowKind::ClosureCapture}, +BorrowKind::Mut{kind:MutBorrowKind::ClosureCapture},)=>{{();};first_borrow_desc= +"first ";if true{};self.cannot_uniquely_borrow_by_two_closures(span,&desc_place, +issued_span,None)}(BorrowKind::Mut{..},BorrowKind::Fake)=>{if let Some(//*&*&(); +immutable_section_description)=self.classify_immutable_section(issued_borrow.//; +assigned_place){*&*&();let mut err=self.cannot_mutate_in_immutable_section(span, +issued_span,&desc_place,immutable_section_description,"mutably borrow",);{;};(); +borrow_spans.var_subdiag(((self.dcx())),((& mut err)),Some(BorrowKind::Mut{kind: +MutBorrowKind::ClosureCapture}),|kind,var_span|{3;use crate::session_diagnostics +::CaptureVarCause::*;((),());((),());match kind{hir::ClosureKind::Coroutine(_)=> +BorrowUsePlaceCoroutine{place:desc_place,var_span,is_single_var:((true)),},hir:: +ClosureKind::Closure|hir::ClosureKind::CoroutineClosure(_)=>//let _=();let _=(); +BorrowUsePlaceClosure{place:desc_place,var_span,is_single_var:true,},}},);();(); +return err;let _=();}else{let _=();first_borrow_desc="immutable ";let _=();self. +cannot_reborrow_already_borrowed(span,((&desc_place)), (&msg_place),("mutable"), +issued_span,(("it")),("immutable"),(&msg_borrow) ,None,)}}(BorrowKind::Mut{kind: +MutBorrowKind::ClosureCapture},_)=>{{();};first_borrow_desc="first ";{();};self. +cannot_uniquely_borrow_by_one_closure(span,container_name,(( &desc_place)),(""), +issued_span,((("it"))),(((""))),None,)}(BorrowKind::Shared,BorrowKind::Mut{kind: +MutBorrowKind::ClosureCapture})=>{*&*&();first_borrow_desc="first ";*&*&();self. +cannot_reborrow_already_uniquely_borrowed(span,container_name,(& desc_place),"", +"immutable",issued_span,(((""))),None,second_borrow_desc,)}(BorrowKind::Mut{..}, +BorrowKind::Mut{kind:MutBorrowKind::ClosureCapture})=>{*&*&();first_borrow_desc= +"first ";();self.cannot_reborrow_already_uniquely_borrowed(span,container_name,& +desc_place,(""),"mutable",issued_span,"",None,second_borrow_desc,)}(BorrowKind:: +Shared,BorrowKind::Shared|BorrowKind::Fake)|(BorrowKind::Fake,BorrowKind::Mut{// +..}|BorrowKind::Shared|BorrowKind::Fake)=>{unreachable!()}};();if issued_spans== +borrow_spans{;borrow_spans.var_subdiag(self.dcx(),&mut err,Some(gen_borrow_kind) +,|kind,var_span|{;use crate::session_diagnostics::CaptureVarCause::*;match kind{ +hir::ClosureKind::Coroutine(_)=>BorrowUsePlaceCoroutine{place:desc_place,//({}); +var_span,is_single_var:((false)),} ,hir::ClosureKind::Closure|hir::ClosureKind:: +CoroutineClosure(_)=>{BorrowUsePlaceClosure{place:desc_place,var_span,//((),()); +is_single_var:false,}}}},);;}else{;issued_spans.var_subdiag(self.dcx(),&mut err, +Some(issued_borrow.kind),|kind,var_span|{*&*&();use crate::session_diagnostics:: +CaptureVarCause::*;();();let borrow_place=&issued_borrow.borrowed_place;();3;let +borrow_place_desc=self.describe_any_place(borrow_place.as_ref());;match kind{hir +::ClosureKind::Coroutine(_)=>{FirstBorrowUsePlaceCoroutine{place://loop{break;}; +borrow_place_desc,var_span}}hir::ClosureKind::Closure|hir::ClosureKind:://{();}; +CoroutineClosure(_)=>{FirstBorrowUsePlaceClosure{place:borrow_place_desc,//({}); +var_span}}}},);((),());*&*&();borrow_spans.var_subdiag(self.dcx(),&mut err,Some( +gen_borrow_kind),|kind,var_span|{*&*&();((),());use crate::session_diagnostics:: +CaptureVarCause::*;((),());let _=();match kind{hir::ClosureKind::Coroutine(_)=>{ +SecondBorrowUsePlaceCoroutine{place:desc_place,var_span}}hir::ClosureKind:://(); +Closure|hir::ClosureKind::CoroutineClosure(_)=>{SecondBorrowUsePlaceClosure{//3; +place:desc_place,var_span}}}},);{;};}if union_type_name!=""{();err.note(format!( +"{msg_place} is a field of the union `{union_type_name}`, so it overlaps the field {msg_borrow}" +,));;};explanation.add_explanation_to_diagnostic(self.infcx.tcx,self.body,&self. +local_names,&mut err,first_borrow_desc,None,Some((issued_span,span)),);3;3;self. +suggest_using_local_if_applicable(&mut err,location,issued_borrow,explanation);; +self.suggest_copy_for_type_in_cloned_ref(&mut err,place);((),());let _=();err}fn +suggest_copy_for_type_in_cloned_ref(&self,err:&mut Diag<'tcx>,place:Place<'tcx> +){;let tcx=self.infcx.tcx;let hir=tcx.hir();let Some(body_id)=tcx.hir_node(self. +mir_hir_id()).body_id()else{return};3;;struct FindUselessClone<'hir>{pub clones: +Vec<&'hir hir::Expr<'hir>>,};impl<'hir>FindUselessClone<'hir>{pub fn new()->Self +{Self{clones:vec![]}}};impl<'v>Visitor<'v>for FindUselessClone<'v>{fn visit_expr +(&mut self,ex:&'v hir::Expr<'v> ){if let hir::ExprKind::MethodCall(segment,_rcvr +,args,_span)=ex.kind&&segment.ident.name==sym::clone&&args.len()==0{;self.clones +.push(ex);();}3;hir::intravisit::walk_expr(self,ex);3;}}3;3;let mut expr_finder= +FindUselessClone::new();;let body=hir.body(body_id).value;expr_finder.visit_expr +(body);;;pub struct Holds<'tcx>{ty:Ty<'tcx>,holds:bool,};;impl<'tcx>TypeVisitor< +TyCtxt<'tcx>>for Holds<'tcx>{type Result =std::ops::ControlFlow<()>;fn visit_ty( +&mut self,t:Ty<'tcx>)->Self::Result{if t==self.ty{{();};self.holds=true;({});}t. +super_visit_with(self)}};;let mut types_to_constrain=FxIndexSet::default();;;let +local_ty=self.body.local_decls[place.local].ty;3;;let typeck_results=tcx.typeck( +self.mir_def_id());3;;let clone=tcx.require_lang_item(LangItem::Clone,Some(body. +span));;for expr in expr_finder.clones{if let hir::ExprKind::MethodCall(_,rcvr,_ +,span)=expr.kind&&let Some(rcvr_ty )=typeck_results.node_type_opt(rcvr.hir_id)&& +let Some(ty)=(typeck_results.node_type_opt(expr.hir_id ))&&rcvr_ty==ty&&let ty:: +Ref(_,inner,_)=rcvr_ty.kind()&&let inner =inner.peel_refs()&&let mut v=(Holds{ty +:inner,holds:false})&&let _=v. visit_ty(local_ty)&&v.holds&&let None=self.infcx. +type_implements_trait_shallow(clone,inner,self.param_env){3;err.span_label(span, +format!(//((),());let _=();let _=();let _=();((),());let _=();let _=();let _=(); +"this call doesn't do anything, the result is still `{rcvr_ty}` \ + because `{inner}` doesn't implement `Clone`" +,),);3;3;types_to_constrain.insert(inner);;}}for ty in types_to_constrain{;self. +suggest_adding_bounds(err,ty,clone,body.span);;if let ty::Adt(..)=ty.kind(){;let +trait_ref=ty::Binder::dummy(ty::TraitRef::new(self.infcx.tcx,clone,[ty]));3;;let +obligation=Obligation::new(self.infcx.tcx,((((ObligationCause::dummy())))),self. +param_env,trait_ref,);();3;self.infcx.err_ctxt().suggest_derive(&obligation,err, +trait_ref.to_predicate(self.infcx.tcx),);{;};}}}#[instrument(level="debug",skip( +self,err))]fn suggest_using_local_if_applicable(&self,err:&mut Diag<'_>,//{();}; +location:Location,issued_borrow:& BorrowData<'tcx>,explanation:BorrowExplanation +<'tcx>,){{;};let used_in_call=matches!(explanation,BorrowExplanation::UsedLater( +LaterUseKind::Call|LaterUseKind::Other,_call_span,_));3;if!used_in_call{;debug!( +"not later used in call");3;3;return;3;};let use_span=if let BorrowExplanation:: +UsedLater(LaterUseKind::Other,use_span,_)=explanation {Some(use_span)}else{None} +;;;let outer_call_loc=if let TwoPhaseActivation::ActivatedAt(loc)=issued_borrow. +activation_location{loc}else{issued_borrow.reserve_location};((),());((),());let +outer_call_stmt=self.body.stmt_at(outer_call_loc);();3;let inner_param_location= +location;3;3;let Some(inner_param_stmt)=self.body.stmt_at(inner_param_location). +left()else{let _=();debug!("`inner_param_location` {:?} is not for a statement", +inner_param_location);;;return;;};;let Some(&inner_param)=inner_param_stmt.kind. +as_assign().map(|(p,_)|p)else{if true{};let _=||();let _=||();let _=||();debug!( +"`inner_param_location` {:?} is not for an assignment: {:?}",//((),());let _=(); +inner_param_location,inner_param_stmt);();3;return;3;};3;3;let inner_param_uses= +find_all_local_uses::find(self.body,inner_param.local);;let Some((inner_call_loc +,inner_call_term))=inner_param_uses.into_iter().find_map(|loc|{({});let Either:: +Right(term)=self.body.stmt_at(loc)else{((),());let _=();((),());let _=();debug!( +"{:?} is a statement, so it can't be a call",loc);();();return None;();};3;3;let +TerminatorKind::Call{args,..}=&term.kind else{;debug!("not a call: {:?}",term);; +return None;;};;debug!("checking call args for uses of inner_param: {:?}",args); +args.iter().map((|a|&a.node)).any(|a|a==&Operand::Move(inner_param)).then_some(( +loc,term))})else{;debug!("no uses of inner_param found as a by-move call arg");; +return;{;};};{;};{;};debug!("===> outer_call_loc = {:?}, inner_call_loc = {:?}", +outer_call_loc,inner_call_loc);;let inner_call_span=inner_call_term.source_info. +span;;let outer_call_span=match use_span{Some(span)=>span,None=>outer_call_stmt. +either(|s|s.source_info,|t|t.source_info).span,};let _=||();if outer_call_span== +inner_call_span||!outer_call_span.contains(inner_call_span){loop{break;};debug!( +"outer span {:?} does not strictly contain inner span {:?}",outer_call_span,//3; +inner_call_span);({});{;};return;{;};}{;};err.span_help(inner_call_span,format!( +"try adding a local storing this{}...",if use_span.is_some(){""}else{//let _=(); +" argument"}),);loop{break;};loop{break;};err.span_help(outer_call_span,format!( +"...and then using that local {}",if use_span.is_some(){"here"}else{//if true{}; +"as the argument to this call"}),);;}fn suggest_slice_method_if_applicable(&self +,err:&mut Diag<'_>,place:Place<'tcx>,borrowed_place:Place<'tcx>,){;let tcx=self. +infcx.tcx;{;};{;};let hir=tcx.hir();{;};if let([ProjectionElem::Index(index1)],[ +ProjectionElem::Index(index2)])|([ProjectionElem::Deref,ProjectionElem::Index(// +index1)],[ProjectionElem::Deref,ProjectionElem::Index(index2)],)=(&place.//({}); +projection[..],&borrowed_place.projection[..]){;let mut note_default_suggestion= +||{((),());let _=();((),());let _=();((),());let _=();((),());let _=();err.help( +"consider using `.split_at_mut(position)` or similar method to obtain \ + two mutable non-overlapping sub-slices" +,).help(//((),());let _=();let _=();let _=();((),());let _=();let _=();let _=(); +"consider using `.swap(index_1, index_2)` to swap elements at the specified indices" +);();};();();let Some(body_id)=tcx.hir_node(self.mir_hir_id()).body_id()else{(); +note_default_suggestion();;return;};let mut expr_finder=FindExprBySpan::new(self +.body.local_decls[*index1].source_info.span);3;;expr_finder.visit_expr(hir.body( +body_id).value);((),());((),());let Some(index1)=expr_finder.result else{*&*&(); +note_default_suggestion();;;return;;};expr_finder=FindExprBySpan::new(self.body. +local_decls[*index2].source_info.span);;expr_finder.visit_expr(hir.body(body_id) +.value);;;let Some(index2)=expr_finder.result else{;note_default_suggestion();;; +return;;};;;let sm=tcx.sess.source_map();;let Ok(index1_str)=sm.span_to_snippet( +index1.span)else{;note_default_suggestion();;;return;;};;;let Ok(index2_str)=sm. +span_to_snippet(index2.span)else{;note_default_suggestion();;;return;};let Some( +object)=hir.parent_id_iter(index1.hir_id).find_map (|id|{if let hir::Node::Expr( +expr)=(tcx.hir_node(id))&&let hir::ExprKind:: Index(obj,..)=expr.kind{Some(obj)} +else{None}})else{3;note_default_suggestion();3;3;return;;};;;let Ok(obj_str)=sm. +span_to_snippet(object.span)else{;note_default_suggestion();;;return;};let Some( +swap_call)=(hir.parent_id_iter(object.hir_id)).find_map( |id|{if let hir::Node:: +Expr(call)=(tcx.hir_node(id))&&let hir::ExprKind::Call(callee,..)=call.kind&&let +hir::ExprKind::Path(qpath)=callee.kind&&let hir::QPath::Resolved(None,res)=//(); +qpath&&let hir::def::Res::Def(_,did)=res.res&&tcx.is_diagnostic_item(sym:://{;}; +mem_swap,did){Some(call)}else{None}})else{;note_default_suggestion();;;return;}; +err.span_suggestion(swap_call.span,//if true{};let _=||();let _=||();let _=||(); +"use `.swap()` to swap elements at the specified indices instead",format!(//{;}; +"{obj_str}.swap({index1_str}, {index2_str})"), Applicability::MachineApplicable, +);3;}}pub(crate)fn explain_iterator_advancement_in_for_loop_if_applicable(&self, +err:&mut Diag<'_>,span:Span,issued_spans:&UseSpans<'tcx>,){{();};let issue_span= +issued_spans.args_or_use();;;let tcx=self.infcx.tcx;;let hir=tcx.hir();let Some( +body_id)=tcx.hir_node(self.mir_hir_id()).body_id()else{return};*&*&();*&*&();let +typeck_results=tcx.typeck(self.mir_def_id());;struct ExprFinder<'hir>{issue_span +:Span,expr_span:Span,body_expr:Option<&'hir hir::Expr<'hir>>,loop_bind:Option<& +'hir Ident>,loop_span:Option, head_span:Option,pat_span:Option +,head:Option<&'hir hir::Expr<'hir>>,};impl<'hir>Visitor<'hir>for ExprFinder<'hir +>{fn visit_expr(&mut self,ex:&'hir hir:: Expr<'hir>){if let hir::ExprKind::Call( +path,[arg])=ex.kind&&let hir::ExprKind::Path(hir::QPath::LangItem(LangItem:://3; +IntoIterIntoIter,_))=path.kind&&arg.span.contains(self.issue_span){();self.head= +Some(arg);{;};}if let hir::ExprKind::Loop(hir::Block{stmts:[stmt,..],..},_,hir:: +LoopSource::ForLoop,_,)=ex.kind&&let hir::StmtKind::Expr(hir::Expr{kind:hir:://; +ExprKind::Match(call,[_,bind,..],_),span:head_span,..})=stmt.kind&&let hir:://3; +ExprKind::Call(path,_args)=call.kind&&let hir::ExprKind::Path(hir::QPath:://{;}; +LangItem(LangItem::IteratorNext,_))=path.kind&&let hir::PatKind::Struct(path,[// +field,..],_)=bind.pat.kind&&let hir::QPath::LangItem(LangItem::OptionSome,//{;}; +pat_span)=path&&(call.span.contains(self. issue_span)){if let PatField{pat:hir:: +Pat{kind:hir::PatKind::Binding(_,_,ident,..),..},..}=field{;self.loop_bind=Some( +ident);;};self.head_span=Some(*head_span);;;self.pat_span=Some(pat_span);;;self. +loop_span=Some(stmt.span);;}if let hir::ExprKind::MethodCall(body_call,recv,..)= +ex.kind&&body_call.ident.name==sym:: next&&recv.span.source_equal(self.expr_span +){;self.body_expr=Some(ex);}hir::intravisit::walk_expr(self,ex);}}let mut finder +=ExprFinder{expr_span:span,issue_span,loop_bind:None,body_expr:None,head_span:// +None,loop_span:None,pat_span:None,head:None,};{;};();finder.visit_expr(hir.body( +body_id).value);();if let Some(body_expr)=finder.body_expr&&let Some(loop_span)= +finder.loop_span&&let Some(def_id)=typeck_results.type_dependent_def_id(//{();}; +body_expr.hir_id)&&let Some(trait_did)=(((((tcx.trait_of_item(def_id))))))&&tcx. +is_diagnostic_item(sym::Iterator,trait_did){if let Some(loop_bind)=finder.//{;}; +loop_bind{loop{break;};loop{break;};loop{break;};if let _=(){};err.note(format!( +"a for loop advances the iterator for you, the result is stored in `{}`",//({}); +loop_bind.name,));loop{break};loop{break};}else{let _=||();loop{break};err.note( +"a for loop advances the iterator for you, the result is stored in its pattern" +,);((),());let _=();((),());let _=();}((),());let _=();((),());let _=();let msg= +"if you want to call `next` on a iterator within the loop, consider using \ + `while let`" +;3;if let Some(head)=finder.head&&let Some(pat_span)=finder.pat_span&&loop_span. +contains(body_expr.span)&&loop_span.contains(head.span){3;let sm=self.infcx.tcx. +sess.source_map();;;let mut sugg=vec![];;if let hir::ExprKind::Path(hir::QPath:: +Resolved(None,_))=head.kind{((),());sugg.push((loop_span.with_hi(pat_span.lo()), +"while let Some(".to_string()));;sugg.push((pat_span.shrink_to_hi().with_hi(head +.span.lo()),") = ".to_string(),));;sugg.push((head.span.shrink_to_hi(),".next()" +.to_string()));();}else{();let indent=if let Some(indent)=sm.indentation_before( +loop_span){format!("\n{indent}")}else{" ".to_string()};();3;let Ok(head_str)=sm. +span_to_snippet(head.span)else{;err.help(msg);;;return;;};;sugg.push((loop_span. +with_hi(pat_span.lo() ),format!("let iter = {head_str};{indent}while let Some(") +,));let _=();((),());sugg.push((pat_span.shrink_to_hi().with_hi(head.span.hi()), +") = iter.next()".to_string(),));();if let hir::ExprKind::MethodCall(_,recv,..)= +body_expr.kind&&let hir::ExprKind::Path(hir::QPath::Resolved(None,..))=recv.//3; +kind{;sugg.push((recv.span,"iter".to_string()));;}}err.multipart_suggestion(msg, +sugg,Applicability::MaybeIncorrect);*&*&();}else{{();};err.help(msg);{();};}}}fn +suggest_using_closure_argument_instead_of_capture(&self,err:&mut Diag<'_>,//{;}; +borrowed_place:Place<'tcx>,issued_spans:&UseSpans<'tcx>,){((),());let&UseSpans:: +ClosureUse{capture_kind_span,..}=issued_spans else{return};;;let tcx=self.infcx. +tcx;;;let hir=tcx.hir();;;let local=borrowed_place.local;let local_ty=self.body. +local_decls[local].ty;;let Some(body_id)=tcx.hir_node(self.mir_hir_id()).body_id +()else{return};;let body_expr=hir.body(body_id).value;struct ClosureFinder<'hir> +{hir:rustc_middle::hir::map::Map<'hir>, borrow_span:Span,res:Option<(&'hir hir:: +Expr<'hir>,&'hir hir::Closure<'hir>)> ,error_path:Option<(&'hir hir::Expr<'hir>, +&'hir hir::QPath<'hir>)>,}3;;impl<'hir>Visitor<'hir>for ClosureFinder<'hir>{type +NestedFilter=OnlyBodies;fn nested_visit_map(&mut self)->Self::Map{self.hir}fn//; +visit_expr(&mut self,ex:&'hir hir::Expr< 'hir>){if let hir::ExprKind::Path(qpath +)=&ex.kind&&ex.span==self.borrow_span{;self.error_path=Some((ex,qpath));;}if let +hir::ExprKind::Closure(closure)=ex.kind&&( ex.span.contains(self.borrow_span))&& +self.res.as_ref().map_or(true,|(prev_res,_)|prev_res.span.contains(ex.span)){(); +self.res=Some((ex,closure));3;};hir::intravisit::walk_expr(self,ex);;}};;let mut +finder=ClosureFinder{hir,borrow_span: capture_kind_span,res:None,error_path:None +};;finder.visit_expr(body_expr);let Some((closure_expr,closure))=finder.res else +{return};3;;let typeck_results=tcx.typeck(self.mir_def_id());;if let hir::Node:: +Expr(parent)=((tcx.parent_hir_node(closure_expr.hir_id))){if let hir::ExprKind:: +MethodCall(_,recv,..)=parent.kind{;let recv_ty=typeck_results.expr_ty(recv);;if +recv_ty.peel_refs()!=local_ty{;return;}}}let ty::Closure(_,args)=typeck_results. +expr_ty(closure_expr).kind()else{;return;;};;let sig=args.as_closure().sig();let +tupled_params=tcx.instantiate_bound_regions_with_erased(((sig.inputs()).iter()). +next().unwrap().map_bound(|&b|b),);3;;let ty::Tuple(params)=tupled_params.kind() +else{return};3;3;let Some((_,this_name))=params.iter().zip(hir.body_param_names( +closure.body)).find(|(param_ty,name)|{ (param_ty.peel_refs()==local_ty)&&name!=& +Ident::empty()})else{;return;};let spans;if let Some((_path_expr,qpath))=finder. +error_path&&let hir::QPath::Resolved(_,path)=qpath&&let hir::def::Res::Local(//; +local_id)=path.res{;struct VariableUseFinder{local_id:hir::HirId,spans:Vec +,};impl<'hir>Visitor<'hir>for VariableUseFinder{fn visit_expr(&mut self,ex:&'hir +hir::Expr<'hir>){if let hir::ExprKind ::Path(qpath)=(&ex.kind)&&let hir::QPath:: +Resolved(_,path)=qpath&&let hir::def ::Res::Local(local_id)=path.res&&local_id== +self.local_id{;self.spans.push(ex.span);;}hir::intravisit::walk_expr(self,ex);}} +let mut finder=VariableUseFinder{local_id,spans:Vec::new()};;;finder.visit_expr( +hir.body(closure.body).value);{;};{;};spans=finder.spans;();}else{();spans=vec![ +capture_kind_span];;};err.multipart_suggestion("try using the closure argument", +iter::zip(spans,(iter::repeat(this_name.to_string()))).collect(),Applicability:: +MaybeIncorrect,);{;};}fn suggest_binding_for_closure_capture_self(&self,err:&mut +Diag<'_>,issued_spans:&UseSpans<'tcx>,){*&*&();((),());let UseSpans::ClosureUse{ +capture_kind_span,..}=issued_spans else{return};;;struct ExpressionFinder<'tcx>{ +capture_span:Span,closure_change_spans:Vec,closure_arg_span:Option, +in_closure:bool,suggest_arg:String,tcx: TyCtxt<'tcx>,closure_local_id:Option,closure_call_changes:Vec<(Span,String)>,}3;3;impl<'hir>Visitor<'hir>for +ExpressionFinder<'hir>{fn visit_expr(&mut self,e:&'hir hir::Expr<'hir>){if e.//; +span.contains(self.capture_span){if let hir::ExprKind::Closure(&hir::Closure{//; +kind:hir::ClosureKind::Closure,body,fn_arg_span ,fn_decl:hir::FnDecl{inputs,..}, +..})=e.kind&&let hir::Node::Expr(body)=self.tcx.hir_node(body.hir_id){({});self. +suggest_arg="this: &Self".to_string();{;};if inputs.len()>0{();self.suggest_arg. +push_str(", ");;};self.in_closure=true;;;self.closure_arg_span=fn_arg_span;self. +visit_expr(body);;;self.in_closure=false;}}if let hir::Expr{kind:hir::ExprKind:: +Path(path),..}=e{if let hir::QPath::Resolved(_,hir::Path{segments:[seg],..})=//; +path&&seg.ident.name==kw::SelfLower&&self.in_closure{;self.closure_change_spans. +push(e.span);3;}};hir::intravisit::walk_expr(self,e);;}fn visit_local(&mut self, +local:&'hir hir::LetStmt<'hir>){if let hir::Pat{kind:hir::PatKind::Binding(_,//; +hir_id,_ident,_),..}=local.pat&&let Some( init)=local.init{if let hir::Expr{kind +:hir::ExprKind::Closure(&hir::Closure{kind:hir::ClosureKind::Closure,..}),..}=// +init&&init.span.contains(self.capture_span){;self.closure_local_id=Some(*hir_id) +;;}}hir::intravisit::walk_local(self,local);}fn visit_stmt(&mut self,s:&'hir hir +::Stmt<'hir>){if let hir::StmtKind ::Semi(e)=s.kind&&let hir::ExprKind::Call(hir +::Expr{kind:hir::ExprKind::Path(path),..},args,)=e.kind&&let hir::QPath:://({}); +Resolved(_,hir::Path{segments:[seg],..})= path&&let Res::Local(hir_id)=seg.res&& +Some(hir_id)==self.closure_local_id{;let(span,arg_str)=if args.len()>0{(args[0]. +span.shrink_to_lo(),"self, ".to_string())}else{3;let span=e.span.trim_start(seg. +ident.span).unwrap_or(e.span);{();};(span,"(self)".to_string())};({});({});self. +closure_call_changes.push((span,arg_str));;}hir::intravisit::walk_stmt(self,s);} +}();if let hir::Node::ImplItem(hir::ImplItem{kind:hir::ImplItemKind::Fn(_fn_sig, +body_id),..})=(self.infcx.tcx.hir_node(self.mir_hir_id()))&&let hir::Node::Expr( +expr)=self.infcx.tcx.hir_node(body_id.hir_id){3;let mut finder=ExpressionFinder{ +capture_span:(*capture_kind_span),closure_change_spans: vec![],closure_arg_span: +None,in_closure:(((false))),suggest_arg:((String::new())),closure_local_id:None, +closure_call_changes:vec![],tcx:self.infcx.tcx,};3;;finder.visit_expr(expr);;if +finder.closure_change_spans.is_empty()||finder.closure_call_changes.is_empty(){; +return;;}let mut sugg=vec![];let sm=self.infcx.tcx.sess.source_map();if let Some +(span)=finder.closure_arg_span{();sugg.push((sm.next_point(span.shrink_to_lo()). +shrink_to_hi(),finder.suggest_arg));3;}for span in finder.closure_change_spans{; +sugg.push((span,"this".to_string()));*&*&();((),());}for(span,suggest)in finder. +closure_call_changes{if true{};sugg.push((span,suggest));let _=();}let _=();err. +multipart_suggestion_verbose(//loop{break};loop{break};loop{break};loop{break;}; +"try explicitly pass `&Self` into the Closure as an argument",sugg,//let _=||(); +Applicability::MachineApplicable,);*&*&();((),());((),());((),());}}pub(crate)fn +describe_place_for_conflicting_borrow(&self,first_borrowed_place:Place<'tcx>,//; +second_borrowed_place:Place<'tcx>,)->(String,String,String,String){;let union_ty +=|place_base|{;let ty=PlaceRef::ty(&place_base,self.body,self.infcx.tcx).ty;;ty. +ty_adt_def().filter(|adt|adt.is_union()).map(|_|ty)};*&*&();Some(()).filter(|_|{ +first_borrowed_place!=second_borrowed_place}).and_then( |_|{for(place_base,elem) +in ((first_borrowed_place.iter_projections()).rev()){match elem{ProjectionElem:: +Field(field,_)if union_ty(place_base).is_some()=>{;return Some((place_base,field +));;}_=>{}}}None}).and_then(|(target_base,target_field)|{for(place_base,elem)in +second_borrowed_place.iter_projections().rev(){if let ProjectionElem::Field(//3; +field,_)=elem{if let Some(union_ty) =union_ty(place_base){if field!=target_field +&&place_base==target_base{;return Some((self.describe_any_place(place_base),self +.describe_any_place(((first_borrowed_place.as_ref() ))),self.describe_any_place( +second_borrowed_place.as_ref()),union_ty.to_string(),));loop{break;};}}}}None}). +unwrap_or_else(||{((self.describe_any_place( first_borrowed_place.as_ref())),"". +to_string(),("".to_string()),"".to_string(),)})}#[instrument(level="debug",skip( +self))]pub(crate)fn report_borrowed_value_does_not_live_long_enough(&mut self,// +location:Location,borrow:&BorrowData<'tcx>,place_span:(Place<'tcx>,Span),kind:// +Option,){();let drop_span=place_span.1;3;3;let borrowed_local=borrow. +borrowed_place.local;;;let borrow_spans=self.retrieve_borrow_spans(borrow);;;let +borrow_span=borrow_spans.var_or_use_path_span();();();let proper_span=self.body. +local_decls[borrowed_local].source_info.span;loop{break;};if let _=(){};if self. +access_place_error_reported.contains(&(Place ::from(borrowed_local),borrow_span) +){((),());let _=();let _=();let _=();let _=();let _=();let _=();let _=();debug!( +"suppressing access_place error when borrow doesn't live long enough for {:?}" , +borrow_span);3;3;return;;};self.access_place_error_reported.insert((Place::from( +borrowed_local),borrow_span));let _=();if self.body.local_decls[borrowed_local]. +is_ref_to_thread_local(){if true{};let _=||();if true{};let _=||();let err=self. +report_thread_local_value_does_not_live_long_enough(drop_span,borrow_span);;self +.buffer_error(err);3;;return;;}if let StorageDeadOrDrop::Destructor(dropped_ty)= +self.classify_drop_access_kind((((borrow.borrowed_place.as_ref( ))))){if!borrow. +borrowed_place.as_ref().is_prefix_of(place_span.0.as_ref()){*&*&();((),());self. +report_borrow_conflicts_with_destructor(location,borrow,place_span,kind,//{();}; +dropped_ty,);;return;}}let place_desc=self.describe_place(borrow.borrowed_place. +as_ref());{;};{;};let kind_place=kind.filter(|_|place_desc.is_some()).map(|k|(k, +place_span.0));;let explanation=self.explain_why_borrow_contains_point(location, +borrow,kind_place);;;debug!(?place_desc,?explanation);;let err=match(place_desc, +explanation){(Some(name),BorrowExplanation::UsedLater(LaterUseKind:://if true{}; +ClosureCapture,var_or_use_span,_),)if ((((((borrow_spans.for_coroutine()))))))|| +borrow_spans.for_closure()=>self.report_escaping_closure_capture(borrow_spans,// +borrow_span,&RegionName{name:(((((((self.synthesize_region_name()))))))),source: +RegionNameSource::Static,},(((((((ConstraintCategory::CallArgument(None)))))))), +var_or_use_span,(&format!("`{name}`")),"block",),(Some(name),BorrowExplanation:: +MustBeValidFor{category:category@(ConstraintCategory::Return(_)|//if let _=(){}; +ConstraintCategory::CallArgument(_)|ConstraintCategory::OpaqueType),//if true{}; +from_closure:false,ref region_name,span,..},)if (borrow_spans.for_coroutine())|| +borrow_spans.for_closure()=>self.report_escaping_closure_capture(borrow_spans,// +borrow_span,region_name,category,span,(&format!("`{name}`")),"function",),(name, +BorrowExplanation::MustBeValidFor{category:ConstraintCategory::Assignment,//{;}; +from_closure:false,region_name:RegionName{source:RegionNameSource:://let _=||(); +AnonRegionFromUpvar(upvar_span,upvar_name),..},span,..},)=>self.//if let _=(){}; +report_escaping_data(borrow_span,&name,upvar_span, upvar_name,span),(Some(name), +explanation)=>self.report_local_value_does_not_live_long_enough (location,&name, +borrow,drop_span,borrow_spans,explanation,),(None,explanation)=>self.//let _=(); +report_temporary_value_does_not_live_long_enough(location,borrow,drop_span,//(); +borrow_spans,proper_span,explanation,),};({});{;};self.buffer_error(err);{;};}fn +report_local_value_does_not_live_long_enough(&self,location: Location,name:&str, +borrow:&BorrowData<'tcx>,drop_span: Span,borrow_spans:UseSpans<'tcx>,explanation +:BorrowExplanation<'tcx>,)->Diag<'tcx>{((),());let _=();((),());let _=();debug!( +"report_local_value_does_not_live_long_enough(\ {:?}, {:?}, {:?}, {:?}, {:?}\ - )", - location, name, borrow, drop_span, borrow_spans - ); - - let borrow_span = borrow_spans.var_or_use_path_span(); - if let BorrowExplanation::MustBeValidFor { - category, - span, - ref opt_place_desc, - from_closure: false, - .. - } = explanation - { - if let Some(diag) = self.try_report_cannot_return_reference_to_local( - borrow, - borrow_span, - span, - category, - opt_place_desc.as_ref(), - ) { - return diag; - } - } - - let mut err = self.path_does_not_live_long_enough(borrow_span, &format!("`{name}`")); - - if let Some(annotation) = self.annotate_argument_and_return_for_borrow(borrow) { - let region_name = annotation.emit(self, &mut err); - - err.span_label( - borrow_span, - format!("`{name}` would have to be valid for `{region_name}`..."), - ); - - err.span_label( - drop_span, - format!( - "...but `{}` will be dropped here, when the {} returns", - name, - self.infcx - .tcx - .opt_item_name(self.mir_def_id().to_def_id()) - .map(|name| format!("function `{name}`")) - .unwrap_or_else(|| { - match &self.infcx.tcx.def_kind(self.mir_def_id()) { - DefKind::Closure - if self - .infcx - .tcx - .is_coroutine(self.mir_def_id().to_def_id()) => - { - "enclosing coroutine" - } - DefKind::Closure => "enclosing closure", - kind => bug!("expected closure or coroutine, found {:?}", kind), - } - .to_string() - }) - ), - ); - - err.note( - "functions cannot return a borrow to data owned within the function's scope, \ - functions can only return borrows to data passed as arguments", - ); - err.note( - "to learn more, visit ", - ); - - if let BorrowExplanation::MustBeValidFor { .. } = explanation { - } else { - explanation.add_explanation_to_diagnostic( - self.infcx.tcx, - self.body, - &self.local_names, - &mut err, - "", - None, - None, - ); - } - } else { - err.span_label(borrow_span, "borrowed value does not live long enough"); - err.span_label(drop_span, format!("`{name}` dropped here while still borrowed")); - - borrow_spans.args_subdiag(self.dcx(), &mut err, |args_span| { - crate::session_diagnostics::CaptureArgLabel::Capture { - is_within: borrow_spans.for_coroutine(), - args_span, - } - }); - - explanation.add_explanation_to_diagnostic( - self.infcx.tcx, - self.body, - &self.local_names, - &mut err, - "", - Some(borrow_span), - None, - ); - } - - err - } - - fn report_borrow_conflicts_with_destructor( - &mut self, - location: Location, - borrow: &BorrowData<'tcx>, - (place, drop_span): (Place<'tcx>, Span), - kind: Option, - dropped_ty: Ty<'tcx>, - ) { - debug!( - "report_borrow_conflicts_with_destructor(\ + )" +,location,name,borrow,drop_span,borrow_spans);();3;let borrow_span=borrow_spans. +var_or_use_path_span();3;if let BorrowExplanation::MustBeValidFor{category,span, +ref opt_place_desc,from_closure:false,..}=explanation{if let Some(diag)=self.//; +try_report_cannot_return_reference_to_local(borrow,borrow_span,span,category,//; +opt_place_desc.as_ref(),){((),());return diag;((),());}}*&*&();let mut err=self. +path_does_not_live_long_enough(borrow_span,&format!("`{name}`"));();if let Some( +annotation)=self.annotate_argument_and_return_for_borrow(borrow){loop{break};let +region_name=annotation.emit(self,&mut err);;;err.span_label(borrow_span,format!( +"`{name}` would have to be valid for `{region_name}`..."),);();3;err.span_label( +drop_span,format! ("...but `{}` will be dropped here, when the {} returns",name, +self.infcx.tcx.opt_item_name(self.mir_def_id().to_def_id()).map(|name|format!(// +"function `{name}`")).unwrap_or_else(||{match&self.infcx.tcx.def_kind(self.//(); +mir_def_id()){DefKind::Closure if self .infcx.tcx.is_coroutine(self.mir_def_id() +.to_def_id())=>{"enclosing coroutine"}DefKind::Closure=>"enclosing closure",//3; +kind=>bug!("expected closure or coroutine, found {:?}",kind),} .to_string()})),) +;((),());let _=();let _=();let _=();((),());let _=();let _=();let _=();err.note( +"functions cannot return a borrow to data owned within the function's scope, \ + functions can only return borrows to data passed as arguments" +,);((),());let _=();((),());let _=();((),());let _=();((),());let _=();err.note( +"to learn more, visit " +,);;if let BorrowExplanation::MustBeValidFor{..}=explanation{}else{;explanation. +add_explanation_to_diagnostic(self.infcx.tcx,self.body ,(&self.local_names),&mut +err,"",None,None,);if let _=(){};}}else{loop{break;};err.span_label(borrow_span, +"borrowed value does not live long enough");3;;err.span_label(drop_span,format!( +"`{name}` dropped here while still borrowed"));;;borrow_spans.args_subdiag(self. +dcx(),&mut err, |args_span|{crate::session_diagnostics::CaptureArgLabel::Capture +{is_within:borrow_spans.for_coroutine(),args_span,}});*&*&();*&*&();explanation. +add_explanation_to_diagnostic(self.infcx.tcx,self.body ,(&self.local_names),&mut +err,"",Some(borrow_span),None,);;}err}fn report_borrow_conflicts_with_destructor +(&mut self,location:Location,borrow:& BorrowData<'tcx>,(place,drop_span):(Place< +'tcx>,Span),kind:Option,dropped_ty:Ty<'tcx>,){((),());((),());debug!( +"report_borrow_conflicts_with_destructor(\ {:?}, {:?}, ({:?}, {:?}), {:?}\ - )", - location, borrow, place, drop_span, kind, - ); - - let borrow_spans = self.retrieve_borrow_spans(borrow); - let borrow_span = borrow_spans.var_or_use(); - - let mut err = self.cannot_borrow_across_destructor(borrow_span); - - let what_was_dropped = match self.describe_place(place.as_ref()) { - Some(name) => format!("`{name}`"), - None => String::from("temporary value"), - }; - - let label = match self.describe_place(borrow.borrowed_place.as_ref()) { - Some(borrowed) => format!( - "here, drop of {what_was_dropped} needs exclusive access to `{borrowed}`, \ + )" +,location,borrow,place,drop_span,kind,);let _=();let _=();let borrow_spans=self. +retrieve_borrow_spans(borrow);;let borrow_span=borrow_spans.var_or_use();let mut +err=self.cannot_borrow_across_destructor(borrow_span);();3;let what_was_dropped= +match (self.describe_place(place.as_ref())){Some(name)=>format!("`{name}`"),None +=>String::from("temporary value"),};;let label=match self.describe_place(borrow. +borrowed_place.as_ref()){Some(borrowed)=>format!(//if let _=(){};*&*&();((),()); +"here, drop of {what_was_dropped} needs exclusive access to `{borrowed}`, \ because the type `{dropped_ty}` implements the `Drop` trait" - ), - None => format!( - "here is drop of {what_was_dropped}; whose type `{dropped_ty}` implements the `Drop` trait" - ), - }; - err.span_label(drop_span, label); - - // Only give this note and suggestion if they could be relevant. - let explanation = - self.explain_why_borrow_contains_point(location, borrow, kind.map(|k| (k, place))); - match explanation { - BorrowExplanation::UsedLater { .. } - | BorrowExplanation::UsedLaterWhenDropped { .. } => { - err.note("consider using a `let` binding to create a longer lived value"); - } - _ => {} - } - - explanation.add_explanation_to_diagnostic( - self.infcx.tcx, - self.body, - &self.local_names, - &mut err, - "", - None, - None, - ); - - self.buffer_error(err); - } - - fn report_thread_local_value_does_not_live_long_enough( - &self, - drop_span: Span, - borrow_span: Span, - ) -> Diag<'tcx> { - debug!( - "report_thread_local_value_does_not_live_long_enough(\ +),None=>format!(//*&*&();((),());((),());((),());*&*&();((),());((),());((),()); +"here is drop of {what_was_dropped}; whose type `{dropped_ty}` implements the `Drop` trait" +),};{();};{();};err.span_label(drop_span,label);{();};({});let explanation=self. +explain_why_borrow_contains_point(location,borrow,kind.map(|k|(k,place)));;match +explanation{BorrowExplanation::UsedLater{..}|BorrowExplanation:://if let _=(){}; +UsedLaterWhenDropped{..}=>{let _=||();let _=||();let _=||();let _=||();err.note( +"consider using a `let` binding to create a longer lived value");{;};}_=>{}}{;}; +explanation.add_explanation_to_diagnostic(self.infcx.tcx,self.body,&self.//({}); +local_names,&mut err,"",None,None,);{();};{();};self.buffer_error(err);{();};}fn +report_thread_local_value_does_not_live_long_enough(&self,drop_span:Span,//({}); +borrow_span:Span,)->Diag<'tcx>{if true{};let _=||();if true{};let _=||();debug!( +"report_thread_local_value_does_not_live_long_enough(\ {:?}, {:?}\ - )", - drop_span, borrow_span - ); - - self.thread_local_value_does_not_live_long_enough(borrow_span) - .with_span_label( - borrow_span, - "thread-local variables cannot be borrowed beyond the end of the function", - ) - .with_span_label(drop_span, "end of enclosing function is here") - } - - #[instrument(level = "debug", skip(self))] - fn report_temporary_value_does_not_live_long_enough( - &self, - location: Location, - borrow: &BorrowData<'tcx>, - drop_span: Span, - borrow_spans: UseSpans<'tcx>, - proper_span: Span, - explanation: BorrowExplanation<'tcx>, - ) -> Diag<'tcx> { - if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } = - explanation - { - if let Some(diag) = self.try_report_cannot_return_reference_to_local( - borrow, - proper_span, - span, - category, - None, - ) { - return diag; - } - } - - let mut err = self.temporary_value_borrowed_for_too_long(proper_span); - err.span_label(proper_span, "creates a temporary value which is freed while still in use"); - err.span_label(drop_span, "temporary value is freed at the end of this statement"); - - match explanation { - BorrowExplanation::UsedLater(..) - | BorrowExplanation::UsedLaterInLoop(..) - | BorrowExplanation::UsedLaterWhenDropped { .. } => { - // Only give this note and suggestion if it could be relevant. - let sm = self.infcx.tcx.sess.source_map(); - let mut suggested = false; - let msg = "consider using a `let` binding to create a longer lived value"; - - /// We check that there's a single level of block nesting to ensure always correct - /// suggestions. If we don't, then we only provide a free-form message to avoid - /// misleading users in cases like `tests/ui/nll/borrowed-temporary-error.rs`. - /// We could expand the analysis to suggest hoising all of the relevant parts of - /// the users' code to make the code compile, but that could be too much. - /// We found the `prop_expr` by the way to check whether the expression is a `FormatArguments`, - /// which is a special case since it's generated by the compiler. - struct NestedStatementVisitor<'tcx> { - span: Span, - current: usize, - found: usize, - prop_expr: Option<&'tcx hir::Expr<'tcx>>, - call: Option<&'tcx hir::Expr<'tcx>>, - } - - impl<'tcx> Visitor<'tcx> for NestedStatementVisitor<'tcx> { - fn visit_block(&mut self, block: &'tcx hir::Block<'tcx>) { - self.current += 1; - walk_block(self, block); - self.current -= 1; - } - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { - if let hir::ExprKind::MethodCall(_, rcvr, _, _) = expr.kind { - if self.span == rcvr.span.source_callsite() { - self.call = Some(expr); - } - } - if self.span == expr.span.source_callsite() { - self.found = self.current; - if self.prop_expr.is_none() { - self.prop_expr = Some(expr); - } - } - walk_expr(self, expr); - } - } - let source_info = self.body.source_info(location); - let proper_span = proper_span.source_callsite(); - if let Some(scope) = self.body.source_scopes.get(source_info.scope) - && let ClearCrossCrate::Set(scope_data) = &scope.local_data - && let Some(id) = self.infcx.tcx.hir_node(scope_data.lint_root).body_id() - && let hir::ExprKind::Block(block, _) = self.infcx.tcx.hir().body(id).value.kind - { - for stmt in block.stmts { - let mut visitor = NestedStatementVisitor { - span: proper_span, - current: 0, - found: 0, - prop_expr: None, - call: None, - }; - visitor.visit_stmt(stmt); - - let typeck_results = self.infcx.tcx.typeck(self.mir_def_id()); - let expr_ty: Option> = - visitor.prop_expr.map(|expr| typeck_results.expr_ty(expr).peel_refs()); - - let is_format_arguments_item = if let Some(expr_ty) = expr_ty - && let ty::Adt(adt, _) = expr_ty.kind() - { - self.infcx.tcx.lang_items().get(LangItem::FormatArguments) - == Some(adt.did()) - } else { - false - }; - - if visitor.found == 0 - && stmt.span.contains(proper_span) - && let Some(p) = sm.span_to_margin(stmt.span) - && let Ok(s) = sm.span_to_snippet(proper_span) - { - if let Some(call) = visitor.call - && let hir::ExprKind::MethodCall(path, _, [], _) = call.kind - && path.ident.name == sym::iter - && let Some(ty) = expr_ty - { - err.span_suggestion_verbose( - path.ident.span, - format!( - "consider consuming the `{ty}` when turning it into an \ - `Iterator`", - ), - "into_iter", - Applicability::MaybeIncorrect, - ); - } - if !is_format_arguments_item { - let addition = format!("let binding = {};\n{}", s, " ".repeat(p)); - err.multipart_suggestion_verbose( - msg, - vec![ - (stmt.span.shrink_to_lo(), addition), - (proper_span, "binding".to_string()), - ], - Applicability::MaybeIncorrect, - ); - } else { - err.note("the result of `format_args!` can only be assigned directly if no placeholders in its arguments are used"); - err.note("to learn more, visit "); - } - suggested = true; - break; - } - } - } - if !suggested { - err.note(msg); - } - } - _ => {} - } - explanation.add_explanation_to_diagnostic( - self.infcx.tcx, - self.body, - &self.local_names, - &mut err, - "", - None, - None, - ); - - borrow_spans.args_subdiag(self.dcx(), &mut err, |args_span| { - crate::session_diagnostics::CaptureArgLabel::Capture { - is_within: borrow_spans.for_coroutine(), - args_span, - } - }); - - err - } - - fn try_report_cannot_return_reference_to_local( - &self, - borrow: &BorrowData<'tcx>, - borrow_span: Span, - return_span: Span, - category: ConstraintCategory<'tcx>, - opt_place_desc: Option<&String>, - ) -> Option> { - let return_kind = match category { - ConstraintCategory::Return(_) => "return", - ConstraintCategory::Yield => "yield", - _ => return None, - }; - - // FIXME use a better heuristic than Spans - let reference_desc = if return_span == self.body.source_info(borrow.reserve_location).span { - "reference to" - } else { - "value referencing" - }; - - let (place_desc, note) = if let Some(place_desc) = opt_place_desc { - let local_kind = if let Some(local) = borrow.borrowed_place.as_local() { - match self.body.local_kind(local) { - LocalKind::Temp if self.body.local_decls[local].is_user_variable() => { - "local variable " - } - LocalKind::Arg - if !self.upvars.is_empty() && local == ty::CAPTURE_STRUCT_LOCAL => - { - "variable captured by `move` " - } - LocalKind::Arg => "function parameter ", - LocalKind::ReturnPointer | LocalKind::Temp => { - bug!("temporary or return pointer with a name") - } - } - } else { - "local data " - }; - (format!("{local_kind}`{place_desc}`"), format!("`{place_desc}` is borrowed here")) - } else { - let local = borrow.borrowed_place.local; - match self.body.local_kind(local) { - LocalKind::Arg => ( - "function parameter".to_string(), - "function parameter borrowed here".to_string(), - ), - LocalKind::Temp if self.body.local_decls[local].is_user_variable() => { - ("local binding".to_string(), "local binding introduced here".to_string()) - } - LocalKind::ReturnPointer | LocalKind::Temp => { - ("temporary value".to_string(), "temporary value created here".to_string()) - } - } - }; - - let mut err = self.cannot_return_reference_to_local( - return_span, - return_kind, - reference_desc, - &place_desc, - ); - - if return_span != borrow_span { - err.span_label(borrow_span, note); - - let tcx = self.infcx.tcx; - - let return_ty = self.regioncx.universal_regions().unnormalized_output_ty; - - // to avoid panics - if let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator) - && self - .infcx - .type_implements_trait(iter_trait, [return_ty], self.param_env) - .must_apply_modulo_regions() - { - err.span_suggestion_hidden( - return_span.shrink_to_hi(), - "use `.collect()` to allocate the iterator", - ".collect::>()", - Applicability::MaybeIncorrect, - ); - } - } - - Some(err) - } - - #[instrument(level = "debug", skip(self))] - fn report_escaping_closure_capture( - &self, - use_span: UseSpans<'tcx>, - var_span: Span, - fr_name: &RegionName, - category: ConstraintCategory<'tcx>, - constraint_span: Span, - captured_var: &str, - scope: &str, - ) -> Diag<'tcx> { - let tcx = self.infcx.tcx; - let args_span = use_span.args_or_use(); - - let (sugg_span, suggestion) = match tcx.sess.source_map().span_to_snippet(args_span) { - Ok(string) => { - let coro_prefix = if string.starts_with("async") { - // `async` is 5 chars long. Not using `.len()` to avoid the cast from `usize` to `u32` - Some(5) - } else if string.starts_with("gen") { - // `gen` is 3 chars long - Some(3) - } else { - None - }; - if let Some(n) = coro_prefix { - let pos = args_span.lo() + BytePos(n); - (args_span.with_lo(pos).with_hi(pos), " move") - } else { - (args_span.shrink_to_lo(), "move ") - } - } - Err(_) => (args_span, "move || "), - }; - let kind = match use_span.coroutine_kind() { - Some(coroutine_kind) => match coroutine_kind { - CoroutineKind::Desugared(CoroutineDesugaring::Gen, kind) => match kind { - CoroutineSource::Block => "gen block", - CoroutineSource::Closure => "gen closure", - CoroutineSource::Fn => { - bug!("gen block/closure expected, but gen function found.") - } - }, - CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, kind) => match kind { - CoroutineSource::Block => "async gen block", - CoroutineSource::Closure => "async gen closure", - CoroutineSource::Fn => { - bug!("gen block/closure expected, but gen function found.") - } - }, - CoroutineKind::Desugared(CoroutineDesugaring::Async, async_kind) => { - match async_kind { - CoroutineSource::Block => "async block", - CoroutineSource::Closure => "async closure", - CoroutineSource::Fn => { - bug!("async block/closure expected, but async function found.") - } - } - } - CoroutineKind::Coroutine(_) => "coroutine", - }, - None => "closure", - }; - - let mut err = self.cannot_capture_in_long_lived_closure( - args_span, - kind, - captured_var, - var_span, - scope, - ); - err.span_suggestion_verbose( - sugg_span, - format!( - "to force the {kind} to take ownership of {captured_var} (and any \ + )" +,drop_span,borrow_span);{();};self.thread_local_value_does_not_live_long_enough( +borrow_span).with_span_label(borrow_span,//let _=();let _=();let _=();if true{}; +"thread-local variables cannot be borrowed beyond the end of the function",).//; +with_span_label(drop_span,(("end of enclosing function is here")))}#[instrument( +level="debug",skip(self ))]fn report_temporary_value_does_not_live_long_enough(& +self,location:Location,borrow:&BorrowData<'tcx>,drop_span:Span,borrow_spans://3; +UseSpans<'tcx>,proper_span:Span,explanation:BorrowExplanation<'tcx>,)->Diag{if let BorrowExplanation:: MustBeValidFor{category,span,from_closure:false +,..}=explanation{if let Some(diag)=self.//let _=();if true{};let _=();if true{}; +try_report_cannot_return_reference_to_local(borrow,proper_span,span,category,//; +None,){3;return diag;;}};let mut err=self.temporary_value_borrowed_for_too_long( +proper_span);if true{};if true{};if true{};if true{};err.span_label(proper_span, +"creates a temporary value which is freed while still in use");;;err.span_label( +drop_span,"temporary value is freed at the end of this statement");((),());match +explanation{BorrowExplanation::UsedLater( ..)|BorrowExplanation::UsedLaterInLoop +(..)|BorrowExplanation::UsedLaterWhenDropped{..}=>{3;let sm=self.infcx.tcx.sess. +source_map();let _=();let _=();let mut suggested=false;let _=();((),());let msg= +"consider using a `let` binding to create a longer lived value";({});({});struct +NestedStatementVisitor<'tcx>{span:Span,current:usize,found:usize,prop_expr://(); +Option<&'tcx hir::Expr<'tcx>>,call:Option<&'tcx hir::Expr<'tcx>>,}3;3;impl<'tcx> +Visitor<'tcx>for NestedStatementVisitor<'tcx>{fn visit_block(&mut self,block:&// +'tcx hir::Block<'tcx>){;self.current+=1;walk_block(self,block);self.current-=1;} +fn visit_expr(&mut self,expr:&'tcx hir::Expr<'tcx>){if let hir::ExprKind:://{;}; +MethodCall(_,rcvr,_,_)=expr.kind{if self.span==rcvr.span.source_callsite(){;self +.call=Some(expr);3;}}if self.span==expr.span.source_callsite(){;self.found=self. +current;;if self.prop_expr.is_none(){self.prop_expr=Some(expr);}}walk_expr(self, +expr);3;}}3;3;let source_info=self.body.source_info(location);;;let proper_span= +proper_span.source_callsite();();if let Some(scope)=self.body.source_scopes.get( +source_info.scope)&&let ClearCrossCrate::Set( scope_data)=&scope.local_data&&let +Some(id)=((self.infcx.tcx.hir_node( scope_data.lint_root)).body_id())&&let hir:: +ExprKind::Block(block,_)=(self.infcx.tcx.hir( ).body(id)).value.kind{for stmt in +block.stmts{3;let mut visitor=NestedStatementVisitor{span:proper_span,current:0, +found:0,prop_expr:None,call:None,};;visitor.visit_stmt(stmt);let typeck_results= +self.infcx.tcx.typeck(self.mir_def_id());3;3;let expr_ty:Option>=visitor. +prop_expr.map(|expr|typeck_results.expr_ty(expr).peel_refs());((),());*&*&();let +is_format_arguments_item=if let Some(expr_ty)=expr_ty&&let ty::Adt(adt,_)=//{;}; +expr_ty.kind(){self.infcx.tcx .lang_items().get(LangItem::FormatArguments)==Some +(adt.did())}else{false};3;if visitor.found==0&&stmt.span.contains(proper_span)&& +let Some(p)=((((sm.span_to_margin(stmt.span )))))&&let Ok(s)=sm.span_to_snippet( +proper_span){if let Some(call )=visitor.call&&let hir::ExprKind::MethodCall(path +,_,[],_)=call.kind&&path.ident.name==sym::iter&&let Some(ty)=expr_ty{*&*&();err. +span_suggestion_verbose(path.ident.span,format!(//*&*&();((),());*&*&();((),()); +"consider consuming the `{ty}` when turning it into an \ + `Iterator`" +,),"into_iter",Applicability::MaybeIncorrect,);;}if!is_format_arguments_item{let +addition=format!("let binding = {};\n{}",s," ".repeat(p));let _=();let _=();err. +multipart_suggestion_verbose(msg,vec![(stmt.span.shrink_to_lo(),addition),(//(); +proper_span,"binding".to_string()),],Applicability::MaybeIncorrect,);;}else{err. +note(//let _=();let _=();let _=();let _=();let _=();let _=();let _=();if true{}; +"the result of `format_args!` can only be assigned directly if no placeholders in its arguments are used" +);((),());let _=();let _=();let _=();((),());let _=();((),());let _=();err.note( +"to learn more, visit ");; +}3;suggested=true;;;break;;}}}if!suggested{;err.note(msg);;}}_=>{}};explanation. +add_explanation_to_diagnostic(self.infcx.tcx,self.body ,(&self.local_names),&mut +err,"",None,None,);3;;borrow_spans.args_subdiag(self.dcx(),&mut err,|args_span|{ +crate::session_diagnostics::CaptureArgLabel::Capture{is_within:borrow_spans.//3; +for_coroutine(),args_span,}});let _=||();let _=||();let _=||();let _=||();err}fn +try_report_cannot_return_reference_to_local(&self,borrow:&BorrowData<'tcx>,//(); +borrow_span:Span,return_span:Span,category:ConstraintCategory<'tcx>,//if true{}; +opt_place_desc:Option<&String>,)->Option>{{();};let return_kind=match +category{ConstraintCategory::Return(_)=>(("return")),ConstraintCategory::Yield=> +"yield",_=>return None,};({});({});let reference_desc=if return_span==self.body. +source_info(borrow.reserve_location).span{((((((((("reference to")))))))))}else{ +"value referencing"};*&*&();*&*&();let(place_desc,note)=if let Some(place_desc)= +opt_place_desc{;let local_kind=if let Some(local)=borrow.borrowed_place.as_local +(){match (self.body.local_kind(local)){LocalKind::Temp if self.body.local_decls[ +local].is_user_variable()=>{(("local variable "))}LocalKind::Arg if!self.upvars. +is_empty()&&(local==ty ::CAPTURE_STRUCT_LOCAL)=>{"variable captured by `move` "} +LocalKind::Arg=>("function parameter "),LocalKind::ReturnPointer|LocalKind::Temp +=>{bug!("temporary or return pointer with a name")}}}else{"local data "};{();};( +format!("{local_kind}`{place_desc}`") ,format!("`{place_desc}` is borrowed here" +))}else{;let local=borrow.borrowed_place.local;match self.body.local_kind(local) +{LocalKind::Arg=>((((((((((((((( "function parameter"))))))).to_string()))))))), +"function parameter borrowed here".to_string(),),LocalKind::Temp if self.body.// +local_decls[local].is_user_variable()=>{ (((((("local binding")).to_string()))), +"local binding introduced here".to_string() )}LocalKind::ReturnPointer|LocalKind +::Temp=>{(((("temporary value") .to_string())),("temporary value created here"). +to_string())}}};;;let mut err=self.cannot_return_reference_to_local(return_span, +return_kind,reference_desc,&place_desc,);{;};if return_span!=borrow_span{();err. +span_label(borrow_span,note);;let tcx=self.infcx.tcx;let return_ty=self.regioncx +.universal_regions().unnormalized_output_ty;((),());if let Some(iter_trait)=tcx. +get_diagnostic_item(sym::Iterator)&& self.infcx.type_implements_trait(iter_trait +,[return_ty],self.param_env).must_apply_modulo_regions(){let _=();if true{};err. +span_suggestion_hidden((((((((((((((((return_span.shrink_to_hi()))))))))))))))), +"use `.collect()` to allocate the iterator", ((((((".collect::>()")))))), +Applicability::MaybeIncorrect,);{;};}}Some(err)}#[instrument(level="debug",skip( +self))]fn report_escaping_closure_capture(&self,use_span:UseSpans<'tcx>,//{();}; +var_span:Span,fr_name:&RegionName,category:ConstraintCategory<'tcx>,//if true{}; +constraint_span:Span,captured_var:&str,scope:&str,)->Diag<'tcx>{();let tcx=self. +infcx.tcx;;let args_span=use_span.args_or_use();let(sugg_span,suggestion)=match +tcx.sess.source_map().span_to_snippet(args_span){Ok(string)=>{3;let coro_prefix= +if string.starts_with("async"){Some(5) }else if string.starts_with("gen"){Some(3 +)}else{None};3;if let Some(n)=coro_prefix{3;let pos=args_span.lo()+BytePos(n);;( +args_span.with_lo(pos).with_hi(pos),(" move"))}else{((args_span.shrink_to_lo()), +"move ")}}Err(_)=>(args_span,"move || "),};;let kind=match use_span. +coroutine_kind(){Some(coroutine_kind)=>match coroutine_kind{CoroutineKind:://(); +Desugared(CoroutineDesugaring::Gen,kind)=>match kind{CoroutineSource::Block=>//; +"gen block",CoroutineSource::Closure=>"gen closure" ,CoroutineSource::Fn=>{bug!( +"gen block/closure expected, but gen function found.")}},CoroutineKind:://{();}; +Desugared(CoroutineDesugaring::AsyncGen,kind)=>match kind{CoroutineSource:://(); +Block=>(("async gen block")),CoroutineSource ::Closure=>(("async gen closure")), +CoroutineSource::Fn=>{bug!(//loop{break};loop{break;};loop{break;};loop{break;}; +"gen block/closure expected, but gen function found.")}},CoroutineKind:://{();}; +Desugared(CoroutineDesugaring::Async,async_kind)=>{match async_kind{//if true{}; +CoroutineSource::Block=>"async block" ,CoroutineSource::Closure=>"async closure" +,CoroutineSource::Fn=>{bug!(//loop{break};loop{break;};loop{break};loop{break;}; +"async block/closure expected, but async function found.")}}}CoroutineKind:://3; +Coroutine(_)=>"coroutine",},None=>"closure",};let _=();((),());let mut err=self. +cannot_capture_in_long_lived_closure(args_span,kind ,captured_var,var_span,scope +,);((),());((),());*&*&();((),());err.span_suggestion_verbose(sugg_span,format!( +"to force the {kind} to take ownership of {captured_var} (and any \ other referenced variables), use the `move` keyword" - ), - suggestion, - Applicability::MachineApplicable, - ); - - match category { - ConstraintCategory::Return(_) | ConstraintCategory::OpaqueType => { - let msg = format!("{kind} is returned here"); - err.span_note(constraint_span, msg); - } - ConstraintCategory::CallArgument(_) => { - fr_name.highlight_region_name(&mut err); - if matches!( - use_span.coroutine_kind(), - Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) - ) { - err.note( - "async blocks are not executed immediately and must either take a \ - reference or ownership of outside variables they use", - ); - } else { - let msg = format!("{scope} requires argument type to outlive `{fr_name}`"); - err.span_note(constraint_span, msg); - } - } - _ => bug!( - "report_escaping_closure_capture called with unexpected constraint \ - category: `{:?}`", - category - ), - } - - err - } - - fn report_escaping_data( - &self, - borrow_span: Span, - name: &Option, - upvar_span: Span, - upvar_name: Symbol, - escape_span: Span, - ) -> Diag<'tcx> { - let tcx = self.infcx.tcx; - - let escapes_from = tcx.def_descr(self.mir_def_id().to_def_id()); - - let mut err = - borrowck_errors::borrowed_data_escapes_closure(tcx, escape_span, escapes_from); - - err.span_label( - upvar_span, - format!("`{upvar_name}` declared here, outside of the {escapes_from} body"), - ); - - err.span_label(borrow_span, format!("borrow is only valid in the {escapes_from} body")); - - if let Some(name) = name { - err.span_label( - escape_span, - format!("reference to `{name}` escapes the {escapes_from} body here"), - ); - } else { - err.span_label(escape_span, format!("reference escapes the {escapes_from} body here")); - } - - err - } - - fn get_moved_indexes( - &self, - location: Location, - mpi: MovePathIndex, - ) -> (Vec, Vec) { - fn predecessor_locations<'tcx, 'a>( - body: &'a mir::Body<'tcx>, - location: Location, - ) -> impl Iterator + Captures<'tcx> + 'a { - if location.statement_index == 0 { - let predecessors = body.basic_blocks.predecessors()[location.block].to_vec(); - Either::Left(predecessors.into_iter().map(move |bb| body.terminator_loc(bb))) - } else { - Either::Right(std::iter::once(Location { - statement_index: location.statement_index - 1, - ..location - })) - } - } - - let mut mpis = vec![mpi]; - let move_paths = &self.move_data.move_paths; - mpis.extend(move_paths[mpi].parents(move_paths).map(|(mpi, _)| mpi)); - - let mut stack = Vec::new(); - let mut back_edge_stack = Vec::new(); - - predecessor_locations(self.body, location).for_each(|predecessor| { - if location.dominates(predecessor, self.dominators()) { - back_edge_stack.push(predecessor) - } else { - stack.push(predecessor); - } - }); - - let mut reached_start = false; - - /* Check if the mpi is initialized as an argument */ - let mut is_argument = false; - for arg in self.body.args_iter() { - if let Some(path) = self.move_data.rev_lookup.find_local(arg) { - if mpis.contains(&path) { - is_argument = true; - } - } - } - - let mut visited = FxIndexSet::default(); - let mut move_locations = FxIndexSet::default(); - let mut reinits = vec![]; - let mut result = vec![]; - - let mut dfs_iter = |result: &mut Vec, location: Location, is_back_edge: bool| { - debug!( - "report_use_of_moved_or_uninitialized: (current_location={:?}, back_edge={})", - location, is_back_edge - ); - - if !visited.insert(location) { - return true; - } - - // check for moves - let stmt_kind = - self.body[location.block].statements.get(location.statement_index).map(|s| &s.kind); - if let Some(StatementKind::StorageDead(..)) = stmt_kind { - // this analysis only tries to find moves explicitly - // written by the user, so we ignore the move-outs - // created by `StorageDead` and at the beginning - // of a function. - } else { - // If we are found a use of a.b.c which was in error, then we want to look for - // moves not only of a.b.c but also a.b and a. - // - // Note that the moves data already includes "parent" paths, so we don't have to - // worry about the other case: that is, if there is a move of a.b.c, it is already - // marked as a move of a.b and a as well, so we will generate the correct errors - // there. - for moi in &self.move_data.loc_map[location] { - debug!("report_use_of_moved_or_uninitialized: moi={:?}", moi); - let path = self.move_data.moves[*moi].path; - if mpis.contains(&path) { - debug!( - "report_use_of_moved_or_uninitialized: found {:?}", - move_paths[path].place - ); - result.push(MoveSite { moi: *moi, traversed_back_edge: is_back_edge }); - move_locations.insert(location); - - // Strictly speaking, we could continue our DFS here. There may be - // other moves that can reach the point of error. But it is kind of - // confusing to highlight them. - // - // Example: - // - // ``` - // let a = vec![]; - // let b = a; - // let c = a; - // drop(a); // <-- current point of error - // ``` - // - // Because we stop the DFS here, we only highlight `let c = a`, - // and not `let b = a`. We will of course also report an error at - // `let c = a` which highlights `let b = a` as the move. - return true; - } - } - } - - // check for inits - let mut any_match = false; - for ii in &self.move_data.init_loc_map[location] { - let init = self.move_data.inits[*ii]; - match init.kind { - InitKind::Deep | InitKind::NonPanicPathOnly => { - if mpis.contains(&init.path) { - any_match = true; - } - } - InitKind::Shallow => { - if mpi == init.path { - any_match = true; - } - } - } - } - if any_match { - reinits.push(location); - return true; - } - return false; - }; - - while let Some(location) = stack.pop() { - if dfs_iter(&mut result, location, false) { - continue; - } - - let mut has_predecessor = false; - predecessor_locations(self.body, location).for_each(|predecessor| { - if location.dominates(predecessor, self.dominators()) { - back_edge_stack.push(predecessor) - } else { - stack.push(predecessor); - } - has_predecessor = true; - }); - - if !has_predecessor { - reached_start = true; - } - } - if (is_argument || !reached_start) && result.is_empty() { - /* Process back edges (moves in future loop iterations) only if - the move path is definitely initialized upon loop entry, - to avoid spurious "in previous iteration" errors. - During DFS, if there's a path from the error back to the start - of the function with no intervening init or move, then the - move path may be uninitialized at loop entry. - */ - while let Some(location) = back_edge_stack.pop() { - if dfs_iter(&mut result, location, true) { - continue; - } - - predecessor_locations(self.body, location) - .for_each(|predecessor| back_edge_stack.push(predecessor)); - } - } - - // Check if we can reach these reinits from a move location. - let reinits_reachable = reinits - .into_iter() - .filter(|reinit| { - let mut visited = FxIndexSet::default(); - let mut stack = vec![*reinit]; - while let Some(location) = stack.pop() { - if !visited.insert(location) { - continue; - } - if move_locations.contains(&location) { - return true; - } - stack.extend(predecessor_locations(self.body, location)); - } - false - }) - .collect::>(); - (result, reinits_reachable) - } - - pub(crate) fn report_illegal_mutation_of_borrowed( - &mut self, - location: Location, - (place, span): (Place<'tcx>, Span), - loan: &BorrowData<'tcx>, - ) { - let loan_spans = self.retrieve_borrow_spans(loan); - let loan_span = loan_spans.args_or_use(); - - let descr_place = self.describe_any_place(place.as_ref()); - if loan.kind == BorrowKind::Fake { - if let Some(section) = self.classify_immutable_section(loan.assigned_place) { - let mut err = self.cannot_mutate_in_immutable_section( - span, - loan_span, - &descr_place, - section, - "assign", - ); - - loan_spans.var_subdiag(self.dcx(), &mut err, Some(loan.kind), |kind, var_span| { - use crate::session_diagnostics::CaptureVarCause::*; - match kind { - hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span }, - hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { - BorrowUseInClosure { var_span } - } - } - }); - - self.buffer_error(err); - - return; - } - } - - let mut err = self.cannot_assign_to_borrowed(span, loan_span, &descr_place); - - loan_spans.var_subdiag(self.dcx(), &mut err, Some(loan.kind), |kind, var_span| { - use crate::session_diagnostics::CaptureVarCause::*; - match kind { - hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span }, - hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { - BorrowUseInClosure { var_span } - } - } - }); - - self.explain_why_borrow_contains_point(location, loan, None).add_explanation_to_diagnostic( - self.infcx.tcx, - self.body, - &self.local_names, - &mut err, - "", - None, - None, - ); - - self.explain_deref_coercion(loan, &mut err); - - self.buffer_error(err); - } - - fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut Diag<'_>) { - let tcx = self.infcx.tcx; - if let ( - Some(Terminator { - kind: TerminatorKind::Call { call_source: CallSource::OverloadedOperator, .. }, - .. - }), - Some((method_did, method_args)), - ) = ( - &self.body[loan.reserve_location.block].terminator, - rustc_middle::util::find_self_call( - tcx, - self.body, - loan.assigned_place.local, - loan.reserve_location.block, - ), - ) { - if tcx.is_diagnostic_item(sym::deref_method, method_did) { - let deref_target = - tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| { - Instance::resolve(tcx, self.param_env, deref_target, method_args) - .transpose() - }); - if let Some(Ok(instance)) = deref_target { - let deref_target_ty = instance.ty(tcx, self.param_env); - err.note(format!("borrow occurs due to deref coercion to `{deref_target_ty}`")); - err.span_note(tcx.def_span(instance.def_id()), "deref defined here"); - } - } - } - } - - /// Reports an illegal reassignment; for example, an assignment to - /// (part of) a non-`mut` local that occurs potentially after that - /// local has already been initialized. `place` is the path being - /// assigned; `err_place` is a place providing a reason why - /// `place` is not mutable (e.g., the non-`mut` local `x` in an - /// assignment to `x.f`). - pub(crate) fn report_illegal_reassignment( - &mut self, - (place, span): (Place<'tcx>, Span), - assigned_span: Span, - err_place: Place<'tcx>, - ) { - let (from_arg, local_decl, local_name) = match err_place.as_local() { - Some(local) => ( - self.body.local_kind(local) == LocalKind::Arg, - Some(&self.body.local_decls[local]), - self.local_names[local], - ), - None => (false, None, None), - }; - - // If root local is initialized immediately (everything apart from let - // PATTERN;) then make the error refer to that local, rather than the - // place being assigned later. - let (place_description, assigned_span) = match local_decl { - Some(LocalDecl { - local_info: - ClearCrossCrate::Set( - box LocalInfo::User(BindingForm::Var(VarBindingForm { - opt_match_place: None, - .. - })) - | box LocalInfo::StaticRef { .. } - | box LocalInfo::Boring, - ), - .. - }) - | None => (self.describe_any_place(place.as_ref()), assigned_span), - Some(decl) => (self.describe_any_place(err_place.as_ref()), decl.source_info.span), - }; - - let mut err = self.cannot_reassign_immutable(span, &place_description, from_arg); - let msg = if from_arg { - "cannot assign to immutable argument" - } else { - "cannot assign twice to immutable variable" - }; - if span != assigned_span && !from_arg { - err.span_label(assigned_span, format!("first assignment to {place_description}")); - } - if let Some(decl) = local_decl - && let Some(name) = local_name - && decl.can_be_made_mutable() - { - err.span_suggestion( - decl.source_info.span, - "consider making this binding mutable", - format!("mut {name}"), - Applicability::MachineApplicable, - ); - } - err.span_label(span, msg); - self.buffer_error(err); - } - - fn classify_drop_access_kind(&self, place: PlaceRef<'tcx>) -> StorageDeadOrDrop<'tcx> { - let tcx = self.infcx.tcx; - let (kind, _place_ty) = place.projection.iter().fold( - (LocalStorageDead, PlaceTy::from_ty(self.body.local_decls[place.local].ty)), - |(kind, place_ty), &elem| { - ( - match elem { - ProjectionElem::Deref => match kind { - StorageDeadOrDrop::LocalStorageDead - | StorageDeadOrDrop::BoxedStorageDead => { - assert!( - place_ty.ty.is_box(), - "Drop of value behind a reference or raw pointer" - ); - StorageDeadOrDrop::BoxedStorageDead - } - StorageDeadOrDrop::Destructor(_) => kind, - }, - 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 - match kind { - StorageDeadOrDrop::Destructor(_) => kind, - StorageDeadOrDrop::LocalStorageDead - | StorageDeadOrDrop::BoxedStorageDead => { - StorageDeadOrDrop::Destructor(place_ty.ty) - } - } - } - _ => kind, - } - } - ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. } - | ProjectionElem::Subtype(_) - | ProjectionElem::Index(_) => kind, - }, - place_ty.projection_ty(tcx, elem), - ) - }, - ); - kind - } - - /// Describe the reason for the fake borrow that was assigned to `place`. - fn classify_immutable_section(&self, place: Place<'tcx>) -> Option<&'static str> { - use rustc_middle::mir::visit::Visitor; - struct FakeReadCauseFinder<'tcx> { - place: Place<'tcx>, - cause: Option, - } - impl<'tcx> Visitor<'tcx> for FakeReadCauseFinder<'tcx> { - fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) { - match statement { - Statement { kind: StatementKind::FakeRead(box (cause, place)), .. } - if *place == self.place => - { - self.cause = Some(*cause); - } - _ => (), - } - } - } - let mut visitor = FakeReadCauseFinder { place, cause: None }; - visitor.visit_body(self.body); - match visitor.cause { - Some(FakeReadCause::ForMatchGuard) => Some("match guard"), - Some(FakeReadCause::ForIndex) => Some("indexing expression"), - _ => None, - } - } - - /// Annotate argument and return type of function and closure with (synthesized) lifetime for - /// borrow of local value that does not live long enough. - fn annotate_argument_and_return_for_borrow( - &self, - borrow: &BorrowData<'tcx>, - ) -> Option> { - // Define a fallback for when we can't match a closure. - let fallback = || { - let is_closure = self.infcx.tcx.is_closure_like(self.mir_def_id().to_def_id()); - if is_closure { - None - } else { - let ty = self.infcx.tcx.type_of(self.mir_def_id()).instantiate_identity(); - match ty.kind() { - ty::FnDef(_, _) | ty::FnPtr(_) => self.annotate_fn_sig( - self.mir_def_id(), - self.infcx.tcx.fn_sig(self.mir_def_id()).instantiate_identity(), - ), - _ => None, - } - } - }; - - // In order to determine whether we need to annotate, we need to check whether the reserve - // place was an assignment into a temporary. - // - // If it was, we check whether or not that temporary is eventually assigned into the return - // place. If it was, we can add annotations about the function's return type and arguments - // and it'll make sense. - let location = borrow.reserve_location; - debug!("annotate_argument_and_return_for_borrow: location={:?}", location); - if let Some(Statement { kind: StatementKind::Assign(box (reservation, _)), .. }) = - &self.body[location.block].statements.get(location.statement_index) - { - debug!("annotate_argument_and_return_for_borrow: reservation={:?}", reservation); - // Check that the initial assignment of the reserve location is into a temporary. - let mut target = match reservation.as_local() { - Some(local) if self.body.local_kind(local) == LocalKind::Temp => local, - _ => return None, - }; - - // Next, look through the rest of the block, checking if we are assigning the - // `target` (that is, the place that contains our borrow) to anything. - let mut annotated_closure = None; - for stmt in &self.body[location.block].statements[location.statement_index + 1..] { - debug!( - "annotate_argument_and_return_for_borrow: target={:?} stmt={:?}", - target, stmt - ); - if let StatementKind::Assign(box (place, rvalue)) = &stmt.kind { - if let Some(assigned_to) = place.as_local() { - debug!( - "annotate_argument_and_return_for_borrow: assigned_to={:?} \ - rvalue={:?}", - assigned_to, rvalue - ); - // Check if our `target` was captured by a closure. - if let Rvalue::Aggregate( - box AggregateKind::Closure(def_id, args), - operands, - ) = rvalue - { - let def_id = def_id.expect_local(); - for operand in operands { - let (Operand::Copy(assigned_from) | Operand::Move(assigned_from)) = - operand - else { - continue; - }; - debug!( - "annotate_argument_and_return_for_borrow: assigned_from={:?}", - assigned_from - ); - - // Find the local from the operand. - let Some(assigned_from_local) = - assigned_from.local_or_deref_local() - else { - continue; - }; - - if assigned_from_local != target { - continue; - } - - // If a closure captured our `target` and then assigned - // into a place then we should annotate the closure in - // case it ends up being assigned into the return place. - annotated_closure = - self.annotate_fn_sig(def_id, args.as_closure().sig()); - debug!( - "annotate_argument_and_return_for_borrow: \ +),suggestion,Applicability::MachineApplicable,);((),());let _=();match category{ +ConstraintCategory::Return(_)|ConstraintCategory::OpaqueType=>{;let msg=format!( +"{kind} is returned here");{();};{();};err.span_note(constraint_span,msg);({});} +ConstraintCategory::CallArgument(_)=>{;fr_name.highlight_region_name(&mut err);; +if matches!(use_span.coroutine_kind(),Some(CoroutineKind::Desugared(//if true{}; +CoroutineDesugaring::Async,_))){let _=();if true{};if true{};if true{};err.note( +"async blocks are not executed immediately and must either take a \ + reference or ownership of outside variables they use" +,);if let _=(){};if let _=(){};}else{loop{break;};if let _=(){};let msg=format!( +"{scope} requires argument type to outlive `{fr_name}`");({});{;};err.span_note( +constraint_span,msg);loop{break};loop{break};loop{break};loop{break;};}}_=>bug!( +"report_escaping_closure_capture called with unexpected constraint \ + category: `{:?}`" +,category),}err}fn report_escaping_data(&self,borrow_span:Span,name:&Option,upvar_span:Span,upvar_name:Symbol,escape_span:Span,)->Diag<'tcx>{{;};let +tcx=self.infcx.tcx;;let escapes_from=tcx.def_descr(self.mir_def_id().to_def_id() +);3;;let mut err=borrowck_errors::borrowed_data_escapes_closure(tcx,escape_span, +escapes_from);((),());((),());((),());((),());err.span_label(upvar_span,format!( +"`{upvar_name}` declared here, outside of the {escapes_from} body"),);();();err. +span_label(borrow_span,format!(//let _=||();loop{break};loop{break};loop{break}; +"borrow is only valid in the {escapes_from} body"));;if let Some(name)=name{err. +span_label(escape_span,format!(//let _=||();loop{break};loop{break};loop{break}; +"reference to `{name}` escapes the {escapes_from} body here"),);();}else{();err. +span_label(escape_span, format!("reference escapes the {escapes_from} body here" +));;}err}fn get_moved_indexes(&self,location:Location,mpi:MovePathIndex,)->(Vec< +MoveSite>,Vec){3;fn predecessor_locations<'tcx,'a>(body:&'a mir::Body< +'tcx>,location:Location,)->impl Iterator+Captures<'tcx>+'a{if //; +location.statement_index==0{3;let predecessors=body.basic_blocks.predecessors()[ +location.block].to_vec();;Either::Left(predecessors.into_iter().map(move|bb|body +.terminator_loc(bb)))}else{Either::Right(std::iter::once(Location{//loop{break}; +statement_index:location.statement_index-1,..location}))}};let mut mpis=vec![mpi +];;let move_paths=&self.move_data.move_paths;mpis.extend(move_paths[mpi].parents +(move_paths).map(|(mpi,_)|mpi));{;};{;};let mut stack=Vec::new();{;};{;};let mut +back_edge_stack=Vec::new();;predecessor_locations(self.body,location).for_each(| +predecessor|{if ((((location.dominates(predecessor,(((self.dominators())))))))){ +back_edge_stack.push(predecessor)}else{3;stack.push(predecessor);3;}});;;let mut +reached_start=false;;let mut is_argument=false;for arg in self.body.args_iter(){ +if let Some(path)=(self.move_data.rev_lookup.find_local(arg)){if mpis.contains(& +path){3;is_argument=true;3;}}}3;let mut visited=FxIndexSet::default();3;;let mut +move_locations=FxIndexSet::default();;let mut reinits=vec![];let mut result=vec! +[];;;let mut dfs_iter=|result:&mut Vec,location:Location,is_back_edge: +bool|{((),());((),());((),());let _=();((),());let _=();((),());let _=();debug!( +"report_use_of_moved_or_uninitialized: (current_location={:?}, back_edge={})",// +location,is_back_edge);;if!visited.insert(location){;return true;}let stmt_kind= +self.body[location.block].statements.get(location.statement_index).map(|s|&s.//; +kind);();if let Some(StatementKind::StorageDead(..))=stmt_kind{}else{for moi in& +self.move_data.loc_map[location]{if true{};if true{};if true{};if true{};debug!( +"report_use_of_moved_or_uninitialized: moi={:?}",moi);;;let path=self.move_data. +moves[*moi].path;((),());((),());if mpis.contains(&path){((),());((),());debug!( +"report_use_of_moved_or_uninitialized: found {:?}",move_paths[path].place);();3; +result.push(MoveSite{moi:*moi,traversed_back_edge:is_back_edge});;move_locations +.insert(location);3;3;return true;3;}}};let mut any_match=false;;for ii in&self. +move_data.init_loc_map[location]{;let init=self.move_data.inits[*ii];match init. +kind{InitKind::Deep|InitKind::NonPanicPathOnly=>{if mpis.contains(&init.path){3; +any_match=true;3;}}InitKind::Shallow=>{if mpi==init.path{;any_match=true;;}}}}if +any_match{;reinits.push(location);;;return true;;}return false;};while let Some( +location)=stack.pop(){if dfs_iter(&mut result,location,false){;continue;}let mut +has_predecessor=false;();();predecessor_locations(self.body,location).for_each(| +predecessor|{if ((((location.dominates(predecessor,(((self.dominators())))))))){ +back_edge_stack.push(predecessor)}else{;stack.push(predecessor);}has_predecessor +=true;;});if!has_predecessor{reached_start=true;}}if(is_argument||!reached_start +)&&result.is_empty(){while let Some(location)=back_edge_stack.pop(){if dfs_iter +(&mut result,location,true){;continue;}predecessor_locations(self.body,location) +.for_each(|predecessor|back_edge_stack.push(predecessor));let _=();}}((),());let +reinits_reachable=reinits.into_iter().filter(|reinit|{if true{};let mut visited= +FxIndexSet::default();3;3;let mut stack=vec![*reinit];;while let Some(location)= +stack.pop(){if!visited.insert(location){;continue;;}if move_locations.contains(& +location){;return true;}stack.extend(predecessor_locations(self.body,location)); +}false}).collect::>();({});(result,reinits_reachable)}pub(crate)fn +report_illegal_mutation_of_borrowed(&mut self,location:Location,(place,span):(// +Place<'tcx>,Span),loan:&BorrowData<'tcx>,){((),());let _=();let loan_spans=self. +retrieve_borrow_spans(loan);();();let loan_span=loan_spans.args_or_use();3;3;let +descr_place=self.describe_any_place(place.as_ref());3;if loan.kind==BorrowKind:: +Fake{if let Some(section)=self.classify_immutable_section(loan.assigned_place){; +let mut err=self. cannot_mutate_in_immutable_section(span,loan_span,&descr_place +,section,"assign",);;loan_spans.var_subdiag(self.dcx(),&mut err,Some(loan.kind), +|kind,var_span|{;use crate::session_diagnostics::CaptureVarCause::*;;match kind{ +hir::ClosureKind::Coroutine(_)=> BorrowUseInCoroutine{var_span},hir::ClosureKind +::Closure|hir::ClosureKind::CoroutineClosure(_ )=>{BorrowUseInClosure{var_span}} +}});;self.buffer_error(err);return;}}let mut err=self.cannot_assign_to_borrowed( +span,loan_span,&descr_place);3;;loan_spans.var_subdiag(self.dcx(),&mut err,Some( +loan.kind),|kind,var_span|{;use crate::session_diagnostics::CaptureVarCause::*;; +match kind{hir::ClosureKind::Coroutine(_ )=>BorrowUseInCoroutine{var_span},hir:: +ClosureKind::Closure|hir::ClosureKind:: CoroutineClosure(_)=>{BorrowUseInClosure +{var_span}}}});();();self.explain_why_borrow_contains_point(location,loan,None). +add_explanation_to_diagnostic(self.infcx.tcx,self.body ,(&self.local_names),&mut +err,"",None,None,);;self.explain_deref_coercion(loan,&mut err);self.buffer_error +(err);;}fn explain_deref_coercion(&mut self,loan:&BorrowData<'tcx>,err:&mut Diag +<'_>){;let tcx=self.infcx.tcx;;if let(Some(Terminator{kind:TerminatorKind::Call{ +call_source:CallSource::OverloadedOperator,..},..}),Some((method_did,//let _=(); +method_args)),)=((((&(((self.body[loan.reserve_location.block]))).terminator))), +rustc_middle::util::find_self_call(tcx,self .body,loan.assigned_place.local,loan +.reserve_location.block,),){if tcx.is_diagnostic_item(sym::deref_method,//{();}; +method_did){((),());let deref_target=tcx.get_diagnostic_item(sym::deref_target). +and_then(|deref_target|{Instance::resolve(tcx,self.param_env,deref_target,//{;}; +method_args).transpose()});{();};if let Some(Ok(instance))=deref_target{({});let +deref_target_ty=instance.ty(tcx,self.param_env);((),());*&*&();err.note(format!( +"borrow occurs due to deref coercion to `{deref_target_ty}`"));3;;err.span_note( +tcx.def_span(instance.def_id()),"deref defined here");if true{};}}}}pub(crate)fn +report_illegal_reassignment(&mut self,(place,span):(Place<'tcx>,Span),//((),()); +assigned_span:Span,err_place:Place<'tcx>,){;let(from_arg,local_decl,local_name)= +match err_place.as_local(){Some(local)=> (self.body.local_kind(local)==LocalKind +::Arg,(Some((&self.body.local_decls[local]) )),self.local_names[local],),None=>( +false,None,None),};;;let(place_description,assigned_span)=match local_decl{Some( +LocalDecl{local_info:ClearCrossCrate::Set(box LocalInfo::User(BindingForm::Var( +VarBindingForm{opt_match_place:None,..}))|box LocalInfo::StaticRef{..}|box//{;}; +LocalInfo::Boring,),..})|None=>(((self.describe_any_place(((place.as_ref()))))), +assigned_span),Some(decl)=>((self. describe_any_place(err_place.as_ref())),decl. +source_info.span),};{();};({});let mut err=self.cannot_reassign_immutable(span,& +place_description,from_arg);((),());((),());((),());((),());let msg=if from_arg{ +"cannot assign to immutable argument"}else{//((),());let _=();let _=();let _=(); +"cannot assign twice to immutable variable"};;if span!=assigned_span&&!from_arg{ +err.span_label(assigned_span, format!("first assignment to {place_description}") +);*&*&();((),());}if let Some(decl)=local_decl&&let Some(name)=local_name&&decl. +can_be_made_mutable(){((),());((),());err.span_suggestion(decl.source_info.span, +"consider making this binding mutable",((format!("mut {name}"))),Applicability:: +MachineApplicable,);3;}3;err.span_label(span,msg);3;;self.buffer_error(err);;}fn +classify_drop_access_kind(&self,place:PlaceRef<'tcx>)->StorageDeadOrDrop<'tcx>{; +let tcx=self.infcx.tcx;{;};();let(kind,_place_ty)=place.projection.iter().fold(( +LocalStorageDead,(PlaceTy::from_ty((self.body.local_decls[place.local]).ty))),|( +kind,place_ty),&elem|{(match elem{ProjectionElem::Deref=>match kind{//if true{}; +StorageDeadOrDrop::LocalStorageDead|StorageDeadOrDrop::BoxedStorageDead=>{{();}; +assert!(place_ty.ty .is_box(),"Drop of value behind a reference or raw pointer") +;3;StorageDeadOrDrop::BoxedStorageDead}StorageDeadOrDrop::Destructor(_)=>kind,}, +ProjectionElem::OpaqueCast{..}|ProjectionElem::Field(..)|ProjectionElem:://({}); +Downcast(..)=>{match (place_ty.ty.kind()){ty ::Adt(def,_)if def.has_dtor(tcx)=>{ +match kind{StorageDeadOrDrop::Destructor(_)=>kind,StorageDeadOrDrop:://let _=(); +LocalStorageDead|StorageDeadOrDrop::BoxedStorageDead=>{StorageDeadOrDrop:://{;}; +Destructor(place_ty.ty)}}}_=>kind,}}ProjectionElem::ConstantIndex{..}|//((),()); +ProjectionElem::Subslice{..}|ProjectionElem:: Subtype(_)|ProjectionElem::Index(_ +)=>kind,},place_ty.projection_ty(tcx,elem),)},);loop{break};loop{break;};kind}fn +classify_immutable_section(&self,place:Place<'tcx>)->Option<&'static str>{();use +rustc_middle::mir::visit::Visitor;;struct FakeReadCauseFinder<'tcx>{place:Place< +'tcx>,cause:Option,}if true{};let _=();impl<'tcx>Visitor<'tcx>for +FakeReadCauseFinder<'tcx>{fn visit_statement(&mut self,statement:&Statement,_:Location){match statement{Statement{kind:StatementKind::FakeRead(box(//; +cause,place)),..}if*place==self.place=>{;self.cause=Some(*cause);;}_=>(),}}};let +mut visitor=FakeReadCauseFinder{place,cause:None};;visitor.visit_body(self.body) +;();match visitor.cause{Some(FakeReadCause::ForMatchGuard)=>Some("match guard"), +Some(FakeReadCause::ForIndex)=>((Some((( "indexing expression"))))),_=>None,}}fn +annotate_argument_and_return_for_borrow(&self,borrow:&BorrowData<'tcx>,)->//{;}; +Option>{3;let fallback=||{;let is_closure=self. +infcx.tcx.is_closure_like(self.mir_def_id().to_def_id());{;};if is_closure{None} +else{3;let ty=self.infcx.tcx.type_of(self.mir_def_id()).instantiate_identity();; +match ((((ty.kind())))){ty::FnDef(_,_ )|ty::FnPtr(_)=>self.annotate_fn_sig(self. +mir_def_id(),self.infcx.tcx.fn_sig( self.mir_def_id()).instantiate_identity(),), +_=>None,}}};{();};{();};let location=borrow.reserve_location;{();};{();};debug!( +"annotate_argument_and_return_for_borrow: location={:?}",location);;if let Some( +Statement{kind:StatementKind::Assign(box(reservation,_)),..})=&self.body[//({}); +location.block].statements.get(location.statement_index){((),());((),());debug!( +"annotate_argument_and_return_for_borrow: reservation={:?}",reservation);3;3;let +mut target=match ((reservation.as_local())){ Some(local)if self.body.local_kind( +local)==LocalKind::Temp=>local,_=>return None,};;let mut annotated_closure=None; +for stmt in&self.body[location.block].statements[location.statement_index+1..]{; +debug!( "annotate_argument_and_return_for_borrow: target={:?} stmt={:?}",target, +stmt);();if let StatementKind::Assign(box(place,rvalue))=&stmt.kind{if let Some( +assigned_to)=place.as_local(){if true{};let _=||();let _=||();let _=||();debug!( +"annotate_argument_and_return_for_borrow: assigned_to={:?} \ + rvalue={:?}" +,assigned_to,rvalue);;if let Rvalue::Aggregate(box AggregateKind::Closure(def_id +,args),operands,)=rvalue{{;};let def_id=def_id.expect_local();{;};for operand in +operands{;let(Operand::Copy(assigned_from)|Operand::Move(assigned_from))=operand +else{*&*&();((),());continue;if let _=(){};};if let _=(){};if let _=(){};debug!( +"annotate_argument_and_return_for_borrow: assigned_from={:?}",assigned_from);3;; +let Some(assigned_from_local)=assigned_from.local_or_deref_local()else{;continue +;();};();if assigned_from_local!=target{();continue;3;}3;annotated_closure=self. +annotate_fn_sig(def_id,args.as_closure().sig());loop{break;};loop{break};debug!( +"annotate_argument_and_return_for_borrow: \ annotated_closure={:?} assigned_from_local={:?} \ - assigned_to={:?}", - annotated_closure, assigned_from_local, assigned_to - ); - - if assigned_to == mir::RETURN_PLACE { - // If it was assigned directly into the return place, then - // return now. - return annotated_closure; - } else { - // Otherwise, update the target. - target = assigned_to; - } - } - - // If none of our closure's operands matched, then skip to the next - // statement. - continue; - } - - // Otherwise, look at other types of assignment. - let assigned_from = match rvalue { - Rvalue::Ref(_, _, assigned_from) => assigned_from, - Rvalue::Use(operand) => match operand { - Operand::Copy(assigned_from) | Operand::Move(assigned_from) => { - assigned_from - } - _ => continue, - }, - _ => continue, - }; - debug!( - "annotate_argument_and_return_for_borrow: \ - assigned_from={:?}", - assigned_from, - ); - - // Find the local from the rvalue. - let Some(assigned_from_local) = assigned_from.local_or_deref_local() else { - continue; - }; - debug!( - "annotate_argument_and_return_for_borrow: \ - assigned_from_local={:?}", - assigned_from_local, - ); - - // Check if our local matches the target - if so, we've assigned our - // borrow to a new place. - if assigned_from_local != target { - continue; - } - - // If we assigned our `target` into a new place, then we should - // check if it was the return place. - debug!( - "annotate_argument_and_return_for_borrow: \ - assigned_from_local={:?} assigned_to={:?}", - assigned_from_local, assigned_to - ); - if assigned_to == mir::RETURN_PLACE { - // If it was then return the annotated closure if there was one, - // else, annotate this function. - return annotated_closure.or_else(fallback); - } - - // If we didn't assign into the return place, then we just update - // the target. - target = assigned_to; - } - } - } - - // Check the terminator if we didn't find anything in the statements. - let terminator = &self.body[location.block].terminator(); - debug!( - "annotate_argument_and_return_for_borrow: target={:?} terminator={:?}", - target, terminator - ); - if let TerminatorKind::Call { destination, target: Some(_), args, .. } = - &terminator.kind - { - if let Some(assigned_to) = destination.as_local() { - debug!( - "annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}", - assigned_to, args - ); - for operand in args { - let (Operand::Copy(assigned_from) | Operand::Move(assigned_from)) = - &operand.node - else { - continue; - }; - debug!( - "annotate_argument_and_return_for_borrow: assigned_from={:?}", - assigned_from, - ); - - if let Some(assigned_from_local) = assigned_from.local_or_deref_local() { - debug!( - "annotate_argument_and_return_for_borrow: assigned_from_local={:?}", - assigned_from_local, - ); - - if assigned_to == mir::RETURN_PLACE && assigned_from_local == target { - return annotated_closure.or_else(fallback); - } - } - } - } - } - } - - // If we haven't found an assignment into the return place, then we need not add - // any annotations. - debug!("annotate_argument_and_return_for_borrow: none found"); - None - } - - /// Annotate the first argument and return type of a function signature if they are - /// references. - fn annotate_fn_sig( - &self, - did: LocalDefId, - sig: ty::PolyFnSig<'tcx>, - ) -> Option> { - debug!("annotate_fn_sig: did={:?} sig={:?}", did, sig); - let is_closure = self.infcx.tcx.is_closure_like(did.to_def_id()); - let fn_hir_id = self.infcx.tcx.local_def_id_to_hir_id(did); - let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(fn_hir_id)?; - - // We need to work out which arguments to highlight. We do this by looking - // at the return type, where there are three cases: - // - // 1. If there are named arguments, then we should highlight the return type and - // highlight any of the arguments that are also references with that lifetime. - // If there are no arguments that have the same lifetime as the return type, - // then don't highlight anything. - // 2. The return type is a reference with an anonymous lifetime. If this is - // the case, then we can take advantage of (and teach) the lifetime elision - // rules. - // - // We know that an error is being reported. So the arguments and return type - // must satisfy the elision rules. Therefore, if there is a single argument - // then that means the return type and first (and only) argument have the same - // lifetime and the borrow isn't meeting that, we can highlight the argument - // and return type. - // - // If there are multiple arguments then the first argument must be self (else - // it would not satisfy the elision rules), so we can highlight self and the - // return type. - // 3. The return type is not a reference. In this case, we don't highlight - // anything. - let return_ty = sig.output(); - match return_ty.skip_binder().kind() { - ty::Ref(return_region, _, _) if return_region.has_name() && !is_closure => { - // This is case 1 from above, return type is a named reference so we need to - // search for relevant arguments. - let mut arguments = Vec::new(); - for (index, argument) in sig.inputs().skip_binder().iter().enumerate() { - if let ty::Ref(argument_region, _, _) = argument.kind() { - if argument_region == return_region { - // Need to use the `rustc_middle::ty` types to compare against the - // `return_region`. Then use the `rustc_hir` type to get only - // the lifetime span. - if let hir::TyKind::Ref(lifetime, _) = &fn_decl.inputs[index].kind { - // With access to the lifetime, we can get - // the span of it. - arguments.push((*argument, lifetime.ident.span)); - } else { - bug!("ty type is a ref but hir type is not"); - } - } - } - } - - // We need to have arguments. This shouldn't happen, but it's worth checking. - if arguments.is_empty() { - return None; - } - - // We use a mix of the HIR and the Ty types to get information - // as the HIR doesn't have full types for closure arguments. - let return_ty = sig.output().skip_binder(); - let mut return_span = fn_decl.output.span(); - if let hir::FnRetTy::Return(ty) = &fn_decl.output { - if let hir::TyKind::Ref(lifetime, _) = ty.kind { - return_span = lifetime.ident.span; - } - } - - Some(AnnotatedBorrowFnSignature::NamedFunction { - arguments, - return_ty, - return_span, - }) - } - ty::Ref(_, _, _) if is_closure => { - // This is case 2 from above but only for closures, return type is anonymous - // reference so we select - // the first argument. - let argument_span = fn_decl.inputs.first()?.span; - let argument_ty = sig.inputs().skip_binder().first()?; - - // Closure arguments are wrapped in a tuple, so we need to get the first - // from that. - if let ty::Tuple(elems) = argument_ty.kind() { - let &argument_ty = elems.first()?; - if let ty::Ref(_, _, _) = argument_ty.kind() { - return Some(AnnotatedBorrowFnSignature::Closure { - argument_ty, - argument_span, - }); - } - } - - None - } - ty::Ref(_, _, _) => { - // This is also case 2 from above but for functions, return type is still an - // anonymous reference so we select the first argument. - let argument_span = fn_decl.inputs.first()?.span; - let argument_ty = *sig.inputs().skip_binder().first()?; - - let return_span = fn_decl.output.span(); - let return_ty = sig.output().skip_binder(); - - // We expect the first argument to be a reference. - match argument_ty.kind() { - ty::Ref(_, _, _) => {} - _ => return None, - } - - Some(AnnotatedBorrowFnSignature::AnonymousFunction { - argument_ty, - argument_span, - return_ty, - return_span, - }) - } - _ => { - // This is case 3 from above, return type is not a reference so don't highlight - // anything. - None - } - } - } -} - -#[derive(Debug)] -enum AnnotatedBorrowFnSignature<'tcx> { - NamedFunction { - arguments: Vec<(Ty<'tcx>, Span)>, - return_ty: Ty<'tcx>, - return_span: Span, - }, - AnonymousFunction { - argument_ty: Ty<'tcx>, - argument_span: Span, - return_ty: Ty<'tcx>, - return_span: Span, - }, - Closure { - argument_ty: Ty<'tcx>, - argument_span: Span, - }, -} - -impl<'tcx> AnnotatedBorrowFnSignature<'tcx> { - /// Annotate the provided diagnostic with information about borrow from the fn signature that - /// helps explain. - pub(crate) fn emit(&self, cx: &MirBorrowckCtxt<'_, 'tcx>, diag: &mut Diag<'_>) -> String { - match self { - &AnnotatedBorrowFnSignature::Closure { argument_ty, argument_span } => { - diag.span_label( - argument_span, - format!("has type `{}`", cx.get_name_for_ty(argument_ty, 0)), - ); - - cx.get_region_name_for_ty(argument_ty, 0) - } - &AnnotatedBorrowFnSignature::AnonymousFunction { - argument_ty, - argument_span, - return_ty, - return_span, - } => { - let argument_ty_name = cx.get_name_for_ty(argument_ty, 0); - diag.span_label(argument_span, format!("has type `{argument_ty_name}`")); - - let return_ty_name = cx.get_name_for_ty(return_ty, 0); - let types_equal = return_ty_name == argument_ty_name; - diag.span_label( - return_span, - format!( - "{}has type `{}`", - if types_equal { "also " } else { "" }, - return_ty_name, - ), - ); - - diag.note( - "argument and return type have the same lifetime due to lifetime elision rules", - ); - diag.note( - "to learn more, visit ", - ); - - cx.get_region_name_for_ty(return_ty, 0) - } - AnnotatedBorrowFnSignature::NamedFunction { arguments, return_ty, return_span } => { - // Region of return type and arguments checked to be the same earlier. - let region_name = cx.get_region_name_for_ty(*return_ty, 0); - for (_, argument_span) in arguments { - diag.span_label(*argument_span, format!("has lifetime `{region_name}`")); - } - - diag.span_label(*return_span, format!("also has lifetime `{region_name}`",)); - - diag.help(format!( - "use data from the highlighted arguments which match the `{region_name}` lifetime of \ - the return type", - )); - - region_name - } - } - } -} - -/// Detect whether one of the provided spans is a statement nested within the top-most visited expr -struct ReferencedStatementsVisitor<'a>(&'a [Span], bool); - -impl<'a, 'v> Visitor<'v> for ReferencedStatementsVisitor<'a> { - fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) { - match s.kind { - hir::StmtKind::Semi(expr) if self.0.contains(&expr.span) => { - self.1 = true; - } - _ => {} - } - } -} - -/// Look for `break` expressions within any arbitrary expressions. We'll do this to infer -/// whether this is a case where the moved value would affect the exit of a loop, making it -/// unsuitable for a `.clone()` suggestion. -struct BreakFinder { - found_breaks: Vec<(hir::Destination, Span)>, - found_continues: Vec<(hir::Destination, Span)>, -} -impl<'hir> Visitor<'hir> for BreakFinder { - fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) { - match ex.kind { - hir::ExprKind::Break(destination, _) => { - self.found_breaks.push((destination, ex.span)); - } - hir::ExprKind::Continue(destination) => { - self.found_continues.push((destination, ex.span)); - } - _ => {} - } - hir::intravisit::walk_expr(self, ex); - } -} - -/// Given a set of spans representing statements initializing the relevant binding, visit all the -/// function expressions looking for branching code paths that *do not* initialize the binding. -struct ConditionVisitor<'b> { - spans: &'b [Span], - name: &'b str, - errors: Vec<(Span, String)>, -} - -impl<'b, 'v> Visitor<'v> for ConditionVisitor<'b> { - fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { - match ex.kind { - hir::ExprKind::If(cond, body, None) => { - // `if` expressions with no `else` that initialize the binding might be missing an - // `else` arm. - let mut v = ReferencedStatementsVisitor(self.spans, false); - v.visit_expr(body); - if v.1 { - self.errors.push(( - cond.span, - format!( - "if this `if` condition is `false`, {} is not initialized", - self.name, - ), - )); - self.errors.push(( - ex.span.shrink_to_hi(), - format!("an `else` arm might be missing here, initializing {}", self.name), - )); - } - } - hir::ExprKind::If(cond, body, Some(other)) => { - // `if` expressions where the binding is only initialized in one of the two arms - // might be missing a binding initialization. - let mut a = ReferencedStatementsVisitor(self.spans, false); - a.visit_expr(body); - let mut b = ReferencedStatementsVisitor(self.spans, false); - b.visit_expr(other); - match (a.1, b.1) { - (true, true) | (false, false) => {} - (true, false) => { - if other.span.is_desugaring(DesugaringKind::WhileLoop) { - self.errors.push(( - cond.span, - format!( - "if this condition isn't met and the `while` loop runs 0 \ - times, {} is not initialized", - self.name - ), - )); - } else { - self.errors.push(( - body.span.shrink_to_hi().until(other.span), - format!( - "if the `if` condition is `false` and this `else` arm is \ - executed, {} is not initialized", - self.name - ), - )); - } - } - (false, true) => { - self.errors.push(( - cond.span, - format!( - "if this condition is `true`, {} is not initialized", - self.name - ), - )); - } - } - } - hir::ExprKind::Match(e, arms, loop_desugar) => { - // If the binding is initialized in one of the match arms, then the other match - // arms might be missing an initialization. - let results: Vec = arms - .iter() - .map(|arm| { - let mut v = ReferencedStatementsVisitor(self.spans, false); - v.visit_arm(arm); - v.1 - }) - .collect(); - if results.iter().any(|x| *x) && !results.iter().all(|x| *x) { - for (arm, seen) in arms.iter().zip(results) { - if !seen { - if loop_desugar == hir::MatchSource::ForLoopDesugar { - self.errors.push(( - e.span, - format!( - "if the `for` loop runs 0 times, {} is not initialized", - self.name - ), - )); - } else if let Some(guard) = &arm.guard { - self.errors.push(( - arm.pat.span.to(guard.span), - format!( - "if this pattern and condition are matched, {} is not \ - initialized", - self.name - ), - )); - } else { - self.errors.push(( - arm.pat.span, - format!( - "if this pattern is matched, {} is not initialized", - self.name - ), - )); - } - } - } - } - } - // FIXME: should we also account for binops, particularly `&&` and `||`? `try` should - // also be accounted for. For now it is fine, as if we don't find *any* relevant - // branching code paths, we point at the places where the binding *is* initialized for - // *some* context. - _ => {} - } - walk_expr(self, ex); - } -} + assigned_to={:?}" +,annotated_closure,assigned_from_local,assigned_to);*&*&();if assigned_to==mir:: +RETURN_PLACE{;return annotated_closure;;}else{target=assigned_to;}}continue;}let +assigned_from=match rvalue{Rvalue::Ref( _,_,assigned_from)=>assigned_from,Rvalue +::Use(operand)=>match operand{Operand::Copy(assigned_from)|Operand::Move(//({}); +assigned_from)=>{assigned_from}_=>continue,},_=>continue,};*&*&();*&*&();debug!( +"annotate_argument_and_return_for_borrow: \ + assigned_from={:?}" +,assigned_from,);if true{};let _=();let Some(assigned_from_local)=assigned_from. +local_or_deref_local()else{let _=();continue;let _=();};let _=();((),());debug!( +"annotate_argument_and_return_for_borrow: \ + assigned_from_local={:?}" +,assigned_from_local,);();if assigned_from_local!=target{3;continue;3;}3;debug!( +"annotate_argument_and_return_for_borrow: \ + assigned_from_local={:?} assigned_to={:?}" +,assigned_from_local,assigned_to);();if assigned_to==mir::RETURN_PLACE{3;return +annotated_closure.or_else(fallback);;}target=assigned_to;}}}let terminator=&self +.body[location.block].terminator();let _=();if true{};let _=();if true{};debug!( +"annotate_argument_and_return_for_borrow: target={:?} terminator={:?}",target,// +terminator);();if let TerminatorKind::Call{destination,target:Some(_),args,..}=& +terminator.kind{if let Some(assigned_to)=destination.as_local(){let _=();debug!( +"annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}",//((),()); +assigned_to,args);;for operand in args{;let(Operand::Copy(assigned_from)|Operand +::Move(assigned_from))=&operand.node else{({});continue;({});};({});({});debug!( +"annotate_argument_and_return_for_borrow: assigned_from={:?}",assigned_from,);3; +if let Some(assigned_from_local)=assigned_from.local_or_deref_local(){();debug!( +"annotate_argument_and_return_for_borrow: assigned_from_local={:?}",//if true{}; +assigned_from_local,);3;if assigned_to==mir::RETURN_PLACE&&assigned_from_local== +target{{();};return annotated_closure.or_else(fallback);{();};}}}}}}({});debug!( +"annotate_argument_and_return_for_borrow: none found");;None}fn annotate_fn_sig( +&self,did:LocalDefId,sig:ty::PolyFnSig<'tcx>,)->Option>{3;debug!("annotate_fn_sig: did={:?} sig={:?}", +did,sig);3;;let is_closure=self.infcx.tcx.is_closure_like(did.to_def_id());;;let +fn_hir_id=self.infcx.tcx.local_def_id_to_hir_id(did);;let fn_decl=self.infcx.tcx +.hir().fn_decl_by_hir_id(fn_hir_id)?;;let return_ty=sig.output();match return_ty +.skip_binder().kind(){ty::Ref(return_region,_,_)if (return_region.has_name())&&! +is_closure=>{3;let mut arguments=Vec::new();;for(index,argument)in sig.inputs(). +skip_binder().iter().enumerate(){if let ty::Ref(argument_region,_,_)=argument.// +kind(){if (argument_region==return_region){if let hir::TyKind::Ref(lifetime,_)=& +fn_decl.inputs[index].kind{3;arguments.push((*argument,lifetime.ident.span));3;} +else{;bug!("ty type is a ref but hir type is not");;}}}}if arguments.is_empty(){ +return None;3;}3;let return_ty=sig.output().skip_binder();;;let mut return_span= +fn_decl.output.span();{;};if let hir::FnRetTy::Return(ty)=&fn_decl.output{if let +hir::TyKind::Ref(lifetime,_)=ty.kind{3;return_span=lifetime.ident.span;3;}}Some( +AnnotatedBorrowFnSignature::NamedFunction{arguments,return_ty, return_span,})}ty +::Ref(_,_,_)if is_closure=>{;let argument_span=fn_decl.inputs.first()?.span;;let +argument_ty=sig.inputs().skip_binder().first()?;((),());if let ty::Tuple(elems)= +argument_ty.kind(){{;};let&argument_ty=elems.first()?;{;};if let ty::Ref(_,_,_)= +argument_ty.kind(){;return Some(AnnotatedBorrowFnSignature::Closure{argument_ty, +argument_span,});;}}None}ty::Ref(_,_,_)=>{let argument_span=fn_decl.inputs.first +()?.span;;;let argument_ty=*sig.inputs().skip_binder().first()?;let return_span= +fn_decl.output.span();{;};{;};let return_ty=sig.output().skip_binder();();match +argument_ty.kind(){ty::Ref(_,_,_)=>{}_=>(((((((((((return None))))))))))),}Some( +AnnotatedBorrowFnSignature::AnonymousFunction{argument_ty,argument_span,//{();}; +return_ty,return_span,})}_=>{None}}}}#[derive(Debug)]enum//if true{};let _=||(); +AnnotatedBorrowFnSignature<'tcx>{NamedFunction{arguments:Vec<(Ty<'tcx>,Span)>,// +return_ty:Ty<'tcx>,return_span:Span,},AnonymousFunction{argument_ty:Ty<'tcx>,//; +argument_span:Span,return_ty:Ty<'tcx>, return_span:Span,},Closure{argument_ty:Ty +<'tcx>,argument_span:Span,},}impl<'tcx>AnnotatedBorrowFnSignature<'tcx>{pub(//3; +crate)fn emit(&self,cx:&MirBorrowckCtxt<'_,'tcx>,diag:&mut Diag<'_>)->String{//; +match self{&AnnotatedBorrowFnSignature::Closure{argument_ty,argument_span}=>{(); +diag.span_label(argument_span,format!("has type `{}`",cx.get_name_for_ty(//({}); +argument_ty,0)),);if true{};if true{};cx.get_region_name_for_ty(argument_ty,0)}& +AnnotatedBorrowFnSignature::AnonymousFunction{argument_ty,argument_span,//{();}; +return_ty,return_span,}=>{;let argument_ty_name=cx.get_name_for_ty(argument_ty,0 +);;;diag.span_label(argument_span,format!("has type `{argument_ty_name}`"));;let +return_ty_name=cx.get_name_for_ty(return_ty,0);;let types_equal=return_ty_name== +argument_ty_name;{;};();diag.span_label(return_span,format!("{}has type `{}`",if +types_equal{"also "}else{""},return_ty_name,),);let _=||();let _=||();diag.note( +"argument and return type have the same lifetime due to lifetime elision rules" +,);((),());let _=();((),());let _=();((),());((),());((),());let _=();diag.note( +"to learn more, visit " +,);if true{};cx.get_region_name_for_ty(return_ty,0)}AnnotatedBorrowFnSignature:: +NamedFunction{arguments,return_ty,return_span}=>{loop{break};let region_name=cx. +get_region_name_for_ty(*return_ty,0);();for(_,argument_span)in arguments{3;diag. +span_label(*argument_span,format!("has lifetime `{region_name}`"));{;};}();diag. +span_label(*return_span,format!("also has lifetime `{region_name}`",));3;3;diag. +help(format!(//((),());((),());((),());((),());((),());((),());((),());let _=(); +"use data from the highlighted arguments which match the `{region_name}` lifetime of \ + the return type" +,));;region_name}}}}struct ReferencedStatementsVisitor<'a>(&'a[Span],bool);impl< +'a,'v>Visitor<'v>for ReferencedStatementsVisitor<'a >{fn visit_stmt(&mut self,s: +&'v hir::Stmt<'v>){match s.kind{hir::StmtKind::Semi(expr)if self.0.contains(&//; +expr.span)=>{3;self.1=true;3;}_=>{}}}}struct BreakFinder{found_breaks:Vec<(hir:: +Destination,Span)>,found_continues:Vec<(hir::Destination,Span)>,}impl<'hir>//(); +Visitor<'hir>for BreakFinder{fn visit_expr(&mut self,ex:&'hir hir::Expr<'hir>){ +match ex.kind{hir::ExprKind::Break(destination,_)=>{{;};self.found_breaks.push(( +destination,ex.span));*&*&();}hir::ExprKind::Continue(destination)=>{{();};self. +found_continues.push((destination,ex.span));;}_=>{}};hir::intravisit::walk_expr( +self,ex);;}}struct ConditionVisitor<'b>{spans:&'b[Span],name:&'b str,errors:Vec< +(Span,String)>,}impl<'b,'v>Visitor<'v>for ConditionVisitor<'b>{fn visit_expr(&// +mut self,ex:&'v hir::Expr<'v>){match ex.kind{hir::ExprKind::If(cond,body,None)// +=>{;let mut v=ReferencedStatementsVisitor(self.spans,false);;v.visit_expr(body); +if v.1{let _=();let _=();let _=();if true{};self.errors.push((cond.span,format!( +"if this `if` condition is `false`, {} is not initialized",self.name,),));;self. +errors.push((((((((((((((((((((ex.span.shrink_to_hi())))))))))))))))))),format!( +"an `else` arm might be missing here, initializing {}",self.name),));{;};}}hir:: +ExprKind::If(cond,body,Some(other))=>{{;};let mut a=ReferencedStatementsVisitor( +self.spans,false);;a.visit_expr(body);let mut b=ReferencedStatementsVisitor(self +.spans,false);;b.visit_expr(other);match(a.1,b.1){(true,true)|(false,false)=>{}( +true,false)=>{if other.span.is_desugaring(DesugaringKind::WhileLoop){{();};self. +errors.push((cond.span,format!(//let _=||();loop{break};loop{break};loop{break}; +"if this condition isn't met and the `while` loop runs 0 \ + times, {} is not initialized" +,self.name),));3;}else{3;self.errors.push((body.span.shrink_to_hi().until(other. +span),format!(//((),());((),());((),());((),());((),());((),());((),());((),()); +"if the `if` condition is `false` and this `else` arm is \ + executed, {} is not initialized" +,self.name),));{();};}}(false,true)=>{{();};self.errors.push((cond.span,format!( +"if this condition is `true`, {} is not initialized",self.name),));({});}}}hir:: +ExprKind::Match(e,arms,loop_desugar)=>{3;let results:Vec=arms.iter().map(| +arm|{;let mut v=ReferencedStatementsVisitor(self.spans,false);v.visit_arm(arm);v +.1}).collect();;if results.iter().any(|x|*x)&&!results.iter().all(|x|*x){for(arm +,seen)in (arms.iter().zip(results )){if!seen{if loop_desugar==hir::MatchSource:: +ForLoopDesugar{((),());((),());((),());((),());self.errors.push((e.span,format!( +"if the `for` loop runs 0 times, {} is not initialized",self.name),));3;}else if +let Some(guard)=&arm.guard{;self.errors.push((arm.pat.span.to(guard.span),format +!(//let _=();if true{};let _=();if true{};let _=();if true{};let _=();if true{}; +"if this pattern and condition are matched, {} is not \ + initialized" +,self.name),));if true{};}else{if true{};self.errors.push((arm.pat.span,format!( +"if this pattern is matched, {} is not initialized",self.name),));3;}}}}}_=>{}}; +walk_expr(self,ex);if let _=(){};*&*&();((),());*&*&();((),());*&*&();((),());}} diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 418eabe3ae242..56ecad872ea7a 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -1,723 +1,228 @@ -//! Print diagnostics to explain why values are borrowed. - -#![allow(rustc::diagnostic_outside_of_impl)] -#![allow(rustc::untranslatable_diagnostic)] - -use rustc_errors::{Applicability, Diag}; -use rustc_hir as hir; -use rustc_hir::intravisit::Visitor; -use rustc_index::IndexSlice; -use rustc_infer::infer::NllRegionVariableOrigin; -use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault; -use rustc_middle::mir::{ - Body, CallSource, CastKind, ConstraintCategory, FakeReadCause, Local, LocalInfo, Location, - Operand, Place, Rvalue, Statement, StatementKind, TerminatorKind, -}; -use rustc_middle::ty::adjustment::PointerCoercion; -use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt}; -use rustc_span::symbol::{kw, Symbol}; -use rustc_span::{sym, DesugaringKind, Span}; -use rustc_trait_selection::traits::error_reporting::FindExprBySpan; - -use crate::region_infer::{BlameConstraint, ExtraConstraintInfo}; -use crate::{ - borrow_set::BorrowData, nll::ConstraintDescription, region_infer::Cause, MirBorrowckCtxt, - WriteKind, -}; - -use super::{find_use, RegionName, UseSpans}; - -#[derive(Debug)] -pub(crate) enum BorrowExplanation<'tcx> { - UsedLater(LaterUseKind, Span, Option), - UsedLaterInLoop(LaterUseKind, Span, Option), - UsedLaterWhenDropped { - drop_loc: Location, - dropped_local: Local, - should_note_order: bool, - }, - MustBeValidFor { - category: ConstraintCategory<'tcx>, - from_closure: bool, - span: Span, - region_name: RegionName, - opt_place_desc: Option, - extra_info: Vec, - }, - Unexplained, -} - -#[derive(Clone, Copy, Debug)] -pub(crate) enum LaterUseKind { - TraitCapture, - ClosureCapture, - Call, - FakeLetRead, - Other, -} - -impl<'tcx> BorrowExplanation<'tcx> { - pub(crate) fn is_explained(&self) -> bool { - !matches!(self, BorrowExplanation::Unexplained) - } - pub(crate) fn add_explanation_to_diagnostic( - &self, - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - local_names: &IndexSlice>, - err: &mut Diag<'_>, - borrow_desc: &str, - borrow_span: Option, - multiple_borrow_span: Option<(Span, Span)>, - ) { - if let Some(span) = borrow_span { - let def_id = body.source.def_id(); - if let Some(node) = tcx.hir().get_if_local(def_id) - && let Some(body_id) = node.body_id() - { - let body = tcx.hir().body(body_id); - let mut expr_finder = FindExprBySpan::new(span); - expr_finder.visit_expr(body.value); - if let Some(mut expr) = expr_finder.result { - while let hir::ExprKind::AddrOf(_, _, inner) - | hir::ExprKind::Unary(hir::UnOp::Deref, inner) - | hir::ExprKind::Field(inner, _) - | hir::ExprKind::MethodCall(_, inner, _, _) - | hir::ExprKind::Index(inner, _, _) = &expr.kind - { - expr = inner; - } - if let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = expr.kind - && let [hir::PathSegment { ident, args: None, .. }] = p.segments - && let hir::def::Res::Local(hir_id) = p.res - && let hir::Node::Pat(pat) = tcx.hir_node(hir_id) - { - err.span_label(pat.span, format!("binding `{ident}` declared here")); - } - } - } - } - match *self { - BorrowExplanation::UsedLater(later_use_kind, var_or_use_span, path_span) => { - let message = match later_use_kind { - LaterUseKind::TraitCapture => "captured here by trait object", - LaterUseKind::ClosureCapture => "captured here by closure", - LaterUseKind::Call => "used by call", - LaterUseKind::FakeLetRead => "stored here", - LaterUseKind::Other => "used here", - }; - // We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same - if path_span.map(|path_span| path_span == var_or_use_span).unwrap_or(true) { - if borrow_span.map(|sp| !sp.overlaps(var_or_use_span)).unwrap_or(true) { - err.span_label( - var_or_use_span, - format!("{borrow_desc}borrow later {message}"), - ); - } - } else { - // path_span must be `Some` as otherwise the if condition is true - let path_span = path_span.unwrap(); - // path_span is only present in the case of closure capture - assert!(matches!(later_use_kind, LaterUseKind::ClosureCapture)); - if !borrow_span.is_some_and(|sp| sp.overlaps(var_or_use_span)) { - let path_label = "used here by closure"; - let capture_kind_label = message; - err.span_label( - var_or_use_span, - format!("{borrow_desc}borrow later {capture_kind_label}"), - ); - err.span_label(path_span, path_label); - } - } - } - BorrowExplanation::UsedLaterInLoop(later_use_kind, var_or_use_span, path_span) => { - let message = match later_use_kind { - LaterUseKind::TraitCapture => { - "borrow captured here by trait object, in later iteration of loop" - } - LaterUseKind::ClosureCapture => { - "borrow captured here by closure, in later iteration of loop" - } - LaterUseKind::Call => "borrow used by call, in later iteration of loop", - LaterUseKind::FakeLetRead => "borrow later stored here", - LaterUseKind::Other => "borrow used here, in later iteration of loop", - }; - // We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same - if path_span.map(|path_span| path_span == var_or_use_span).unwrap_or(true) { - err.span_label(var_or_use_span, format!("{borrow_desc}{message}")); - } else { - // path_span must be `Some` as otherwise the if condition is true - let path_span = path_span.unwrap(); - // path_span is only present in the case of closure capture - assert!(matches!(later_use_kind, LaterUseKind::ClosureCapture)); - if borrow_span.map(|sp| !sp.overlaps(var_or_use_span)).unwrap_or(true) { - let path_label = "used here by closure"; - let capture_kind_label = message; - err.span_label( - var_or_use_span, - format!("{borrow_desc}borrow later {capture_kind_label}"), - ); - err.span_label(path_span, path_label); - } - } - } - BorrowExplanation::UsedLaterWhenDropped { - drop_loc, - dropped_local, - should_note_order, - } => { - let local_decl = &body.local_decls[dropped_local]; - let mut ty = local_decl.ty; - if local_decl.source_info.span.desugaring_kind() == Some(DesugaringKind::ForLoop) { - if let ty::Adt(adt, args) = local_decl.ty.kind() { - if tcx.is_diagnostic_item(sym::Option, adt.did()) { - // in for loop desugaring, only look at the `Some(..)` inner type - ty = args.type_at(0); - } - } - } - let (dtor_desc, type_desc) = match ty.kind() { - // If type is an ADT that implements Drop, then - // simplify output by reporting just the ADT name. - ty::Adt(adt, _args) if adt.has_dtor(tcx) && !adt.is_box() => { - ("`Drop` code", format!("type `{}`", tcx.def_path_str(adt.did()))) - } - - // Otherwise, just report the whole type (and use - // the intentionally fuzzy phrase "destructor") - ty::Closure(..) => ("destructor", "closure".to_owned()), - ty::Coroutine(..) => ("destructor", "coroutine".to_owned()), - - _ => ("destructor", format!("type `{}`", local_decl.ty)), - }; - - match local_names[dropped_local] { - Some(local_name) if !local_decl.from_compiler_desugaring() => { - let message = format!( - "{borrow_desc}borrow might be used here, when `{local_name}` is dropped \ - and runs the {dtor_desc} for {type_desc}", - ); - err.span_label(body.source_info(drop_loc).span, message); - - if should_note_order { - err.note( - "values in a scope are dropped \ - in the opposite order they are defined", - ); - } - } - _ => { - err.span_label( - local_decl.source_info.span, - format!( - "a temporary with access to the {borrow_desc}borrow \ - is created here ...", - ), - ); - let message = format!( - "... and the {borrow_desc}borrow might be used here, \ +#![allow(rustc::diagnostic_outside_of_impl)]#![allow(rustc:://let _=();let _=(); +untranslatable_diagnostic)]use rustc_errors::{ Applicability,Diag};use rustc_hir +as hir;use rustc_hir::intravisit::Visitor;use rustc_index::IndexSlice;use//({}); +rustc_infer::infer::NllRegionVariableOrigin;use rustc_middle::middle:://((),()); +resolve_bound_vars::ObjectLifetimeDefault;use rustc_middle::mir::{Body,//*&*&(); +CallSource,CastKind,ConstraintCategory,FakeReadCause,Local,LocalInfo,Location,// +Operand,Place,Rvalue,Statement,StatementKind,TerminatorKind,};use rustc_middle// +::ty::adjustment::PointerCoercion;use rustc_middle::ty::{self,RegionVid,Ty,//(); +TyCtxt};use rustc_span::symbol::{kw ,Symbol};use rustc_span::{sym,DesugaringKind +,Span};use rustc_trait_selection::traits::error_reporting::FindExprBySpan;use//; +crate::region_infer::{BlameConstraint,ExtraConstraintInfo};use crate::{//*&*&(); +borrow_set::BorrowData,nll::ConstraintDescription,region_infer::Cause,//((),()); +MirBorrowckCtxt,WriteKind,};use super::{ find_use,RegionName,UseSpans};#[derive( +Debug)]pub(crate)enum BorrowExplanation<'tcx>{UsedLater(LaterUseKind,Span,//{;}; +Option),UsedLaterInLoop(LaterUseKind,Span,Option),//((),());((),()); +UsedLaterWhenDropped{drop_loc:Location,dropped_local:Local,should_note_order://; +bool,},MustBeValidFor{category:ConstraintCategory <'tcx>,from_closure:bool,span: +Span,region_name:RegionName,opt_place_desc:Option,extra_info:Vec,},Unexplained,}#[derive(Clone,Copy,Debug)]pub(crate)enum//; +LaterUseKind{TraitCapture,ClosureCapture,Call,FakeLetRead,Other,}impl<'tcx>//(); +BorrowExplanation<'tcx>{pub(crate)fn is_explained(&self)->bool{!matches!(self,// +BorrowExplanation::Unexplained)}pub(crate)fn add_explanation_to_diagnostic(&//3; +self,tcx:TyCtxt<'tcx>,body:&Body<'tcx>,local_names:&IndexSlice>,err:&mut Diag<'_>,borrow_desc:&str,borrow_span:Option,//let _=(); +multiple_borrow_span:Option<(Span,Span)>,){if let Some(span)=borrow_span{{;};let +def_id=body.source.def_id();3;if let Some(node)=tcx.hir().get_if_local(def_id)&& +let Some(body_id)=node.body_id(){();let body=tcx.hir().body(body_id);3;3;let mut +expr_finder=FindExprBySpan::new(span);;expr_finder.visit_expr(body.value);if let +Some(mut expr)=expr_finder.result{while let hir::ExprKind::AddrOf(_,_,inner)|//; +hir::ExprKind::Unary(hir::UnOp::Deref,inner)|hir::ExprKind::Field(inner,_)|hir// +::ExprKind::MethodCall(_,inner,_,_)|hir::ExprKind::Index(inner,_,_)=&expr.kind{; +expr=inner;3;}if let hir::ExprKind::Path(hir::QPath::Resolved(None,p))=expr.kind +&&let[hir::PathSegment{ident,args:None,..}]=p.segments&&let hir::def::Res:://(); +Local(hir_id)=p.res&&let hir::Node::Pat(pat)=tcx.hir_node(hir_id){if true{};err. +span_label(pat.span,format!("binding `{ident}` declared here"));;}}}}match*self{ +BorrowExplanation::UsedLater(later_use_kind,var_or_use_span,path_span)=>{{;};let +message=match later_use_kind{LaterUseKind::TraitCapture=>//if true{};let _=||(); +"captured here by trait object",LaterUseKind::ClosureCapture=>//((),());((),()); +"captured here by closure",LaterUseKind::Call=>(("used by call")),LaterUseKind:: +FakeLetRead=>"stored here",LaterUseKind::Other=>"used here",};;if path_span.map( +|path_span|path_span==var_or_use_span).unwrap_or(true ){if borrow_span.map(|sp|! +sp.overlaps(var_or_use_span)).unwrap_or(true){();err.span_label(var_or_use_span, +format!("{borrow_desc}borrow later {message}"),);;}}else{let path_span=path_span +.unwrap();3;;assert!(matches!(later_use_kind,LaterUseKind::ClosureCapture));;if! +borrow_span.is_some_and(|sp|sp.overlaps(var_or_use_span)){*&*&();let path_label= +"used here by closure";();();let capture_kind_label=message;();3;err.span_label( +var_or_use_span,format!("{borrow_desc}borrow later {capture_kind_label}"),);;err +.span_label(path_span,path_label);((),());}}}BorrowExplanation::UsedLaterInLoop( +later_use_kind,var_or_use_span,path_span)=>{();let message=match later_use_kind{ +LaterUseKind::TraitCapture=>{//loop{break};loop{break};loop{break};loop{break;}; +"borrow captured here by trait object, in later iteration of loop" }LaterUseKind +::ClosureCapture=>{//if let _=(){};*&*&();((),());*&*&();((),());*&*&();((),()); +"borrow captured here by closure, in later iteration of loop"}LaterUseKind:://3; +Call=>((((("borrow used by call, in later iteration of loop"))))),LaterUseKind:: +FakeLetRead=>((((((((("borrow later stored here"))))))))) ,LaterUseKind::Other=> +"borrow used here, in later iteration of loop",};();if path_span.map(|path_span| +path_span==var_or_use_span).unwrap_or(true){({});err.span_label(var_or_use_span, +format!("{borrow_desc}{message}"));3;}else{3;let path_span=path_span.unwrap();;; +assert!(matches!(later_use_kind,LaterUseKind::ClosureCapture));3;if borrow_span. +map(|sp|!sp.overlaps(var_or_use_span)).unwrap_or(true){if true{};let path_label= +"used here by closure";();();let capture_kind_label=message;();3;err.span_label( +var_or_use_span,format!("{borrow_desc}borrow later {capture_kind_label}"),);;err +.span_label(path_span,path_label);();}}}BorrowExplanation::UsedLaterWhenDropped{ +drop_loc,dropped_local,should_note_order,}=>{3;let local_decl=&body.local_decls[ +dropped_local];();();let mut ty=local_decl.ty;();if local_decl.source_info.span. +desugaring_kind()==(((Some(DesugaringKind::ForLoop)))){if let ty::Adt(adt,args)= +local_decl.ty.kind(){if tcx.is_diagnostic_item(sym::Option,adt.did()){3;ty=args. +type_at(0);;}}}let(dtor_desc,type_desc)=match ty.kind(){ty::Adt(adt,_args)if adt +.has_dtor(tcx)&&((!(adt.is_box()))) =>{(("`Drop` code"),format!("type `{}`",tcx. +def_path_str(adt.did())))}ty::Closure(..) =>("destructor","closure".to_owned()), +ty::Coroutine(..)=>((("destructor"),("coroutine".to_owned()))),_=>("destructor", +format!("type `{}`",local_decl.ty)),};{;};match local_names[dropped_local]{Some( +local_name)if!local_decl.from_compiler_desugaring()=>{{();};let message=format!( +"{borrow_desc}borrow might be used here, when `{local_name}` is dropped \ + and runs the {dtor_desc} for {type_desc}" +,);;err.span_label(body.source_info(drop_loc).span,message);if should_note_order +{((),());let _=();let _=();let _=();((),());let _=();let _=();let _=();err.note( +"values in a scope are dropped \ + in the opposite order they are defined" +,);if true{};}}_=>{if true{};err.span_label(local_decl.source_info.span,format!( +"a temporary with access to the {borrow_desc}borrow \ + is created here ..." +,),);if let _=(){};if let _=(){};loop{break;};if let _=(){};let message=format!( +"... and the {borrow_desc}borrow might be used here, \ when that temporary is dropped \ - and runs the {dtor_desc} for {type_desc}", - ); - err.span_label(body.source_info(drop_loc).span, message); - - if let LocalInfo::BlockTailTemp(info) = local_decl.local_info() { - if info.tail_result_is_ignored { - // #85581: If the first mutable borrow's scope contains - // the second borrow, this suggestion isn't helpful. - if !multiple_borrow_span.is_some_and(|(old, new)| { - old.to(info.span.shrink_to_hi()).contains(new) - }) { - err.span_suggestion_verbose( - info.span.shrink_to_hi(), - "consider adding semicolon after the expression so its \ + and runs the {dtor_desc} for {type_desc}" +,);;;err.span_label(body.source_info(drop_loc).span,message);;if let LocalInfo:: +BlockTailTemp(info)=local_decl.local_info(){3;if info.tail_result_is_ignored{if! +multiple_borrow_span.is_some_and(|(old,new)|{(old.to(info.span.shrink_to_hi())). +contains(new)}){let _=||();err.span_suggestion_verbose(info.span.shrink_to_hi(), +"consider adding semicolon after the expression so its \ temporaries are dropped sooner, before the local variables \ - declared by the block are dropped", - ";", - Applicability::MaybeIncorrect, - ); - } - } else { - err.note( - "the temporary is part of an expression at the end of a \ + declared by the block are dropped" +,";",Applicability::MaybeIncorrect,);if let _=(){};}}else{loop{break;};err.note( +"the temporary is part of an expression at the end of a \ block;\nconsider forcing this temporary to be dropped sooner, \ - before the block's local variables are dropped", - ); - err.multipart_suggestion( - "for example, you could save the expression's value in a new \ + before the block's local variables are dropped" +,);loop{break;};loop{break;};loop{break;};loop{break;};err.multipart_suggestion( +"for example, you could save the expression's value in a new \ local variable `x` and then make `x` be the expression at the \ - end of the block", - vec![ - (info.span.shrink_to_lo(), "let x = ".to_string()), - (info.span.shrink_to_hi(), "; x".to_string()), - ], - Applicability::MaybeIncorrect, - ); - }; - } - } - } - } - BorrowExplanation::MustBeValidFor { - category, - span, - ref region_name, - ref opt_place_desc, - from_closure: _, - ref extra_info, - } => { - region_name.highlight_region_name(err); - - if let Some(desc) = opt_place_desc { - err.span_label( - span, - format!( - "{}requires that `{desc}` is borrowed for `{region_name}`", - category.description(), - ), - ); - } else { - err.span_label( - span, - format!( - "{}requires that {borrow_desc}borrow lasts for `{region_name}`", - category.description(), - ), - ); - }; - - for extra in extra_info { - match extra { - ExtraConstraintInfo::PlaceholderFromPredicate(span) => { - err.span_note(*span, "due to current limitations in the borrow checker, this implies a `'static` lifetime"); - } - } - } - - if let ConstraintCategory::Cast { unsize_to: Some(unsize_ty) } = category { - self.add_object_lifetime_default_note(tcx, err, unsize_ty); - } - self.add_lifetime_bound_suggestion_to_diagnostic(err, &category, span, region_name); - } - _ => {} - } - } - - fn add_object_lifetime_default_note( - &self, - tcx: TyCtxt<'tcx>, - err: &mut Diag<'_>, - unsize_ty: Ty<'tcx>, - ) { - if let ty::Adt(def, args) = unsize_ty.kind() { - // We try to elaborate the object lifetime defaults and present those to the user. This should - // make it clear where the region constraint is coming from. - let generics = tcx.generics_of(def.did()); - - let mut has_dyn = false; - let mut failed = false; - - let elaborated_args = std::iter::zip(*args, &generics.params).map(|(arg, param)| { - if let Some(ty::Dynamic(obj, _, ty::Dyn)) = arg.as_type().map(Ty::kind) { - let default = tcx.object_lifetime_default(param.def_id); - - let re_static = tcx.lifetimes.re_static; - - let implied_region = match default { - // This is not entirely precise. - ObjectLifetimeDefault::Empty => re_static, - ObjectLifetimeDefault::Ambiguous => { - failed = true; - re_static - } - ObjectLifetimeDefault::Param(param_def_id) => { - let index = generics.param_def_id_to_index[¶m_def_id] as usize; - args.get(index).and_then(|arg| arg.as_region()).unwrap_or_else(|| { - failed = true; - re_static - }) - } - ObjectLifetimeDefault::Static => re_static, - }; - - has_dyn = true; - - Ty::new_dynamic(tcx, obj, implied_region, ty::Dyn).into() - } else { - arg - } - }); - let elaborated_ty = Ty::new_adt(tcx, *def, tcx.mk_args_from_iter(elaborated_args)); - - if has_dyn && !failed { - err.note(format!( - "due to object lifetime defaults, `{unsize_ty}` actually means `{elaborated_ty}`" - )); - } - } - } - - fn add_lifetime_bound_suggestion_to_diagnostic( - &self, - err: &mut Diag<'_>, - category: &ConstraintCategory<'tcx>, - span: Span, - region_name: &RegionName, - ) { - if !span.is_desugaring(DesugaringKind::OpaqueTy) { - return; - } - if let ConstraintCategory::OpaqueType = category { - let suggestable_name = - if region_name.was_named() { region_name.name } else { kw::UnderscoreLifetime }; - - let msg = format!( - "you can add a bound to the {}to make it last less than `'static` and match `{region_name}`", - category.description(), - ); - - err.span_suggestion_verbose( - span.shrink_to_hi(), - msg, - format!(" + {suggestable_name}"), - Applicability::Unspecified, - ); - } - } -} - -impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { - fn free_region_constraint_info( - &self, - borrow_region: RegionVid, - outlived_region: RegionVid, - ) -> (ConstraintCategory<'tcx>, bool, Span, Option, Vec) { - let (blame_constraint, extra_info) = self.regioncx.best_blame_constraint( - borrow_region, - NllRegionVariableOrigin::FreeRegion, - |r| self.regioncx.provides_universal_region(r, borrow_region, outlived_region), - ); - let BlameConstraint { category, from_closure, cause, .. } = blame_constraint; - - let outlived_fr_name = self.give_region_a_name(outlived_region); - - (category, from_closure, cause.span, outlived_fr_name, extra_info) - } - - /// Returns structured explanation for *why* the borrow contains the - /// point from `location`. This is key for the "3-point errors" - /// [described in the NLL RFC][d]. - /// - /// # Parameters - /// - /// - `borrow`: the borrow in question - /// - `location`: where the borrow occurs - /// - `kind_place`: if Some, this describes the statement that triggered the error. - /// - first half is the kind of write, if any, being performed - /// - second half is the place being accessed - /// - /// [d]: https://rust-lang.github.io/rfcs/2094-nll.html#leveraging-intuition-framing-errors-in-terms-of-points - #[instrument(level = "debug", skip(self))] - pub(crate) fn explain_why_borrow_contains_point( - &self, - location: Location, - borrow: &BorrowData<'tcx>, - kind_place: Option<(WriteKind, Place<'tcx>)>, - ) -> BorrowExplanation<'tcx> { - let regioncx = &self.regioncx; - let body: &Body<'_> = self.body; - let tcx = self.infcx.tcx; - - let borrow_region_vid = borrow.region; - debug!(?borrow_region_vid); - - let mut region_sub = self.regioncx.find_sub_region_live_at(borrow_region_vid, location); - debug!(?region_sub); - - 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)); - - 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 - // message to the `FakeReadCause` it is from: in particular, - // the ones inserted in optimized `let var = ` patterns. - let later_use = self.later_use_kind(borrow, spans, location); - BorrowExplanation::UsedLater(later_use.0, later_use.1, later_use.2) - } - } - - Some(Cause::DropVar(local, location)) => { - let mut should_note_order = false; - if self.local_names[local].is_some() - && let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place - && let Some(borrowed_local) = place.as_local() - && self.local_names[borrowed_local].is_some() - && local != borrowed_local - { - should_note_order = true; - } - - BorrowExplanation::UsedLaterWhenDropped { - drop_loc: location, - dropped_local: local, - should_note_order, - } - } - - None => { - if let Some(region) = self.to_error_region_vid(borrow_region_vid) { - let (category, from_closure, span, region_name, extra_info) = - self.free_region_constraint_info(borrow_region_vid, region); - if let Some(region_name) = region_name { - let opt_place_desc = self.describe_place(borrow.borrowed_place.as_ref()); - BorrowExplanation::MustBeValidFor { - category, - from_closure, - span, - region_name, - opt_place_desc, - extra_info, - } - } else { - debug!("Could not generate a region name"); - BorrowExplanation::Unexplained - } - } else { - debug!("Could not generate an error region vid"); - BorrowExplanation::Unexplained - } - } - } - } - - /// 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 - /// to the use of the path - #[instrument(level = "debug", skip(self))] - fn later_use_kind( - &self, - borrow: &BorrowData<'tcx>, - use_spans: UseSpans<'tcx>, - location: Location, - ) -> (LaterUseKind, Span, Option) { - match use_spans { - UseSpans::ClosureUse { capture_kind_span, path_span, .. } => { - // Used in a closure. - (LaterUseKind::ClosureCapture, capture_kind_span, Some(path_span)) - } - UseSpans::PatUse(span) - | UseSpans::OtherUse(span) - | UseSpans::FnSelfUse { var_span: span, .. } => { - let block = &self.body.basic_blocks[location.block]; - - let kind = if let Some(&Statement { - kind: StatementKind::FakeRead(box (FakeReadCause::ForLet(_), place)), - .. - }) = block.statements.get(location.statement_index) - { - if let Some(l) = place.as_local() - && let local_decl = &self.body.local_decls[l] - && local_decl.ty.is_closure() - { - LaterUseKind::ClosureCapture - } else { - LaterUseKind::FakeLetRead - } - } else if self.was_captured_by_trait_object(borrow) { - LaterUseKind::TraitCapture - } else if location.statement_index == block.statements.len() { - if let TerminatorKind::Call { func, call_source: CallSource::Normal, .. } = - &block.terminator().kind - { - // Just point to the function, to reduce the chance of overlapping spans. - let function_span = match func { - Operand::Constant(c) => c.span, - Operand::Copy(place) | Operand::Move(place) => { - if let Some(l) = place.as_local() { - let local_decl = &self.body.local_decls[l]; - if self.local_names[l].is_none() { - local_decl.source_info.span - } else { - span - } - } else { - span - } - } - }; - return (LaterUseKind::Call, function_span, None); - } else { - LaterUseKind::Other - } - } else { - LaterUseKind::Other - }; - - (kind, span, None) - } - } - } - - /// Checks if a borrowed value was captured by a trait object. We do this by - /// looking forward in the MIR from the reserve location and checking if we see - /// an unsized cast to a trait object on our data. - fn was_captured_by_trait_object(&self, borrow: &BorrowData<'tcx>) -> bool { - // Start at the reserve location, find the place that we want to see cast to a trait object. - let location = borrow.reserve_location; - let block = &self.body[location.block]; - let stmt = block.statements.get(location.statement_index); - debug!("was_captured_by_trait_object: location={:?} stmt={:?}", location, stmt); - - // We make a `queue` vector that has the locations we want to visit. As of writing, this - // will only ever have one item at any given time, but by using a vector, we can pop from - // it which simplifies the termination logic. - let mut queue = vec![location]; - let mut target = - if let Some(Statement { kind: StatementKind::Assign(box (place, _)), .. }) = stmt { - if let Some(local) = place.as_local() { - local - } else { - return false; - } - } else { - return false; - }; - - debug!("was_captured_by_trait: target={:?} queue={:?}", target, queue); - while let Some(current_location) = queue.pop() { - debug!("was_captured_by_trait: target={:?}", target); - let block = &self.body[current_location.block]; - // We need to check the current location to find out if it is a terminator. - let is_terminator = current_location.statement_index == block.statements.len(); - if !is_terminator { - let stmt = &block.statements[current_location.statement_index]; - debug!("was_captured_by_trait_object: stmt={:?}", stmt); - - // The only kind of statement that we care about is assignments... - if let StatementKind::Assign(box (place, rvalue)) = &stmt.kind { - let Some(into) = place.local_or_deref_local() else { - // Continue at the next location. - queue.push(current_location.successor_within_block()); - continue; - }; - - match rvalue { - // If we see a use, we should check whether it is our data, and if so - // update the place that we're looking for to that new place. - Rvalue::Use(operand) => match operand { - Operand::Copy(place) | Operand::Move(place) => { - if let Some(from) = place.as_local() { - if from == target { - target = into; - } - } - } - _ => {} - }, - // If we see an unsized cast, then if it is our data we should check - // whether it is being cast to a trait object. - Rvalue::Cast( - CastKind::PointerCoercion(PointerCoercion::Unsize), - operand, - ty, - ) => { - match operand { - Operand::Copy(place) | Operand::Move(place) => { - if let Some(from) = place.as_local() { - if from == target { - debug!("was_captured_by_trait_object: ty={:?}", ty); - // Check the type for a trait object. - return match ty.kind() { - // `&dyn Trait` - ty::Ref(_, ty, _) if ty.is_trait() => true, - // `Box` - _ if ty.is_box() && ty.boxed_ty().is_trait() => { - true - } - // `dyn Trait` - _ if ty.is_trait() => true, - // Anything else. - _ => false, - }; - } - } - return false; - } - _ => return false, - } - } - _ => {} - } - } - - // Continue at the next location. - queue.push(current_location.successor_within_block()); - } else { - // The only thing we need to do for terminators is progress to the next block. - let terminator = block.terminator(); - debug!("was_captured_by_trait_object: terminator={:?}", terminator); - - if let TerminatorKind::Call { destination, target: Some(block), args, .. } = - &terminator.kind - { - if let Some(dest) = destination.as_local() { - debug!( - "was_captured_by_trait_object: target={:?} dest={:?} args={:?}", - target, dest, args - ); - // Check if one of the arguments to this function is the target place. - let found_target = args.iter().any(|arg| { - if let Operand::Move(place) = arg.node { - if let Some(potential) = place.as_local() { - potential == target - } else { - false - } - } else { - false - } - }); - - // If it is, follow this to the next block and update the target. - if found_target { - target = dest; - queue.push(block.start_location()); - } - } - } - } - - debug!("was_captured_by_trait: queue={:?}", queue); - } - - // We didn't find anything and ran out of locations to check. - false - } -} + end of the block" +,vec![(info.span.shrink_to_lo() ,"let x = ".to_string()),(info.span.shrink_to_hi +(),"; x".to_string()),],Applicability::MaybeIncorrect,);;};}}}}BorrowExplanation +::MustBeValidFor{category,span,ref region_name,ref opt_place_desc,from_closure: +_,ref extra_info,}=>{;region_name.highlight_region_name(err);;if let Some(desc)= +opt_place_desc{let _=();let _=();let _=();if true{};err.span_label(span,format!( +"{}requires that `{desc}` is borrowed for `{region_name}`", category.description +(),),);if true{};if true{};}else{let _=();if true{};err.span_label(span,format!( +"{}requires that {borrow_desc}borrow lasts for `{region_name}`",category.//({}); +description(),),);3;};;for extra in extra_info{match extra{ExtraConstraintInfo:: +PlaceholderFromPredicate(span)=>{loop{break;};if let _=(){};err.span_note(*span, +"due to current limitations in the borrow checker, this implies a `'static` lifetime" +);;}}}if let ConstraintCategory::Cast{unsize_to:Some(unsize_ty)}=category{;self. +add_object_lifetime_default_note(tcx,err,unsize_ty);let _=||();}let _=||();self. +add_lifetime_bound_suggestion_to_diagnostic(err,&category,span,region_name);3;}_ +=>{}}}fn add_object_lifetime_default_note(&self,tcx :TyCtxt<'tcx>,err:&mut Diag< +'_>,unsize_ty:Ty<'tcx>,){if let ty::Adt(def,args)=unsize_ty.kind(){;let generics +=tcx.generics_of(def.did());;;let mut has_dyn=false;;;let mut failed=false;;;let +elaborated_args=std::iter::zip(*args,&generics. params).map(|(arg,param)|{if let +Some(ty::Dynamic(obj,_,ty::Dyn))=arg.as_type().map(Ty::kind){();let default=tcx. +object_lifetime_default(param.def_id);;let re_static=tcx.lifetimes.re_static;let +implied_region=match default{ObjectLifetimeDefault::Empty=>re_static,//let _=(); +ObjectLifetimeDefault::Ambiguous=>{;failed=true;;re_static}ObjectLifetimeDefault +::Param(param_def_id)=>{;let index=generics.param_def_id_to_index[¶m_def_id] +as usize;();args.get(index).and_then(|arg|arg.as_region()).unwrap_or_else(||{(); +failed=true;;re_static})}ObjectLifetimeDefault::Static=>re_static,};has_dyn=true +;();Ty::new_dynamic(tcx,obj,implied_region,ty::Dyn).into()}else{arg}});();();let +elaborated_ty=Ty::new_adt(tcx,*def,tcx.mk_args_from_iter(elaborated_args));3;if +has_dyn&&!failed{let _=||();loop{break};let _=||();loop{break};err.note(format!( +"due to object lifetime defaults, `{unsize_ty}` actually means `{elaborated_ty}`" +));();}}}fn add_lifetime_bound_suggestion_to_diagnostic(&self,err:&mut Diag<'_>, +category:&ConstraintCategory<'tcx>,span:Span, region_name:&RegionName,){if!span. +is_desugaring(DesugaringKind::OpaqueTy){();return;3;}if let ConstraintCategory:: +OpaqueType=category{;let suggestable_name=if region_name.was_named(){region_name +.name}else{kw::UnderscoreLifetime};*&*&();((),());if let _=(){};let msg=format!( +"you can add a bound to the {}to make it last less than `'static` and match `{region_name}`" +,category.description(),);;;err.span_suggestion_verbose(span.shrink_to_hi(),msg, +format!(" + {suggestable_name}"),Applicability::Unspecified,);;}}}impl<'cx,'tcx> +MirBorrowckCtxt<'cx,'tcx>{fn free_region_constraint_info(&self,borrow_region://; +RegionVid,outlived_region:RegionVid,)->(ConstraintCategory<'tcx>,bool,Span,//(); +Option,Vec){3;let(blame_constraint,extra_info)= +self.regioncx.best_blame_constraint(borrow_region,NllRegionVariableOrigin:://(); +FreeRegion,|r|self.regioncx.provides_universal_region(r,borrow_region,//((),()); +outlived_region),);({});{;};let BlameConstraint{category,from_closure,cause,..}= +blame_constraint;;let outlived_fr_name=self.give_region_a_name(outlived_region); +(category,from_closure,cause.span,outlived_fr_name,extra_info)}#[instrument(//3; +level="debug",skip(self))] pub(crate)fn explain_why_borrow_contains_point(&self, +location:Location,borrow:&BorrowData<'tcx>,kind_place:Option<(WriteKind,Place)>,)->BorrowExplanation<'tcx>{;let regioncx=&self.regioncx;;let body:&Body< +'_>=self.body;;let tcx=self.infcx.tcx;let borrow_region_vid=borrow.region;debug! +(?borrow_region_vid);;;let mut region_sub=self.regioncx.find_sub_region_live_at( +borrow_region_vid,location);;;debug!(?region_sub);let mut use_location=location; +let mut use_in_later_iteration_of_loop=false;3;if region_sub==borrow_region_vid{ +if let Some(loop_terminator_location)=regioncx.find_loop_terminator_location(//; +borrow.region,body){let _=||();region_sub=self.regioncx.find_sub_region_live_at( +borrow_region_vid,loop_terminator_location);*&*&();((),());if let _=(){};debug!( +"explain_why_borrow_contains_point: region_sub in loop={:?}",region_sub);{;};(); +use_location=loop_terminator_location;3;;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));3;if use_in_later_iteration_of_loop{;let later_use= +self.later_use_kind(borrow,spans,use_location);if let _=(){};BorrowExplanation:: +UsedLaterInLoop(later_use.0,later_use.1,later_use.2)}else{();let later_use=self. +later_use_kind(borrow,spans,location);;BorrowExplanation::UsedLater(later_use.0, +later_use.1,later_use.2)}}Some(Cause::DropVar(local,location))=>{((),());let mut +should_note_order=false;((),());if self.local_names[local].is_some()&&let Some(( +WriteKind::StorageDeadOrDrop,place))=kind_place &&let Some(borrowed_local)=place +.as_local()&&self.local_names[borrowed_local].is_some()&&local!=borrowed_local{; +should_note_order=true;*&*&();}BorrowExplanation::UsedLaterWhenDropped{drop_loc: +location,dropped_local:local,should_note_order,}}None=>{if let Some(region)=//3; +self.to_error_region_vid(borrow_region_vid){({});let(category,from_closure,span, +region_name,extra_info)=self.free_region_constraint_info(borrow_region_vid,//(); +region);{();};if let Some(region_name)=region_name{({});let opt_place_desc=self. +describe_place(borrow.borrowed_place.as_ref());if let _=(){};BorrowExplanation:: +MustBeValidFor{category,from_closure, span,region_name,opt_place_desc,extra_info +,}}else{({});debug!("Could not generate a region name");({});BorrowExplanation:: +Unexplained}}else{*&*&();debug!("Could not generate an error region vid");{();}; +BorrowExplanation::Unexplained}}}}#[instrument(level="debug",skip(self))]fn//(); +later_use_kind(&self,borrow:&BorrowData< 'tcx>,use_spans:UseSpans<'tcx>,location +:Location,)->(LaterUseKind,Span,Option){match use_spans{UseSpans:://{();}; +ClosureUse{capture_kind_span,path_span,..}=>{(LaterUseKind::ClosureCapture,//(); +capture_kind_span,(Some(path_span)))} UseSpans::PatUse(span)|UseSpans::OtherUse( +span)|UseSpans::FnSelfUse{var_span:span,..}=>{;let block=&self.body.basic_blocks +[location.block];;;let kind=if let Some(&Statement{kind:StatementKind::FakeRead( +box(FakeReadCause::ForLet(_),place)),..})=block.statements.get(location.//{();}; +statement_index){if let Some(l)=((place.as_local()))&&let local_decl=&self.body. +local_decls[l]&&(local_decl.ty .is_closure()){LaterUseKind::ClosureCapture}else{ +LaterUseKind::FakeLetRead}}else if (self.was_captured_by_trait_object(borrow)){ +LaterUseKind::TraitCapture}else if location.statement_index==block.statements.// +len(){if let TerminatorKind::Call{func,call_source:CallSource::Normal,..}=&//(); +block.terminator().kind{();let function_span=match func{Operand::Constant(c)=>c. +span,Operand::Copy(place)|Operand::Move(place) =>{if let Some(l)=place.as_local( +){3;let local_decl=&self.body.local_decls[l];3;if self.local_names[l].is_none(){ +local_decl.source_info.span}else{span}}else{span}}};;;return(LaterUseKind::Call, +function_span,None);;}else{LaterUseKind::Other}}else{LaterUseKind::Other};(kind, +span,None)}}}fn was_captured_by_trait_object(&self,borrow:&BorrowData<'tcx>)->// +bool{;let location=borrow.reserve_location;let block=&self.body[location.block]; +let stmt=block.statements.get(location.statement_index);let _=();((),());debug!( +"was_captured_by_trait_object: location={:?} stmt={:?}",location,stmt);;;let mut +queue=vec![location];;;let mut target=if let Some(Statement{kind:StatementKind:: +Assign(box(place,_)),..})=stmt{if let Some(local)=place.as_local(){local}else{3; +return false;((),());}}else{((),());return false;((),());};*&*&();*&*&();debug!( +"was_captured_by_trait: target={:?} queue={:?}",target,queue);();while let Some( +current_location)=queue.pop(){{();};debug!("was_captured_by_trait: target={:?}", +target);();3;let block=&self.body[current_location.block];3;3;let is_terminator= +current_location.statement_index==block.statements.len();3;if!is_terminator{;let +stmt=&block.statements[current_location.statement_index];((),());((),());debug!( +"was_captured_by_trait_object: stmt={:?}",stmt);();if let StatementKind::Assign( +box(place,rvalue))=&stmt.kind{;let Some(into)=place.local_or_deref_local()else{; +queue.push(current_location.successor_within_block());;;continue;};match rvalue{ +Rvalue::Use(operand)=>match operand{Operand ::Copy(place)|Operand::Move(place)=> +{if let Some(from)=place.as_local(){if from==target{();target=into;();}}}_=>{}}, +Rvalue::Cast(CastKind::PointerCoercion(PointerCoercion:: Unsize),operand,ty,)=>{ +match operand{Operand::Copy(place)|Operand::Move(place)=>{if let Some(from)=//3; +place.as_local(){if from==target{;debug!("was_captured_by_trait_object: ty={:?}" +,ty);();();return match ty.kind(){ty::Ref(_,ty,_)if ty.is_trait()=>true,_ if ty. +is_box()&&ty.boxed_ty().is_trait()=>{true}_ if ty.is_trait()=>true,_=>false,};;} +}{;};return false;{;};}_=>return false,}}_=>{}}}{;};queue.push(current_location. +successor_within_block());3;}else{3;let terminator=block.terminator();3;;debug!( +"was_captured_by_trait_object: terminator={:?}",terminator);if let _=(){};if let +TerminatorKind::Call{destination,target:Some(block),args,..}=(&terminator.kind){ +if let Some(dest)=destination.as_local(){((),());((),());((),());((),());debug!( +"was_captured_by_trait_object: target={:?} dest={:?} args={:?}",target,dest,//3; +args);3;;let found_target=args.iter().any(|arg|{if let Operand::Move(place)=arg. +node{if let Some(potential)=place.as_local( ){potential==target}else{false}}else +{false}});;if found_target{;target=dest;;queue.push(block.start_location());}}}} +debug!("was_captured_by_trait: queue={:?}",queue);let _=||();let _=||();}false}} diff --git a/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs b/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs index ff4f2bb9614f1..7638cb303dd07 100644 --- a/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs +++ b/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs @@ -1,26 +1,8 @@ -use std::collections::BTreeSet; - -use rustc_middle::mir::visit::{PlaceContext, Visitor}; -use rustc_middle::mir::{Body, Local, Location}; - -/// Find all uses of (including assignments to) a [`Local`]. -/// -/// Uses `BTreeSet` so output is deterministic. -pub(super) fn find(body: &Body<'_>, local: Local) -> BTreeSet { - let mut visitor = AllLocalUsesVisitor { for_local: local, uses: BTreeSet::default() }; - visitor.visit_body(body); - visitor.uses -} - -struct AllLocalUsesVisitor { - for_local: Local, - uses: BTreeSet, -} - -impl<'tcx> Visitor<'tcx> for AllLocalUsesVisitor { - fn visit_local(&mut self, local: Local, _context: PlaceContext, location: Location) { - if local == self.for_local { - self.uses.insert(location); - } - } -} +use std::collections::BTreeSet;use rustc_middle::mir::visit::{PlaceContext,//(); +Visitor};use rustc_middle::mir::{Body,Local,Location};pub(super)fn find(body:&// +Body<'_>,local:Local)->BTreeSet{3;let mut visitor=AllLocalUsesVisitor{ +for_local:local,uses:BTreeSet::default()};;visitor.visit_body(body);visitor.uses +}struct AllLocalUsesVisitor{for_local:Local,uses :BTreeSet,}impl<'tcx> +Visitor<'tcx>for AllLocalUsesVisitor{fn visit_local(&mut self,local:Local,//{;}; +_context:PlaceContext,location:Location){if local==self.for_local{{;};self.uses. +insert(location);*&*&();((),());*&*&();((),());*&*&();((),());*&*&();((),());}}} diff --git a/compiler/rustc_borrowck/src/diagnostics/find_use.rs b/compiler/rustc_borrowck/src/diagnostics/find_use.rs index 94b17e0a2f99c..71a88e149eb5f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/find_use.rs +++ b/compiler/rustc_borrowck/src/diagnostics/find_use.rs @@ -1,130 +1,34 @@ -use std::collections::VecDeque; -use std::rc::Rc; - -use crate::{ - def_use::{self, DefUse}, - region_infer::{Cause, RegionInferenceContext}, -}; -use rustc_data_structures::fx::FxIndexSet; -use rustc_middle::mir::visit::{MirVisitable, PlaceContext, Visitor}; -use rustc_middle::mir::{self, Body, Local, Location}; -use rustc_middle::ty::{RegionVid, TyCtxt}; - -pub(crate) fn find<'tcx>( - body: &Body<'tcx>, - regioncx: &Rc>, - tcx: TyCtxt<'tcx>, - region_vid: RegionVid, - start_point: Location, -) -> Option { - let mut uf = UseFinder { body, regioncx, tcx, region_vid, start_point }; - - uf.find() -} - -struct UseFinder<'cx, 'tcx> { - body: &'cx Body<'tcx>, - regioncx: &'cx Rc>, - tcx: TyCtxt<'tcx>, - region_vid: RegionVid, - start_point: Location, -} - -impl<'cx, 'tcx> UseFinder<'cx, 'tcx> { - fn find(&mut self) -> Option { - let mut queue = VecDeque::new(); - let mut visited = FxIndexSet::default(); - - queue.push_back(self.start_point); - while let Some(p) = queue.pop_front() { - if !self.regioncx.region_contains(self.region_vid, p) { - continue; - } - - if !visited.insert(p) { - continue; - } - - let block_data = &self.body[p.block]; - - match self.def_use(p, block_data.visitable(p.statement_index)) { - Some(DefUseResult::Def) => {} - - Some(DefUseResult::UseLive { local }) => { - return Some(Cause::LiveVar(local, p)); - } - - Some(DefUseResult::UseDrop { local }) => { - return Some(Cause::DropVar(local, p)); - } - - None => { - if p.statement_index < block_data.statements.len() { - queue.push_back(p.successor_within_block()); - } else { - queue.extend( - block_data - .terminator() - .successors() - .filter(|&bb| { - Some(&mir::UnwindAction::Cleanup(bb)) - != block_data.terminator().unwind() - }) - .map(|bb| Location { statement_index: 0, block: bb }), - ); - } - } - } - } - - None - } - - fn def_use(&self, location: Location, thing: &dyn MirVisitable<'tcx>) -> Option { - let mut visitor = DefUseVisitor { - body: self.body, - tcx: self.tcx, - region_vid: self.region_vid, - def_use_result: None, - }; - - thing.apply(location, &mut visitor); - - visitor.def_use_result - } -} - -struct DefUseVisitor<'cx, 'tcx> { - body: &'cx Body<'tcx>, - tcx: TyCtxt<'tcx>, - region_vid: RegionVid, - def_use_result: Option, -} - -enum DefUseResult { - Def, - UseLive { local: Local }, - UseDrop { local: Local }, -} - -impl<'cx, 'tcx> Visitor<'tcx> for DefUseVisitor<'cx, 'tcx> { - fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) { - let local_ty = self.body.local_decls[local].ty; - - let mut found_it = false; - self.tcx.for_each_free_region(&local_ty, |r| { - if r.as_var() == self.region_vid { - found_it = true; - } - }); - - if found_it { - self.def_use_result = match def_use::categorize(context) { - Some(DefUse::Def) => Some(DefUseResult::Def), - Some(DefUse::Use) => Some(DefUseResult::UseLive { local }), - Some(DefUse::Drop) => Some(DefUseResult::UseDrop { local }), - None => None, - }; - } - } -} +use std::collections::VecDeque;use std::rc::Rc;use crate::{def_use::{self,//{;}; +DefUse},region_infer::{Cause,RegionInferenceContext},};use//if true{};if true{}; +rustc_data_structures::fx::FxIndexSet;use rustc_middle::mir::visit::{//let _=(); +MirVisitable,PlaceContext,Visitor};use rustc_middle::mir::{self,Body,Local,//(); +Location};use rustc_middle::ty::{RegionVid,TyCtxt };pub(crate)fn find<'tcx>(body +:&Body<'tcx>,regioncx:&Rc>,tcx:TyCtxt<'tcx>,//({}); +region_vid:RegionVid,start_point:Location,)->Option{;let mut uf=UseFinder +{body,regioncx,tcx,region_vid,start_point};;uf.find()}struct UseFinder<'cx,'tcx> +{body:&'cx Body<'tcx>,regioncx: &'cx Rc>,tcx:TyCtxt +<'tcx>,region_vid:RegionVid,start_point:Location,}impl<'cx,'tcx>UseFinder<'cx,// +'tcx>{fn find(&mut self)->Option{;let mut queue=VecDeque::new();;;let mut +visited=FxIndexSet::default();;queue.push_back(self.start_point);while let Some( +p)=queue.pop_front(){if!self.regioncx.region_contains(self.region_vid,p){*&*&(); +continue;;}if!visited.insert(p){;continue;;};let block_data=&self.body[p.block]; +match self.def_use(p,block_data. visitable(p.statement_index)){Some(DefUseResult +::Def)=>{}Some(DefUseResult::UseLive{local})=>{;return Some(Cause::LiveVar(local +,p));;}Some(DefUseResult::UseDrop{local})=>{return Some(Cause::DropVar(local,p)) +;3;}None=>{if p.statement_index)->Option{(); +let mut visitor=DefUseVisitor{body:self.body,tcx:self.tcx,region_vid:self.//{;}; +region_vid,def_use_result:None,};3;;thing.apply(location,&mut visitor);;visitor. +def_use_result}}struct DefUseVisitor<'cx,'tcx>{body :&'cx Body<'tcx>,tcx:TyCtxt< +'tcx>,region_vid:RegionVid,def_use_result:Option,}enum//if true{}; +DefUseResult{Def,UseLive{local:Local},UseDrop{local:Local},}impl<'cx,'tcx>//{;}; +Visitor<'tcx>for DefUseVisitor<'cx,'tcx>{fn visit_local(&mut self,local:Local,// +context:PlaceContext,_:Location){;let local_ty=self.body.local_decls[local].ty;; +let mut found_it=false;;self.tcx.for_each_free_region(&local_ty,|r|{if r.as_var( +)==self.region_vid{3;found_it=true;;}});;if found_it{;self.def_use_result=match +def_use::categorize(context){Some(DefUse::Def )=>(Some(DefUseResult::Def)),Some( +DefUse::Use)=>((Some((DefUseResult::UseLive{local})))),Some(DefUse::Drop)=>Some( +DefUseResult::UseDrop{local}),None=>None,};((),());let _=();((),());let _=();}}} diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 0106e285604d6..5cfe6250b6951 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -1,1310 +1,379 @@ -//! Borrow checker diagnostics. - -use crate::session_diagnostics::{ - CaptureArgLabel, CaptureReasonLabel, CaptureReasonNote, CaptureReasonSuggest, CaptureVarCause, - CaptureVarKind, CaptureVarPathUseCause, OnClosureNote, -}; -use rustc_errors::{Applicability, Diag}; -use rustc_hir as hir; -use rustc_hir::def::{CtorKind, Namespace}; -use rustc_hir::CoroutineKind; -use rustc_index::IndexSlice; -use rustc_infer::infer::BoundRegionConversionTime; -use rustc_infer::traits::{FulfillmentErrorCode, SelectionError}; -use rustc_middle::mir::tcx::PlaceTy; -use rustc_middle::mir::{ - AggregateKind, CallSource, ConstOperand, FakeReadCause, Local, LocalInfo, LocalKind, Location, - Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, - TerminatorKind, -}; -use rustc_middle::ty::print::Print; -use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; -use rustc_middle::util::{call_kind, CallDesugaringKind}; -use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult}; -use rustc_span::def_id::LocalDefId; -use rustc_span::source_map::Spanned; -use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP}; -use rustc_target::abi::{FieldIdx, VariantIdx}; -use rustc_trait_selection::infer::InferCtxtExt; -use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _; -use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions; - -use super::borrow_set::BorrowData; -use super::MirBorrowckCtxt; - -mod find_all_local_uses; -mod find_use; -mod outlives_suggestion; -mod region_name; -mod var_name; - -mod bound_region_errors; -mod conflict_errors; -mod explain_borrow; -mod move_errors; -mod mutability_errors; -mod region_errors; - -pub(crate) use bound_region_errors::{ToUniverseInfo, UniverseInfo}; -pub(crate) use move_errors::{IllegalMoveOriginKind, MoveError}; -pub(crate) use mutability_errors::AccessKind; -pub(crate) use outlives_suggestion::OutlivesSuggestionBuilder; -pub(crate) use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors}; -pub(crate) use region_name::{RegionName, RegionNameSource}; -pub(crate) use rustc_middle::util::CallKind; - -pub(super) struct DescribePlaceOpt { - pub including_downcast: bool, - - /// Enable/Disable tuple fields. - /// For example `x` tuple. if it's `true` `x.0`. Otherwise `x` - pub including_tuple_field: bool, -} - -pub(super) struct IncludingTupleField(pub(super) bool); - -impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { - /// Adds a suggestion when a closure is invoked twice with a moved variable or when a closure - /// is moved after being invoked. - /// - /// ```text - /// note: closure cannot be invoked more than once because it moves the variable `dict` out of - /// its environment - /// --> $DIR/issue-42065.rs:16:29 - /// | - /// LL | for (key, value) in dict { - /// | ^^^^ - /// ``` - #[allow(rustc::diagnostic_outside_of_impl)] // FIXME - pub(super) fn add_moved_or_invoked_closure_note( - &self, - location: Location, - place: PlaceRef<'tcx>, - diag: &mut Diag<'_>, - ) -> bool { - debug!("add_moved_or_invoked_closure_note: location={:?} place={:?}", location, place); - let mut target = place.local_or_deref_local(); - for stmt in &self.body[location.block].statements[location.statement_index..] { - debug!("add_moved_or_invoked_closure_note: stmt={:?} target={:?}", stmt, target); - if let StatementKind::Assign(box (into, Rvalue::Use(from))) = &stmt.kind { - debug!("add_fnonce_closure_note: into={:?} from={:?}", into, from); - match from { - Operand::Copy(place) | Operand::Move(place) - if target == place.local_or_deref_local() => - { - target = into.local_or_deref_local() - } - _ => {} - } - } - } - - // Check if we are attempting to call a closure after it has been invoked. - let terminator = self.body[location.block].terminator(); - debug!("add_moved_or_invoked_closure_note: terminator={:?}", terminator); - if let TerminatorKind::Call { - func: Operand::Constant(box ConstOperand { const_, .. }), - args, - .. - } = &terminator.kind - { - if let ty::FnDef(id, _) = *const_.ty().kind() { - debug!("add_moved_or_invoked_closure_note: id={:?}", id); - if Some(self.infcx.tcx.parent(id)) == self.infcx.tcx.lang_items().fn_once_trait() { - let closure = match args.first() { - Some(Spanned { - node: Operand::Copy(place) | Operand::Move(place), .. - }) if target == place.local_or_deref_local() => { - place.local_or_deref_local().unwrap() - } - _ => return false, - }; - - debug!("add_moved_or_invoked_closure_note: closure={:?}", closure); - if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() { - let did = did.expect_local(); - if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) { - diag.subdiagnostic( - self.dcx(), - OnClosureNote::InvokedTwice { - place_name: &ty::place_to_string_for_capture( - self.infcx.tcx, - hir_place, - ), - span: *span, - }, - ); - return true; - } - } - } - } - } - - // Check if we are just moving a closure after it has been invoked. - if let Some(target) = target { - if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind() { - let did = did.expect_local(); - if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) { - diag.subdiagnostic( - self.dcx(), - OnClosureNote::MovedTwice { - place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place), - span: *span, - }, - ); - return true; - } - } - } - false - } - - /// End-user visible description of `place` if one can be found. - /// If the place is a temporary for instance, `"value"` will be returned. - pub(super) fn describe_any_place(&self, place_ref: PlaceRef<'tcx>) -> String { - match self.describe_place(place_ref) { - Some(mut descr) => { - // Surround descr with `backticks`. - descr.reserve(2); - descr.insert(0, '`'); - descr.push('`'); - descr - } - None => "value".to_string(), - } - } - - /// End-user visible description of `place` if one can be found. - /// If the place is a temporary for instance, `None` will be returned. - pub(super) fn describe_place(&self, place_ref: PlaceRef<'tcx>) -> Option { - self.describe_place_with_options( - place_ref, - DescribePlaceOpt { including_downcast: false, including_tuple_field: true }, - ) - } - - /// End-user visible description of `place` if one can be found. If the place is a temporary - /// for instance, `None` will be returned. - /// `IncludingDowncast` parameter makes the function return `None` if `ProjectionElem` is - /// `Downcast` and `IncludingDowncast` is true - pub(super) fn describe_place_with_options( - &self, - place: PlaceRef<'tcx>, - opt: DescribePlaceOpt, - ) -> Option { - let local = place.local; - let mut autoderef_index = None; - let mut buf = String::new(); - let mut ok = self.append_local_to_string(local, &mut buf); - - for (index, elem) in place.projection.into_iter().enumerate() { - match elem { - ProjectionElem::Deref => { - if index == 0 { - if self.body.local_decls[local].is_ref_for_guard() { - continue; - } - if let LocalInfo::StaticRef { def_id, .. } = - *self.body.local_decls[local].local_info() - { - buf.push_str(self.infcx.tcx.item_name(def_id).as_str()); - ok = Ok(()); - continue; - } - } - if let Some(field) = self.is_upvar_field_projection(PlaceRef { - local, - projection: place.projection.split_at(index + 1).0, - }) { - let var_index = field.index(); - buf = self.upvars[var_index].to_string(self.infcx.tcx); - ok = Ok(()); - if !self.upvars[var_index].is_by_ref() { - buf.insert(0, '*'); - } - } else { - if autoderef_index.is_none() { - autoderef_index = match place.projection.iter().rposition(|elem| { - !matches!( - elem, - ProjectionElem::Deref | ProjectionElem::Downcast(..) - ) - }) { - Some(index) => Some(index + 1), - None => Some(0), - }; - } - if index >= autoderef_index.unwrap() { - buf.insert(0, '*'); - } - } - } - ProjectionElem::Downcast(..) if opt.including_downcast => return None, - ProjectionElem::Downcast(..) => (), - ProjectionElem::OpaqueCast(..) => (), - ProjectionElem::Subtype(..) => (), - ProjectionElem::Field(field, _ty) => { - // FIXME(project-rfc_2229#36): print capture precisely here. - if let Some(field) = self.is_upvar_field_projection(PlaceRef { - local, - projection: place.projection.split_at(index + 1).0, - }) { - buf = self.upvars[field.index()].to_string(self.infcx.tcx); - ok = Ok(()); - } else { - let field_name = self.describe_field( - PlaceRef { local, projection: place.projection.split_at(index).0 }, - *field, - IncludingTupleField(opt.including_tuple_field), - ); - if let Some(field_name_str) = field_name { - buf.push('.'); - buf.push_str(&field_name_str); - } - } - } - ProjectionElem::Index(index) => { - buf.push('['); - if self.append_local_to_string(*index, &mut buf).is_err() { - buf.push('_'); - } - buf.push(']'); - } - ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { - // Since it isn't possible to borrow an element on a particular index and - // then use another while the borrow is held, don't output indices details - // to avoid confusing the end-user - buf.push_str("[..]"); - } - } - } - ok.ok().map(|_| buf) - } - - fn describe_name(&self, place: PlaceRef<'tcx>) -> Option { - for elem in place.projection.into_iter() { - match elem { - ProjectionElem::Downcast(Some(name), _) => { - return Some(*name); - } - _ => {} - } - } - None - } - - /// Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have - /// a name, or its name was generated by the compiler, then `Err` is returned - fn append_local_to_string(&self, local: Local, buf: &mut String) -> Result<(), ()> { - let decl = &self.body.local_decls[local]; - match self.local_names[local] { - Some(name) if !decl.from_compiler_desugaring() => { - buf.push_str(name.as_str()); - Ok(()) - } - _ => Err(()), - } - } - - /// End-user visible description of the `field`nth field of `base` - fn describe_field( - &self, - place: PlaceRef<'tcx>, - field: FieldIdx, - including_tuple_field: IncludingTupleField, - ) -> Option { - let place_ty = match place { - PlaceRef { local, projection: [] } => PlaceTy::from_ty(self.body.local_decls[local].ty), - PlaceRef { local, projection: [proj_base @ .., elem] } => match elem { - ProjectionElem::Deref - | ProjectionElem::Index(..) - | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. } => { - PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx) - } - ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx), - ProjectionElem::Subtype(ty) | ProjectionElem::OpaqueCast(ty) => { - PlaceTy::from_ty(*ty) - } - ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type), - }, - }; - self.describe_field_from_ty( - place_ty.ty, - field, - place_ty.variant_index, - including_tuple_field, - ) - } - - /// End-user visible description of the `field_index`nth field of `ty` - fn describe_field_from_ty( - &self, - ty: Ty<'_>, - field: FieldIdx, - variant_index: Option, - including_tuple_field: IncludingTupleField, - ) -> Option { - if ty.is_box() { - // If the type is a box, the field is described from the boxed type - self.describe_field_from_ty(ty.boxed_ty(), field, variant_index, including_tuple_field) - } else { - match *ty.kind() { - ty::Adt(def, _) => { - let variant = if let Some(idx) = variant_index { - assert!(def.is_enum()); - def.variant(idx) - } else { - def.non_enum_variant() - }; - if !including_tuple_field.0 && variant.ctor_kind() == Some(CtorKind::Fn) { - return None; - } - Some(variant.fields[field].name.to_string()) - } - ty::Tuple(_) => Some(field.index().to_string()), - ty::Ref(_, ty, _) | ty::RawPtr(ty, _) => { - self.describe_field_from_ty(ty, field, variant_index, including_tuple_field) - } - ty::Array(ty, _) | ty::Slice(ty) => { - self.describe_field_from_ty(ty, field, variant_index, including_tuple_field) - } - ty::Closure(def_id, _) | ty::Coroutine(def_id, _) => { - // We won't be borrowck'ing here if the closure came from another crate, - // so it's safe to call `expect_local`. - // - // We know the field exists so it's safe to call operator[] and `unwrap` here. - let def_id = def_id.expect_local(); - let var_id = - self.infcx.tcx.closure_captures(def_id)[field.index()].get_root_variable(); - - Some(self.infcx.tcx.hir().name(var_id).to_string()) - } - _ => { - // Might need a revision when the fields in trait RFC is implemented - // (https://github.com/rust-lang/rfcs/pull/1546) - bug!("End-user description not implemented for field access on `{:?}`", ty); - } - } - } - } - - pub(super) fn borrowed_content_source( - &self, - deref_base: PlaceRef<'tcx>, - ) -> BorrowedContentSource<'tcx> { - let tcx = self.infcx.tcx; - - // Look up the provided place and work out the move path index for it, - // we'll use this to check whether it was originally from an overloaded - // operator. - match self.move_data.rev_lookup.find(deref_base) { - LookupResult::Exact(mpi) | LookupResult::Parent(Some(mpi)) => { - debug!("borrowed_content_source: mpi={:?}", mpi); - - for i in &self.move_data.init_path_map[mpi] { - let init = &self.move_data.inits[*i]; - debug!("borrowed_content_source: init={:?}", init); - // We're only interested in statements that initialized a value, not the - // initializations from arguments. - let InitLocation::Statement(loc) = init.location else { continue }; - - let bbd = &self.body[loc.block]; - let is_terminator = bbd.statements.len() == loc.statement_index; - debug!( - "borrowed_content_source: loc={:?} is_terminator={:?}", - loc, is_terminator, - ); - if !is_terminator { - continue; - } else if let Some(Terminator { - kind: - TerminatorKind::Call { - func, - call_source: CallSource::OverloadedOperator, - .. - }, - .. - }) = &bbd.terminator - { - if let Some(source) = - BorrowedContentSource::from_call(func.ty(self.body, tcx), tcx) - { - return source; - } - } - } - } - // Base is a `static` so won't be from an overloaded operator - _ => (), - }; - - // If we didn't find an overloaded deref or index, then assume it's a - // built in deref and check the type of the base. - let base_ty = deref_base.ty(self.body, tcx).ty; - if base_ty.is_unsafe_ptr() { - BorrowedContentSource::DerefRawPointer - } else if base_ty.is_mutable_ptr() { - BorrowedContentSource::DerefMutableRef - } else { - BorrowedContentSource::DerefSharedRef - } - } - - /// Return the name of the provided `Ty` (that must be a reference) with a synthesized lifetime - /// name where required. - pub(super) fn get_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String { - let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, Namespace::TypeNS); - - // We need to add synthesized lifetimes where appropriate. We do - // this by hooking into the pretty printer and telling it to label the - // lifetimes without names with the value `'0`. - if let ty::Ref(region, ..) = ty.kind() { - match **region { - ty::ReBound(_, ty::BoundRegion { kind: br, .. }) - | ty::RePlaceholder(ty::PlaceholderRegion { - bound: ty::BoundRegion { kind: br, .. }, - .. - }) => printer.region_highlight_mode.highlighting_bound_region(br, counter), - _ => {} - } - } - - ty.print(&mut printer).unwrap(); - printer.into_buffer() - } - - /// Returns the name of the provided `Ty` (that must be a reference)'s region with a - /// synthesized lifetime name where required. - pub(super) fn get_region_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String { - let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, Namespace::TypeNS); - - let region = if let ty::Ref(region, ..) = ty.kind() { - match **region { - ty::ReBound(_, ty::BoundRegion { kind: br, .. }) - | ty::RePlaceholder(ty::PlaceholderRegion { - bound: ty::BoundRegion { kind: br, .. }, - .. - }) => printer.region_highlight_mode.highlighting_bound_region(br, counter), - _ => {} - } - region - } else { - bug!("ty for annotation of borrow region is not a reference"); - }; - - region.print(&mut printer).unwrap(); - printer.into_buffer() - } -} - -/// The span(s) associated to a use of a place. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub(super) enum UseSpans<'tcx> { - /// The access is caused by capturing a variable for a closure. - ClosureUse { - /// This is true if the captured variable was from a coroutine. - closure_kind: hir::ClosureKind, - /// The span of the args of the closure, including the `move` keyword if - /// it's present. - args_span: Span, - /// The span of the use resulting in capture kind - /// Check `ty::CaptureInfo` for more details - capture_kind_span: Span, - /// The span of the use resulting in the captured path - /// Check `ty::CaptureInfo` for more details - path_span: Span, - }, - /// The access is caused by using a variable as the receiver of a method - /// that takes 'self' - FnSelfUse { - /// The span of the variable being moved - var_span: Span, - /// The span of the method call on the variable - fn_call_span: Span, - /// The definition span of the method being called - fn_span: Span, - kind: CallKind<'tcx>, - }, - /// This access is caused by a `match` or `if let` pattern. - PatUse(Span), - /// This access has a single span associated to it: common case. - OtherUse(Span), -} - -impl UseSpans<'_> { - pub(super) fn args_or_use(self) -> Span { - match self { - UseSpans::ClosureUse { args_span: span, .. } - | UseSpans::PatUse(span) - | UseSpans::OtherUse(span) => span, - UseSpans::FnSelfUse { fn_call_span, kind: CallKind::DerefCoercion { .. }, .. } => { - fn_call_span - } - UseSpans::FnSelfUse { var_span, .. } => var_span, - } - } - - /// Returns the span of `self`, in the case of a `ClosureUse` returns the `path_span` - pub(super) fn var_or_use_path_span(self) -> Span { - match self { - UseSpans::ClosureUse { path_span: span, .. } - | UseSpans::PatUse(span) - | UseSpans::OtherUse(span) => span, - UseSpans::FnSelfUse { fn_call_span, kind: CallKind::DerefCoercion { .. }, .. } => { - fn_call_span - } - UseSpans::FnSelfUse { var_span, .. } => var_span, - } - } - - /// Returns the span of `self`, in the case of a `ClosureUse` returns the `capture_kind_span` - pub(super) fn var_or_use(self) -> Span { - match self { - UseSpans::ClosureUse { capture_kind_span: span, .. } - | UseSpans::PatUse(span) - | UseSpans::OtherUse(span) => span, - UseSpans::FnSelfUse { fn_call_span, kind: CallKind::DerefCoercion { .. }, .. } => { - fn_call_span - } - UseSpans::FnSelfUse { var_span, .. } => var_span, - } - } - - // FIXME(coroutines): Make this just return the `ClosureKind` directly? - pub(super) fn coroutine_kind(self) -> Option { - match self { - UseSpans::ClosureUse { - closure_kind: hir::ClosureKind::Coroutine(coroutine_kind), - .. - } => Some(coroutine_kind), - _ => None, - } - } - - /// Add a span label to the arguments of the closure, if it exists. - #[allow(rustc::diagnostic_outside_of_impl)] - pub(super) fn args_subdiag( - self, - dcx: &rustc_errors::DiagCtxt, - err: &mut Diag<'_>, - f: impl FnOnce(Span) -> CaptureArgLabel, - ) { - if let UseSpans::ClosureUse { args_span, .. } = self { - err.subdiagnostic(dcx, f(args_span)); - } - } - - /// Add a span label to the use of the captured variable, if it exists. - /// only adds label to the `path_span` - #[allow(rustc::diagnostic_outside_of_impl)] - pub(super) fn var_path_only_subdiag( - self, - dcx: &rustc_errors::DiagCtxt, - err: &mut Diag<'_>, - action: crate::InitializationRequiringAction, - ) { - use crate::InitializationRequiringAction::*; - use CaptureVarPathUseCause::*; - if let UseSpans::ClosureUse { closure_kind, path_span, .. } = self { - match closure_kind { - hir::ClosureKind::Coroutine(_) => { - err.subdiagnostic( - dcx, - match action { - Borrow => BorrowInCoroutine { path_span }, - MatchOn | Use => UseInCoroutine { path_span }, - Assignment => AssignInCoroutine { path_span }, - PartialAssignment => AssignPartInCoroutine { path_span }, - }, - ); - } - hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { - err.subdiagnostic( - dcx, - match action { - Borrow => BorrowInClosure { path_span }, - MatchOn | Use => UseInClosure { path_span }, - Assignment => AssignInClosure { path_span }, - PartialAssignment => AssignPartInClosure { path_span }, - }, - ); - } - } - } - } - - /// Add a subdiagnostic to the use of the captured variable, if it exists. - #[allow(rustc::diagnostic_outside_of_impl)] - pub(super) fn var_subdiag( - self, - dcx: &rustc_errors::DiagCtxt, - err: &mut Diag<'_>, - kind: Option, - f: impl FnOnce(hir::ClosureKind, Span) -> CaptureVarCause, - ) { - if let UseSpans::ClosureUse { closure_kind, capture_kind_span, path_span, .. } = self { - if capture_kind_span != path_span { - err.subdiagnostic( - dcx, - match kind { - Some(kd) => match kd { - rustc_middle::mir::BorrowKind::Shared - | rustc_middle::mir::BorrowKind::Fake => { - CaptureVarKind::Immut { kind_span: capture_kind_span } - } - - rustc_middle::mir::BorrowKind::Mut { .. } => { - CaptureVarKind::Mut { kind_span: capture_kind_span } - } - }, - None => CaptureVarKind::Move { kind_span: capture_kind_span }, - }, - ); - }; - let diag = f(closure_kind, path_span); - err.subdiagnostic(dcx, diag); - } - } - - /// Returns `false` if this place is not used in a closure. - pub(super) fn for_closure(&self) -> bool { - match *self { - UseSpans::ClosureUse { closure_kind, .. } => { - matches!(closure_kind, hir::ClosureKind::Closure) - } - _ => false, - } - } - - /// Returns `false` if this place is not used in a coroutine. - pub(super) fn for_coroutine(&self) -> bool { - match *self { - // FIXME(coroutines): Do we want this to apply to synthetic coroutines? - UseSpans::ClosureUse { closure_kind, .. } => { - matches!(closure_kind, hir::ClosureKind::Coroutine(..)) - } - _ => false, - } - } - - pub(super) fn or_else(self, if_other: F) -> Self - where - F: FnOnce() -> Self, - { - match self { - closure @ UseSpans::ClosureUse { .. } => closure, - UseSpans::PatUse(_) | UseSpans::OtherUse(_) => if_other(), - fn_self @ UseSpans::FnSelfUse { .. } => fn_self, - } - } -} - -pub(super) enum BorrowedContentSource<'tcx> { - DerefRawPointer, - DerefMutableRef, - DerefSharedRef, - OverloadedDeref(Ty<'tcx>), - OverloadedIndex(Ty<'tcx>), -} - -impl<'tcx> BorrowedContentSource<'tcx> { - pub(super) fn describe_for_unnamed_place(&self, tcx: TyCtxt<'_>) -> String { - match *self { - BorrowedContentSource::DerefRawPointer => "a raw pointer".to_string(), - BorrowedContentSource::DerefSharedRef => "a shared reference".to_string(), - BorrowedContentSource::DerefMutableRef => "a mutable reference".to_string(), - BorrowedContentSource::OverloadedDeref(ty) => ty - .ty_adt_def() - .and_then(|adt| match tcx.get_diagnostic_name(adt.did())? { - name @ (sym::Rc | sym::Arc) => Some(format!("an `{name}`")), - _ => None, - }) - .unwrap_or_else(|| format!("dereference of `{ty}`")), - BorrowedContentSource::OverloadedIndex(ty) => format!("index of `{ty}`"), - } - } - - pub(super) fn describe_for_named_place(&self) -> Option<&'static str> { - match *self { - BorrowedContentSource::DerefRawPointer => Some("raw pointer"), - BorrowedContentSource::DerefSharedRef => Some("shared reference"), - BorrowedContentSource::DerefMutableRef => Some("mutable reference"), - // Overloaded deref and index operators should be evaluated into a - // temporary. So we don't need a description here. - BorrowedContentSource::OverloadedDeref(_) - | BorrowedContentSource::OverloadedIndex(_) => None, - } - } - - pub(super) fn describe_for_immutable_place(&self, tcx: TyCtxt<'_>) -> String { - match *self { - BorrowedContentSource::DerefRawPointer => "a `*const` pointer".to_string(), - BorrowedContentSource::DerefSharedRef => "a `&` reference".to_string(), - BorrowedContentSource::DerefMutableRef => { - bug!("describe_for_immutable_place: DerefMutableRef isn't immutable") - } - BorrowedContentSource::OverloadedDeref(ty) => ty - .ty_adt_def() - .and_then(|adt| match tcx.get_diagnostic_name(adt.did())? { - name @ (sym::Rc | sym::Arc) => Some(format!("an `{name}`")), - _ => None, - }) - .unwrap_or_else(|| format!("dereference of `{ty}`")), - BorrowedContentSource::OverloadedIndex(ty) => format!("an index of `{ty}`"), - } - } - - fn from_call(func: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Option { - match *func.kind() { - ty::FnDef(def_id, args) => { - let trait_id = tcx.trait_of_item(def_id)?; - - let lang_items = tcx.lang_items(); - if Some(trait_id) == lang_items.deref_trait() - || Some(trait_id) == lang_items.deref_mut_trait() - { - Some(BorrowedContentSource::OverloadedDeref(args.type_at(0))) - } else if Some(trait_id) == lang_items.index_trait() - || Some(trait_id) == lang_items.index_mut_trait() - { - Some(BorrowedContentSource::OverloadedIndex(args.type_at(0))) - } else { - None - } - } - _ => None, - } - } -} - -///helper struct for explain_captures() -struct CapturedMessageOpt { - is_partial_move: bool, - is_loop_message: bool, - is_move_msg: bool, - is_loop_move: bool, - maybe_reinitialized_locations_is_empty: bool, -} - -impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { - /// Finds the spans associated to a move or copy of move_place at location. - pub(super) fn move_spans( - &self, - moved_place: PlaceRef<'tcx>, // Could also be an upvar. - location: Location, - ) -> UseSpans<'tcx> { - use self::UseSpans::*; - - let Some(stmt) = self.body[location.block].statements.get(location.statement_index) else { - return OtherUse(self.body.source_info(location).span); - }; - - debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt); - if let StatementKind::Assign(box (_, Rvalue::Aggregate(kind, places))) = &stmt.kind - && let AggregateKind::Closure(def_id, _) | AggregateKind::Coroutine(def_id, _) = **kind - { - debug!("move_spans: def_id={:?} places={:?}", def_id, places); - let def_id = def_id.expect_local(); - if let Some((args_span, closure_kind, capture_kind_span, path_span)) = - self.closure_span(def_id, moved_place, places) - { - return ClosureUse { closure_kind, args_span, capture_kind_span, path_span }; - } - } - - // StatementKind::FakeRead only contains a def_id if they are introduced as a result - // of pattern matching within a closure. - if let StatementKind::FakeRead(box (cause, place)) = stmt.kind { - match cause { - FakeReadCause::ForMatchedPlace(Some(closure_def_id)) - | FakeReadCause::ForLet(Some(closure_def_id)) => { - debug!("move_spans: def_id={:?} place={:?}", closure_def_id, place); - let places = &[Operand::Move(place)]; - if let Some((args_span, closure_kind, capture_kind_span, path_span)) = - self.closure_span(closure_def_id, moved_place, IndexSlice::from_raw(places)) - { - return ClosureUse { - closure_kind, - args_span, - capture_kind_span, - path_span, - }; - } - } - _ => {} - } - } - - let normal_ret = - if moved_place.projection.iter().any(|p| matches!(p, ProjectionElem::Downcast(..))) { - PatUse(stmt.source_info.span) - } else { - OtherUse(stmt.source_info.span) - }; - - // We are trying to find MIR of the form: - // ``` - // _temp = _moved_val; - // ... - // FnSelfCall(_temp, ...) - // ``` - // - // where `_moved_val` is the place we generated the move error for, - // `_temp` is some other local, and `FnSelfCall` is a function - // that has a `self` parameter. - - let target_temp = match stmt.kind { - StatementKind::Assign(box (temp, _)) if temp.as_local().is_some() => { - temp.as_local().unwrap() - } - _ => return normal_ret, - }; - - debug!("move_spans: target_temp = {:?}", target_temp); - - if let Some(Terminator { - kind: TerminatorKind::Call { fn_span, call_source, .. }, .. - }) = &self.body[location.block].terminator - { - let Some((method_did, method_args)) = rustc_middle::util::find_self_call( - self.infcx.tcx, - self.body, - target_temp, - location.block, - ) else { - return normal_ret; - }; - - let kind = call_kind( - self.infcx.tcx, - self.param_env, - method_did, - method_args, - *fn_span, - call_source.from_hir_call(), - Some(self.infcx.tcx.fn_arg_names(method_did)[0]), - ); - - return FnSelfUse { - var_span: stmt.source_info.span, - fn_call_span: *fn_span, - fn_span: self.infcx.tcx.def_span(method_did), - kind, - }; - } - normal_ret - } - - /// Finds the span of arguments of a closure (within `maybe_closure_span`) - /// and its usage of the local assigned at `location`. - /// This is done by searching in statements succeeding `location` - /// and originating from `maybe_closure_span`. - pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans<'tcx> { - use self::UseSpans::*; - debug!("borrow_spans: use_span={:?} location={:?}", use_span, location); - - let target = match self.body[location.block].statements.get(location.statement_index) { - Some(Statement { kind: StatementKind::Assign(box (place, _)), .. }) => { - if let Some(local) = place.as_local() { - local - } else { - return OtherUse(use_span); - } - } - _ => return OtherUse(use_span), - }; - - if self.body.local_kind(target) != LocalKind::Temp { - // operands are always temporaries. - return OtherUse(use_span); - } - - // drop and replace might have moved the assignment to the next block - let maybe_additional_statement = - if let TerminatorKind::Drop { target: drop_target, .. } = - self.body[location.block].terminator().kind - { - self.body[drop_target].statements.first() - } else { - None - }; - - let statements = - self.body[location.block].statements[location.statement_index + 1..].iter(); - - for stmt in statements.chain(maybe_additional_statement) { - if let StatementKind::Assign(box (_, Rvalue::Aggregate(kind, places))) = &stmt.kind { - let (&def_id, is_coroutine) = match kind { - box AggregateKind::Closure(def_id, _) => (def_id, false), - box AggregateKind::Coroutine(def_id, _) => (def_id, true), - _ => continue, - }; - let def_id = def_id.expect_local(); - - debug!( - "borrow_spans: def_id={:?} is_coroutine={:?} places={:?}", - def_id, is_coroutine, places - ); - if let Some((args_span, closure_kind, capture_kind_span, path_span)) = - self.closure_span(def_id, Place::from(target).as_ref(), places) - { - return ClosureUse { closure_kind, args_span, capture_kind_span, path_span }; - } else { - return OtherUse(use_span); - } - } - - if use_span != stmt.source_info.span { - break; - } - } - - OtherUse(use_span) - } - - /// Finds the spans of a captured place within a closure or coroutine. - /// The first span is the location of the use resulting in the capture kind of the capture - /// The second span is the location the use resulting in the captured path of the capture - fn closure_span( - &self, - def_id: LocalDefId, - target_place: PlaceRef<'tcx>, - places: &IndexSlice>, - ) -> Option<(Span, hir::ClosureKind, Span, Span)> { - debug!( - "closure_span: def_id={:?} target_place={:?} places={:?}", - def_id, target_place, places - ); - let hir_id = self.infcx.tcx.local_def_id_to_hir_id(def_id); - let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind; - debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr); - if let hir::ExprKind::Closure(&hir::Closure { kind, fn_decl_span, .. }) = expr { - for (captured_place, place) in - self.infcx.tcx.closure_captures(def_id).iter().zip(places) - { - match place { - Operand::Copy(place) | Operand::Move(place) - if target_place == place.as_ref() => - { - debug!("closure_span: found captured local {:?}", place); - return Some(( - fn_decl_span, - kind, - captured_place.get_capture_kind_span(self.infcx.tcx), - captured_place.get_path_span(self.infcx.tcx), - )); - } - _ => {} - } - } - } - None - } - - /// Helper to retrieve span(s) of given borrow from the current MIR - /// representation - pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData<'_>) -> UseSpans<'tcx> { - let span = self.body.source_info(borrow.reserve_location).span; - self.borrow_spans(span, borrow.reserve_location) - } - - #[allow(rustc::diagnostic_outside_of_impl)] - #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable - fn explain_captures( - &mut self, - err: &mut Diag<'_>, - span: Span, - move_span: Span, - move_spans: UseSpans<'tcx>, - moved_place: Place<'tcx>, - msg_opt: CapturedMessageOpt, - ) { - let CapturedMessageOpt { - is_partial_move: is_partial, - is_loop_message, - is_move_msg, - is_loop_move, - maybe_reinitialized_locations_is_empty, - } = msg_opt; - if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans { - let place_name = self - .describe_place(moved_place.as_ref()) - .map(|n| format!("`{n}`")) - .unwrap_or_else(|| "value".to_owned()); - match kind { - CallKind::FnCall { fn_trait_id, .. } - if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() => - { - err.subdiagnostic( - self.dcx(), - CaptureReasonLabel::Call { - fn_call_span, - place_name: &place_name, - is_partial, - is_loop_message, - }, - ); - err.subdiagnostic(self.dcx(), CaptureReasonNote::FnOnceMoveInCall { var_span }); - } - CallKind::Operator { self_arg, trait_id, .. } => { - let self_arg = self_arg.unwrap(); - err.subdiagnostic( - self.dcx(), - CaptureReasonLabel::OperatorUse { - fn_call_span, - place_name: &place_name, - is_partial, - is_loop_message, - }, - ); - if self.fn_self_span_reported.insert(fn_span) { - let lang = self.infcx.tcx.lang_items(); - err.subdiagnostic( - self.dcx(), - if [lang.not_trait(), lang.deref_trait(), lang.neg_trait()] - .contains(&Some(trait_id)) - { - CaptureReasonNote::UnOpMoveByOperator { span: self_arg.span } - } else { - CaptureReasonNote::LhsMoveByOperator { span: self_arg.span } - }, - ); - } - } - CallKind::Normal { self_arg, desugaring, method_did, method_args } => { - let self_arg = self_arg.unwrap(); - let mut has_sugg = false; - let tcx = self.infcx.tcx; - // Avoid pointing to the same function in multiple different - // error messages. - if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) { - self.explain_iterator_advancement_in_for_loop_if_applicable( - err, - span, - &move_spans, - ); - - let func = tcx.def_path_str(method_did); - err.subdiagnostic( - self.dcx(), - CaptureReasonNote::FuncTakeSelf { - func, - place_name: place_name.clone(), - span: self_arg.span, - }, - ); - } - let parent_did = tcx.parent(method_did); - let parent_self_ty = - matches!(tcx.def_kind(parent_did), rustc_hir::def::DefKind::Impl { .. }) - .then_some(parent_did) - .and_then(|did| match tcx.type_of(did).instantiate_identity().kind() { - ty::Adt(def, ..) => Some(def.did()), - _ => None, - }); - let is_option_or_result = parent_self_ty.is_some_and(|def_id| { - matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result)) - }); - if is_option_or_result && maybe_reinitialized_locations_is_empty { - err.subdiagnostic( - self.dcx(), - CaptureReasonLabel::BorrowContent { var_span }, - ); - } - if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring { - let ty = moved_place.ty(self.body, tcx).ty; - let suggest = match tcx.get_diagnostic_item(sym::IntoIterator) { - Some(def_id) => type_known_to_meet_bound_modulo_regions( - self.infcx, - self.param_env, - Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, ty), - def_id, - ), - _ => false, - }; - if suggest { - err.subdiagnostic( - self.dcx(), - CaptureReasonSuggest::IterateSlice { - ty, - span: move_span.shrink_to_lo(), - }, - ); - } - - err.subdiagnostic( - self.dcx(), - CaptureReasonLabel::ImplicitCall { - fn_call_span, - place_name: &place_name, - is_partial, - is_loop_message, - }, - ); - // If the moved place was a `&mut` ref, then we can - // suggest to reborrow it where it was moved, so it - // will still be valid by the time we get to the usage. - 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 { - err.span_suggestion_verbose( - move_span.shrink_to_lo(), - format!( - "consider creating a fresh reborrow of {} here", - self.describe_place(moved_place.as_ref()) - .map(|n| format!("`{n}`")) - .unwrap_or_else(|| "the mutable reference".to_string()), - ), - "&mut *", - Applicability::MachineApplicable, - ); - } - } - } else { - if let Some((CallDesugaringKind::Await, _)) = desugaring { - err.subdiagnostic( - self.dcx(), - CaptureReasonLabel::Await { - fn_call_span, - place_name: &place_name, - is_partial, - is_loop_message, - }, - ); - } else { - err.subdiagnostic( - self.dcx(), - CaptureReasonLabel::MethodCall { - fn_call_span, - place_name: &place_name, - is_partial, - is_loop_message, - }, - ); - } - // Erase and shadow everything that could be passed to the new infcx. - let ty = moved_place.ty(self.body, tcx).ty; - - if let ty::Adt(def, args) = ty.peel_refs().kind() - && Some(def.did()) == tcx.lang_items().pin_type() - && let ty::Ref(_, _, hir::Mutability::Mut) = args.type_at(0).kind() - && let self_ty = self.infcx.instantiate_binder_with_fresh_vars( - fn_call_span, - BoundRegionConversionTime::FnCall, - tcx.fn_sig(method_did).instantiate(tcx, method_args).input(0), - ) - && self.infcx.can_eq(self.param_env, ty, self_ty) - { - err.subdiagnostic( - self.dcx(), - CaptureReasonSuggest::FreshReborrow { - span: move_span.shrink_to_hi(), - }, - ); - has_sugg = true; - } - if let Some(clone_trait) = tcx.lang_items().clone_trait() { - let sugg = if moved_place - .iter_projections() - .any(|(_, elem)| matches!(elem, ProjectionElem::Deref)) - { - vec![ - // We use the fully-qualified path because `.clone()` can - // sometimes choose `<&T as Clone>` instead of `` - // when going through auto-deref, so this ensures that doesn't - // happen, causing suggestions for `.clone().clone()`. - (move_span.shrink_to_lo(), format!("<{ty} as Clone>::clone(&")), - (move_span.shrink_to_hi(), ")".to_string()), - ] - } else { - vec![(move_span.shrink_to_hi(), ".clone()".to_string())] - }; - if let Some(errors) = self.infcx.type_implements_trait_shallow( - clone_trait, - ty, - self.param_env, - ) && !has_sugg - { - let msg = match &errors[..] { - [] => "you can `clone` the value and consume it, but this \ +use crate::session_diagnostics::{CaptureArgLabel,CaptureReasonLabel,//if true{}; +CaptureReasonNote,CaptureReasonSuggest,CaptureVarCause,CaptureVarKind,//((),()); +CaptureVarPathUseCause,OnClosureNote,};use rustc_errors::{Applicability,Diag};// +use rustc_hir as hir;use rustc_hir::def::{CtorKind,Namespace};use rustc_hir:://; +CoroutineKind;use rustc_index::IndexSlice;use rustc_infer::infer:://loop{break}; +BoundRegionConversionTime;use rustc_infer::traits::{FulfillmentErrorCode,//({}); +SelectionError};use rustc_middle::mir::tcx::PlaceTy;use rustc_middle::mir::{//3; +AggregateKind,CallSource,ConstOperand,FakeReadCause,Local,LocalInfo,LocalKind,// +Location,Operand,Place,PlaceRef,ProjectionElem,Rvalue,Statement,StatementKind,// +Terminator,TerminatorKind,};use rustc_middle ::ty::print::Print;use rustc_middle +::ty::{self,Instance,Ty,TyCtxt};use rustc_middle::util::{call_kind,//let _=||(); +CallDesugaringKind};use rustc_mir_dataflow::move_paths::{InitLocation,//((),()); +LookupResult};use rustc_span::def_id::LocalDefId;use rustc_span::source_map:://; +Spanned;use rustc_span::{symbol::sym,Span,Symbol,DUMMY_SP};use rustc_target:://; +abi::{FieldIdx,VariantIdx};use rustc_trait_selection::infer::InferCtxtExt;use//; +rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as// +_;use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;//; +use super::borrow_set::BorrowData;use super::MirBorrowckCtxt;mod//if let _=(){}; +find_all_local_uses;mod find_use;mod outlives_suggestion;mod region_name;mod//3; +var_name;mod bound_region_errors;mod conflict_errors;mod explain_borrow;mod//(); +move_errors;mod mutability_errors;mod region_errors;pub(crate)use//loop{break;}; +bound_region_errors::{ToUniverseInfo,UniverseInfo}; pub(crate)use move_errors::{ +IllegalMoveOriginKind,MoveError};pub(crate)use mutability_errors::AccessKind;//; +pub(crate)use outlives_suggestion::OutlivesSuggestionBuilder;pub(crate)use//{;}; +region_errors::{ErrorConstraintInfo,RegionErrorKind, RegionErrors};pub(crate)use +region_name::{RegionName,RegionNameSource};pub(crate)use rustc_middle::util:://; +CallKind;pub(super)struct DescribePlaceOpt{pub including_downcast:bool,pub//{;}; +including_tuple_field:bool,}pub(super) struct IncludingTupleField(pub(super)bool +);impl<'cx,'tcx>MirBorrowckCtxt<'cx,'tcx>{#[allow(rustc:://if true{};let _=||(); +diagnostic_outside_of_impl)]pub(super)fn add_moved_or_invoked_closure_note(&//3; +self,location:Location,place:PlaceRef<'tcx>,diag:&mut Diag<'_>,)->bool{3;debug!( +"add_moved_or_invoked_closure_note: location={:?} place={:?}",location,place);;; +let mut target=place.local_or_deref_local();({});for stmt in&self.body[location. +block].statements[location.statement_index..]{loop{break;};if let _=(){};debug!( +"add_moved_or_invoked_closure_note: stmt={:?} target={:?}",stmt,target);3;if let +StatementKind::Assign(box(into,Rvalue::Use(from)))=&stmt.kind{let _=||();debug!( +"add_fnonce_closure_note: into={:?} from={:?}",into,from);3;match from{Operand:: +Copy(place)|Operand::Move(place)if ((target==(place.local_or_deref_local())))=>{ +target=into.local_or_deref_local()}_=>{}}}}();let terminator=self.body[location. +block].terminator();;debug!("add_moved_or_invoked_closure_note: terminator={:?}" +,terminator);loop{break;};if let TerminatorKind::Call{func:Operand::Constant(box +ConstOperand{const_,..}),args,..}=((&terminator.kind )){if let ty::FnDef(id,_)=* +const_.ty().kind(){;debug!("add_moved_or_invoked_closure_note: id={:?}",id);;if +Some(self.infcx.tcx.parent(id))==self.infcx.tcx.lang_items().fn_once_trait(){(); +let closure=match args.first(){ Some(Spanned{node:Operand::Copy(place)|Operand:: +Move(place),..})if ((((target==((((place.local_or_deref_local()))))))))=>{place. +local_or_deref_local().unwrap()}_=>return false,};loop{break};let _=||();debug!( +"add_moved_or_invoked_closure_note: closure={:?}",closure);3;if let ty::Closure( +did,_)=self.body.local_decls[closure].ty.kind(){3;let did=did.expect_local();;if +let Some((span,hir_place))=self.infcx.tcx.closure_kind_origin(did){((),());diag. +subdiagnostic((((((self.dcx()))))), OnClosureNote::InvokedTwice{place_name:&ty:: +place_to_string_for_capture(self.infcx.tcx,hir_place,),span:*span,},);3;;return +true;*&*&();}}}}}if let Some(target)=target{if let ty::Closure(did,_)=self.body. +local_decls[target].ty.kind(){();let did=did.expect_local();3;if let Some((span, +hir_place))=self.infcx.tcx.closure_kind_origin(did){;diag.subdiagnostic(self.dcx +(),OnClosureNote::MovedTwice{place_name:&ty::place_to_string_for_capture(self.// +infcx.tcx,hir_place),span:*span,},);{;};{;};return true;();}}}false}pub(super)fn +describe_any_place(&self,place_ref:PlaceRef<'tcx>)->String{match self.//((),()); +describe_place(place_ref){Some(mut descr)=>{;descr.reserve(2);descr.insert(0,'`' +);;descr.push('`');descr}None=>"value".to_string(),}}pub(super)fn describe_place +(&self,place_ref:PlaceRef<'tcx>)->Option{self.//loop{break};loop{break}; +describe_place_with_options(place_ref,DescribePlaceOpt {including_downcast:false +,including_tuple_field:(true)},)}pub(super)fn describe_place_with_options(&self, +place:PlaceRef<'tcx>,opt:DescribePlaceOpt,)->Option{{;};let local=place. +local;;;let mut autoderef_index=None;;let mut buf=String::new();let mut ok=self. +append_local_to_string(local,&mut buf);{();};for(index,elem)in place.projection. +into_iter().enumerate(){match elem{ProjectionElem::Deref =>{if index==0{if self. +body.local_decls[local].is_ref_for_guard(){({});continue;{;};}if let LocalInfo:: +StaticRef{def_id,..}=*self.body.local_decls[local].local_info(){();buf.push_str( +self.infcx.tcx.item_name(def_id).as_str());;;ok=Ok(());;;continue;}}if let Some( +field)=self.is_upvar_field_projection(PlaceRef{local,projection:place.//((),()); +projection.split_at(index+1).0,}){;let var_index=field.index();;buf=self.upvars[ +var_index].to_string(self.infcx.tcx);();3;ok=Ok(());3;if!self.upvars[var_index]. +is_by_ref(){({});buf.insert(0,'*');({});}}else{if autoderef_index.is_none(){{;}; +autoderef_index=match (place.projection.iter()).rposition(|elem|{!matches!(elem, +ProjectionElem::Deref|ProjectionElem::Downcast(..))}) {Some(index)=>Some(index+1 +),None=>Some(0),};3;}if index>=autoderef_index.unwrap(){3;buf.insert(0,'*');;}}} +ProjectionElem::Downcast(..)if opt .including_downcast=>((((((return None)))))), +ProjectionElem::Downcast(..)=>(((()))),ProjectionElem::OpaqueCast(..)=>(((()))), +ProjectionElem::Subtype(..)=>(),ProjectionElem:: Field(field,_ty)=>{if let Some( +field)=self.is_upvar_field_projection(PlaceRef{local,projection:place.//((),()); +projection.split_at(index+1).0,}){;buf=self.upvars[field.index()].to_string(self +.infcx.tcx);;;ok=Ok(());}else{let field_name=self.describe_field(PlaceRef{local, +projection:(place.projection.split_at(index)).0},*field,IncludingTupleField(opt. +including_tuple_field),);;if let Some(field_name_str)=field_name{;buf.push('.'); +buf.push_str(&field_name_str);;}}}ProjectionElem::Index(index)=>{;buf.push('['); +if self.append_local_to_string(*index,&mut buf).is_err(){3;buf.push('_');;};buf. +push(']');;}ProjectionElem::ConstantIndex{..}|ProjectionElem::Subslice{..}=>{buf +.push_str("[..]");;}}}ok.ok().map(|_|buf)}fn describe_name(&self,place:PlaceRef< +'tcx>)->Option{for elem in ((place.projection.into_iter())){match elem{ +ProjectionElem::Downcast(Some(name),_)=>{();return Some(*name);3;}_=>{}}}None}fn +append_local_to_string(&self,local:Local,buf:&mut String)->Result<(),()>{{;};let +decl=&self.body.local_decls[local];3;match self.local_names[local]{Some(name)if! +decl.from_compiler_desugaring()=>{;buf.push_str(name.as_str());Ok(())}_=>Err(()) +,}}fn describe_field(&self,place:PlaceRef<'tcx>,field:FieldIdx,//*&*&();((),()); +including_tuple_field:IncludingTupleField,)->Option{3;let place_ty=match +place{PlaceRef{local,projection:[]}=>PlaceTy::from_ty(self.body.local_decls[//3; +local].ty),PlaceRef{local,projection:[proj_base@..,elem]}=>match elem{//((),()); +ProjectionElem::Deref|ProjectionElem::Index(..)|ProjectionElem::ConstantIndex{// +..}|ProjectionElem::Subslice{..}=>{ PlaceRef{local,projection:proj_base}.ty(self +.body,self.infcx.tcx)}ProjectionElem::Downcast(..)=>place.ty(self.body,self.//3; +infcx.tcx),ProjectionElem::Subtype(ty )|ProjectionElem::OpaqueCast(ty)=>{PlaceTy +::from_ty((((((*ty))))))}ProjectionElem::Field(_,field_type)=>PlaceTy::from_ty(* +field_type),},};let _=();self.describe_field_from_ty(place_ty.ty,field,place_ty. +variant_index,including_tuple_field,)}fn describe_field_from_ty (&self,ty:Ty<'_> +,field:FieldIdx,variant_index:Option,including_tuple_field://*&*&(); +IncludingTupleField,)->Option{if (((((((((((ty.is_box()))))))))))){self. +describe_field_from_ty(ty.boxed_ty() ,field,variant_index,including_tuple_field) +}else{match*ty.kind(){ty::Adt(def,_)=>{loop{break};let variant=if let Some(idx)= +variant_index{;assert!(def.is_enum());def.variant(idx)}else{def.non_enum_variant +()};;if!including_tuple_field.0&&variant.ctor_kind()==Some(CtorKind::Fn){;return +None;{;};}Some(variant.fields[field].name.to_string())}ty::Tuple(_)=>Some(field. +index().to_string()),ty::Ref(_,ty,_)|ty::RawPtr(ty,_)=>{self.//((),());let _=(); +describe_field_from_ty(ty,field,variant_index, including_tuple_field)}ty::Array( +ty,_)|ty::Slice(ty)=>{self.describe_field_from_ty(ty,field,variant_index,//({}); +including_tuple_field)}ty::Closure(def_id,_)|ty::Coroutine(def_id,_)=>{{();};let +def_id=def_id.expect_local();;let var_id=self.infcx.tcx.closure_captures(def_id) +[field.index()].get_root_variable();({});Some(self.infcx.tcx.hir().name(var_id). +to_string())}_=>{if let _=(){};*&*&();((),());if let _=(){};*&*&();((),());bug!( +"End-user description not implemented for field access on `{:?}`",ty);3;}}}}pub( +super)fn borrowed_content_source(&self,deref_base:PlaceRef<'tcx>,)->//if true{}; +BorrowedContentSource<'tcx>{();let tcx=self.infcx.tcx;();3;match self.move_data. +rev_lookup.find(deref_base){LookupResult:: Exact(mpi)|LookupResult::Parent(Some( +mpi))=>{;debug!("borrowed_content_source: mpi={:?}",mpi);for i in&self.move_data +.init_path_map[mpi]{{();};let init=&self.move_data.inits[*i];{();};{();};debug!( +"borrowed_content_source: init={:?}",init);3;3;let InitLocation::Statement(loc)= +init.location else{continue};;;let bbd=&self.body[loc.block];;let is_terminator= +bbd.statements.len()==loc.statement_index;((),());((),());*&*&();((),());debug!( +"borrowed_content_source: loc={:?} is_terminator={:?}",loc,is_terminator,);3;if! +is_terminator{;continue;;}else if let Some(Terminator{kind:TerminatorKind::Call{ +func,call_source:CallSource::OverloadedOperator,..},.. })=&bbd.terminator{if let +Some(source)=BorrowedContentSource::from_call(func.ty(self.body,tcx),tcx){{();}; +return source;3;}}}}_=>(),};3;3;let base_ty=deref_base.ty(self.body,tcx).ty;;if +base_ty.is_unsafe_ptr(){BorrowedContentSource:: DerefRawPointer}else if base_ty. +is_mutable_ptr(){BorrowedContentSource::DerefMutableRef}else{//((),());let _=(); +BorrowedContentSource::DerefSharedRef}}pub(super) fn get_name_for_ty(&self,ty:Ty +<'tcx>,counter:usize)->String{3;let mut printer=ty::print::FmtPrinter::new(self. +infcx.tcx,Namespace::TypeNS);;if let ty::Ref(region,..)=ty.kind(){match**region{ +ty::ReBound(_,ty::BoundRegion{kind:br,..})|ty::RePlaceholder(ty:://loop{break;}; +PlaceholderRegion{bound:ty::BoundRegion{kind:br,..},..})=>printer.//loop{break}; +region_highlight_mode.highlighting_bound_region(br,counter),_=>{}}}();ty.print(& +mut printer).unwrap();;printer.into_buffer()}pub(super)fn get_region_name_for_ty +(&self,ty:Ty<'tcx>,counter:usize)->String{;let mut printer=ty::print::FmtPrinter +::new(self.infcx.tcx,Namespace::TypeNS);;let region=if let ty::Ref(region,..)=ty +.kind(){match(((*((*region))))){ty:: ReBound(_,ty::BoundRegion{kind:br,..})|ty:: +RePlaceholder(ty::PlaceholderRegion{bound:ty::BoundRegion{kind:br,..},..})=>//3; +printer.region_highlight_mode.highlighting_bound_region(br,counter),_=>{}}//{;}; +region}else{;bug!("ty for annotation of borrow region is not a reference");;};;; +region.print(&mut printer).unwrap();;printer.into_buffer()}}#[derive(Copy,Clone, +PartialEq,Eq,Debug)]pub(super)enum UseSpans<'tcx>{ClosureUse{closure_kind:hir:: +ClosureKind,args_span:Span,capture_kind_span:Span,path_span:Span,},FnSelfUse{//; +var_span:Span,fn_call_span:Span,fn_span:Span, kind:CallKind<'tcx>,},PatUse(Span) +,OtherUse(Span),}impl UseSpans<'_>{pub(super)fn args_or_use(self)->Span{match//; +self{UseSpans::ClosureUse{args_span:span,..}|UseSpans::PatUse(span)|UseSpans::// +OtherUse(span)=>span,UseSpans::FnSelfUse{fn_call_span,kind:CallKind:://let _=(); +DerefCoercion{..},..}=>{fn_call_span }UseSpans::FnSelfUse{var_span,..}=>var_span +,}}pub(super)fn var_or_use_path_span(self)->Span{match self{UseSpans:://((),()); +ClosureUse{path_span:span,..}|UseSpans:: PatUse(span)|UseSpans::OtherUse(span)=> +span,UseSpans::FnSelfUse{fn_call_span,kind:CallKind::DerefCoercion{..},..}=>{//; +fn_call_span}UseSpans::FnSelfUse{var_span,..}=>var_span,}}pub(super)fn//((),()); +var_or_use(self)->Span{match self{UseSpans::ClosureUse{capture_kind_span:span,// +..}|UseSpans::PatUse(span)|UseSpans::OtherUse(span)=>span,UseSpans::FnSelfUse{// +fn_call_span,kind:CallKind::DerefCoercion{..},..}=>{fn_call_span}UseSpans:://(); +FnSelfUse{var_span,..}=>var_span,}}pub(super)fn coroutine_kind(self)->Option{match self{UseSpans::ClosureUse{closure_kind:hir::ClosureKind::// +Coroutine(coroutine_kind),..}=>(Some(coroutine_kind) ),_=>None,}}#[allow(rustc:: +diagnostic_outside_of_impl)]pub(super)fn args_subdiag(self,dcx:&rustc_errors::// +DiagCtxt,err:&mut Diag<'_>,f:impl FnOnce(Span)->CaptureArgLabel,){if let//{();}; +UseSpans::ClosureUse{args_span,..}=self{;err.subdiagnostic(dcx,f(args_span));}}# +[allow(rustc::diagnostic_outside_of_impl)]pub(super)fn var_path_only_subdiag(//; +self,dcx:&rustc_errors::DiagCtxt,err:&mut Diag<'_>,action:crate:://loop{break;}; +InitializationRequiringAction,){;use crate::InitializationRequiringAction::*;use +CaptureVarPathUseCause::*;();if let UseSpans::ClosureUse{closure_kind,path_span, +..}=self{match closure_kind{hir::ClosureKind::Coroutine(_)=>{;err.subdiagnostic( +dcx,match action{Borrow=>((((((BorrowInCoroutine {path_span})))))),MatchOn|Use=> +UseInCoroutine{path_span},Assignment =>((((((AssignInCoroutine{path_span})))))), +PartialAssignment=>AssignPartInCoroutine{path_span},},);({});}hir::ClosureKind:: +Closure|hir::ClosureKind::CoroutineClosure(_)=>{({});err.subdiagnostic(dcx,match +action{Borrow=>BorrowInClosure{path_span}, MatchOn|Use=>UseInClosure{path_span}, +Assignment=>(AssignInClosure{path_span}),PartialAssignment=>AssignPartInClosure{ +path_span},},);{();};}}}}#[allow(rustc::diagnostic_outside_of_impl)]pub(super)fn +var_subdiag(self,dcx:&rustc_errors::DiagCtxt,err:&mut Diag<'_>,kind:Option,f:impl FnOnce(hir::ClosureKind,Span)->//let _=(); +CaptureVarCause,){if let UseSpans::ClosureUse{closure_kind,capture_kind_span,//; +path_span,..}=self{;if capture_kind_span!=path_span{;err.subdiagnostic(dcx,match +kind{Some(kd)=>match kd{ rustc_middle::mir::BorrowKind::Shared|rustc_middle::mir +::BorrowKind::Fake=>{((((CaptureVarKind::Immut{kind_span:capture_kind_span}))))} +rustc_middle::mir::BorrowKind::Mut{..}=>{CaptureVarKind::Mut{kind_span://*&*&(); +capture_kind_span}}},None=>CaptureVarKind ::Move{kind_span:capture_kind_span},}, +);;};let diag=f(closure_kind,path_span);err.subdiagnostic(dcx,diag);}}pub(super) +fn for_closure(&self)->bool{match* self{UseSpans::ClosureUse{closure_kind,..}=>{ +matches!(closure_kind,hir::ClosureKind::Closure)}_=>((((false)))),}}pub(super)fn +for_coroutine(&self)->bool{match(*self){UseSpans::ClosureUse{closure_kind,..}=>{ +matches!(closure_kind,hir::ClosureKind::Coroutine(..))}_=>(false),}}pub(super)fn +or_else(self,if_other:F)->Self where F:FnOnce()->Self,{match self{closure@//; +UseSpans::ClosureUse{..}=>closure,UseSpans::PatUse(_)|UseSpans::OtherUse(_)=>//; +if_other(),fn_self@UseSpans::FnSelfUse{..}=>fn_self,}}}pub(super)enum//let _=(); +BorrowedContentSource<'tcx>{DerefRawPointer,DerefMutableRef,DerefSharedRef,//(); +OverloadedDeref(Ty<'tcx>),OverloadedIndex(Ty<'tcx>),}impl<'tcx>//*&*&();((),()); +BorrowedContentSource<'tcx>{pub(super)fn describe_for_unnamed_place(&self,tcx:// +TyCtxt<'_>)->String{match(((( *self)))){BorrowedContentSource::DerefRawPointer=> +"a raw pointer".to_string(),BorrowedContentSource::DerefSharedRef=>//let _=||(); +"a shared reference".to_string(),BorrowedContentSource::DerefMutableRef=>//({}); +"a mutable reference".to_string(),BorrowedContentSource::OverloadedDeref(ty)=>// +ty.ty_adt_def().and_then(|adt|match (tcx.get_diagnostic_name(adt.did())?){name@( +sym::Rc|sym::Arc)=>(Some((format!("an `{name}`")))),_=>None,}).unwrap_or_else(|| +format!("dereference of `{ty}`")),BorrowedContentSource::OverloadedIndex(ty)=>// +format!("index of `{ty}`"),}}pub(super)fn describe_for_named_place(&self)->//(); +Option<&'static str>{match(* self){BorrowedContentSource::DerefRawPointer=>Some( +"raw pointer"),BorrowedContentSource::DerefSharedRef=> Some("shared reference"), +BorrowedContentSource::DerefMutableRef=>((((Some(((("mutable reference")))))))), +BorrowedContentSource::OverloadedDeref(_)|BorrowedContentSource:://loop{break;}; +OverloadedIndex(_)=>None,}}pub( super)fn describe_for_immutable_place(&self,tcx: +TyCtxt<'_>)->String{match(((( *self)))){BorrowedContentSource::DerefRawPointer=> +"a `*const` pointer".to_string(),BorrowedContentSource::DerefSharedRef=>//{();}; +"a `&` reference".to_string(),BorrowedContentSource::DerefMutableRef=>{bug!(//3; +"describe_for_immutable_place: DerefMutableRef isn't immutable")}//loop{break;}; +BorrowedContentSource::OverloadedDeref(ty)=>ty. ty_adt_def().and_then(|adt|match +((tcx.get_diagnostic_name((adt.did())))?){name@(sym::Rc|sym::Arc)=>Some(format!( +"an `{name}`")),_=>None,}).unwrap_or_else((||format!("dereference of `{ty}`"))), +BorrowedContentSource::OverloadedIndex(ty)=>(format!("an index of `{ty}`")),}}fn +from_call(func:Ty<'tcx>,tcx:TyCtxt<'tcx>)->Option{match(*func.kind()){ty:: +FnDef(def_id,args)=>{;let trait_id=tcx.trait_of_item(def_id)?;let lang_items=tcx +.lang_items();({});if Some(trait_id)==lang_items.deref_trait()||Some(trait_id)== +lang_items.deref_mut_trait(){Some(BorrowedContentSource::OverloadedDeref(args.// +type_at(0)))}else if Some( trait_id)==lang_items.index_trait()||Some(trait_id)== +lang_items.index_mut_trait(){Some(BorrowedContentSource::OverloadedIndex(args.// +type_at((0))))}else{None }}_=>None,}}}struct CapturedMessageOpt{is_partial_move: +bool,is_loop_message:bool,is_move_msg:bool,is_loop_move:bool,//((),());let _=(); +maybe_reinitialized_locations_is_empty:bool,}impl< 'cx,'tcx>MirBorrowckCtxt<'cx, +'tcx>{pub(super)fn move_spans(&self,moved_place:PlaceRef<'tcx>,location://{();}; +Location,)->UseSpans<'tcx>{3;use self::UseSpans::*;3;3;let Some(stmt)=self.body[ +location.block].statements.get(location.statement_index)else{();return OtherUse( +self.body.source_info(location).span);let _=||();};let _=||();let _=||();debug!( +"move_spans: moved_place={:?} location={:?} stmt={:?}",moved_place,location,//3; +stmt);;if let StatementKind::Assign(box(_,Rvalue::Aggregate(kind,places)))=&stmt +.kind&&let AggregateKind::Closure(def_id, _)|AggregateKind::Coroutine(def_id,_)= +**kind{;debug!("move_spans: def_id={:?} places={:?}",def_id,places);;let def_id= +def_id.expect_local();{;};if let Some((args_span,closure_kind,capture_kind_span, +path_span))=self.closure_span(def_id,moved_place,places){({});return ClosureUse{ +closure_kind,args_span,capture_kind_span,path_span};{;};}}if let StatementKind:: +FakeRead(box(cause,place))= stmt.kind{match cause{FakeReadCause::ForMatchedPlace +(Some(closure_def_id))|FakeReadCause::ForLet(Some(closure_def_id))=>{{;};debug!( +"move_spans: def_id={:?} place={:?}",closure_def_id,place);;let places=&[Operand +::Move(place)];;if let Some((args_span,closure_kind,capture_kind_span,path_span) +)=self.closure_span(closure_def_id,moved_place,IndexSlice::from_raw(places)){(); +return ClosureUse{closure_kind,args_span,capture_kind_span,path_span,};;}}_=>{}} +}loop{break;};let normal_ret=if moved_place.projection.iter().any(|p|matches!(p, +ProjectionElem::Downcast(..))){PatUse (stmt.source_info.span)}else{OtherUse(stmt +.source_info.span)};;;let target_temp=match stmt.kind{StatementKind::Assign(box( +temp,_))if ((temp.as_local()).is_some()) =>{(temp.as_local().unwrap())}_=>return +normal_ret,};;;debug!("move_spans: target_temp = {:?}",target_temp);if let Some( +Terminator{kind:TerminatorKind::Call{fn_span,call_source,..},..})=&self.body[//; +location.block].terminator{{;};let Some((method_did,method_args))=rustc_middle:: +util::find_self_call(self.infcx.tcx,self.body,target_temp,location.block,)else{; +return normal_ret;;};let kind=call_kind(self.infcx.tcx,self.param_env,method_did +,method_args,(((*fn_span))),((call_source.from_hir_call())),Some(self.infcx.tcx. +fn_arg_names(method_did)[0]),);;return FnSelfUse{var_span:stmt.source_info.span, +fn_call_span:*fn_span,fn_span:self.infcx.tcx.def_span(method_did),kind,};{();};} +normal_ret}pub(super)fn borrow_spans(&self,use_span:Span,location:Location)->//; +UseSpans<'tcx>{loop{break};use self::UseSpans::*;loop{break};loop{break};debug!( +"borrow_spans: use_span={:?} location={:?}",use_span,location);;let target=match +((((self.body[location.block])).statements.get(location.statement_index))){Some( +Statement{kind:StatementKind::Assign(box(place,_)),..})=>{if let Some(local)=//; +place.as_local(){local}else{();return OtherUse(use_span);3;}}_=>return OtherUse( +use_span),};3;if self.body.local_kind(target)!=LocalKind::Temp{;return OtherUse( +use_span);3;};let maybe_additional_statement=if let TerminatorKind::Drop{target: +drop_target,..}=(((((self.body[location.block])).terminator()))).kind{self.body[ +drop_target].statements.first()}else{None};3;;let statements=self.body[location. +block].statements[location.statement_index+1..].iter();3;for stmt in statements. +chain(maybe_additional_statement){if let StatementKind::Assign(box(_,Rvalue:://; +Aggregate(kind,places)))=&stmt.kind{{;};let(&def_id,is_coroutine)=match kind{box +AggregateKind::Closure(def_id,_)=>((def_id,false)),box AggregateKind::Coroutine( +def_id,_)=>(def_id,true),_=>continue,};;let def_id=def_id.expect_local();debug!( +"borrow_spans: def_id={:?} is_coroutine={:?} places={:?}",def_id,is_coroutine,// +places);;if let Some((args_span,closure_kind,capture_kind_span,path_span))=self. +closure_span(def_id,Place::from(target).as_ref(),places){({});return ClosureUse{ +closure_kind,args_span,capture_kind_span,path_span};();}else{();return OtherUse( +use_span);3;}}if use_span!=stmt.source_info.span{;break;;}}OtherUse(use_span)}fn +closure_span(&self,def_id:LocalDefId,target_place:PlaceRef<'tcx>,places:&//({}); +IndexSlice>,)->Option <(Span,hir::ClosureKind,Span,Span)> +{*&*&();debug!("closure_span: def_id={:?} target_place={:?} places={:?}",def_id, +target_place,places);;;let hir_id=self.infcx.tcx.local_def_id_to_hir_id(def_id); +let expr=&self.infcx.tcx.hir().expect_expr(hir_id).kind;let _=();((),());debug!( +"closure_span: hir_id={:?} expr={:?}",hir_id,expr);*&*&();if let hir::ExprKind:: +Closure(&hir::Closure{kind,fn_decl_span,..})=expr{for(captured_place,place)in // +self.infcx.tcx.closure_captures(def_id).iter().zip(places){match place{Operand// +::Copy(place)|Operand::Move(place)if target_place==place.as_ref()=>{({});debug!( +"closure_span: found captured local {:?}",place);;return Some((fn_decl_span,kind +,(((((captured_place.get_capture_kind_span(self. infcx.tcx)))))),captured_place. +get_path_span(self.infcx.tcx),));if true{};let _=||();}_=>{}}}}None}pub(super)fn +retrieve_borrow_spans(&self,borrow:&BorrowData<'_>)->UseSpans<'tcx>{();let span= +self.body.source_info(borrow.reserve_location).span;({});self.borrow_spans(span, +borrow.reserve_location)}#[allow(rustc::diagnostic_outside_of_impl)]#[allow(//3; +rustc::untranslatable_diagnostic)]fn explain_captures(&mut self,err:&mut Diag,span:Span,move_span:Span,move_spans :UseSpans<'tcx>,moved_place:Place<'tcx>, +msg_opt:CapturedMessageOpt,){;let CapturedMessageOpt{is_partial_move:is_partial, +is_loop_message,is_move_msg ,is_loop_move,maybe_reinitialized_locations_is_empty +,}=msg_opt;{();};if let UseSpans::FnSelfUse{var_span,fn_call_span,fn_span,kind}= +move_spans{({});let place_name=self.describe_place(moved_place.as_ref()).map(|n| +format!("`{n}`")).unwrap_or_else(||"value".to_owned());{;};match kind{CallKind:: +FnCall{fn_trait_id,..}if ((Some(fn_trait_id)))==((self.infcx.tcx.lang_items())). +fn_once_trait()=>{((),());err.subdiagnostic(self.dcx(),CaptureReasonLabel::Call{ +fn_call_span,place_name:&place_name,is_partial,is_loop_message,},);({});{;};err. +subdiagnostic(self.dcx(),CaptureReasonNote::FnOnceMoveInCall{var_span});*&*&();} +CallKind::Operator{self_arg,trait_id,..}=>{;let self_arg=self_arg.unwrap();;err. +subdiagnostic((((((self.dcx()))))),CaptureReasonLabel::OperatorUse{fn_call_span, +place_name:&place_name,is_partial,is_loop_message,},);let _=();let _=();if self. +fn_self_span_reported.insert(fn_span){;let lang=self.infcx.tcx.lang_items();err. +subdiagnostic(self.dcx(),if[lang. not_trait(),lang.deref_trait(),lang.neg_trait( +)].contains(((&((Some(trait_id)))))){CaptureReasonNote::UnOpMoveByOperator{span: +self_arg.span}}else{CaptureReasonNote::LhsMoveByOperator {span:self_arg.span}},) +;;}}CallKind::Normal{self_arg,desugaring,method_did,method_args}=>{let self_arg= +self_arg.unwrap();3;3;let mut has_sugg=false;;;let tcx=self.infcx.tcx;;if span!= +DUMMY_SP&&self.fn_self_span_reported.insert(self_arg.span){((),());((),());self. +explain_iterator_advancement_in_for_loop_if_applicable(err,span,&move_spans,);;; +let func=tcx.def_path_str(method_did);*&*&();{();};err.subdiagnostic(self.dcx(), +CaptureReasonNote::FuncTakeSelf{func,place_name:((((place_name.clone())))),span: +self_arg.span,},);;};let parent_did=tcx.parent(method_did);;;let parent_self_ty= +matches!(tcx.def_kind(parent_did),rustc_hir:: def::DefKind::Impl{..}).then_some( +parent_did).and_then(|did|match tcx .type_of(did).instantiate_identity().kind(){ +ty::Adt(def,..)=>Some(def.did()),_=>None,});{();};{();};let is_option_or_result= +parent_self_ty.is_some_and(|def_id|{matches!(tcx.get_diagnostic_name(def_id),//; +Some(sym::Option|sym::Result))});let _=||();loop{break};if is_option_or_result&& +maybe_reinitialized_locations_is_empty{loop{break};err.subdiagnostic(self.dcx(), +CaptureReasonLabel::BorrowContent{var_span},);3;}if let Some((CallDesugaringKind +::ForLoopIntoIter,_))=desugaring{3;let ty=moved_place.ty(self.body,tcx).ty;;;let +suggest=match ((((tcx.get_diagnostic_item(sym ::IntoIterator))))){Some(def_id)=> +type_known_to_meet_bound_modulo_regions(self.infcx,self.param_env,Ty:://((),()); +new_imm_ref(tcx,tcx.lifetimes.re_erased,ty),def_id,),_=>false,};;if suggest{err. +subdiagnostic((self.dcx()),CaptureReasonSuggest::IterateSlice{ty,span:move_span. +shrink_to_lo(),},);{();};}({});err.subdiagnostic(self.dcx(),CaptureReasonLabel:: +ImplicitCall{fn_call_span,place_name:&place_name ,is_partial,is_loop_message,},) +;3;if let ty::Ref(_,_,hir::Mutability::Mut)=moved_place.ty(self.body,self.infcx. +tcx).ty.kind(){if!is_loop_move{let _=||();err.span_suggestion_verbose(move_span. +shrink_to_lo(),format!("consider creating a fresh reborrow of {} here",self.//3; +describe_place(moved_place.as_ref()).map(| n|format!("`{n}`")).unwrap_or_else(|| +"the mutable reference".to_string()),) ,(((((((("&mut *")))))))),Applicability:: +MachineApplicable,);let _=();}}}else{if let Some((CallDesugaringKind::Await,_))= +desugaring{;err.subdiagnostic(self.dcx(),CaptureReasonLabel::Await{fn_call_span, +place_name:&place_name,is_partial,is_loop_message,},);;}else{;err.subdiagnostic( +self.dcx(),CaptureReasonLabel::MethodCall{fn_call_span,place_name:(&place_name), +is_partial,is_loop_message,},);;};let ty=moved_place.ty(self.body,tcx).ty;if let +ty::Adt(def,args)=((ty.peel_refs()).kind())&& Some(def.did())==tcx.lang_items(). +pin_type()&&let ty::Ref(_,_,hir::Mutability:: Mut)=(args.type_at(0).kind())&&let +self_ty=self.infcx.instantiate_binder_with_fresh_vars(fn_call_span,//let _=||(); +BoundRegionConversionTime::FnCall,(((tcx. fn_sig(method_did)))).instantiate(tcx, +method_args).input(0),)&&self.infcx.can_eq(self.param_env,ty,self_ty){{();};err. +subdiagnostic(((self.dcx())),CaptureReasonSuggest::FreshReborrow{span:move_span. +shrink_to_hi(),},);3;;has_sugg=true;;}if let Some(clone_trait)=tcx.lang_items(). +clone_trait(){;let sugg=if moved_place.iter_projections().any(|(_,elem)|matches! +(elem,ProjectionElem::Deref)){vec![(move_span.shrink_to_lo(),format!(//let _=(); +"<{ty} as Clone>::clone(&")),(move_span.shrink_to_hi(),")" .to_string()),]}else{ +vec![(move_span.shrink_to_hi(),".clone()".to_string())]};();if let Some(errors)= +self.infcx.type_implements_trait_shallow(clone_trait,ty,self.param_env,)&&!//(); +has_sugg{if true{};let _=||();if true{};let _=||();let msg=match&errors[..]{[]=> +"you can `clone` the value and consume it, but this \ might not be your desired behavior" - .to_string(), - [error] => { - format!( - "you could `clone` the value and consume it, if the \ - `{}` trait bound could be satisfied", - error.obligation.predicate, - ) - } - [errors @ .., last] => { - format!( - "you could `clone` the value and consume it, if the \ +.to_string(),[error]=>{format!(//let _=||();loop{break};loop{break};loop{break}; +"you could `clone` the value and consume it, if the \ + `{}` trait bound could be satisfied" +,error.obligation.predicate,)}[errors@..,last]=>{format!(//if true{};let _=||(); +"you could `clone` the value and consume it, if the \ following trait bounds could be satisfied: \ - {} and `{}`", - errors - .iter() - .map(|e| format!("`{}`", e.obligation.predicate)) - .collect::>() - .join(", "), - last.obligation.predicate, - ) - } - }; - err.multipart_suggestion_verbose( - msg, - sugg, - Applicability::MaybeIncorrect, - ); - for error in errors { - if let FulfillmentErrorCode::SelectionError( - SelectionError::Unimplemented, - ) = error.code - && let ty::PredicateKind::Clause(ty::ClauseKind::Trait( - pred, - )) = error.obligation.predicate.kind().skip_binder() - { - self.infcx.err_ctxt().suggest_derive( - &error.obligation, - err, - error.obligation.predicate.kind().rebind(pred), - ); - } - } - } - } - } - } - // Other desugarings takes &self, which cannot cause a move - _ => {} - } - } else { - if move_span != span || is_loop_message { - err.subdiagnostic( - self.dcx(), - CaptureReasonLabel::MovedHere { - move_span, - is_partial, - is_move_msg, - is_loop_message, - }, - ); - } - // If the move error occurs due to a loop, don't show - // another message for the same span - if !is_loop_message { - move_spans.var_subdiag(self.dcx(), err, None, |kind, var_span| match kind { - hir::ClosureKind::Coroutine(_) => { - CaptureVarCause::PartialMoveUseInCoroutine { var_span, is_partial } - } - hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { - CaptureVarCause::PartialMoveUseInClosure { var_span, is_partial } - } - }) - } - } - } -} + {} and `{}`" +,errors.iter().map(|e|format!("`{}`" ,e.obligation.predicate)).collect::> +().join(", "),last.obligation.predicate,)}};3;;err.multipart_suggestion_verbose( +msg,sugg,Applicability::MaybeIncorrect,);loop{break;};for error in errors{if let +FulfillmentErrorCode::SelectionError(SelectionError:: Unimplemented,)=error.code +&&let ty::PredicateKind::Clause(ty::ClauseKind:: Trait(pred,))=error.obligation. +predicate.kind().skip_binder(){({});self.infcx.err_ctxt().suggest_derive(&error. +obligation,err,error.obligation.predicate.kind().rebind(pred),);();}}}}}}_=>{}}} +else{if move_span!=span||is_loop_message{if true{};err.subdiagnostic(self.dcx(), +CaptureReasonLabel::MovedHere{move_span, is_partial,is_move_msg,is_loop_message, +},);*&*&();}if!is_loop_message{move_spans.var_subdiag(self.dcx(),err,None,|kind, +var_span|match kind{hir::ClosureKind::Coroutine(_)=>{CaptureVarCause:://((),()); +PartialMoveUseInCoroutine{var_span,is_partial}}hir::ClosureKind::Closure|hir::// +ClosureKind::CoroutineClosure(_)=>{CaptureVarCause::PartialMoveUseInClosure{//3; +var_span,is_partial}}})}}}}//loop{break};loop{break;};loop{break;};loop{break;}; diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 0d1b875cbed5b..dc538a41ee6d6 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -1,621 +1,190 @@ -#![allow(rustc::diagnostic_outside_of_impl)] -#![allow(rustc::untranslatable_diagnostic)] - -use rustc_errors::{Applicability, Diag}; -use rustc_middle::mir::*; -use rustc_middle::ty::{self, Ty}; -use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex}; -use rustc_span::{BytePos, ExpnKind, MacroKind, Span}; - -use crate::diagnostics::CapturedMessageOpt; -use crate::diagnostics::{DescribePlaceOpt, UseSpans}; -use crate::prefixes::PrefixSet; -use crate::MirBorrowckCtxt; - -#[derive(Debug)] -pub enum IllegalMoveOriginKind<'tcx> { - /// Illegal move due to attempt to move from behind a reference. - BorrowedContent { - /// The place the reference refers to: if erroneous code was trying to - /// move from `(*x).f` this will be `*x`. - target_place: Place<'tcx>, - }, - - /// Illegal move due to attempt to move from field of an ADT that - /// implements `Drop`. Rust maintains invariant that all `Drop` - /// ADT's remain fully-initialized so that user-defined destructor - /// can safely read from all of the ADT's fields. - InteriorOfTypeWithDestructor { container_ty: Ty<'tcx> }, - - /// Illegal move due to attempt to move out of a slice or array. - InteriorOfSliceOrArray { ty: Ty<'tcx>, is_index: bool }, -} - -#[derive(Debug)] -pub(crate) struct MoveError<'tcx> { - place: Place<'tcx>, - location: Location, - kind: IllegalMoveOriginKind<'tcx>, -} - -impl<'tcx> MoveError<'tcx> { - pub(crate) fn new( - place: Place<'tcx>, - location: Location, - kind: IllegalMoveOriginKind<'tcx>, - ) -> Self { - MoveError { place, location, kind } - } -} - -// Often when desugaring a pattern match we may have many individual moves in -// MIR that are all part of one operation from the user's point-of-view. For -// example: -// -// let (x, y) = foo() -// -// would move x from the 0 field of some temporary, and y from the 1 field. We -// group such errors together for cleaner error reporting. -// -// Errors are kept separate if they are from places with different parent move -// paths. For example, this generates two errors: -// -// let (&x, &y) = (&String::new(), &String::new()); -#[derive(Debug)] -enum GroupedMoveError<'tcx> { - // Place expression can't be moved from, - // e.g., match x[0] { s => (), } where x: &[String] - MovesFromPlace { - original_path: Place<'tcx>, - span: Span, - move_from: Place<'tcx>, - kind: IllegalMoveOriginKind<'tcx>, - binds_to: Vec, - }, - // Part of a value expression can't be moved from, - // e.g., match &String::new() { &x => (), } - MovesFromValue { - original_path: Place<'tcx>, - span: Span, - move_from: MovePathIndex, - kind: IllegalMoveOriginKind<'tcx>, - binds_to: Vec, - }, - // Everything that isn't from pattern matching. - OtherIllegalMove { - original_path: Place<'tcx>, - use_spans: UseSpans<'tcx>, - kind: IllegalMoveOriginKind<'tcx>, - }, -} - -impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { - pub(crate) fn report_move_errors(&mut self) { - let grouped_errors = self.group_move_errors(); - for error in grouped_errors { - self.report(error); - } - } - - fn group_move_errors(&mut self) -> Vec> { - let mut grouped_errors = Vec::new(); - let errors = std::mem::take(&mut self.move_errors); - for error in errors { - self.append_to_grouped_errors(&mut grouped_errors, error); - } - grouped_errors - } - - fn append_to_grouped_errors( - &self, - grouped_errors: &mut Vec>, - error: MoveError<'tcx>, - ) { - let MoveError { place: original_path, location, kind } = error; - - // Note: that the only time we assign a place isn't a temporary - // to a user variable is when initializing it. - // If that ever stops being the case, then the ever initialized - // flow could be used. - if let Some(StatementKind::Assign(box (place, Rvalue::Use(Operand::Move(move_from))))) = - self.body.basic_blocks[location.block] - .statements - .get(location.statement_index) - .map(|stmt| &stmt.kind) - { - if let Some(local) = place.as_local() { - let local_decl = &self.body.local_decls[local]; - // opt_match_place is the - // match_span is the span of the expression being matched on - // match *x.y { ... } match_place is Some(*x.y) - // ^^^^ match_span is the span of *x.y - // - // opt_match_place is None for let [mut] x = ... statements, - // whether or not the right-hand side is a place expression - if let LocalInfo::User(BindingForm::Var(VarBindingForm { - opt_match_place: Some((opt_match_place, match_span)), - binding_mode: _, - opt_ty_info: _, - pat_span: _, - })) = *local_decl.local_info() - { - let stmt_source_info = self.body.source_info(location); - self.append_binding_error( - grouped_errors, - kind, - original_path, - *move_from, - local, - opt_match_place, - match_span, - stmt_source_info.span, - ); - return; - } - } - } - - let move_spans = self.move_spans(original_path.as_ref(), location); - grouped_errors.push(GroupedMoveError::OtherIllegalMove { - use_spans: move_spans, - original_path, - kind, - }); - } - - fn append_binding_error( - &self, - grouped_errors: &mut Vec>, - kind: IllegalMoveOriginKind<'tcx>, - original_path: Place<'tcx>, - move_from: Place<'tcx>, - bind_to: Local, - match_place: Option>, - match_span: Span, - statement_span: Span, - ) { - debug!(?match_place, ?match_span, "append_binding_error"); - - let from_simple_let = match_place.is_none(); - let match_place = match_place.unwrap_or(move_from); - - match self.move_data.rev_lookup.find(match_place.as_ref()) { - // Error with the match place - LookupResult::Parent(_) => { - for ge in &mut *grouped_errors { - if let GroupedMoveError::MovesFromPlace { span, binds_to, .. } = ge - && match_span == *span - { - debug!("appending local({bind_to:?}) to list"); - if !binds_to.is_empty() { - binds_to.push(bind_to); - } - return; - } - } - debug!("found a new move error location"); - - // Don't need to point to x in let x = ... . - let (binds_to, span) = if from_simple_let { - (vec![], statement_span) - } else { - (vec![bind_to], match_span) - }; - grouped_errors.push(GroupedMoveError::MovesFromPlace { - span, - move_from, - original_path, - kind, - binds_to, - }); - } - // Error with the pattern - LookupResult::Exact(_) => { - let LookupResult::Parent(Some(mpi)) = - self.move_data.rev_lookup.find(move_from.as_ref()) - else { - // move_from should be a projection from match_place. - unreachable!("Probably not unreachable..."); - }; - for ge in &mut *grouped_errors { - if let GroupedMoveError::MovesFromValue { - span, - move_from: other_mpi, - binds_to, - .. - } = ge - { - if match_span == *span && mpi == *other_mpi { - debug!("appending local({bind_to:?}) to list"); - binds_to.push(bind_to); - return; - } - } - } - debug!("found a new move error location"); - grouped_errors.push(GroupedMoveError::MovesFromValue { - span: match_span, - move_from: mpi, - original_path, - kind, - binds_to: vec![bind_to], - }); - } - }; - } - - fn report(&mut self, error: GroupedMoveError<'tcx>) { - let (mut err, err_span) = { - let (span, use_spans, original_path, kind) = match error { - GroupedMoveError::MovesFromPlace { span, original_path, ref kind, .. } - | GroupedMoveError::MovesFromValue { span, original_path, ref kind, .. } => { - (span, None, original_path, kind) - } - GroupedMoveError::OtherIllegalMove { use_spans, original_path, ref kind } => { - (use_spans.args_or_use(), Some(use_spans), original_path, kind) - } - }; - debug!( - "report: original_path={:?} span={:?}, kind={:?} \ - original_path.is_upvar_field_projection={:?}", - original_path, - span, - kind, - self.is_upvar_field_projection(original_path.as_ref()) - ); - ( - match kind { - &IllegalMoveOriginKind::BorrowedContent { target_place } => self - .report_cannot_move_from_borrowed_content( - original_path, - target_place, - span, - use_spans, - ), - &IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => { - self.cannot_move_out_of_interior_of_drop(span, ty) - } - &IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } => { - self.cannot_move_out_of_interior_noncopy(span, ty, Some(is_index)) - } - }, - span, - ) - }; - - self.add_move_hints(error, &mut err, err_span); - self.buffer_error(err); - } - - fn report_cannot_move_from_static(&mut self, place: Place<'tcx>, span: Span) -> Diag<'tcx> { - let description = if place.projection.len() == 1 { - format!("static item {}", self.describe_any_place(place.as_ref())) - } else { - let base_static = PlaceRef { local: place.local, projection: &[ProjectionElem::Deref] }; - - format!( - "{} as {} is a static item", - self.describe_any_place(place.as_ref()), - self.describe_any_place(base_static), - ) - }; - - self.cannot_move_out_of(span, &description) - } - - fn report_cannot_move_from_borrowed_content( - &mut self, - move_place: Place<'tcx>, - deref_target_place: Place<'tcx>, - span: Span, - use_spans: Option>, - ) -> Diag<'tcx> { - // Inspect the type of the content behind the - // borrow to provide feedback about why this - // was a move rather than a copy. - let ty = deref_target_place.ty(self.body, self.infcx.tcx).ty; - let upvar_field = self - .prefixes(move_place.as_ref(), PrefixSet::All) - .find_map(|p| self.is_upvar_field_projection(p)); - - let deref_base = match deref_target_place.projection.as_ref() { - [proj_base @ .., ProjectionElem::Deref] => { - PlaceRef { local: deref_target_place.local, projection: proj_base } - } - _ => bug!("deref_target_place is not a deref projection"), - }; - - if let PlaceRef { local, projection: [] } = deref_base { - let decl = &self.body.local_decls[local]; - if decl.is_ref_for_guard() { - return self - .cannot_move_out_of( - span, - &format!("`{}` in pattern guard", self.local_names[local].unwrap()), - ) - .with_note( - "variables bound in patterns cannot be moved from \ - until after the end of the pattern guard", - ); - } else if decl.is_ref_to_static() { - return self.report_cannot_move_from_static(move_place, span); - } - } - - debug!("report: ty={:?}", ty); - let mut err = match ty.kind() { - ty::Array(..) | ty::Slice(..) => { - self.cannot_move_out_of_interior_noncopy(span, ty, None) - } - ty::Closure(def_id, closure_args) - if def_id.as_local() == Some(self.mir_def_id()) && upvar_field.is_some() => - { - let closure_kind_ty = closure_args.as_closure().kind_ty(); - let closure_kind = match closure_kind_ty.to_opt_closure_kind() { - Some(kind @ (ty::ClosureKind::Fn | ty::ClosureKind::FnMut)) => kind, - Some(ty::ClosureKind::FnOnce) => { - bug!("closure kind does not match first argument type") - } - None => bug!("closure kind not inferred by borrowck"), - }; - let capture_description = - format!("captured variable in an `{closure_kind}` closure"); - - let upvar = &self.upvars[upvar_field.unwrap().index()]; - let upvar_hir_id = upvar.get_root_variable(); - let upvar_name = upvar.to_string(self.infcx.tcx); - let upvar_span = self.infcx.tcx.hir().span(upvar_hir_id); - - let place_name = self.describe_any_place(move_place.as_ref()); - - let place_description = - if self.is_upvar_field_projection(move_place.as_ref()).is_some() { - format!("{place_name}, a {capture_description}") - } else { - format!("{place_name}, as `{upvar_name}` is a {capture_description}") - }; - - debug!( - "report: closure_kind_ty={:?} closure_kind={:?} place_description={:?}", - closure_kind_ty, closure_kind, place_description, - ); - - self.cannot_move_out_of(span, &place_description) - .with_span_label(upvar_span, "captured outer variable") - .with_span_label( - self.infcx.tcx.def_span(def_id), - format!("captured by this `{closure_kind}` closure"), - ) - } - _ => { - let source = self.borrowed_content_source(deref_base); - let move_place_ref = move_place.as_ref(); - match ( - self.describe_place_with_options( - move_place_ref, - DescribePlaceOpt { - including_downcast: false, - including_tuple_field: false, - }, - ), - self.describe_name(move_place_ref), - source.describe_for_named_place(), - ) { - (Some(place_desc), Some(name), Some(source_desc)) => self.cannot_move_out_of( - span, - &format!("`{place_desc}` as enum variant `{name}` which is behind a {source_desc}"), - ), - (Some(place_desc), Some(name), None) => self.cannot_move_out_of( - span, - &format!("`{place_desc}` as enum variant `{name}`"), - ), - (Some(place_desc), _, Some(source_desc)) => self.cannot_move_out_of( - span, - &format!("`{place_desc}` which is behind a {source_desc}"), - ), - (_, _, _) => self.cannot_move_out_of( - span, - &source.describe_for_unnamed_place(self.infcx.tcx), - ), - } - } - }; - let msg_opt = CapturedMessageOpt { - is_partial_move: false, - is_loop_message: false, - is_move_msg: false, - is_loop_move: false, - maybe_reinitialized_locations_is_empty: true, - }; - if let Some(use_spans) = use_spans { - self.explain_captures(&mut err, span, span, use_spans, move_place, msg_opt); - } - err - } - - fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diag<'_>, span: Span) { - match error { - GroupedMoveError::MovesFromPlace { mut binds_to, move_from, .. } => { - self.add_borrow_suggestions(err, span); - if binds_to.is_empty() { - let place_ty = move_from.ty(self.body, self.infcx.tcx).ty; - let place_desc = match self.describe_place(move_from.as_ref()) { - Some(desc) => format!("`{desc}`"), - None => "value".to_string(), - }; - - err.subdiagnostic( - self.dcx(), - crate::session_diagnostics::TypeNoCopy::Label { - is_partial_move: false, - ty: place_ty, - place: &place_desc, - span, - }, - ); - } else { - binds_to.sort(); - binds_to.dedup(); - - self.add_move_error_details(err, &binds_to); - } - } - GroupedMoveError::MovesFromValue { mut binds_to, .. } => { - binds_to.sort(); - binds_to.dedup(); - self.add_move_error_suggestions(err, &binds_to); - self.add_move_error_details(err, &binds_to); - } - // No binding. Nothing to suggest. - GroupedMoveError::OtherIllegalMove { ref original_path, use_spans, .. } => { - let span = use_spans.var_or_use(); - let place_ty = original_path.ty(self.body, self.infcx.tcx).ty; - let place_desc = match self.describe_place(original_path.as_ref()) { - Some(desc) => format!("`{desc}`"), - None => "value".to_string(), - }; - err.subdiagnostic( - self.dcx(), - crate::session_diagnostics::TypeNoCopy::Label { - is_partial_move: false, - ty: place_ty, - place: &place_desc, - span, - }, - ); - - use_spans.args_subdiag(self.dcx(), err, |args_span| { - crate::session_diagnostics::CaptureArgLabel::MoveOutPlace { - place: place_desc, - args_span, - } - }); - - self.add_note_for_packed_struct_derive(err, original_path.local); - } - } - } - - fn add_borrow_suggestions(&self, err: &mut Diag<'_>, span: Span) { - match self.infcx.tcx.sess.source_map().span_to_snippet(span) { - Ok(snippet) if snippet.starts_with('*') => { - err.span_suggestion_verbose( - span.with_hi(span.lo() + BytePos(1)), - "consider removing the dereference here", - String::new(), - Applicability::MaybeIncorrect, - ); - } - _ => { - err.span_suggestion_verbose( - span.shrink_to_lo(), - "consider borrowing here", - '&', - Applicability::MaybeIncorrect, - ); - } - } - } - - fn add_move_error_suggestions(&self, err: &mut Diag<'_>, binds_to: &[Local]) { - let mut suggestions: Vec<(Span, String, String)> = Vec::new(); - for local in binds_to { - let bind_to = &self.body.local_decls[*local]; - if let LocalInfo::User(BindingForm::Var(VarBindingForm { pat_span, .. })) = - *bind_to.local_info() - { - let Ok(pat_snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(pat_span) - else { - continue; - }; - let Some(stripped) = pat_snippet.strip_prefix('&') else { - suggestions.push(( - bind_to.source_info.span.shrink_to_lo(), - "consider borrowing the pattern binding".to_string(), - "ref ".to_string(), - )); - continue; - }; - let inner_pat_snippet = stripped.trim_start(); - let (pat_span, suggestion, to_remove) = if inner_pat_snippet.starts_with("mut") - && inner_pat_snippet["mut".len()..].starts_with(rustc_lexer::is_whitespace) - { - let inner_pat_snippet = inner_pat_snippet["mut".len()..].trim_start(); - let pat_span = pat_span.with_hi( - pat_span.lo() - + BytePos((pat_snippet.len() - inner_pat_snippet.len()) as u32), - ); - (pat_span, String::new(), "mutable borrow") - } else { - let pat_span = pat_span.with_hi( - pat_span.lo() - + BytePos( - (pat_snippet.len() - inner_pat_snippet.trim_start().len()) as u32, - ), - ); - (pat_span, String::new(), "borrow") - }; - suggestions.push(( - pat_span, - format!("consider removing the {to_remove}"), - suggestion.to_string(), - )); - } - } - suggestions.sort_unstable_by_key(|&(span, _, _)| span); - suggestions.dedup_by_key(|&mut (span, _, _)| span); - for (span, msg, suggestion) in suggestions { - err.span_suggestion_verbose(span, msg, suggestion, Applicability::MachineApplicable); - } - } - - fn add_move_error_details(&self, err: &mut Diag<'_>, binds_to: &[Local]) { - for (j, local) in binds_to.iter().enumerate() { - let bind_to = &self.body.local_decls[*local]; - let binding_span = bind_to.source_info.span; - - if j == 0 { - err.span_label(binding_span, "data moved here"); - } else { - err.span_label(binding_span, "...and here"); - } - - if binds_to.len() == 1 { - let place_desc = &format!("`{}`", self.local_names[*local].unwrap()); - err.subdiagnostic( - self.dcx(), - crate::session_diagnostics::TypeNoCopy::Label { - is_partial_move: false, - ty: bind_to.ty, - place: place_desc, - span: binding_span, - }, - ); - } - } - - if binds_to.len() > 1 { - err.note( - "move occurs because these variables have types that don't implement the `Copy` \ - trait", - ); - } - } - - /// Adds an explanatory note if the move error occurs in a derive macro - /// expansion of a packed struct. - /// Such errors happen because derive macro expansions shy away from taking - /// references to the struct's fields since doing so would be undefined behaviour - fn add_note_for_packed_struct_derive(&self, err: &mut Diag<'_>, local: Local) { - let local_place: PlaceRef<'tcx> = local.into(); - let local_ty = local_place.ty(self.body.local_decls(), self.infcx.tcx).ty.peel_refs(); - - if let Some(adt) = local_ty.ty_adt_def() - && adt.repr().packed() - && let ExpnKind::Macro(MacroKind::Derive, name) = - self.body.span.ctxt().outer_expn_data().kind - { - err.note(format!("`#[derive({name})]` triggers a move because taking references to the fields of a packed struct is undefined behaviour")); - } - } -} +#![allow(rustc::diagnostic_outside_of_impl)]#![allow(rustc:://let _=();let _=(); +untranslatable_diagnostic)]use rustc_errors::{Applicability,Diag};use//let _=(); +rustc_middle::mir::*;use rustc_middle::ty::{self,Ty};use rustc_mir_dataflow:://; +move_paths::{LookupResult,MovePathIndex};use rustc_span::{BytePos,ExpnKind,//(); +MacroKind,Span};use crate::diagnostics::CapturedMessageOpt;use crate:://((),()); +diagnostics::{DescribePlaceOpt,UseSpans};use crate::prefixes::PrefixSet;use//(); +crate::MirBorrowckCtxt;#[derive(Debug)]pub enum IllegalMoveOriginKind<'tcx>{//3; +BorrowedContent{target_place:Place<'tcx>,},InteriorOfTypeWithDestructor{//{();}; +container_ty:Ty<'tcx>},InteriorOfSliceOrArray{ty:Ty<'tcx>,is_index:bool},}#[//3; +derive(Debug)]pub(crate)struct MoveError<'tcx>{place:Place<'tcx>,location://{;}; +Location,kind:IllegalMoveOriginKind<'tcx>,}impl <'tcx>MoveError<'tcx>{pub(crate) +fn new(place:Place<'tcx>,location :Location,kind:IllegalMoveOriginKind<'tcx>,)-> +Self{MoveError{place,location,kind}} }#[derive(Debug)]enum GroupedMoveError<'tcx +>{MovesFromPlace{original_path:Place<'tcx>, span:Span,move_from:Place<'tcx>,kind +:IllegalMoveOriginKind<'tcx>,binds_to:Vec ,},MovesFromValue{original_path +:Place<'tcx>,span:Span, move_from:MovePathIndex,kind:IllegalMoveOriginKind<'tcx> +,binds_to:Vec,},OtherIllegalMove{original_path:Place<'tcx>,use_spans://3; +UseSpans<'tcx>,kind:IllegalMoveOriginKind<'tcx> ,},}impl<'a,'tcx>MirBorrowckCtxt +<'a,'tcx>{pub(crate)fn report_move_errors(&mut self){();let grouped_errors=self. +group_move_errors();();for error in grouped_errors{();self.report(error);();}}fn +group_move_errors(&mut self)->Vec>{*&*&();((),());let mut +grouped_errors=Vec::new();;;let errors=std::mem::take(&mut self.move_errors);for +error in errors{();self.append_to_grouped_errors(&mut grouped_errors,error);();} +grouped_errors}fn append_to_grouped_errors(&self,grouped_errors:&mut Vec>,error:MoveError<'tcx>,){loop{break};let MoveError{place: +original_path,location,kind}=error;;if let Some(StatementKind::Assign(box(place, +Rvalue::Use(Operand::Move(move_from))))) =self.body.basic_blocks[location.block] +.statements.get(location.statement_index).map((|stmt|(&stmt.kind))){if let Some( +local)=place.as_local(){();let local_decl=&self.body.local_decls[local];3;if let +LocalInfo::User(BindingForm::Var(VarBindingForm{opt_match_place:Some((//((),()); +opt_match_place,match_span)),binding_mode:_,opt_ty_info:_,pat_span:_,}))=*//{;}; +local_decl.local_info(){;let stmt_source_info=self.body.source_info(location);;; +self.append_binding_error(grouped_errors,kind, original_path,(*move_from),local, +opt_match_place,match_span,stmt_source_info.span,);;;return;;}}};let move_spans= +self.move_spans(original_path.as_ref(),location);{();};({});grouped_errors.push( +GroupedMoveError::OtherIllegalMove{use_spans:move_spans,original_path,kind,});;} +fn append_binding_error(&self,grouped_errors:&mut Vec>,// +kind:IllegalMoveOriginKind<'tcx>,original_path: Place<'tcx>,move_from:Place<'tcx +>,bind_to:Local,match_place:Option< Place<'tcx>>,match_span:Span,statement_span: +Span,){({});debug!(?match_place,?match_span,"append_binding_error");({});{;};let +from_simple_let=match_place.is_none();3;3;let match_place=match_place.unwrap_or( +move_from);({});({});match self.move_data.rev_lookup.find(match_place.as_ref()){ +LookupResult::Parent(_)=>{for ge in(&mut*grouped_errors){if let GroupedMoveError +::MovesFromPlace{span,binds_to,..}=ge&&match_span==*span{((),());((),());debug!( +"appending local({bind_to:?}) to list");3;if!binds_to.is_empty(){;binds_to.push( +bind_to);;}return;}}debug!("found a new move error location");let(binds_to,span) +=if from_simple_let{(vec![],statement_span)}else{(vec![bind_to],match_span)};3;; +grouped_errors.push(GroupedMoveError::MovesFromPlace{span,move_from,//if true{}; +original_path,kind,binds_to,});();}LookupResult::Exact(_)=>{3;let LookupResult:: +Parent(Some(mpi))=self.move_data.rev_lookup.find(move_from.as_ref())else{*&*&(); +unreachable!("Probably not unreachable...");3;};;for ge in&mut*grouped_errors{if +let GroupedMoveError::MovesFromValue{span,move_from:other_mpi,binds_to,..}=ge{// +if match_span==*span&&mpi==*other_mpi{((),());let _=();let _=();let _=();debug!( +"appending local({bind_to:?}) to list");;binds_to.push(bind_to);return;}}}debug! +("found a new move error location");();();grouped_errors.push(GroupedMoveError:: +MovesFromValue{span:match_span,move_from:mpi,original_path,kind,binds_to:vec![// +bind_to],});;}};;}fn report(&mut self,error:GroupedMoveError<'tcx>){let(mut err, +err_span)={3;let(span,use_spans,original_path,kind)=match error{GroupedMoveError +::MovesFromPlace{span,original_path,ref kind,..}|GroupedMoveError:://let _=||(); +MovesFromValue{span,original_path,ref kind,..} =>{(span,None,original_path,kind) +}GroupedMoveError::OtherIllegalMove{use_spans,original_path,ref kind}=>{(//({}); +use_spans.args_or_use(),Some(use_spans),original_path,kind)}};{();};({});debug!( +"report: original_path={:?} span={:?}, kind={:?} \ + original_path.is_upvar_field_projection={:?}" +,original_path,span,kind,self .is_upvar_field_projection(original_path.as_ref()) +);{();};(match kind{&IllegalMoveOriginKind::BorrowedContent{target_place}=>self. +report_cannot_move_from_borrowed_content(original_path,target_place,span,//({}); +use_spans,),&IllegalMoveOriginKind::InteriorOfTypeWithDestructor{container_ty:// +ty}=>{(self.cannot_move_out_of_interior_of_drop(span,ty))}&IllegalMoveOriginKind +::InteriorOfSliceOrArray{ty,is_index}=>{self.//((),());((),());((),());let _=(); +cannot_move_out_of_interior_noncopy(span,ty,Some(is_index))}},span,)};();3;self. +add_move_hints(error,&mut err,err_span);({});({});self.buffer_error(err);{;};}fn +report_cannot_move_from_static(&mut self,place:Place<'tcx>,span:Span)->Diag{{;};let description=if place.projection.len()==1{format!("static item {}", +self.describe_any_place(place.as_ref()))}else{();let base_static=PlaceRef{local: +place.local,projection:&[ProjectionElem::Deref]};let _=||();loop{break};format!( +"{} as {} is a static item",self.describe_any_place(place.as_ref()),self.//({}); +describe_any_place(base_static),)};3;self.cannot_move_out_of(span,&description)} +fn report_cannot_move_from_borrowed_content(&mut self,move_place:Place<'tcx>,//; +deref_target_place:Place<'tcx>,span:Span,use_spans:Option>,)->//; +Diag<'tcx>{();let ty=deref_target_place.ty(self.body,self.infcx.tcx).ty;();3;let +upvar_field=self.prefixes(move_place.as_ref() ,PrefixSet::All).find_map(|p|self. +is_upvar_field_projection(p));({});({});let deref_base=match deref_target_place. +projection.as_ref(){[proj_base@..,ProjectionElem::Deref]=>{PlaceRef{local://{;}; +deref_target_place.local,projection:proj_base}}_=>bug!(//let _=||();loop{break}; +"deref_target_place is not a deref projection"),};((),());if let PlaceRef{local, +projection:[]}=deref_base{{;};let decl=&self.body.local_decls[local];();if decl. +is_ref_for_guard(){((),());((),());return self.cannot_move_out_of(span,&format!( +"`{}` in pattern guard",self.local_names[local].unwrap()),).with_note(//((),()); +"variables bound in patterns cannot be moved from \ + until after the end of the pattern guard" +,);;}else if decl.is_ref_to_static(){return self.report_cannot_move_from_static( +move_place,span);;}};debug!("report: ty={:?}",ty);let mut err=match ty.kind(){ty +::Array(..)|ty::Slice(..)=>{self.cannot_move_out_of_interior_noncopy(span,ty,//; +None)}ty::Closure(def_id,closure_args)if (((((def_id.as_local())))))==Some(self. +mir_def_id())&&upvar_field.is_some()=>{((),());let closure_kind_ty=closure_args. +as_closure().kind_ty();let _=();let _=();let closure_kind=match closure_kind_ty. +to_opt_closure_kind(){Some(kind@(ty:: ClosureKind::Fn|ty::ClosureKind::FnMut))=> +kind,Some(ty::ClosureKind::FnOnce)=>{bug!(//let _=();let _=();let _=();let _=(); +"closure kind does not match first argument type")}None=>bug!(//((),());((),()); +"closure kind not inferred by borrowck"),};();3;let capture_description=format!( +"captured variable in an `{closure_kind}` closure");();3;let upvar=&self.upvars[ +upvar_field.unwrap().index()];;;let upvar_hir_id=upvar.get_root_variable();;;let +upvar_name=upvar.to_string(self.infcx.tcx);;let upvar_span=self.infcx.tcx.hir(). +span(upvar_hir_id);;let place_name=self.describe_any_place(move_place.as_ref()); +let place_description=if (self.is_upvar_field_projection (move_place.as_ref())). +is_some(){((((format!("{place_name}, a {capture_description}")))))}else{format!( +"{place_name}, as `{upvar_name}` is a {capture_description}")};({});({});debug!( +"report: closure_kind_ty={:?} closure_kind={:?} place_description={:?}",//{();}; +closure_kind_ty,closure_kind,place_description,);;self.cannot_move_out_of(span,& +place_description).with_span_label( upvar_span,((("captured outer variable")))). +with_span_label(((((((((((((self.infcx.tcx.def_span(def_id))))))))))))),format!( +"captured by this `{closure_kind}` closure"),)}_=>{loop{break;};let source=self. +borrowed_content_source(deref_base);3;3;let move_place_ref=move_place.as_ref();; +match(self.describe_place_with_options(move_place_ref,DescribePlaceOpt{//*&*&(); +including_downcast:(false),including_tuple_field:(false),},),self.describe_name( +move_place_ref),source.describe_for_named_place(), ){(Some(place_desc),Some(name +),Some(source_desc))=>self.cannot_move_out_of(span,&format!(//let _=();let _=(); +"`{place_desc}` as enum variant `{name}` which is behind a {source_desc}"),),(// +Some(place_desc),Some(name),None)=>self.cannot_move_out_of(span,&format!(//({}); +"`{place_desc}` as enum variant `{name}`"),),(Some(place_desc),_,Some(//((),()); +source_desc))=>self.cannot_move_out_of(span,&format!(//loop{break};loop{break;}; +"`{place_desc}` which is behind a {source_desc}"),),(_,_,_)=>self.//loop{break}; +cannot_move_out_of(span,&source.describe_for_unnamed_place(self .infcx.tcx),),}} +};3;;let msg_opt=CapturedMessageOpt{is_partial_move:false,is_loop_message:false, +is_move_msg:(false),is_loop_move:(false),maybe_reinitialized_locations_is_empty: +true,};3;if let Some(use_spans)=use_spans{3;self.explain_captures(&mut err,span, +span,use_spans,move_place,msg_opt);if true{};}err}fn add_move_hints(&self,error: +GroupedMoveError<'tcx>,err:&mut Diag<'_>,span:Span){match error{//if let _=(){}; +GroupedMoveError::MovesFromPlace{mut binds_to,move_from,..}=>{loop{break;};self. +add_borrow_suggestions(err,span);;if binds_to.is_empty(){let place_ty=move_from. +ty(self.body,self.infcx.tcx).ty;{;};();let place_desc=match self.describe_place( +move_from.as_ref()){Some(desc)=>format! ("`{desc}`"),None=>"value".to_string(),} +;3;3;err.subdiagnostic(self.dcx(),crate::session_diagnostics::TypeNoCopy::Label{ +is_partial_move:false,ty:place_ty,place:&place_desc,span,},);3;}else{3;binds_to. +sort();();3;binds_to.dedup();3;3;self.add_move_error_details(err,&binds_to);3;}} +GroupedMoveError::MovesFromValue{mut binds_to,..}=>{;binds_to.sort();;;binds_to. +dedup();({});({});self.add_move_error_suggestions(err,&binds_to);({});({});self. +add_move_error_details(err,&binds_to);();}GroupedMoveError::OtherIllegalMove{ref +original_path,use_spans,..}=>{3;let span=use_spans.var_or_use();3;;let place_ty= +original_path.ty(self.body,self.infcx.tcx).ty;{;};{;};let place_desc=match self. +describe_place((original_path.as_ref())){Some( desc)=>format!("`{desc}`"),None=> +"value".to_string(),};;err.subdiagnostic(self.dcx(),crate::session_diagnostics:: +TypeNoCopy::Label{is_partial_move:false,ty:place_ty,place:&place_desc,span,},);; +use_spans.args_subdiag((self.dcx()),err,|args_span|{crate::session_diagnostics:: +CaptureArgLabel::MoveOutPlace{place:place_desc,args_span,}});*&*&();*&*&();self. +add_note_for_packed_struct_derive(err,original_path.local);((),());((),());}}}fn +add_borrow_suggestions(&self,err:&mut Diag<'_>, span:Span){match self.infcx.tcx. +sess.source_map().span_to_snippet(span){Ok(snippet)if (snippet.starts_with('*')) +=>{if let _=(){};err.span_suggestion_verbose(span.with_hi(span.lo()+BytePos(1)), +"consider removing the dereference here",(((((String::new()))))),Applicability:: +MaybeIncorrect,);({});}_=>{({});err.span_suggestion_verbose(span.shrink_to_lo(), +"consider borrowing here",'&',Applicability::MaybeIncorrect,);loop{break;};}}}fn +add_move_error_suggestions(&self,err:&mut Diag<'_>,binds_to:&[Local]){();let mut +suggestions:Vec<(Span,String,String)>=Vec::new();();for local in binds_to{();let +bind_to=&self.body.local_decls[*local];;if let LocalInfo::User(BindingForm::Var( +VarBindingForm{pat_span,..}))=*bind_to.local_info(){();let Ok(pat_snippet)=self. +infcx.tcx.sess.source_map().span_to_snippet(pat_span)else{;continue;;};let Some( +stripped)=pat_snippet.strip_prefix('&')else{if true{};suggestions.push((bind_to. +source_info.span.shrink_to_lo() ,((("consider borrowing the pattern binding"))). +to_string(),"ref ".to_string(),));;;continue;;};;let inner_pat_snippet=stripped. +trim_start();{();};({});let(pat_span,suggestion,to_remove)=if inner_pat_snippet. +starts_with(("mut"))&&inner_pat_snippet["mut".len()..].starts_with(rustc_lexer:: +is_whitespace){if true{};let inner_pat_snippet=inner_pat_snippet["mut".len()..]. +trim_start();;;let pat_span=pat_span.with_hi(pat_span.lo()+BytePos((pat_snippet. +len()-inner_pat_snippet.len())as u32),);((),());((),());(pat_span,String::new(), +"mutable borrow")}else{{;};let pat_span=pat_span.with_hi(pat_span.lo()+BytePos(( +pat_snippet.len()-inner_pat_snippet.trim_start().len())as u32,),);{;};(pat_span, +String::new(),"borrow")};if true{};if true{};suggestions.push((pat_span,format!( +"consider removing the {to_remove}"),suggestion.to_string(),));3;}};suggestions. +sort_unstable_by_key(|&(span,_,_)|span);;suggestions.dedup_by_key(|&mut(span,_,_ +)|span);;for(span,msg,suggestion)in suggestions{err.span_suggestion_verbose(span +,msg,suggestion,Applicability::MachineApplicable);;}}fn add_move_error_details(& +self,err:&mut Diag<'_>,binds_to:&[Local] ){for(j,local)in (((binds_to.iter()))). +enumerate(){;let bind_to=&self.body.local_decls[*local];let binding_span=bind_to +.source_info.span;;if j==0{err.span_label(binding_span,"data moved here");}else{ +err.span_label(binding_span,"...and here");;}if binds_to.len()==1{let place_desc +=&format!("`{}`",self.local_names[*local].unwrap());;err.subdiagnostic(self.dcx( +),crate::session_diagnostics::TypeNoCopy:: Label{is_partial_move:(((false))),ty: +bind_to.ty,place:place_desc,span:binding_span,},);3;}}if binds_to.len()>1{3;err. +note(//let _=();let _=();let _=();let _=();let _=();let _=();let _=();if true{}; +"move occurs because these variables have types that don't implement the `Copy` \ + trait" +,);;}}fn add_note_for_packed_struct_derive(&self,err:&mut Diag<'_>,local:Local){ +let local_place:PlaceRef<'tcx>=local.into();3;;let local_ty=local_place.ty(self. +body.local_decls(),self.infcx.tcx).ty.peel_refs();{;};if let Some(adt)=local_ty. +ty_adt_def()&&adt.repr().packed() &&let ExpnKind::Macro(MacroKind::Derive,name)= +self.body.span.ctxt().outer_expn_data().kind{let _=();let _=();err.note(format!( +"`#[derive({name})]` triggers a move because taking references to the fields of a packed struct is undefined behaviour" +));let _=();let _=();let _=();if true{};let _=();let _=();let _=();if true{};}}} diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs index 1a42e551597bb..2e117dbd18232 100644 --- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs +++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs @@ -1,257 +1,64 @@ -//! Contains utilities for generating suggestions for borrowck errors related to unsatisfied -//! outlives constraints. - -#![allow(rustc::diagnostic_outside_of_impl)] -#![allow(rustc::untranslatable_diagnostic)] - -use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::Diag; -use rustc_middle::ty::RegionVid; -use smallvec::SmallVec; -use std::collections::BTreeMap; - -use crate::MirBorrowckCtxt; - -use super::{ErrorConstraintInfo, RegionName, RegionNameSource}; - -/// The different things we could suggest. -enum SuggestedConstraint { - /// Outlives(a, [b, c, d, ...]) => 'a: 'b + 'c + 'd + ... - Outlives(RegionName, SmallVec<[RegionName; 2]>), - - /// 'a = 'b - Equal(RegionName, RegionName), - - /// 'a: 'static i.e. 'a = 'static and the user should just use 'static - Static(RegionName), -} - -/// Collects information about outlives constraints that needed to be added for a given MIR node -/// corresponding to a function definition. -/// -/// Adds a help note suggesting adding a where clause with the needed constraints. -#[derive(Default)] -pub struct OutlivesSuggestionBuilder { - /// The list of outlives constraints that need to be added. Specifically, we map each free - /// region to all other regions that it must outlive. I will use the shorthand `fr: - /// outlived_frs`. Not all of these regions will already have names necessarily. Some could be - /// implicit free regions that we inferred. These will need to be given names in the final - /// suggestion message. - constraints_to_add: BTreeMap>, -} - -impl OutlivesSuggestionBuilder { - /// Returns `true` iff the `RegionNameSource` is a valid source for an outlives - /// suggestion. - // - // FIXME: Currently, we only report suggestions if the `RegionNameSource` is an early-bound - // region or a named region, avoiding using regions with synthetic names altogether. This - // allows us to avoid giving impossible suggestions (e.g. adding bounds to closure args). - // We can probably be less conservative, since some inferred free regions are namable (e.g. - // the user can explicitly name them. To do this, we would allow some regions whose names - // come from `MatchedAdtAndSegment`, being careful to filter out bad suggestions, such as - // naming the `'self` lifetime in methods, etc. - fn region_name_is_suggestable(name: &RegionName) -> bool { - match name.source { - RegionNameSource::NamedEarlyParamRegion(..) - | RegionNameSource::NamedLateParamRegion(..) - | RegionNameSource::Static => true, - - // Don't give suggestions for upvars, closure return types, or other unnameable - // regions. - RegionNameSource::SynthesizedFreeEnvRegion(..) - | RegionNameSource::AnonRegionFromArgument(..) - | RegionNameSource::AnonRegionFromUpvar(..) - | RegionNameSource::AnonRegionFromOutput(..) - | RegionNameSource::AnonRegionFromYieldTy(..) - | RegionNameSource::AnonRegionFromAsyncFn(..) - | RegionNameSource::AnonRegionFromImplSignature(..) => { - debug!("Region {:?} is NOT suggestable", name); - false - } - } - } - - /// Returns a name for the region if it is suggestable. See `region_name_is_suggestable`. - fn region_vid_to_name( - &self, - mbcx: &MirBorrowckCtxt<'_, '_>, - region: RegionVid, - ) -> Option { - mbcx.give_region_a_name(region).filter(Self::region_name_is_suggestable) - } - - /// Compiles a list of all suggestions to be printed in the final big suggestion. - fn compile_all_suggestions( - &self, - mbcx: &MirBorrowckCtxt<'_, '_>, - ) -> SmallVec<[SuggestedConstraint; 2]> { - let mut suggested = SmallVec::new(); - - // Keep track of variables that we have already suggested unifying so that we don't print - // out silly duplicate messages. - let mut unified_already = FxIndexSet::default(); - - for (fr, outlived) in &self.constraints_to_add { - let Some(fr_name) = self.region_vid_to_name(mbcx, *fr) else { - continue; - }; - - let outlived = outlived - .iter() - // if there is a `None`, we will just omit that constraint - .filter_map(|fr| self.region_vid_to_name(mbcx, *fr).map(|rname| (fr, rname))) - .collect::>(); - - // No suggestable outlived lifetimes. - if outlived.is_empty() { - continue; - } - - // There are three types of suggestions we can make: - // 1) Suggest a bound: 'a: 'b - // 2) Suggest replacing 'a with 'static. If any of `outlived` is `'static`, then we - // should just replace 'a with 'static. - // 3) Suggest unifying 'a with 'b if we have both 'a: 'b and 'b: 'a - - if outlived - .iter() - .any(|(_, outlived_name)| matches!(outlived_name.source, RegionNameSource::Static)) - { - suggested.push(SuggestedConstraint::Static(fr_name)); - } else { - // We want to isolate out all lifetimes that should be unified and print out - // separate messages for them. - - let (unified, other): (Vec<_>, Vec<_>) = outlived.into_iter().partition( - // Do we have both 'fr: 'r and 'r: 'fr? - |(r, _)| { - self.constraints_to_add - .get(r) - .is_some_and(|r_outlived| r_outlived.as_slice().contains(fr)) - }, - ); - - for (r, bound) in unified.into_iter() { - if !unified_already.contains(fr) { - suggested.push(SuggestedConstraint::Equal(fr_name, bound)); - unified_already.insert(r); - } - } - - if !other.is_empty() { - let other = other.iter().map(|(_, rname)| *rname).collect::>(); - suggested.push(SuggestedConstraint::Outlives(fr_name, other)) - } - } - } - - suggested - } - - /// Add the outlives constraint `fr: outlived_fr` to the set of constraints we need to suggest. - pub(crate) fn collect_constraint(&mut self, fr: RegionVid, outlived_fr: RegionVid) { - debug!("Collected {:?}: {:?}", fr, outlived_fr); - - // Add to set of constraints for final help note. - self.constraints_to_add.entry(fr).or_default().push(outlived_fr); - } - - /// Emit an intermediate note on the given `Diag` if the involved regions are suggestable. - pub(crate) fn intermediate_suggestion( - &mut self, - mbcx: &MirBorrowckCtxt<'_, '_>, - errci: &ErrorConstraintInfo<'_>, - diag: &mut Diag<'_>, - ) { - // Emit an intermediate note. - let fr_name = self.region_vid_to_name(mbcx, errci.fr); - let outlived_fr_name = self.region_vid_to_name(mbcx, errci.outlived_fr); - - if let (Some(fr_name), Some(outlived_fr_name)) = (fr_name, outlived_fr_name) - && !matches!(outlived_fr_name.source, RegionNameSource::Static) - { - diag.help(format!( - "consider adding the following bound: `{fr_name}: {outlived_fr_name}`", - )); - } - } - - /// If there is a suggestion to emit, add a diagnostic to the buffer. This is the final - /// suggestion including all collected constraints. - pub(crate) fn add_suggestion(&self, mbcx: &mut MirBorrowckCtxt<'_, '_>) { - // No constraints to add? Done. - if self.constraints_to_add.is_empty() { - debug!("No constraints to suggest."); - return; - } - - // If there is only one constraint to suggest, then we already suggested it in the - // intermediate suggestion above. - if self.constraints_to_add.len() == 1 - && self.constraints_to_add.values().next().unwrap().len() == 1 - { - debug!("Only 1 suggestion. Skipping."); - return; - } - - // Get all suggestable constraints. - let suggested = self.compile_all_suggestions(mbcx); - - // If there are no suggestable constraints... - if suggested.is_empty() { - debug!("Only 1 suggestable constraint. Skipping."); - return; - } - - // If there is exactly one suggestable constraints, then just suggest it. Otherwise, emit a - // list of diagnostics. - let mut diag = if suggested.len() == 1 { - mbcx.dcx().struct_help(match suggested.last().unwrap() { - SuggestedConstraint::Outlives(a, bs) => { - let bs: SmallVec<[String; 2]> = bs.iter().map(|r| r.to_string()).collect(); - format!("add bound `{a}: {}`", bs.join(" + ")) - } - - SuggestedConstraint::Equal(a, b) => { - format!("`{a}` and `{b}` must be the same: replace one with the other") - } - SuggestedConstraint::Static(a) => format!("replace `{a}` with `'static`"), - }) - } else { - // Create a new diagnostic. - let mut diag = mbcx - .infcx - .tcx - .dcx() - .struct_help("the following changes may resolve your lifetime errors"); - - // Add suggestions. - for constraint in suggested { - match constraint { - SuggestedConstraint::Outlives(a, bs) => { - let bs: SmallVec<[String; 2]> = bs.iter().map(|r| r.to_string()).collect(); - diag.help(format!("add bound `{a}: {}`", bs.join(" + "))); - } - SuggestedConstraint::Equal(a, b) => { - diag.help(format!( - "`{a}` and `{b}` must be the same: replace one with the other", - )); - } - SuggestedConstraint::Static(a) => { - diag.help(format!("replace `{a}` with `'static`")); - } - } - } - - diag - }; - - // We want this message to appear after other messages on the mir def. - let mir_span = mbcx.body.span; - diag.sort_span = mir_span.shrink_to_hi(); - - // Buffer the diagnostic - mbcx.buffer_non_error(diag); - } -} +#![allow(rustc::diagnostic_outside_of_impl)]#![allow(rustc:://let _=();let _=(); +untranslatable_diagnostic)]use rustc_data_structures::fx::FxIndexSet;use//{();}; +rustc_errors::Diag;use rustc_middle::ty::RegionVid;use smallvec::SmallVec;use//; +std::collections::BTreeMap;use crate::MirBorrowckCtxt;use super::{//loop{break}; +ErrorConstraintInfo,RegionName,RegionNameSource};enum SuggestedConstraint{//{;}; +Outlives(RegionName,SmallVec<[RegionName;((2 ))]>),Equal(RegionName,RegionName), +Static(RegionName),}#[derive(Default)]pub struct OutlivesSuggestionBuilder{//(); +constraints_to_add:BTreeMap>,}impl//let _=();if true{}; +OutlivesSuggestionBuilder{fn region_name_is_suggestable( name:&RegionName)->bool +{match name.source{ RegionNameSource::NamedEarlyParamRegion(..)|RegionNameSource +::NamedLateParamRegion(..)|RegionNameSource::Static=>((true)),RegionNameSource:: +SynthesizedFreeEnvRegion(..)|RegionNameSource::AnonRegionFromArgument(..)|//{;}; +RegionNameSource::AnonRegionFromUpvar(..)|RegionNameSource:://let _=();let _=(); +AnonRegionFromOutput(..)|RegionNameSource::AnonRegionFromYieldTy(..)|//let _=(); +RegionNameSource::AnonRegionFromAsyncFn(..)|RegionNameSource:://((),());((),()); +AnonRegionFromImplSignature(..)=>{;debug!("Region {:?} is NOT suggestable",name) +;*&*&();false}}}fn region_vid_to_name(&self,mbcx:&MirBorrowckCtxt<'_,'_>,region: +RegionVid,)->Option{( mbcx.give_region_a_name(region)).filter(Self:: +region_name_is_suggestable)}fn compile_all_suggestions(&self,mbcx:&//let _=||(); +MirBorrowckCtxt<'_,'_>,)->SmallVec<[SuggestedConstraint;2]>{3;let mut suggested= +SmallVec::new();;;let mut unified_already=FxIndexSet::default();for(fr,outlived) +in&self.constraints_to_add{3;let Some(fr_name)=self.region_vid_to_name(mbcx,*fr) +else{{;};continue;{;};};{;};();let outlived=outlived.iter().filter_map(|fr|self. +region_vid_to_name(mbcx,*fr).map(|rname|(fr,rname))).collect::>();{;};if +outlived.is_empty(){;continue;}if outlived.iter().any(|(_,outlived_name)|matches +!(outlived_name.source,RegionNameSource::Static)){*&*&();((),());suggested.push( +SuggestedConstraint::Static(fr_name));;}else{let(unified,other):(Vec<_>,Vec<_>)= +outlived.into_iter().partition(|(r,_)|{(((((self.constraints_to_add.get(r)))))). +is_some_and(|r_outlived|r_outlived.as_slice().contains(fr))},);3;for(r,bound)in +unified.into_iter(){if!unified_already.contains(fr){loop{break;};suggested.push( +SuggestedConstraint::Equal(fr_name,bound));;unified_already.insert(r);}}if!other +.is_empty(){3;let other=other.iter().map(|(_,rname)|*rname).collect::>();3;suggested.push(SuggestedConstraint::Outlives(fr_name,other))}}}suggested} +pub(crate)fn collect_constraint(&mut self,fr:RegionVid,outlived_fr:RegionVid){3; +debug!("Collected {:?}: {:?}",fr,outlived_fr);;self.constraints_to_add.entry(fr) +.or_default().push(outlived_fr);;}pub(crate)fn intermediate_suggestion(&mut self +,mbcx:&MirBorrowckCtxt<'_,'_>,errci:& ErrorConstraintInfo<'_>,diag:&mut Diag<'_> +,){;let fr_name=self.region_vid_to_name(mbcx,errci.fr);let outlived_fr_name=self +.region_vid_to_name(mbcx,errci.outlived_fr);if true{};if let(Some(fr_name),Some( +outlived_fr_name))=((((fr_name,outlived_fr_name))))&&!matches!(outlived_fr_name. +source,RegionNameSource::Static){if let _=(){};*&*&();((),());diag.help(format!( +"consider adding the following bound: `{fr_name}: {outlived_fr_name}`",));;}}pub +(crate)fn add_suggestion(&self,mbcx:&mut MirBorrowckCtxt<'_,'_>){if self.//({}); +constraints_to_add.is_empty(){;debug!("No constraints to suggest.");;return;}if +self.constraints_to_add.len()==(1)&&((self.constraints_to_add.values()).next()). +unwrap().len()==1{;debug!("Only 1 suggestion. Skipping.");return;}let suggested= +self.compile_all_suggestions(mbcx);*&*&();if suggested.is_empty(){*&*&();debug!( +"Only 1 suggestable constraint. Skipping.");;;return;}let mut diag=if suggested. +len()==((1)){((mbcx.dcx())).struct_help(match ((((suggested.last())).unwrap())){ +SuggestedConstraint::Outlives(a,bs)=>{;let bs:SmallVec<[String;2]>=bs.iter().map +(|r|r.to_string()).collect();({});format!("add bound `{a}: {}`",bs.join(" + "))} +SuggestedConstraint::Equal(a,b)=>{format!(//let _=();let _=();let _=();let _=(); +"`{a}` and `{b}` must be the same: replace one with the other")}//if let _=(){}; +SuggestedConstraint::Static(a)=>format! ("replace `{a}` with `'static`"),})}else +{((),());((),());((),());let _=();let mut diag=mbcx.infcx.tcx.dcx().struct_help( +"the following changes may resolve your lifetime errors");({});for constraint in +suggested{match constraint{SuggestedConstraint::Outlives(a,bs)=>{((),());let bs: +SmallVec<[String;2]>=bs.iter().map(|r|r.to_string()).collect();;diag.help(format +!("add bound `{a}: {}`",bs.join(" + ")));3;}SuggestedConstraint::Equal(a,b)=>{3; +diag.help(format!(//*&*&();((),());*&*&();((),());*&*&();((),());*&*&();((),()); +"`{a}` and `{b}` must be the same: replace one with the other",));loop{break;};} +SuggestedConstraint::Static(a)=>{if let _=(){};*&*&();((),());diag.help(format!( +"replace `{a}` with `'static`"));;}}}diag};;;let mir_span=mbcx.body.span;;;diag. +sort_span=mir_span.shrink_to_hi();{();};({});mbcx.buffer_non_error(diag);({});}} diff --git a/compiler/rustc_borrowck/src/diagnostics/var_name.rs b/compiler/rustc_borrowck/src/diagnostics/var_name.rs index 0479cd8af35e2..66940bf92ad2a 100644 --- a/compiler/rustc_borrowck/src/diagnostics/var_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/var_name.rs @@ -1,127 +1,46 @@ -use crate::region_infer::RegionInferenceContext; -use rustc_index::IndexSlice; -use rustc_middle::mir::{Body, Local}; -use rustc_middle::ty::{self, RegionVid, TyCtxt}; -use rustc_span::symbol::Symbol; -use rustc_span::Span; - -impl<'tcx> RegionInferenceContext<'tcx> { - pub(crate) fn get_var_name_and_span_for_region( - &self, - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - local_names: &IndexSlice>, - upvars: &[&ty::CapturedPlace<'tcx>], - fr: RegionVid, - ) -> Option<(Option, Span)> { - debug!("get_var_name_and_span_for_region(fr={fr:?})"); - assert!(self.universal_regions().is_universal_region(fr)); - - debug!("get_var_name_and_span_for_region: attempting upvar"); - self.get_upvar_index_for_region(tcx, fr) - .map(|index| { - // FIXME(project-rfc-2229#8): Use place span for diagnostics - let (name, span) = self.get_upvar_name_and_span_for_region(tcx, upvars, index); - (Some(name), span) - }) - .or_else(|| { - debug!("get_var_name_and_span_for_region: attempting argument"); - self.get_argument_index_for_region(tcx, fr).map(|index| { - self.get_argument_name_and_span_for_region(body, local_names, index) - }) - }) - } - - /// Search the upvars (if any) to find one that references fr. Return its index. - pub(crate) fn get_upvar_index_for_region( - &self, - tcx: TyCtxt<'tcx>, - fr: RegionVid, - ) -> Option { - let upvar_index = - self.universal_regions().defining_ty.upvar_tys().iter().position(|upvar_ty| { - debug!("get_upvar_index_for_region: upvar_ty={upvar_ty:?}"); - tcx.any_free_region_meets(&upvar_ty, |r| { - let r = r.as_var(); - debug!("get_upvar_index_for_region: r={r:?} fr={fr:?}"); - r == fr - }) - })?; - - let upvar_ty = self.universal_regions().defining_ty.upvar_tys().get(upvar_index); - - debug!( - "get_upvar_index_for_region: found {fr:?} in upvar {upvar_index} which has type {upvar_ty:?}", - ); - - Some(upvar_index) - } - - /// Given the index of an upvar, finds its name and the span from where it was - /// declared. - pub(crate) fn get_upvar_name_and_span_for_region( - &self, - tcx: TyCtxt<'tcx>, - upvars: &[&ty::CapturedPlace<'tcx>], - upvar_index: usize, - ) -> (Symbol, Span) { - let upvar_hir_id = upvars[upvar_index].get_root_variable(); - debug!("get_upvar_name_and_span_for_region: upvar_hir_id={upvar_hir_id:?}"); - - let upvar_name = tcx.hir().name(upvar_hir_id); - let upvar_span = tcx.hir().span(upvar_hir_id); - debug!( - "get_upvar_name_and_span_for_region: upvar_name={upvar_name:?} upvar_span={upvar_span:?}", - ); - - (upvar_name, upvar_span) - } - - /// Search the argument types for one that references fr (which should be a free region). - /// Returns Some(_) with the index of the input if one is found. - /// - /// N.B., in the case of a closure, the index is indexing into the signature as seen by the - /// user - in particular, index 0 is not the implicit self parameter. - pub(crate) fn get_argument_index_for_region( - &self, - tcx: TyCtxt<'tcx>, - fr: RegionVid, - ) -> Option { - let implicit_inputs = self.universal_regions().defining_ty.implicit_inputs(); - let argument_index = - self.universal_regions().unnormalized_input_tys.iter().skip(implicit_inputs).position( - |arg_ty| { - debug!("get_argument_index_for_region: arg_ty = {arg_ty:?}"); - tcx.any_free_region_meets(arg_ty, |r| r.as_var() == fr) - }, - )?; - - debug!( - "get_argument_index_for_region: found {fr:?} in argument {argument_index} which has type {:?}", - self.universal_regions().unnormalized_input_tys[argument_index], - ); - - Some(argument_index) - } - - /// Given the index of an argument, finds its name (if any) and the span from where it was - /// declared. - pub(crate) fn get_argument_name_and_span_for_region( - &self, - body: &Body<'tcx>, - local_names: &IndexSlice>, - argument_index: usize, - ) -> (Option, Span) { - let implicit_inputs = self.universal_regions().defining_ty.implicit_inputs(); - let argument_local = Local::from_usize(implicit_inputs + argument_index + 1); - debug!("get_argument_name_and_span_for_region: argument_local={argument_local:?}"); - - let argument_name = local_names[argument_local]; - let argument_span = body.local_decls[argument_local].source_info.span; - debug!( - "get_argument_name_and_span_for_region: argument_name={argument_name:?} argument_span={argument_span:?}", - ); - - (argument_name, argument_span) - } -} +use crate::region_infer::RegionInferenceContext ;use rustc_index::IndexSlice;use +rustc_middle::mir::{Body,Local};use rustc_middle::ty::{self,RegionVid,TyCtxt};// +use rustc_span::symbol::Symbol;use rustc_span::Span;impl<'tcx>//((),());((),()); +RegionInferenceContext<'tcx>{pub(crate)fn get_var_name_and_span_for_region(&//3; +self,tcx:TyCtxt<'tcx>,body:&Body<'tcx>,local_names:&IndexSlice>,upvars:&[&ty::CapturedPlace<'tcx>],fr:RegionVid,)->Option<(Option,Span)>{;debug!("get_var_name_and_span_for_region(fr={fr:?})");;;assert!( +self.universal_regions().is_universal_region(fr));loop{break};let _=||();debug!( +"get_var_name_and_span_for_region: attempting upvar");if true{};let _=||();self. +get_upvar_index_for_region(tcx,fr).map(|index|{loop{break;};let(name,span)=self. +get_upvar_name_and_span_for_region(tcx,upvars,index);*&*&();(Some(name),span)}). +or_else(||{;debug!("get_var_name_and_span_for_region: attempting argument");self +.get_argument_index_for_region(tcx,fr).map(|index|{self.//let _=||();let _=||(); +get_argument_name_and_span_for_region(body,local_names,index)})})}pub(crate)fn// +get_upvar_index_for_region(&self,tcx:TyCtxt<'tcx> ,fr:RegionVid,)->Option +{*&*&();let upvar_index=self.universal_regions().defining_ty.upvar_tys().iter(). +position(|upvar_ty|{;debug!("get_upvar_index_for_region: upvar_ty={upvar_ty:?}") +;{;};tcx.any_free_region_meets(&upvar_ty,|r|{{;};let r=r.as_var();{;};();debug!( +"get_upvar_index_for_region: r={r:?} fr={fr:?}");;r==fr})})?;;let upvar_ty=self. +universal_regions().defining_ty.upvar_tys().get(upvar_index);{();};{();};debug!( +"get_upvar_index_for_region: found {fr:?} in upvar {upvar_index} which has type {upvar_ty:?}" +,);;Some(upvar_index)}pub(crate)fn get_upvar_name_and_span_for_region(&self,tcx: +TyCtxt<'tcx>,upvars:&[&ty::CapturedPlace<'tcx>],upvar_index:usize,)->(Symbol,//; +Span){{;};let upvar_hir_id=upvars[upvar_index].get_root_variable();();();debug!( +"get_upvar_name_and_span_for_region: upvar_hir_id={upvar_hir_id:?}");{;};{;};let +upvar_name=tcx.hir().name(upvar_hir_id);({});({});let upvar_span=tcx.hir().span( +upvar_hir_id);*&*&();((),());*&*&();((),());if let _=(){};*&*&();((),());debug!( +"get_upvar_name_and_span_for_region: upvar_name={upvar_name:?} upvar_span={upvar_span:?}" +,);;(upvar_name,upvar_span)}pub(crate)fn get_argument_index_for_region(&self,tcx +:TyCtxt<'tcx>,fr:RegionVid,)->Option{let _=||();let implicit_inputs=self. +universal_regions().defining_ty.implicit_inputs();();();let argument_index=self. +universal_regions().unnormalized_input_tys.iter().skip(implicit_inputs).//{();}; +position(|arg_ty|{;debug!("get_argument_index_for_region: arg_ty = {arg_ty:?}"); +tcx.any_free_region_meets(arg_ty,|r|r.as_var()==fr)},)?;let _=();((),());debug!( +"get_argument_index_for_region: found {fr:?} in argument {argument_index} which has type {:?}" +,self.universal_regions().unnormalized_input_tys[argument_index],);((),());Some( +argument_index)}pub(crate)fn get_argument_name_and_span_for_region(&self,body:& +Body<'tcx>,local_names:&IndexSlice>,argument_index:usize,) +->(Option,Span){let _=||();let implicit_inputs=self.universal_regions(). +defining_ty.implicit_inputs();*&*&();{();};let argument_local=Local::from_usize( +implicit_inputs+argument_index+1);if true{};if true{};let _=();if true{};debug!( +"get_argument_name_and_span_for_region: argument_local={argument_local:?}");;let +argument_name=local_names[argument_local];3;;let argument_span=body.local_decls[ +argument_local].source_info.span;if true{};if true{};if true{};if true{};debug!( +"get_argument_name_and_span_for_region: argument_name={argument_name:?} argument_span={argument_span:?}" +,);let _=||();loop{break};let _=||();loop{break};(argument_name,argument_span)}} diff --git a/compiler/rustc_borrowck/src/facts.rs b/compiler/rustc_borrowck/src/facts.rs index e7faec7bbac1e..c7b88c077de78 100644 --- a/compiler/rustc_borrowck/src/facts.rs +++ b/compiler/rustc_borrowck/src/facts.rs @@ -1,203 +1,48 @@ -use crate::location::{LocationIndex, LocationTable}; -use crate::BorrowIndex; -use polonius_engine::AllFacts as PoloniusFacts; -use polonius_engine::Atom; -use rustc_macros::extension; -use rustc_middle::mir::Local; -use rustc_middle::ty::{RegionVid, TyCtxt}; -use rustc_mir_dataflow::move_paths::MovePathIndex; -use std::error::Error; -use std::fmt::Debug; -use std::fs::{self, File}; -use std::io::{BufWriter, Write}; -use std::path::Path; - -#[derive(Copy, Clone, Debug)] -pub struct RustcFacts; - -impl polonius_engine::FactTypes for RustcFacts { - type Origin = RegionVid; - type Loan = BorrowIndex; - type Point = LocationIndex; - type Variable = Local; - type Path = MovePathIndex; -} - -pub type AllFacts = PoloniusFacts; - -#[extension(pub(crate) trait AllFactsExt)] -impl AllFacts { - /// Returns `true` if there is a need to gather `AllFacts` given the - /// current `-Z` flags. - fn enabled(tcx: TyCtxt<'_>) -> bool { - tcx.sess.opts.unstable_opts.nll_facts - || tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled() - } - - fn write_to_dir( - &self, - dir: impl AsRef, - location_table: &LocationTable, - ) -> Result<(), Box> { - let dir: &Path = dir.as_ref(); - fs::create_dir_all(dir)?; - let wr = FactWriter { location_table, dir }; - macro_rules! write_facts_to_path { - ($wr:ident . write_facts_to_path($this:ident . [ - $($field:ident,)* - ])) => { - $( - $wr.write_facts_to_path( - &$this.$field, - &format!("{}.facts", stringify!($field)) - )?; - )* - } - } - write_facts_to_path! { - wr.write_facts_to_path(self.[ - loan_issued_at, - universal_region, - cfg_edge, - loan_killed_at, - subset_base, - loan_invalidated_at, - var_used_at, - var_defined_at, - var_dropped_at, - use_of_var_derefs_origin, - drop_of_var_derefs_origin, - child_path, - path_is_var, - path_assigned_at_base, - path_moved_at_base, - path_accessed_at_base, - known_placeholder_subset, - placeholder, - ]) - } - Ok(()) - } -} - -impl Atom for BorrowIndex { - fn index(self) -> usize { - self.as_usize() - } -} - -impl Atom for LocationIndex { - fn index(self) -> usize { - self.as_usize() - } -} - -struct FactWriter<'w> { - location_table: &'w LocationTable, - dir: &'w Path, -} - -impl<'w> FactWriter<'w> { - fn write_facts_to_path(&self, rows: &[T], file_name: &str) -> Result<(), Box> - where - T: FactRow, - { - let file = &self.dir.join(file_name); - let mut file = BufWriter::new(File::create(file)?); - for row in rows { - row.write(&mut file, self.location_table)?; - } - Ok(()) - } -} - -trait FactRow { - fn write( - &self, - out: &mut dyn Write, - location_table: &LocationTable, - ) -> Result<(), Box>; -} - -impl FactRow for RegionVid { - fn write( - &self, - out: &mut dyn Write, - location_table: &LocationTable, - ) -> Result<(), Box> { - write_row(out, location_table, &[self]) - } -} - -impl FactRow for (A, B) -where - A: FactCell, - B: FactCell, -{ - fn write( - &self, - out: &mut dyn Write, - location_table: &LocationTable, - ) -> Result<(), Box> { - write_row(out, location_table, &[&self.0, &self.1]) - } -} - -impl FactRow for (A, B, C) -where - A: FactCell, - B: FactCell, - C: FactCell, -{ - fn write( - &self, - out: &mut dyn Write, - location_table: &LocationTable, - ) -> Result<(), Box> { - write_row(out, location_table, &[&self.0, &self.1, &self.2]) - } -} - -impl FactRow for (A, B, C, D) -where - A: FactCell, - B: FactCell, - C: FactCell, - D: FactCell, -{ - fn write( - &self, - out: &mut dyn Write, - location_table: &LocationTable, - ) -> Result<(), Box> { - write_row(out, location_table, &[&self.0, &self.1, &self.2, &self.3]) - } -} - -fn write_row( - out: &mut dyn Write, - location_table: &LocationTable, - columns: &[&dyn FactCell], -) -> Result<(), Box> { - for (index, c) in columns.iter().enumerate() { - let tail = if index == columns.len() - 1 { "\n" } else { "\t" }; - write!(out, "{:?}{tail}", c.to_string(location_table))?; - } - Ok(()) -} - -trait FactCell { - fn to_string(&self, location_table: &LocationTable) -> String; -} - -impl FactCell for A { - default fn to_string(&self, _location_table: &LocationTable) -> String { - format!("{self:?}") - } -} - -impl FactCell for LocationIndex { - fn to_string(&self, location_table: &LocationTable) -> String { - format!("{:?}", location_table.to_location(*self)) - } -} +use crate::location::{LocationIndex,LocationTable};use crate::BorrowIndex;use//; +polonius_engine::AllFacts as PoloniusFacts;use polonius_engine::Atom;use//{();}; +rustc_macros::extension;use rustc_middle::mir::Local;use rustc_middle::ty::{//3; +RegionVid,TyCtxt};use rustc_mir_dataflow::move_paths::MovePathIndex;use std:://; +error::Error;use std::fmt::Debug;use std::fs::{self,File};use std::io::{//{();}; +BufWriter,Write};use std::path::Path;#[derive(Copy,Clone,Debug)]pub struct//{;}; +RustcFacts;impl polonius_engine::FactTypes for RustcFacts{type Origin=RegionVid +;type Loan=BorrowIndex;type Point=LocationIndex;type Variable=Local;type Path=// +MovePathIndex;}pub type AllFacts=PoloniusFacts;#[extension(pub(//(); +crate)trait AllFactsExt)]impl AllFacts{fn enabled(tcx:TyCtxt<'_>)->bool{tcx.//3; +sess.opts.unstable_opts.nll_facts||tcx.sess.opts.unstable_opts.polonius.//{();}; +is_legacy_enabled()}fn write_to_dir(&self ,dir:impl AsRef,location_table:& +LocationTable,)->Result<(),Box>{3;let dir:&Path=dir.as_ref();3;3;fs:: +create_dir_all(dir)?;();3;let wr=FactWriter{location_table,dir};3;3;macro_rules! +write_facts_to_path{($wr:ident.write_facts_to_path($ this:ident.[$($field:ident, +)*]))=>{$($wr.write_facts_to_path(& $this.$field,&format!("{}.facts",stringify!( +$field)))?;)*}};write_facts_to_path!{wr.write_facts_to_path(self.[loan_issued_at +,universal_region,cfg_edge,loan_killed_at,subset_base,loan_invalidated_at,//{;}; +var_used_at,var_defined_at,var_dropped_at,use_of_var_derefs_origin,//let _=||(); +drop_of_var_derefs_origin,child_path,path_is_var,path_assigned_at_base,//*&*&(); +path_moved_at_base,path_accessed_at_base, known_placeholder_subset,placeholder,] +)}Ok(())}}impl Atom for BorrowIndex {fn index(self)->usize{self.as_usize()}}impl +Atom for LocationIndex{fn index(self)->usize{((((((self.as_usize()))))))}}struct +FactWriter<'w>{location_table:&'w LocationTable,dir:&'w Path,}impl<'w>//((),()); +FactWriter<'w>{fn write_facts_to_path(&self,rows:&[T],file_name:&str)->//{;}; +Result<(),Box>where T:FactRow,{;let file=&self.dir.join(file_name);;; +let mut file=BufWriter::new(File::create(file)?);;for row in rows{row.write(&mut +file,self.location_table)?;();}Ok(())}}trait FactRow{fn write(&self,out:&mut dyn +Write,location_table:&LocationTable,)->Result<(),Box>;}impl FactRow// +for RegionVid{fn write(&self,out: &mut dyn Write,location_table:&LocationTable,) +->Result<(),Box>{(write_row(out,location_table,(&[self])))}}impl +FactRow for(A,B)where A:FactCell,B:FactCell ,{fn write(&self,out:&mut dyn Write, +location_table:&LocationTable,)->Result<(),Box>{write_row(out,//({}); +location_table,(&([(&self.0),&self.1]))) }}implFactRow for(A,B,C)where A: +FactCell,B:FactCell,C:FactCell,{fn write(&self,out:&mut dyn Write,//loop{break}; +location_table:&LocationTable,)->Result<(),Box>{write_row(out,//({}); +location_table,(&[&self.0,&self.1,&self.2] ))}}implFactRow for(A,B,C,D) +where A:FactCell,B:FactCell,C:FactCell,D:FactCell,{fn write(&self,out:&mut dyn// +Write,location_table:&LocationTable,)->Result<() ,Box>{write_row(out, +location_table,(&[&self.0,&self.1,&self.2 ,&self.3]))}}fn write_row(out:&mut dyn +Write,location_table:&LocationTable,columns:&[&dyn FactCell],)->Result<(),Box>{for(index,c)in columns.iter().enumerate(){*&*&();let tail=if index== +columns.len()-1{"\n"}else{"\t"};{();};{();};write!(out,"{:?}{tail}",c.to_string( +location_table))?;{;};}Ok(())}trait FactCell{fn to_string(&self,location_table:& +LocationTable)->String;}implFactCell for A{default fn to_string(&self, +_location_table:&LocationTable)->String{(format!("{self:?}"))}}impl FactCell for +LocationIndex{fn to_string(&self,location_table :&LocationTable)->String{format! +("{:?}",location_table.to_location(*self))}}//((),());let _=();((),());let _=(); diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 4a5ba4418783e..f1e13ee3eed55 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1,2544 +1,641 @@ -//! This query borrow-checks the MIR to (further) ensure it is not broken. - -#![allow(internal_features)] -#![feature(rustdoc_internals)] -#![doc(rust_logo)] -#![feature(assert_matches)] -#![cfg_attr(bootstrap, feature(associated_type_bounds))] -#![feature(box_patterns)] -#![feature(control_flow_enum)] -#![feature(let_chains)] -#![feature(min_specialization)] -#![feature(never_type)] -#![feature(rustc_attrs)] -#![feature(stmt_expr_attributes)] -#![feature(try_blocks)] - -#[macro_use] -extern crate rustc_middle; -#[macro_use] -extern crate tracing; - -use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; -use rustc_data_structures::graph::dominators::Dominators; -use rustc_errors::Diag; -use rustc_hir as hir; -use rustc_hir::def_id::LocalDefId; -use rustc_index::bit_set::{BitSet, ChunkedBitSet}; -use rustc_index::{IndexSlice, IndexVec}; -use rustc_infer::infer::{ - InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt, -}; -use rustc_middle::mir::tcx::PlaceTy; -use rustc_middle::mir::*; -use rustc_middle::query::Providers; -use rustc_middle::traits::DefiningAnchor; -use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt}; -use rustc_session::lint::builtin::UNUSED_MUT; -use rustc_span::{Span, Symbol}; -use rustc_target::abi::FieldIdx; - -use smallvec::SmallVec; -use std::cell::RefCell; -use std::collections::BTreeMap; -use std::marker::PhantomData; -use std::ops::Deref; -use std::rc::Rc; - -use rustc_mir_dataflow::impls::{ - EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces, -}; -use rustc_mir_dataflow::move_paths::{InitIndex, MoveOutIndex, MovePathIndex}; -use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult, MoveData}; -use rustc_mir_dataflow::Analysis; -use rustc_mir_dataflow::MoveDataParamEnv; - -use crate::session_diagnostics::VarNeedNotMut; - -use self::diagnostics::{AccessKind, IllegalMoveOriginKind, MoveError, RegionName}; -use self::location::LocationTable; -use self::prefixes::PrefixSet; -use consumers::{BodyWithBorrowckFacts, ConsumerOptions}; - -use self::path_utils::*; - -pub mod borrow_set; -mod borrowck_errors; -mod constraints; -mod dataflow; -mod def_use; -mod diagnostics; -mod facts; -mod location; -mod member_constraints; -mod nll; -mod path_utils; -mod place_ext; -mod places_conflict; -mod polonius; -mod prefixes; -mod region_infer; -mod renumber; -mod session_diagnostics; -mod type_check; -mod universal_regions; -mod used_muts; -mod util; - -/// A public API provided for the Rust compiler consumers. -pub mod consumers; - -use borrow_set::{BorrowData, BorrowSet}; -use dataflow::{BorrowIndex, BorrowckFlowState as Flows, BorrowckResults, Borrows}; -use nll::PoloniusOutput; -use place_ext::PlaceExt; -use places_conflict::{places_conflict, PlaceConflictBias}; -use region_infer::RegionInferenceContext; -use renumber::RegionCtxt; - -rustc_fluent_macro::fluent_messages! { "../messages.ftl" } - -/// Associate some local constants with the `'tcx` lifetime -struct TyCtxtConsts<'tcx>(PhantomData<&'tcx ()>); -impl<'tcx> TyCtxtConsts<'tcx> { - const DEREF_PROJECTION: &'tcx [PlaceElem<'tcx>; 1] = &[ProjectionElem::Deref]; -} - -pub fn provide(providers: &mut Providers) { - *providers = Providers { mir_borrowck, ..*providers }; -} - -fn mir_borrowck(tcx: TyCtxt<'_>, def: LocalDefId) -> &BorrowCheckResult<'_> { - let (input_body, promoted) = tcx.mir_promoted(def); - debug!("run query mir_borrowck: {}", tcx.def_path_str(def)); - - let input_body: &Body<'_> = &input_body.borrow(); - - if input_body.should_skip() || input_body.tainted_by_errors.is_some() { - debug!("Skipping borrowck because of injected body or tainted body"); - // Let's make up a borrowck result! Fun times! - let result = BorrowCheckResult { - concrete_opaque_types: FxIndexMap::default(), - closure_requirements: None, - used_mut_upvars: SmallVec::new(), - tainted_by_errors: input_body.tainted_by_errors, - }; - return tcx.arena.alloc(result); - } - - let infcx = tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::bind(tcx, def)).build(); - let promoted: &IndexSlice<_, _> = &promoted.borrow(); - let opt_closure_req = do_mir_borrowck(&infcx, input_body, promoted, None).0; - debug!("mir_borrowck done"); - - tcx.arena.alloc(opt_closure_req) -} - -/// Perform the actual borrow checking. -/// -/// Use `consumer_options: None` for the default behavior of returning -/// [`BorrowCheckResult`] only. Otherwise, return [`BodyWithBorrowckFacts`] according -/// to the given [`ConsumerOptions`]. -#[instrument(skip(infcx, input_body, input_promoted), fields(id=?input_body.source.def_id()), level = "debug")] -fn do_mir_borrowck<'tcx>( - infcx: &InferCtxt<'tcx>, - input_body: &Body<'tcx>, - input_promoted: &IndexSlice>, - consumer_options: Option, -) -> (BorrowCheckResult<'tcx>, Option>>) { - let def = input_body.source.def_id().expect_local(); - debug!(?def); - - let tcx = infcx.tcx; - let infcx = BorrowckInferCtxt::new(infcx); - let param_env = tcx.param_env(def); - - let mut local_names = IndexVec::from_elem(None, &input_body.local_decls); - for var_debug_info in &input_body.var_debug_info { - if let VarDebugInfoContents::Place(place) = var_debug_info.value { - if let Some(local) = place.as_local() { - if let Some(prev_name) = local_names[local] - && var_debug_info.name != prev_name - { - span_bug!( - var_debug_info.source_info.span, - "local {:?} has many names (`{}` vs `{}`)", - local, - prev_name, - var_debug_info.name - ); - } - local_names[local] = Some(var_debug_info.name); - } - } - } - - let mut diags = diags::BorrowckDiags::new(); - - // Gather the upvars of a closure, if any. - if let Some(e) = input_body.tainted_by_errors { - infcx.set_tainted_by_errors(e); - } - - // Replace all regions with fresh inference variables. This - // requires first making our own copy of the MIR. This copy will - // be modified (in place) to contain non-lexical lifetimes. It - // will have a lifetime tied to the inference context. - let mut body_owned = input_body.clone(); - let mut promoted = input_promoted.to_owned(); - let free_regions = - nll::replace_regions_in_mir(&infcx, param_env, &mut body_owned, &mut promoted); - let body = &body_owned; // no further changes - - let location_table = LocationTable::new(body); - - let move_data = MoveData::gather_moves(body, tcx, param_env, |_| true); - let promoted_move_data = promoted - .iter_enumerated() - .map(|(idx, body)| (idx, MoveData::gather_moves(body, tcx, param_env, |_| true))); - - let mdpe = MoveDataParamEnv { move_data, param_env }; - - let mut flow_inits = MaybeInitializedPlaces::new(tcx, body, &mdpe) - .into_engine(tcx, body) - .pass_name("borrowck") - .iterate_to_fixpoint() - .into_results_cursor(body); - - let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(def).is_fn_or_closure(); - let borrow_set = - Rc::new(BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &mdpe.move_data)); - - // Compute non-lexical lifetimes. - let nll::NllOutput { - regioncx, - opaque_type_values, - polonius_input, - polonius_output, - opt_closure_req, - nll_errors, - } = nll::compute_regions( - &infcx, - free_regions, - body, - &promoted, - &location_table, - param_env, - &mut flow_inits, - &mdpe.move_data, - &borrow_set, - tcx.closure_captures(def), - consumer_options, - ); - - // Dump MIR results into a file, if that is enabled. This let us - // write unit-tests, as well as helping with debugging. - nll::dump_mir_results(&infcx, body, ®ioncx, &opt_closure_req); - - // We also have a `#[rustc_regions]` annotation that causes us to dump - // information. - nll::dump_annotation( - &infcx, - body, - ®ioncx, - &opt_closure_req, - &opaque_type_values, - &mut diags, - ); - - // The various `flow_*` structures can be large. We drop `flow_inits` here - // so it doesn't overlap with the others below. This reduces peak memory - // usage significantly on some benchmarks. - drop(flow_inits); - - let regioncx = Rc::new(regioncx); - - let flow_borrows = Borrows::new(tcx, body, ®ioncx, &borrow_set) - .into_engine(tcx, body) - .pass_name("borrowck") - .iterate_to_fixpoint(); - let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &mdpe) - .into_engine(tcx, body) - .pass_name("borrowck") - .iterate_to_fixpoint(); - let flow_ever_inits = EverInitializedPlaces::new(body, &mdpe) - .into_engine(tcx, body) - .pass_name("borrowck") - .iterate_to_fixpoint(); - - let movable_coroutine = - // The first argument is the coroutine type passed by value - if let Some(local) = body.local_decls.raw.get(1) - // Get the interior types and args which typeck computed - && let ty::Coroutine(def_id, _) = *local.ty.kind() - && tcx.coroutine_movability(def_id) == hir::Movability::Movable - { - true - } else { - false - }; - - for (idx, move_data) in promoted_move_data { - use rustc_middle::mir::visit::Visitor; - - let promoted_body = &promoted[idx]; - let mut promoted_mbcx = MirBorrowckCtxt { - infcx: &infcx, - param_env, - body: promoted_body, - move_data: &move_data, - location_table: &location_table, // no need to create a real one for the promoted, it is not used - movable_coroutine, - fn_self_span_reported: Default::default(), - locals_are_invalidated_at_exit, - access_place_error_reported: Default::default(), - reservation_error_reported: Default::default(), - uninitialized_error_reported: Default::default(), - regioncx: regioncx.clone(), - used_mut: Default::default(), - used_mut_upvars: SmallVec::new(), - borrow_set: Rc::clone(&borrow_set), - upvars: &[], - local_names: IndexVec::from_elem(None, &promoted_body.local_decls), - region_names: RefCell::default(), - next_region_name: RefCell::new(1), - polonius_output: None, - move_errors: Vec::new(), - diags, - }; - MoveVisitor { ctxt: &mut promoted_mbcx }.visit_body(promoted_body); - promoted_mbcx.report_move_errors(); - diags = promoted_mbcx.diags; - - struct MoveVisitor<'a, 'cx, 'tcx> { - ctxt: &'a mut MirBorrowckCtxt<'cx, 'tcx>, - } - - impl<'tcx> Visitor<'tcx> for MoveVisitor<'_, '_, 'tcx> { - fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { - if let Operand::Move(place) = operand { - self.ctxt.check_movable_place(location, *place); - } - } - } - } - - let mut mbcx = MirBorrowckCtxt { - infcx: &infcx, - param_env, - body, - move_data: &mdpe.move_data, - location_table: &location_table, - movable_coroutine, - locals_are_invalidated_at_exit, - fn_self_span_reported: Default::default(), - access_place_error_reported: Default::default(), - reservation_error_reported: Default::default(), - uninitialized_error_reported: Default::default(), - regioncx: Rc::clone(®ioncx), - used_mut: Default::default(), - used_mut_upvars: SmallVec::new(), - borrow_set: Rc::clone(&borrow_set), - upvars: tcx.closure_captures(def), - local_names, - region_names: RefCell::default(), - next_region_name: RefCell::new(1), - polonius_output, - move_errors: Vec::new(), - diags, - }; - - // Compute and report region errors, if any. - mbcx.report_region_errors(nll_errors); - - let mut results = BorrowckResults { - ever_inits: flow_ever_inits, - uninits: flow_uninits, - borrows: flow_borrows, - }; - - rustc_mir_dataflow::visit_results( - body, - traversal::reverse_postorder(body).map(|(bb, _)| bb), - &mut results, - &mut mbcx, - ); - - mbcx.report_move_errors(); - - // For each non-user used mutable variable, check if it's been assigned from - // a user-declared local. If so, then put that local into the used_mut set. - // Note that this set is expected to be small - only upvars from closures - // would have a chance of erroneously adding non-user-defined mutable vars - // to the set. - let temporary_used_locals: FxIndexSet = mbcx - .used_mut - .iter() - .filter(|&local| !mbcx.body.local_decls[*local].is_user_variable()) - .cloned() - .collect(); - // For the remaining unused locals that are marked as mutable, we avoid linting any that - // were never initialized. These locals may have been removed as unreachable code; or will be - // linted as unused variables. - let unused_mut_locals = - mbcx.body.mut_vars_iter().filter(|local| !mbcx.used_mut.contains(local)).collect(); - mbcx.gather_used_muts(temporary_used_locals, unused_mut_locals); - - debug!("mbcx.used_mut: {:?}", mbcx.used_mut); - let used_mut = std::mem::take(&mut mbcx.used_mut); - for local in mbcx.body.mut_vars_and_args_iter().filter(|local| !used_mut.contains(local)) { - let local_decl = &mbcx.body.local_decls[local]; - let lint_root = match &mbcx.body.source_scopes[local_decl.source_info.scope].local_data { - ClearCrossCrate::Set(data) => data.lint_root, - _ => continue, - }; - - // Skip over locals that begin with an underscore or have no name - match mbcx.local_names[local] { - Some(name) => { - if name.as_str().starts_with('_') { - continue; - } - } - None => continue, - } - - let span = local_decl.source_info.span; - if span.desugaring_kind().is_some() { - // If the `mut` arises as part of a desugaring, we should ignore it. - continue; - } - - let mut_span = tcx.sess.source_map().span_until_non_whitespace(span); - - tcx.emit_node_span_lint(UNUSED_MUT, lint_root, span, VarNeedNotMut { span: mut_span }) - } - - let tainted_by_errors = mbcx.emit_errors(); - - let result = BorrowCheckResult { - concrete_opaque_types: opaque_type_values, - closure_requirements: opt_closure_req, - used_mut_upvars: mbcx.used_mut_upvars, - tainted_by_errors, - }; - - let body_with_facts = if consumer_options.is_some() { - let output_facts = mbcx.polonius_output; - Some(Box::new(BodyWithBorrowckFacts { - body: body_owned, - promoted, - borrow_set, - region_inference_context: regioncx, - location_table: polonius_input.as_ref().map(|_| location_table), - input_facts: polonius_input, - output_facts, - })) - } else { - None - }; - - debug!("do_mir_borrowck: result = {:#?}", result); - - (result, body_with_facts) -} - -pub struct BorrowckInferCtxt<'cx, 'tcx> { - pub(crate) infcx: &'cx InferCtxt<'tcx>, - pub(crate) reg_var_to_origin: RefCell>, -} - -impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> { - pub(crate) fn new(infcx: &'cx InferCtxt<'tcx>) -> Self { - BorrowckInferCtxt { infcx, reg_var_to_origin: RefCell::new(Default::default()) } - } - - pub(crate) fn next_region_var( - &self, - origin: RegionVariableOrigin, - get_ctxt_fn: F, - ) -> ty::Region<'tcx> - where - F: Fn() -> RegionCtxt, - { - let next_region = self.infcx.next_region_var(origin); - let vid = next_region.as_var(); - - if cfg!(debug_assertions) { - debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin); - let ctxt = get_ctxt_fn(); - let mut var_to_origin = self.reg_var_to_origin.borrow_mut(); - assert_eq!(var_to_origin.insert(vid, ctxt), None); - } - - next_region - } - - #[instrument(skip(self, get_ctxt_fn), level = "debug")] - pub(crate) fn next_nll_region_var( - &self, - origin: NllRegionVariableOrigin, - get_ctxt_fn: F, - ) -> ty::Region<'tcx> - where - F: Fn() -> RegionCtxt, - { - let next_region = self.infcx.next_nll_region_var(origin); - let vid = next_region.as_var(); - - if cfg!(debug_assertions) { - debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin); - let ctxt = get_ctxt_fn(); - let mut var_to_origin = self.reg_var_to_origin.borrow_mut(); - assert_eq!(var_to_origin.insert(vid, ctxt), None); - } - - next_region - } -} - -impl<'cx, 'tcx> Deref for BorrowckInferCtxt<'cx, 'tcx> { - type Target = InferCtxt<'tcx>; - - fn deref(&self) -> &'cx Self::Target { - self.infcx - } -} - -struct MirBorrowckCtxt<'cx, 'tcx> { - infcx: &'cx BorrowckInferCtxt<'cx, 'tcx>, - param_env: ParamEnv<'tcx>, - body: &'cx Body<'tcx>, - move_data: &'cx MoveData<'tcx>, - - /// Map from MIR `Location` to `LocationIndex`; created - /// when MIR borrowck begins. - location_table: &'cx LocationTable, - - movable_coroutine: bool, - /// This keeps track of whether local variables are free-ed when the function - /// exits even without a `StorageDead`, which appears to be the case for - /// constants. - /// - /// I'm not sure this is the right approach - @eddyb could you try and - /// figure this out? - locals_are_invalidated_at_exit: bool, - /// This field keeps track of when borrow errors are reported in the access_place function - /// so that there is no duplicate reporting. This field cannot also be used for the conflicting - /// borrow errors that is handled by the `reservation_error_reported` field as the inclusion - /// of the `Span` type (while required to mute some errors) stops the muting of the reservation - /// errors. - access_place_error_reported: FxIndexSet<(Place<'tcx>, Span)>, - /// This field keeps track of when borrow conflict errors are reported - /// for reservations, so that we don't report seemingly duplicate - /// errors for corresponding activations. - // - // FIXME: ideally this would be a set of `BorrowIndex`, not `Place`s, - // but it is currently inconvenient to track down the `BorrowIndex` - // at the time we detect and report a reservation error. - reservation_error_reported: FxIndexSet>, - /// This fields keeps track of the `Span`s that we have - /// used to report extra information for `FnSelfUse`, to avoid - /// unnecessarily verbose errors. - fn_self_span_reported: FxIndexSet, - /// This field keeps track of errors reported in the checking of uninitialized variables, - /// so that we don't report seemingly duplicate errors. - uninitialized_error_reported: FxIndexSet>, - /// This field keeps track of all the local variables that are declared mut and are mutated. - /// Used for the warning issued by an unused mutable local variable. - used_mut: FxIndexSet, - /// If the function we're checking is a closure, then we'll need to report back the list of - /// mutable upvars that have been used. This field keeps track of them. - used_mut_upvars: SmallVec<[FieldIdx; 8]>, - /// Region inference context. This contains the results from region inference and lets us e.g. - /// find out which CFG points are contained in each borrow region. - regioncx: Rc>, - - /// The set of borrows extracted from the MIR - borrow_set: Rc>, - - /// Information about upvars not necessarily preserved in types or MIR - upvars: &'tcx [&'tcx ty::CapturedPlace<'tcx>], - - /// Names of local (user) variables (extracted from `var_debug_info`). - local_names: IndexVec>, - - /// Record the region names generated for each region in the given - /// MIR def so that we can reuse them later in help/error messages. - region_names: RefCell>, - - /// The counter for generating new region names. - next_region_name: RefCell, - - /// Results of Polonius analysis. - polonius_output: Option>, - - diags: diags::BorrowckDiags<'tcx>, - move_errors: Vec>, -} - -// Check that: -// 1. assignments are always made to mutable locations (FIXME: does that still really go here?) -// 2. loans made in overlapping scopes do not conflict -// 3. assignments do not affect things loaned out as immutable -// 4. moves do not affect things loaned out in any way -impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorrowckCtxt<'cx, 'tcx> { - type FlowState = Flows<'cx, 'tcx>; - - fn visit_statement_before_primary_effect( - &mut self, - _results: &mut R, - flow_state: &Flows<'cx, 'tcx>, - stmt: &'cx Statement<'tcx>, - location: Location, - ) { - debug!("MirBorrowckCtxt::process_statement({:?}, {:?}): {:?}", location, stmt, flow_state); - let span = stmt.source_info.span; - - self.check_activations(location, span, flow_state); - - match &stmt.kind { - StatementKind::Assign(box (lhs, rhs)) => { - self.consume_rvalue(location, (rhs, span), flow_state); - - self.mutate_place(location, (*lhs, span), Shallow(None), flow_state); - } - StatementKind::FakeRead(box (_, place)) => { - // Read for match doesn't access any memory and is used to - // assert that a place is safe and live. So we don't have to - // do any checks here. - // - // FIXME: Remove check that the place is initialized. This is - // needed for now because matches don't have never patterns yet. - // So this is the only place we prevent - // let x: !; - // match x {}; - // from compiling. - self.check_if_path_or_subpath_is_moved( - location, - InitializationRequiringAction::Use, - (place.as_ref(), span), - flow_state, - ); - } - StatementKind::Intrinsic(box kind) => match kind { - NonDivergingIntrinsic::Assume(op) => self.consume_operand(location, (op, span), flow_state), - NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!( - span, - "Unexpected CopyNonOverlapping, should only appear after lower_intrinsics", - ) - } - // Only relevant for mir typeck - StatementKind::AscribeUserType(..) - // Only relevant for liveness and unsafeck - | StatementKind::PlaceMention(..) - // Doesn't have any language semantics - | StatementKind::Coverage(..) - // These do not actually affect borrowck - | StatementKind::ConstEvalCounter - | StatementKind::StorageLive(..) => {} - StatementKind::StorageDead(local) => { - self.access_place( - location, - (Place::from(*local), span), - (Shallow(None), Write(WriteKind::StorageDeadOrDrop)), - LocalMutationIsAllowed::Yes, - flow_state, - ); - } - StatementKind::Nop - | StatementKind::Retag { .. } - | StatementKind::Deinit(..) - | StatementKind::SetDiscriminant { .. } => { - bug!("Statement not allowed in this MIR phase") - } - } - } - - fn visit_terminator_before_primary_effect( - &mut self, - _results: &mut R, - flow_state: &Flows<'cx, 'tcx>, - term: &'cx Terminator<'tcx>, - loc: Location, - ) { - debug!("MirBorrowckCtxt::process_terminator({:?}, {:?}): {:?}", loc, term, flow_state); - let span = term.source_info.span; - - self.check_activations(loc, span, flow_state); - - match &term.kind { - TerminatorKind::SwitchInt { discr, targets: _ } => { - self.consume_operand(loc, (discr, span), flow_state); - } - TerminatorKind::Drop { place, target: _, unwind: _, replace } => { - debug!( - "visit_terminator_drop \ - loc: {:?} term: {:?} place: {:?} span: {:?}", - loc, term, place, span - ); - - let write_kind = - if *replace { WriteKind::Replace } else { WriteKind::StorageDeadOrDrop }; - self.access_place( - loc, - (*place, span), - (AccessDepth::Drop, Write(write_kind)), - LocalMutationIsAllowed::Yes, - flow_state, - ); - } - TerminatorKind::Call { - func, - args, - destination, - target: _, - unwind: _, - call_source: _, - fn_span: _, - } => { - self.consume_operand(loc, (func, span), flow_state); - for arg in args { - self.consume_operand(loc, (&arg.node, arg.span), flow_state); - } - self.mutate_place(loc, (*destination, span), Deep, flow_state); - } - TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => { - self.consume_operand(loc, (cond, span), flow_state); - if let AssertKind::BoundsCheck { len, index } = &**msg { - self.consume_operand(loc, (len, span), flow_state); - self.consume_operand(loc, (index, span), flow_state); - } - } - - TerminatorKind::Yield { value, resume: _, resume_arg, drop: _ } => { - self.consume_operand(loc, (value, span), flow_state); - self.mutate_place(loc, (*resume_arg, span), Deep, flow_state); - } - - TerminatorKind::InlineAsm { - template: _, - operands, - options: _, - line_spans: _, - targets: _, - unwind: _, - } => { - for op in operands { - match op { - InlineAsmOperand::In { reg: _, value } => { - self.consume_operand(loc, (value, span), flow_state); - } - InlineAsmOperand::Out { reg: _, late: _, place, .. } => { - if let Some(place) = place { - self.mutate_place(loc, (*place, span), Shallow(None), flow_state); - } - } - InlineAsmOperand::InOut { reg: _, late: _, in_value, out_place } => { - self.consume_operand(loc, (in_value, span), flow_state); - if let &Some(out_place) = out_place { - self.mutate_place( - loc, - (out_place, span), - Shallow(None), - flow_state, - ); - } - } - InlineAsmOperand::Const { value: _ } - | InlineAsmOperand::SymFn { value: _ } - | InlineAsmOperand::SymStatic { def_id: _ } - | InlineAsmOperand::Label { target_index: _ } => {} - } - } - } - - TerminatorKind::Goto { target: _ } - | TerminatorKind::UnwindTerminate(_) - | TerminatorKind::Unreachable - | TerminatorKind::UnwindResume - | TerminatorKind::Return - | TerminatorKind::CoroutineDrop - | TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ } - | TerminatorKind::FalseUnwind { real_target: _, unwind: _ } => { - // no data used, thus irrelevant to borrowck - } - } - } - - fn visit_terminator_after_primary_effect( - &mut self, - _results: &mut R, - flow_state: &Flows<'cx, 'tcx>, - term: &'cx Terminator<'tcx>, - loc: Location, - ) { - let span = term.source_info.span; - - match term.kind { - TerminatorKind::Yield { value: _, resume: _, resume_arg: _, drop: _ } => { - if self.movable_coroutine { - // Look for any active borrows to locals - let borrow_set = self.borrow_set.clone(); - for i in flow_state.borrows.iter() { - let borrow = &borrow_set[i]; - self.check_for_local_borrow(borrow, span); - } - } - } - - TerminatorKind::UnwindResume - | TerminatorKind::Return - | TerminatorKind::CoroutineDrop => { - // Returning from the function implicitly kills storage for all locals and statics. - // Often, the storage will already have been killed by an explicit - // StorageDead, but we don't always emit those (notably on unwind paths), - // so this "extra check" serves as a kind of backup. - let borrow_set = self.borrow_set.clone(); - for i in flow_state.borrows.iter() { - let borrow = &borrow_set[i]; - self.check_for_invalidation_at_exit(loc, borrow, span); - } - } - - TerminatorKind::UnwindTerminate(_) - | TerminatorKind::Assert { .. } - | TerminatorKind::Call { .. } - | TerminatorKind::Drop { .. } - | TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ } - | TerminatorKind::FalseUnwind { real_target: _, unwind: _ } - | TerminatorKind::Goto { .. } - | TerminatorKind::SwitchInt { .. } - | TerminatorKind::Unreachable - | TerminatorKind::InlineAsm { .. } => {} - } - } -} - -use self::AccessDepth::{Deep, Shallow}; -use self::ReadOrWrite::{Activation, Read, Reservation, Write}; - -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum ArtificialField { - ArrayLength, - FakeBorrow, -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum AccessDepth { - /// From the RFC: "A *shallow* access means that the immediate - /// fields reached at P are accessed, but references or pointers - /// found within are not dereferenced. Right now, the only access - /// that is shallow is an assignment like `x = ...;`, which would - /// be a *shallow write* of `x`." - Shallow(Option), - - /// From the RFC: "A *deep* access means that all data reachable - /// through the given place may be invalidated or accesses by - /// this action." - Deep, - - /// Access is Deep only when there is a Drop implementation that - /// can reach the data behind the reference. - Drop, -} - -/// Kind of access to a value: read or write -/// (For informational purposes only) -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum ReadOrWrite { - /// From the RFC: "A *read* means that the existing data may be - /// read, but will not be changed." - Read(ReadKind), - - /// From the RFC: "A *write* means that the data may be mutated to - /// new values or otherwise invalidated (for example, it could be - /// de-initialized, as in a move operation). - Write(WriteKind), - - /// For two-phase borrows, we distinguish a reservation (which is treated - /// like a Read) from an activation (which is treated like a write), and - /// each of those is furthermore distinguished from Reads/Writes above. - Reservation(WriteKind), - Activation(WriteKind, BorrowIndex), -} - -/// Kind of read access to a value -/// (For informational purposes only) -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum ReadKind { - Borrow(BorrowKind), - Copy, -} - -/// Kind of write access to a value -/// (For informational purposes only) -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum WriteKind { - StorageDeadOrDrop, - Replace, - MutableBorrow(BorrowKind), - Mutate, - Move, -} - -/// When checking permissions for a place access, this flag is used to indicate that an immutable -/// local place can be mutated. -// -// FIXME: @nikomatsakis suggested that this flag could be removed with the following modifications: -// - Split `is_mutable()` into `is_assignable()` (can be directly assigned) and -// `is_declared_mutable()`. -// - Take flow state into consideration in `is_assignable()` for local variables. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum LocalMutationIsAllowed { - Yes, - /// We want use of immutable upvars to cause a "write to immutable upvar" - /// error, not an "reassignment" error. - ExceptUpvars, - No, -} - -#[derive(Copy, Clone, Debug)] -enum InitializationRequiringAction { - Borrow, - MatchOn, - Use, - Assignment, - PartialAssignment, -} - -#[derive(Debug)] -struct RootPlace<'tcx> { - place_local: Local, - place_projection: &'tcx [PlaceElem<'tcx>], - is_local_mutation_allowed: LocalMutationIsAllowed, -} - -impl InitializationRequiringAction { - fn as_noun(self) -> &'static str { - match self { - InitializationRequiringAction::Borrow => "borrow", - InitializationRequiringAction::MatchOn => "use", // no good noun - InitializationRequiringAction::Use => "use", - InitializationRequiringAction::Assignment => "assign", - InitializationRequiringAction::PartialAssignment => "assign to part", - } - } - - fn as_verb_in_past_tense(self) -> &'static str { - match self { - InitializationRequiringAction::Borrow => "borrowed", - InitializationRequiringAction::MatchOn => "matched on", - InitializationRequiringAction::Use => "used", - InitializationRequiringAction::Assignment => "assigned", - InitializationRequiringAction::PartialAssignment => "partially assigned", - } - } - - fn as_general_verb_in_past_tense(self) -> &'static str { - match self { - InitializationRequiringAction::Borrow - | InitializationRequiringAction::MatchOn - | InitializationRequiringAction::Use => "used", - InitializationRequiringAction::Assignment => "assigned", - InitializationRequiringAction::PartialAssignment => "partially assigned", - } - } -} - -impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { - fn body(&self) -> &'cx Body<'tcx> { - self.body - } - - /// Checks an access to the given place to see if it is allowed. Examines the set of borrows - /// that are in scope, as well as which paths have been initialized, to ensure that (a) the - /// place is initialized and (b) it is not borrowed in some way that would prevent this - /// access. - /// - /// Returns `true` if an error is reported. - fn access_place( - &mut self, - location: Location, - place_span: (Place<'tcx>, Span), - kind: (AccessDepth, ReadOrWrite), - is_local_mutation_allowed: LocalMutationIsAllowed, - flow_state: &Flows<'cx, 'tcx>, - ) { - let (sd, rw) = kind; - - if let Activation(_, borrow_index) = rw { - if self.reservation_error_reported.contains(&place_span.0) { - debug!( - "skipping access_place for activation of invalid reservation \ - place: {:?} borrow_index: {:?}", - place_span.0, borrow_index - ); - return; - } - } - - // Check is_empty() first because it's the common case, and doing that - // way we avoid the clone() call. - if !self.access_place_error_reported.is_empty() - && self.access_place_error_reported.contains(&(place_span.0, place_span.1)) - { - debug!( - "access_place: suppressing error place_span=`{:?}` kind=`{:?}`", - place_span, kind - ); - return; - } - - let mutability_error = self.check_access_permissions( - place_span, - rw, - is_local_mutation_allowed, - flow_state, - location, - ); - let conflict_error = - self.check_access_for_conflict(location, place_span, sd, rw, flow_state); - - if conflict_error || mutability_error { - debug!("access_place: logging error place_span=`{:?}` kind=`{:?}`", place_span, kind); - self.access_place_error_reported.insert((place_span.0, place_span.1)); - } - } - - #[instrument(level = "debug", skip(self, flow_state))] - fn check_access_for_conflict( - &mut self, - location: Location, - place_span: (Place<'tcx>, Span), - sd: AccessDepth, - rw: ReadOrWrite, - flow_state: &Flows<'cx, 'tcx>, - ) -> bool { - let mut error_reported = false; - let borrow_set = Rc::clone(&self.borrow_set); - - // Use polonius output if it has been enabled. - let mut polonius_output; - let borrows_in_scope = if let Some(polonius) = &self.polonius_output { - let location = self.location_table.start_index(location); - polonius_output = BitSet::new_empty(borrow_set.len()); - for &idx in polonius.errors_at(location) { - polonius_output.insert(idx); - } - &polonius_output - } else { - &flow_state.borrows - }; - - each_borrow_involving_path( - self, - self.infcx.tcx, - self.body, - (sd, place_span.0), - &borrow_set, - |borrow_index| borrows_in_scope.contains(borrow_index), - |this, borrow_index, borrow| match (rw, borrow.kind) { - // Obviously an activation is compatible with its own - // reservation (or even prior activating uses of same - // borrow); so don't check if they interfere. - // - // NOTE: *reservations* do conflict with themselves; - // thus aren't injecting unsoundness w/ this check.) - (Activation(_, activating), _) if activating == borrow_index => { - debug!( - "check_access_for_conflict place_span: {:?} sd: {:?} rw: {:?} \ - skipping {:?} b/c activation of same borrow_index", - place_span, - sd, - rw, - (borrow_index, borrow), - ); - Control::Continue - } - - (Read(_), BorrowKind::Shared | BorrowKind::Fake) - | (Read(ReadKind::Borrow(BorrowKind::Fake)), BorrowKind::Mut { .. }) => { - Control::Continue - } - - (Reservation(_), BorrowKind::Fake | BorrowKind::Shared) => { - // This used to be a future compatibility warning (to be - // disallowed on NLL). See rust-lang/rust#56254 - Control::Continue - } - - (Write(WriteKind::Move), BorrowKind::Fake) => { - // Handled by initialization checks. - Control::Continue - } - - (Read(kind), BorrowKind::Mut { .. }) => { - // Reading from mere reservations of mutable-borrows is OK. - if !is_active(this.dominators(), borrow, location) { - assert!(allow_two_phase_borrow(borrow.kind)); - return Control::Continue; - } - - error_reported = true; - match kind { - ReadKind::Copy => { - let err = this - .report_use_while_mutably_borrowed(location, place_span, borrow); - this.buffer_error(err); - } - ReadKind::Borrow(bk) => { - let err = - this.report_conflicting_borrow(location, place_span, bk, borrow); - this.buffer_error(err); - } - } - Control::Break - } - - (Reservation(kind) | Activation(kind, _) | Write(kind), _) => { - match rw { - Reservation(..) => { - debug!( - "recording invalid reservation of \ - place: {:?}", - place_span.0 - ); - this.reservation_error_reported.insert(place_span.0); - } - Activation(_, activating) => { - debug!( - "observing check_place for activation of \ - borrow_index: {:?}", - activating - ); - } - Read(..) | Write(..) => {} - } - - error_reported = true; - match kind { - WriteKind::MutableBorrow(bk) => { - let err = - this.report_conflicting_borrow(location, place_span, bk, borrow); - this.buffer_error(err); - } - WriteKind::StorageDeadOrDrop => this - .report_borrowed_value_does_not_live_long_enough( - location, - borrow, - place_span, - Some(WriteKind::StorageDeadOrDrop), - ), - WriteKind::Mutate => { - this.report_illegal_mutation_of_borrowed(location, place_span, borrow) - } - WriteKind::Move => { - this.report_move_out_while_borrowed(location, place_span, borrow) - } - WriteKind::Replace => { - this.report_illegal_mutation_of_borrowed(location, place_span, borrow) - } - } - Control::Break - } - }, - ); - - error_reported - } - - fn mutate_place( - &mut self, - location: Location, - place_span: (Place<'tcx>, Span), - kind: AccessDepth, - flow_state: &Flows<'cx, 'tcx>, - ) { - // Write of P[i] or *P requires P init'd. - self.check_if_assigned_path_is_moved(location, place_span, flow_state); - - self.access_place( - location, - place_span, - (kind, Write(WriteKind::Mutate)), - LocalMutationIsAllowed::No, - flow_state, - ); - } - - fn consume_rvalue( - &mut self, - location: Location, - (rvalue, span): (&'cx Rvalue<'tcx>, Span), - flow_state: &Flows<'cx, 'tcx>, - ) { - match rvalue { - &Rvalue::Ref(_ /*rgn*/, bk, place) => { - let access_kind = match bk { - BorrowKind::Fake => { - (Shallow(Some(ArtificialField::FakeBorrow)), Read(ReadKind::Borrow(bk))) - } - BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))), - BorrowKind::Mut { .. } => { - let wk = WriteKind::MutableBorrow(bk); - if allow_two_phase_borrow(bk) { - (Deep, Reservation(wk)) - } else { - (Deep, Write(wk)) - } - } - }; - - self.access_place( - location, - (place, span), - access_kind, - LocalMutationIsAllowed::No, - flow_state, - ); - - let action = if bk == BorrowKind::Fake { - InitializationRequiringAction::MatchOn - } else { - InitializationRequiringAction::Borrow - }; - - self.check_if_path_or_subpath_is_moved( - location, - action, - (place.as_ref(), span), - flow_state, - ); - } - - &Rvalue::AddressOf(mutability, place) => { - let access_kind = match mutability { - Mutability::Mut => ( - Deep, - Write(WriteKind::MutableBorrow(BorrowKind::Mut { - kind: MutBorrowKind::Default, - })), - ), - Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))), - }; - - self.access_place( - location, - (place, span), - access_kind, - LocalMutationIsAllowed::No, - flow_state, - ); - - self.check_if_path_or_subpath_is_moved( - location, - InitializationRequiringAction::Borrow, - (place.as_ref(), span), - flow_state, - ); - } - - Rvalue::ThreadLocalRef(_) => {} - - Rvalue::Use(operand) - | Rvalue::Repeat(operand, _) - | Rvalue::UnaryOp(_ /*un_op*/, operand) - | Rvalue::Cast(_ /*cast_kind*/, operand, _ /*ty*/) - | Rvalue::ShallowInitBox(operand, _ /*ty*/) => { - self.consume_operand(location, (operand, span), flow_state) - } - - &Rvalue::CopyForDeref(place) => { - self.access_place( - location, - (place, span), - (Deep, Read(ReadKind::Copy)), - LocalMutationIsAllowed::No, - flow_state, - ); - - // Finally, check if path was already moved. - self.check_if_path_or_subpath_is_moved( - location, - InitializationRequiringAction::Use, - (place.as_ref(), span), - flow_state, - ); - } - - &(Rvalue::Len(place) | Rvalue::Discriminant(place)) => { - let af = match *rvalue { - Rvalue::Len(..) => Some(ArtificialField::ArrayLength), - Rvalue::Discriminant(..) => None, - _ => unreachable!(), - }; - self.access_place( - location, - (place, span), - (Shallow(af), Read(ReadKind::Copy)), - LocalMutationIsAllowed::No, - flow_state, - ); - self.check_if_path_or_subpath_is_moved( - location, - InitializationRequiringAction::Use, - (place.as_ref(), span), - flow_state, - ); - } - - Rvalue::BinaryOp(_bin_op, box (operand1, operand2)) - | Rvalue::CheckedBinaryOp(_bin_op, box (operand1, operand2)) => { - self.consume_operand(location, (operand1, span), flow_state); - self.consume_operand(location, (operand2, span), flow_state); - } - - Rvalue::NullaryOp(_op, _ty) => { - // nullary ops take no dynamic input; no borrowck effect. - } - - Rvalue::Aggregate(aggregate_kind, operands) => { - // We need to report back the list of mutable upvars that were - // moved into the closure and subsequently used by the closure, - // in order to populate our used_mut set. - match **aggregate_kind { - AggregateKind::Closure(def_id, _) - | AggregateKind::CoroutineClosure(def_id, _) - | AggregateKind::Coroutine(def_id, _) => { - let def_id = def_id.expect_local(); - let BorrowCheckResult { used_mut_upvars, .. } = - self.infcx.tcx.mir_borrowck(def_id); - debug!("{:?} used_mut_upvars={:?}", def_id, used_mut_upvars); - for field in used_mut_upvars { - self.propagate_closure_used_mut_upvar(&operands[*field]); - } - } - AggregateKind::Adt(..) - | AggregateKind::Array(..) - | AggregateKind::Tuple { .. } => (), - } - - for operand in operands { - self.consume_operand(location, (operand, span), flow_state); - } - } - } - } - - fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) { - let propagate_closure_used_mut_place = |this: &mut Self, place: Place<'tcx>| { - // We have three possibilities here: - // a. We are modifying something through a mut-ref - // b. We are modifying something that is local to our parent - // c. Current body is a nested closure, and we are modifying path starting from - // a Place captured by our parent closure. - - // Handle (c), the path being modified is exactly the path captured by our parent - if let Some(field) = this.is_upvar_field_projection(place.as_ref()) { - this.used_mut_upvars.push(field); - return; - } - - for (place_ref, proj) in place.iter_projections().rev() { - // Handle (a) - if proj == ProjectionElem::Deref { - match place_ref.ty(this.body(), this.infcx.tcx).ty.kind() { - // We aren't modifying a variable directly - ty::Ref(_, _, hir::Mutability::Mut) => return, - - _ => {} - } - } - - // Handle (c) - if let Some(field) = this.is_upvar_field_projection(place_ref) { - this.used_mut_upvars.push(field); - return; - } - } - - // Handle(b) - this.used_mut.insert(place.local); - }; - - // This relies on the current way that by-value - // captures of a closure are copied/moved directly - // when generating MIR. - match *operand { - Operand::Move(place) | Operand::Copy(place) => { - match place.as_local() { - Some(local) if !self.body.local_decls[local].is_user_variable() => { - if self.body.local_decls[local].ty.is_mutable_ptr() { - // The variable will be marked as mutable by the borrow. - return; - } - // This is an edge case where we have a `move` closure - // inside a non-move closure, and the inner closure - // contains a mutation: - // - // let mut i = 0; - // || { move || { i += 1; }; }; - // - // In this case our usual strategy of assuming that the - // variable will be captured by mutable reference is - // wrong, since `i` can be copied into the inner - // closure from a shared reference. - // - // As such we have to search for the local that this - // capture comes from and mark it as being used as mut. - - let Some(temp_mpi) = self.move_data.rev_lookup.find_local(local) else { - bug!("temporary should be tracked"); - }; - let init = if let [init_index] = *self.move_data.init_path_map[temp_mpi] { - &self.move_data.inits[init_index] - } else { - bug!("temporary should be initialized exactly once") - }; - - let InitLocation::Statement(loc) = init.location else { - bug!("temporary initialized in arguments") - }; - - let body = self.body; - let bbd = &body[loc.block]; - let stmt = &bbd.statements[loc.statement_index]; - debug!("temporary assigned in: stmt={:?}", stmt); - - if let StatementKind::Assign(box (_, Rvalue::Ref(_, _, source))) = stmt.kind - { - propagate_closure_used_mut_place(self, source); - } else { - bug!( - "closures should only capture user variables \ +#![allow(internal_features)]#![feature( rustdoc_internals)]#![doc(rust_logo)]#![ +feature(assert_matches)]#![cfg_attr (bootstrap,feature(associated_type_bounds))] +#![feature(box_patterns)]#![feature (control_flow_enum)]#![feature(let_chains)]# +![feature(min_specialization)]#![feature( never_type)]#![feature(rustc_attrs)]#! +[feature(stmt_expr_attributes)]#![feature(try_blocks)]#[macro_use]extern crate// +rustc_middle;#[macro_use]extern crate tracing;use rustc_data_structures::fx::{// +FxIndexMap,FxIndexSet};use rustc_data_structures::graph::dominators::Dominators +;use rustc_errors::Diag;use rustc_hir as hir;use rustc_hir::def_id::LocalDefId; +use rustc_index::bit_set::{BitSet,ChunkedBitSet};use rustc_index::{IndexSlice,// +IndexVec};use rustc_infer::infer::{InferCtxt,NllRegionVariableOrigin,//let _=(); +RegionVariableOrigin,TyCtxtInferExt,};use rustc_middle::mir::tcx::PlaceTy;use//; +rustc_middle::mir::*;use rustc_middle::query::Providers;use rustc_middle:://{;}; +traits::DefiningAnchor;use rustc_middle::ty::{self,ParamEnv,RegionVid,TyCtxt};// +use rustc_session::lint::builtin::UNUSED_MUT;use rustc_span::{Span,Symbol};use// +rustc_target::abi::FieldIdx;use smallvec::SmallVec;use std::cell::RefCell;use//; +std::collections::BTreeMap;use std::marker ::PhantomData;use std::ops::Deref;use +std::rc::Rc;use rustc_mir_dataflow::impls::{EverInitializedPlaces,//loop{break}; +MaybeInitializedPlaces,MaybeUninitializedPlaces,};use rustc_mir_dataflow:://{;}; +move_paths::{InitIndex,MoveOutIndex,MovePathIndex};use rustc_mir_dataflow:://(); +move_paths::{InitLocation,LookupResult,MoveData};use rustc_mir_dataflow:://({}); +Analysis;use rustc_mir_dataflow::MoveDataParamEnv;use crate:://((),());let _=(); +session_diagnostics::VarNeedNotMut;use self::diagnostics::{AccessKind,//((),()); +IllegalMoveOriginKind,MoveError,RegionName};use self::location::LocationTable;// +use self::prefixes::PrefixSet;use consumers::{BodyWithBorrowckFacts,//if true{}; +ConsumerOptions};use self::path_utils::* ;pub mod borrow_set;mod borrowck_errors +;mod constraints;mod dataflow;mod def_use;mod diagnostics;mod facts;mod//*&*&(); +location;mod member_constraints;mod nll;mod path_utils;mod place_ext;mod//{();}; +places_conflict;mod polonius;mod prefixes;mod region_infer;mod renumber;mod//(); +session_diagnostics;mod type_check;mod universal_regions;mod used_muts;mod util +;pub mod consumers;use borrow_set::{BorrowData,BorrowSet};use dataflow::{//({}); +BorrowIndex,BorrowckFlowState as Flows,BorrowckResults,Borrows};use nll:://({}); +PoloniusOutput;use place_ext::PlaceExt;use places_conflict::{places_conflict,//; +PlaceConflictBias};use region_infer::RegionInferenceContext;use renumber:://{;}; +RegionCtxt;rustc_fluent_macro::fluent_messages!{"../messages.ftl"}struct//{();}; +TyCtxtConsts<'tcx>(PhantomData<&'tcx()>);impl<'tcx>TyCtxtConsts<'tcx>{const//(); +DEREF_PROJECTION:&'tcx[PlaceElem<'tcx>;(1)]=(&([ProjectionElem::Deref]));}pub fn +provide(providers:&mut Providers){let _=();*providers=Providers{mir_borrowck,..* +providers};;}fn mir_borrowck(tcx:TyCtxt<'_>,def:LocalDefId)->&BorrowCheckResult< +'_>{((),());let(input_body,promoted)=tcx.mir_promoted(def);*&*&();*&*&();debug!( +"run query mir_borrowck: {}",tcx.def_path_str(def));;;let input_body:&Body<'_>=& +input_body.borrow();3;if input_body.should_skip()||input_body.tainted_by_errors. +is_some(){;debug!("Skipping borrowck because of injected body or tainted body"); +let result=BorrowCheckResult{concrete_opaque_types :(((FxIndexMap::default()))), +closure_requirements:None,used_mut_upvars:((SmallVec::new())),tainted_by_errors: +input_body.tainted_by_errors,};;;return tcx.arena.alloc(result);;}let infcx=tcx. +infer_ctxt().with_opaque_type_inference(DefiningAnchor::bind(tcx,def)).build();; +let promoted:&IndexSlice<_,_>=&promoted.borrow();{();};({});let opt_closure_req= +do_mir_borrowck(&infcx,input_body,promoted,None).0;;debug!("mir_borrowck done"); +tcx.arena.alloc(opt_closure_req)}#[instrument(skip(infcx,input_body,//if true{}; +input_promoted),fields(id=?input_body.source.def_id()),level="debug")]fn//{();}; +do_mir_borrowck<'tcx>(infcx:&InferCtxt<'tcx>,input_body:&Body<'tcx>,//if true{}; +input_promoted:&IndexSlice>,consumer_options:Option,)->(BorrowCheckResult<'tcx>,Option>>){;let def=input_body.source.def_id().expect_local();debug!(?def);let tcx +=infcx.tcx;;let infcx=BorrowckInferCtxt::new(infcx);let param_env=tcx.param_env( +def);;;let mut local_names=IndexVec::from_elem(None,&input_body.local_decls);for +var_debug_info in&input_body.var_debug_info {if let VarDebugInfoContents::Place( +place)=var_debug_info.value{if let Some(local)=((place.as_local())){if let Some( +prev_name)=local_names[local]&&var_debug_info.name!=prev_name{((),());span_bug!( +var_debug_info.source_info.span,"local {:?} has many names (`{}` vs `{}`)",//(); +local,prev_name,var_debug_info.name);3;};local_names[local]=Some(var_debug_info. +name);;}}};let mut diags=diags::BorrowckDiags::new();;if let Some(e)=input_body. +tainted_by_errors{;infcx.set_tainted_by_errors(e);}let mut body_owned=input_body +.clone();3;3;let mut promoted=input_promoted.to_owned();;;let free_regions=nll:: +replace_regions_in_mir(&infcx,param_env,&mut body_owned,&mut promoted);;let body +=&body_owned;;let location_table=LocationTable::new(body);let move_data=MoveData +::gather_moves(body,tcx,param_env,|_|true);();3;let promoted_move_data=promoted. +iter_enumerated().map(|(idx,body)|(idx,MoveData::gather_moves(body,tcx,//*&*&(); +param_env,|_|true)));3;;let mdpe=MoveDataParamEnv{move_data,param_env};;;let mut +flow_inits=(MaybeInitializedPlaces::new(tcx,body, &mdpe).into_engine(tcx,body)). +pass_name("borrowck").iterate_to_fixpoint().into_results_cursor(body);{;};();let +locals_are_invalidated_at_exit=tcx.hir() .body_owner_kind(def).is_fn_or_closure( +);*&*&();((),());if let _=(){};let borrow_set=Rc::new(BorrowSet::build(tcx,body, +locals_are_invalidated_at_exit,&mdpe.move_data));3;;let nll::NllOutput{regioncx, +opaque_type_values,polonius_input,polonius_output, opt_closure_req,nll_errors,}= +nll::compute_regions(((&infcx)),free_regions,body,(&promoted),(&location_table), +param_env,&mut flow_inits,&mdpe.move_data ,&borrow_set,tcx.closure_captures(def) +,consumer_options,);((),());*&*&();nll::dump_mir_results(&infcx,body,®ioncx,& +opt_closure_req);;;nll::dump_annotation(&infcx,body,®ioncx,&opt_closure_req,& +opaque_type_values,&mut diags,);;drop(flow_inits);let regioncx=Rc::new(regioncx) +;;let flow_borrows=Borrows::new(tcx,body,®ioncx,&borrow_set).into_engine(tcx, +body).pass_name("borrowck").iterate_to_fixpoint();*&*&();{();};let flow_uninits= +MaybeUninitializedPlaces::new(tcx,body,(&mdpe)).into_engine(tcx,body).pass_name( +"borrowck").iterate_to_fixpoint();3;;let flow_ever_inits=EverInitializedPlaces:: +new(body,&mdpe).into_engine(tcx ,body).pass_name("borrowck").iterate_to_fixpoint +();;let movable_coroutine=if let Some(local)=body.local_decls.raw.get(1)&&let ty +::Coroutine(def_id,_)=*local.ty.kind( )&&tcx.coroutine_movability(def_id)==hir:: +Movability::Movable{true}else{false};3;for(idx,move_data)in promoted_move_data{; +use rustc_middle::mir::visit::Visitor;;;let promoted_body=&promoted[idx];let mut +promoted_mbcx=MirBorrowckCtxt{infcx:((((&infcx)))),param_env,body:promoted_body, +move_data:(((&move_data))),location_table:((&location_table)),movable_coroutine, +fn_self_span_reported:((((Default::default())))),locals_are_invalidated_at_exit, +access_place_error_reported:(((Default::default()))),reservation_error_reported: +Default::default(),uninitialized_error_reported:((Default::default())),regioncx: +regioncx.clone(),used_mut:(Default::default ()),used_mut_upvars:SmallVec::new(), +borrow_set:(Rc::clone(&borrow_set)),upvars :&[],local_names:IndexVec::from_elem( +None,((((&promoted_body.local_decls))))) ,region_names:(((RefCell::default()))), +next_region_name:(RefCell::new(1)), polonius_output:None,move_errors:Vec::new(), +diags,};();3;MoveVisitor{ctxt:&mut promoted_mbcx}.visit_body(promoted_body);3;3; +promoted_mbcx.report_move_errors();;diags=promoted_mbcx.diags;struct MoveVisitor +<'a,'cx,'tcx>{ctxt:&'a mut MirBorrowckCtxt<'cx,'tcx>,}3;;impl<'tcx>Visitor<'tcx> +for MoveVisitor<'_,'_,'tcx>{fn visit_operand(&mut self,operand:&Operand<'tcx>,// +location:Location){if let Operand::Move(place)=operand{*&*&();((),());self.ctxt. +check_movable_place(location,*place);;}}};};let mut mbcx=MirBorrowckCtxt{infcx:& +infcx,param_env,body,move_data:(&mdpe.move_data),location_table:&location_table, +movable_coroutine,locals_are_invalidated_at_exit,fn_self_span_reported:Default// +::default(),access_place_error_reported: ((((((((((Default::default())))))))))), +reservation_error_reported:((Default::default ())),uninitialized_error_reported: +Default::default(),regioncx:(Rc::clone( ®ioncx)),used_mut:Default::default(), +used_mut_upvars:(SmallVec::new()),borrow_set:Rc ::clone(&borrow_set),upvars:tcx. +closure_captures(def),local_names,region_names:(((((((RefCell::default()))))))), +next_region_name:RefCell::new(1),polonius_output ,move_errors:Vec::new(),diags,} +;();3;mbcx.report_region_errors(nll_errors);3;3;let mut results=BorrowckResults{ +ever_inits:flow_ever_inits,uninits:flow_uninits,borrows:flow_borrows,};({});{;}; +rustc_mir_dataflow::visit_results(body,traversal:: reverse_postorder(body).map(| +(bb,_)|bb),&mut results,&mut mbcx,);{;};{;};mbcx.report_move_errors();{;};();let +temporary_used_locals:FxIndexSet=(mbcx.used_mut. iter()).filter(|&local|! +mbcx.body.local_decls[*local].is_user_variable()).cloned().collect();{;};{;};let +unused_mut_locals=(((mbcx.body.mut_vars_iter()))) .filter(|local|!mbcx.used_mut. +contains(local)).collect();({});{;};mbcx.gather_used_muts(temporary_used_locals, +unused_mut_locals);;debug!("mbcx.used_mut: {:?}",mbcx.used_mut);let used_mut=std +::mem::take(&mut mbcx.used_mut);;for local in mbcx.body.mut_vars_and_args_iter() +.filter(|local|!used_mut.contains(local)){;let local_decl=&mbcx.body.local_decls +[local];();3;let lint_root=match&mbcx.body.source_scopes[local_decl.source_info. +scope].local_data{ClearCrossCrate::Set(data)=>data.lint_root,_=>continue,};({}); +match mbcx.local_names[local]{Some(name)=>{if name.as_str().starts_with('_'){(); +continue;();}}None=>continue,}();let span=local_decl.source_info.span;3;if span. +desugaring_kind().is_some(){();continue;3;}3;let mut_span=tcx.sess.source_map(). +span_until_non_whitespace(span);();tcx.emit_node_span_lint(UNUSED_MUT,lint_root, +span,VarNeedNotMut{span:mut_span})};let tainted_by_errors=mbcx.emit_errors();let +result=BorrowCheckResult{concrete_opaque_types:opaque_type_values,//loop{break}; +closure_requirements:opt_closure_req,used_mut_upvars:mbcx.used_mut_upvars,//{;}; +tainted_by_errors,};();3;let body_with_facts=if consumer_options.is_some(){3;let +output_facts=mbcx.polonius_output;({});Some(Box::new(BodyWithBorrowckFacts{body: +body_owned,promoted,borrow_set ,region_inference_context:regioncx,location_table +:((polonius_input.as_ref()).map( |_|location_table)),input_facts:polonius_input, +output_facts,}))}else{None};;;debug!("do_mir_borrowck: result = {:#?}",result);( +result,body_with_facts)}pub struct BorrowckInferCtxt <'cx,'tcx>{pub(crate)infcx: +&'cx InferCtxt<'tcx>,pub(crate)reg_var_to_origin:RefCell>,}impl<'cx,'tcx>BorrowckInferCtxt<'cx,'tcx>{pub(crate)fn// +new(infcx:&'cx InferCtxt<'tcx >)->Self{BorrowckInferCtxt{infcx,reg_var_to_origin +:RefCell::new(Default::default())} }pub(crate)fn next_region_var(&self,origin +:RegionVariableOrigin,get_ctxt_fn:F,)->ty::Region <'tcx>where F:Fn()->RegionCtxt +,{;let next_region=self.infcx.next_region_var(origin);let vid=next_region.as_var +();let _=||();let _=||();if cfg!(debug_assertions){let _=||();let _=||();debug!( +"inserting vid {:?} with origin {:?} into var_to_origin",vid,origin);;;let ctxt= +get_ctxt_fn();3;3;let mut var_to_origin=self.reg_var_to_origin.borrow_mut();3;3; +assert_eq!(var_to_origin.insert(vid,ctxt),None);;}next_region}#[instrument(skip( +self,get_ctxt_fn),level="debug")]pub(crate)fn next_nll_region_var(&self,//(); +origin:NllRegionVariableOrigin,get_ctxt_fn:F,)->ty::Region<'tcx>where F:Fn()->// +RegionCtxt,{3;let next_region=self.infcx.next_nll_region_var(origin);3;;let vid= +next_region.as_var();loop{break;};if cfg!(debug_assertions){loop{break;};debug!( +"inserting vid {:?} with origin {:?} into var_to_origin",vid,origin);;;let ctxt= +get_ctxt_fn();3;3;let mut var_to_origin=self.reg_var_to_origin.borrow_mut();3;3; +assert_eq!(var_to_origin.insert(vid,ctxt),None);{;};}next_region}}impl<'cx,'tcx> +Deref for BorrowckInferCtxt<'cx,'tcx>{type Target=InferCtxt<'tcx>;fn deref(&//3; +self)->&'cx Self::Target{self.infcx}}struct MirBorrowckCtxt<'cx,'tcx>{infcx:&//; +'cx BorrowckInferCtxt<'cx,'tcx>,param_env:ParamEnv<'tcx>,body:&'cx Body<'tcx>,// +move_data:&'cx MoveData<'tcx>,location_table:&'cx LocationTable,//if let _=(){}; +movable_coroutine:bool,locals_are_invalidated_at_exit:bool,//let _=();if true{}; +access_place_error_reported:FxIndexSet<(Place<'tcx>,Span)>,//let _=();if true{}; +reservation_error_reported:FxIndexSet>,fn_self_span_reported://({}); +FxIndexSet,uninitialized_error_reported:FxIndexSet>,//({}); +used_mut:FxIndexSet,used_mut_upvars:SmallVec<[FieldIdx;(8)]>,regioncx:Rc< +RegionInferenceContext<'tcx>>,borrow_set:Rc>,upvars:&'tcx[&'tcx +ty::CapturedPlace<'tcx>],local_names:IndexVec>,//if true{}; +region_names:RefCell>,next_region_name:RefCell +,polonius_output:Option>,diags:diags::BorrowckDiags,move_errors:Vec>,}impl<'cx,'tcx,R>rustc_mir_dataflow:://3; +ResultsVisitor<'cx,'tcx,R>for MirBorrowckCtxt<'cx,'tcx>{type FlowState=Flows;fn visit_statement_before_primary_effect(&mut self,_results:&mut R,//; +flow_state:&Flows<'cx,'tcx>,stmt:&'cx Statement<'tcx>,location:Location,){;debug +!("MirBorrowckCtxt::process_statement({:?}, {:?}): {:?}",location,stmt,//*&*&(); +flow_state);;let span=stmt.source_info.span;self.check_activations(location,span +,flow_state);{;};match&stmt.kind{StatementKind::Assign(box(lhs,rhs))=>{{;};self. +consume_rvalue(location,(rhs,span),flow_state);;self.mutate_place(location,(*lhs +,span),Shallow(None),flow_state);;}StatementKind::FakeRead(box(_,place))=>{self. +check_if_path_or_subpath_is_moved(location,InitializationRequiringAction ::Use,( +place.as_ref(),span),flow_state,);{;};}StatementKind::Intrinsic(box kind)=>match +kind{NonDivergingIntrinsic::Assume(op)=>self .consume_operand(location,(op,span) +,flow_state),NonDivergingIntrinsic::CopyNonOverlapping(..)=>span_bug!(span,//(); +"Unexpected CopyNonOverlapping, should only appear after lower_intrinsics",)}//; +StatementKind::AscribeUserType(..)|StatementKind::PlaceMention(..)|//let _=||(); +StatementKind::Coverage(..)|StatementKind::ConstEvalCounter|StatementKind:://(); +StorageLive(..)=>{}StatementKind::StorageDead(local)=>{*&*&();self.access_place( +location,(((((Place::from((*local)))),span))),((Shallow(None)),Write(WriteKind:: +StorageDeadOrDrop)),LocalMutationIsAllowed::Yes,flow_state,);();}StatementKind:: +Nop|StatementKind::Retag{..}|StatementKind::Deinit(..)|StatementKind:://((),()); +SetDiscriminant{..}=>{(((bug!("Statement not allowed in this MIR phase"))))}}}fn +visit_terminator_before_primary_effect(&mut self,_results:&mut R,flow_state:&//; +Flows<'cx,'tcx>,term:&'cx Terminator<'tcx>,loc:Location,){*&*&();((),());debug!( +"MirBorrowckCtxt::process_terminator({:?}, {:?}): {:?}",loc,term,flow_state);3;; +let span=term.source_info.span;3;3;self.check_activations(loc,span,flow_state);; +match&term.kind{TerminatorKind::SwitchInt{discr,targets:_}=>{if let _=(){};self. +consume_operand(loc,(discr,span),flow_state);;}TerminatorKind::Drop{place,target +:_,unwind:_,replace}=>{loop{break};loop{break;};loop{break};loop{break;};debug!( +"visit_terminator_drop \ + loc: {:?} term: {:?} place: {:?} span: {:?}" +,loc,term,place,span);{;};{;};let write_kind=if*replace{WriteKind::Replace}else{ +WriteKind::StorageDeadOrDrop};;;self.access_place(loc,(*place,span),(AccessDepth +::Drop,Write(write_kind)),LocalMutationIsAllowed::Yes,flow_state,);loop{break};} +TerminatorKind::Call{func,args,destination,target:_,unwind:_,call_source:_,//(); +fn_span:_,}=>{;self.consume_operand(loc,(func,span),flow_state);for arg in args{ +self.consume_operand(loc,(&arg.node,arg.span),flow_state);3;};self.mutate_place( +loc,(*destination,span),Deep,flow_state);;}TerminatorKind::Assert{cond,expected: +_,msg,target:_,unwind:_}=>{;self.consume_operand(loc,(cond,span),flow_state);;if +let AssertKind::BoundsCheck{len,index}=&**msg{{;};self.consume_operand(loc,(len, +span),flow_state);{;};();self.consume_operand(loc,(index,span),flow_state);();}} +TerminatorKind::Yield{value,resume:_,resume_arg,drop:_}=>{;self.consume_operand( +loc,(value,span),flow_state);();3;self.mutate_place(loc,(*resume_arg,span),Deep, +flow_state);;}TerminatorKind::InlineAsm{template:_,operands,options:_,line_spans +:_,targets:_,unwind:_,}=>{for op in operands{match op{InlineAsmOperand::In{reg: +_,value}=>{;self.consume_operand(loc,(value,span),flow_state);;}InlineAsmOperand +::Out{reg:_,late:_,place,..}=>{if let Some(place)=place{;self.mutate_place(loc,( +*place,span),Shallow(None),flow_state);3;}}InlineAsmOperand::InOut{reg:_,late:_, +in_value,out_place}=>{3;self.consume_operand(loc,(in_value,span),flow_state);;if +let&Some(out_place)=out_place{();self.mutate_place(loc,(out_place,span),Shallow( +None),flow_state,);3;}}InlineAsmOperand::Const{value:_}|InlineAsmOperand::SymFn{ +value:_}|InlineAsmOperand::SymStatic{def_id:_}|InlineAsmOperand::Label{//*&*&(); +target_index:_}=>{}}}}TerminatorKind::Goto{target:_}|TerminatorKind:://let _=(); +UnwindTerminate(_)|TerminatorKind::Unreachable|TerminatorKind::UnwindResume|//3; +TerminatorKind::Return|TerminatorKind:: CoroutineDrop|TerminatorKind::FalseEdge{ +real_target:_,imaginary_target:_}|TerminatorKind::FalseUnwind{real_target:_,//3; +unwind:_}=>{}}}fn visit_terminator_after_primary_effect(&mut self,_results:&mut +R,flow_state:&Flows<'cx,'tcx>,term:&'cx Terminator<'tcx>,loc:Location,){({});let +span=term.source_info.span;;match term.kind{TerminatorKind::Yield{value:_,resume +:_,resume_arg:_,drop:_}=>{if self.movable_coroutine{((),());let borrow_set=self. +borrow_set.clone();;for i in flow_state.borrows.iter(){let borrow=&borrow_set[i] +;3;3;self.check_for_local_borrow(borrow,span);3;}}}TerminatorKind::UnwindResume| +TerminatorKind::Return|TerminatorKind::CoroutineDrop=>{({});let borrow_set=self. +borrow_set.clone();;for i in flow_state.borrows.iter(){let borrow=&borrow_set[i] +;();();self.check_for_invalidation_at_exit(loc,borrow,span);3;}}TerminatorKind:: +UnwindTerminate(_)|TerminatorKind::Assert{..}|TerminatorKind::Call{..}|//*&*&(); +TerminatorKind::Drop{..}|TerminatorKind::FalseEdge{real_target:_,//loop{break;}; +imaginary_target:_}|TerminatorKind::FalseUnwind{real_target:_,unwind:_}|//{();}; +TerminatorKind::Goto{..}|TerminatorKind::SwitchInt{..}|TerminatorKind:://*&*&(); +Unreachable|TerminatorKind::InlineAsm{..}=>{}}}}use self::AccessDepth::{Deep,//; +Shallow};use self::ReadOrWrite::{Activation,Read,Reservation,Write};#[derive(//; +Copy,Clone,PartialEq,Eq,Debug)]enum ArtificialField{ArrayLength,FakeBorrow,}#[// +derive(Copy,Clone,PartialEq,Eq,Debug)]enum AccessDepth{Shallow(Option),Deep,Drop,}#[derive(Copy,Clone,PartialEq,Eq,Debug)]enum//({}); +ReadOrWrite{Read(ReadKind),Write(WriteKind),Reservation(WriteKind),Activation(// +WriteKind,BorrowIndex),}#[derive(Copy,Clone,PartialEq,Eq,Debug)]enum ReadKind{// +Borrow(BorrowKind),Copy,}#[derive(Copy ,Clone,PartialEq,Eq,Debug)]enum WriteKind +{StorageDeadOrDrop,Replace,MutableBorrow(BorrowKind), Mutate,Move,}#[derive(Copy +,Clone,PartialEq,Eq,Debug)]enum LocalMutationIsAllowed{Yes,ExceptUpvars,No,}#[// +derive(Copy,Clone,Debug)] enum InitializationRequiringAction{Borrow,MatchOn,Use, +Assignment,PartialAssignment,}#[derive(Debug)]struct RootPlace<'tcx>{//let _=(); +place_local:Local,place_projection:&'tcx[PlaceElem<'tcx>],//if true{};if true{}; +is_local_mutation_allowed:LocalMutationIsAllowed,}impl//loop{break};loop{break}; +InitializationRequiringAction{fn as_noun(self)->&'static str{match self{//{();}; +InitializationRequiringAction::Borrow=> "borrow",InitializationRequiringAction:: +MatchOn=>(((((("use")))))),InitializationRequiringAction ::Use=>((((("use"))))), +InitializationRequiringAction::Assignment=>(((((((((((((("assign")))))))))))))), +InitializationRequiringAction::PartialAssignment=>(((( "assign to part")))),}}fn +as_verb_in_past_tense(self)->&'static str{match self{//loop{break};loop{break;}; +InitializationRequiringAction::Borrow=> "borrowed",InitializationRequiringAction +::MatchOn=>((("matched on"))), InitializationRequiringAction::Use=>((("used"))), +InitializationRequiringAction::Assignment=>((((((((((((("assigned"))))))))))))), +InitializationRequiringAction::PartialAssignment=>(( "partially assigned")),}}fn +as_general_verb_in_past_tense(self)->&'static str{match self{//((),());let _=(); +InitializationRequiringAction::Borrow|InitializationRequiringAction::MatchOn|//; +InitializationRequiringAction::Use=>((("used"))),InitializationRequiringAction:: +Assignment=>((("assigned"))) ,InitializationRequiringAction::PartialAssignment=> +"partially assigned",}}}impl<'cx,'tcx>MirBorrowckCtxt<'cx,'tcx>{fn body(&self)// +->&'cx Body<'tcx>{self.body}fn access_place(&mut self,location:Location,//{();}; +place_span:(Place<'tcx>,Span),kind:(AccessDepth,ReadOrWrite),//((),());let _=(); +is_local_mutation_allowed:LocalMutationIsAllowed,flow_state:&Flows<'cx,'tcx>,){; +let(sd,rw)=kind;let _=();if true{};if let Activation(_,borrow_index)=rw{if self. +reservation_error_reported.contains(&place_span.0){let _=||();let _=||();debug!( +"skipping access_place for activation of invalid reservation \ + place: {:?} borrow_index: {:?}" +,place_span.0,borrow_index);();3;return;3;}}if!self.access_place_error_reported. +is_empty()&&self.access_place_error_reported. contains(&(place_span.0,place_span +.1)){{;};debug!("access_place: suppressing error place_span=`{:?}` kind=`{:?}`", +place_span,kind);;;return;;};let mutability_error=self.check_access_permissions( +place_span,rw,is_local_mutation_allowed,flow_state,location,);((),());*&*&();let +conflict_error=self.check_access_for_conflict(location,place_span,sd,rw,//{();}; +flow_state);loop{break;};if conflict_error||mutability_error{loop{break};debug!( +"access_place: logging error place_span=`{:?}` kind=`{:?}`",place_span,kind);3;; +self.access_place_error_reported.insert((place_span.0,place_span.1));*&*&();}}#[ +instrument(level="debug",skip(self,flow_state))]fn check_access_for_conflict(&// +mut self,location:Location,place_span:(Place<'tcx>,Span),sd:AccessDepth,rw://(); +ReadOrWrite,flow_state:&Flows<'cx,'tcx>,)->bool{;let mut error_reported=false;;; +let borrow_set=Rc::clone(&self.borrow_set);();();let mut polonius_output;3;3;let +borrows_in_scope=if let Some(polonius)=&self.polonius_output{;let location=self. +location_table.start_index(location);({});{;};polonius_output=BitSet::new_empty( +borrow_set.len());();for&idx in polonius.errors_at(location){();polonius_output. +insert(idx);((),());}&polonius_output}else{&flow_state.borrows};((),());((),()); +each_borrow_involving_path(self,self.infcx.tcx,self.body,(((sd,place_span.0))),& +borrow_set,((|borrow_index|((borrows_in_scope. contains(borrow_index))))),|this, +borrow_index,borrow|match((((rw,borrow.kind)))) {(Activation(_,activating),_)if +activating==borrow_index=>{let _=||();loop{break};let _=||();loop{break};debug!( +"check_access_for_conflict place_span: {:?} sd: {:?} rw: {:?} \ + skipping {:?} b/c activation of same borrow_index" +,place_span,sd,rw,(borrow_index,borrow),);;Control::Continue}(Read(_),BorrowKind +::Shared|BorrowKind::Fake)|(Read( ReadKind::Borrow(BorrowKind::Fake)),BorrowKind +::Mut{..})=>{Control::Continue}(Reservation(_),BorrowKind::Fake|BorrowKind:://3; +Shared)=>{Control::Continue}(Write( WriteKind::Move),BorrowKind::Fake)=>{Control +::Continue}(Read(kind),BorrowKind::Mut{..}) =>{if!is_active((this.dominators()), +borrow,location){;assert!(allow_two_phase_borrow(borrow.kind));;return Control:: +Continue;();}3;error_reported=true;3;match kind{ReadKind::Copy=>{3;let err=this. +report_use_while_mutably_borrowed(location,place_span,borrow);;this.buffer_error +(err);;}ReadKind::Borrow(bk)=>{;let err=this.report_conflicting_borrow(location, +place_span,bk,borrow);;this.buffer_error(err);}}Control::Break}(Reservation(kind +)|Activation(kind,_)|Write(kind),_)=>{match rw{Reservation(..)=>{((),());debug!( +"recording invalid reservation of \ + place: {:?}" +,place_span.0);;this.reservation_error_reported.insert(place_span.0);}Activation +(_,activating)=>{if let _=(){};if let _=(){};if let _=(){};if let _=(){};debug!( +"observing check_place for activation of \ + borrow_index: {:?}" +,activating);;}Read(..)|Write(..)=>{}}error_reported=true;match kind{WriteKind:: +MutableBorrow(bk)=>{;let err=this.report_conflicting_borrow(location,place_span, +bk,borrow);{;};();this.buffer_error(err);();}WriteKind::StorageDeadOrDrop=>this. +report_borrowed_value_does_not_live_long_enough(location,borrow ,place_span,Some +(WriteKind::StorageDeadOrDrop),),WriteKind::Mutate=>{this.//if true{};if true{}; +report_illegal_mutation_of_borrowed(location,place_span, borrow)}WriteKind::Move +=>{(this.report_move_out_while_borrowed(location,place_span,borrow))}WriteKind:: +Replace=>{this.report_illegal_mutation_of_borrowed( location,place_span,borrow)} +}Control::Break}},);;error_reported}fn mutate_place(&mut self,location:Location, +place_span:(Place<'tcx>,Span),kind:AccessDepth,flow_state:&Flows<'cx,'tcx>,){(); +self.check_if_assigned_path_is_moved(location,place_span,flow_state);();();self. +access_place(location,place_span,(((((kind, (((Write(WriteKind::Mutate))))))))), +LocalMutationIsAllowed::No,flow_state,);3;}fn consume_rvalue(&mut self,location: +Location,(rvalue,span):(&'cx Rvalue<'tcx>,Span),flow_state:&Flows<'cx,'tcx>,){// +match rvalue{&Rvalue::Ref(_,bk,place)=>{();let access_kind=match bk{BorrowKind:: +Fake=>{(Shallow(Some(ArtificialField::FakeBorrow)) ,Read(ReadKind::Borrow(bk)))} +BorrowKind::Shared=>(Deep,Read(ReadKind::Borrow(bk))),BorrowKind::Mut{..}=>{;let +wk=WriteKind::MutableBorrow(bk);loop{break};if allow_two_phase_borrow(bk){(Deep, +Reservation(wk))}else{(Deep,Write(wk))}}};3;3;self.access_place(location,(place, +span),access_kind,LocalMutationIsAllowed::No,flow_state,);3;3;let action=if bk== +BorrowKind::Fake{InitializationRequiringAction::MatchOn}else{//((),());let _=(); +InitializationRequiringAction::Borrow};;;self.check_if_path_or_subpath_is_moved( +location,action,(place.as_ref(),span),flow_state,);let _=();}&Rvalue::AddressOf( +mutability,place)=>{{;};let access_kind=match mutability{Mutability::Mut=>(Deep, +Write(WriteKind::MutableBorrow(BorrowKind::Mut{ kind:MutBorrowKind::Default,})), +),Mutability::Not=>(Deep,Read(ReadKind::Borrow(BorrowKind::Shared))),};3;3;self. +access_place(location,((((place,span)))),access_kind,LocalMutationIsAllowed::No, +flow_state,);if true{};let _=();self.check_if_path_or_subpath_is_moved(location, +InitializationRequiringAction::Borrow,(place.as_ref(),span),flow_state,);{();};} +Rvalue::ThreadLocalRef(_)=>{}Rvalue::Use(operand)|Rvalue::Repeat(operand,_)|//3; +Rvalue::UnaryOp(_,operand)|Rvalue::Cast(_,operand,_)|Rvalue::ShallowInitBox(//3; +operand,_)=>{self.consume_operand(location, (operand,span),flow_state)}&Rvalue:: +CopyForDeref(place)=>{*&*&();self.access_place(location,(place,span),(Deep,Read( +ReadKind::Copy)),LocalMutationIsAllowed::No,flow_state,);let _=();let _=();self. +check_if_path_or_subpath_is_moved(location,InitializationRequiringAction ::Use,( +place.as_ref(),span),flow_state,);();}&(Rvalue::Len(place)|Rvalue::Discriminant( +place))=>{let _=||();let af=match*rvalue{Rvalue::Len(..)=>Some(ArtificialField:: +ArrayLength),Rvalue::Discriminant(..)=>None,_=>unreachable!(),};{();};({});self. +access_place(location,(((place,span))),(((Shallow(af)),(Read(ReadKind::Copy)))), +LocalMutationIsAllowed::No,flow_state,);;self.check_if_path_or_subpath_is_moved( +location,InitializationRequiringAction::Use,(place.as_ref(),span),flow_state,);; +}Rvalue::BinaryOp(_bin_op,box(operand1,operand2))|Rvalue::CheckedBinaryOp(//{;}; +_bin_op,box(operand1,operand2))=>{;self.consume_operand(location,(operand1,span) +,flow_state);;;self.consume_operand(location,(operand2,span),flow_state);}Rvalue +::NullaryOp(_op,_ty)=>{}Rvalue::Aggregate(aggregate_kind,operands)=>{match**//3; +aggregate_kind{AggregateKind::Closure( def_id,_)|AggregateKind::CoroutineClosure +(def_id,_)|AggregateKind::Coroutine(def_id,_)=>{;let def_id=def_id.expect_local( +);;let BorrowCheckResult{used_mut_upvars,..}=self.infcx.tcx.mir_borrowck(def_id) +;();();debug!("{:?} used_mut_upvars={:?}",def_id,used_mut_upvars);3;for field in +used_mut_upvars{();self.propagate_closure_used_mut_upvar(&operands[*field]);3;}} +AggregateKind::Adt(..)|AggregateKind::Array(..)|AggregateKind::Tuple{..}=>(()),} +for operand in operands{;self.consume_operand(location,(operand,span),flow_state +);;}}}}fn propagate_closure_used_mut_upvar(&mut self,operand:&Operand<'tcx>){let +propagate_closure_used_mut_place=|this:&mut Self,place:Place<'tcx>|{if let//{;}; +Some(field)=this.is_upvar_field_projection(place.as_ref()){;this.used_mut_upvars +.push(field);;;return;;}for(place_ref,proj)in place.iter_projections().rev(){if +proj==ProjectionElem::Deref{match (place_ref.ty(this.body(),this.infcx.tcx)).ty. +kind(){ty::Ref(_,_,hir::Mutability::Mut)=> return,_=>{}}}if let Some(field)=this +.is_upvar_field_projection(place_ref){;this.used_mut_upvars.push(field);return;} +};this.used_mut.insert(place.local);};match*operand{Operand::Move(place)|Operand +::Copy(place)=>{match ((place.as_local())) {Some(local)if!self.body.local_decls[ +local].is_user_variable()=>{if self.body.local_decls[local].ty.is_mutable_ptr() +{;return;}let Some(temp_mpi)=self.move_data.rev_lookup.find_local(local)else{bug +!("temporary should be tracked");;};let init=if let[init_index]=*self.move_data. +init_path_map[temp_mpi]{(((&(((self.move_data.inits[init_index]))))))}else{bug!( +"temporary should be initialized exactly once")};3;;let InitLocation::Statement( +loc)=init.location else{bug!("temporary initialized in arguments")};3;;let body= +self.body;;let bbd=&body[loc.block];let stmt=&bbd.statements[loc.statement_index +];;debug!("temporary assigned in: stmt={:?}",stmt);if let StatementKind::Assign( +box(_,Rvalue::Ref(_,_,source)))=stmt.kind{;propagate_closure_used_mut_place(self +,source);*&*&();((),());*&*&();((),());}else{*&*&();((),());*&*&();((),());bug!( +"closures should only capture user variables \ or references to user variables" - ); - } - } - _ => propagate_closure_used_mut_place(self, place), - } - } - Operand::Constant(..) => {} - } - } - - fn consume_operand( - &mut self, - location: Location, - (operand, span): (&'cx Operand<'tcx>, Span), - flow_state: &Flows<'cx, 'tcx>, - ) { - match *operand { - Operand::Copy(place) => { - // copy of place: check if this is "copy of frozen path" - // (FIXME: see check_loans.rs) - self.access_place( - location, - (place, span), - (Deep, Read(ReadKind::Copy)), - LocalMutationIsAllowed::No, - flow_state, - ); - - // Finally, check if path was already moved. - self.check_if_path_or_subpath_is_moved( - location, - InitializationRequiringAction::Use, - (place.as_ref(), span), - flow_state, - ); - } - Operand::Move(place) => { - // Check if moving from this place makes sense. - self.check_movable_place(location, place); - - // move of place: check if this is move of already borrowed path - self.access_place( - location, - (place, span), - (Deep, Write(WriteKind::Move)), - LocalMutationIsAllowed::Yes, - flow_state, - ); - - // Finally, check if path was already moved. - self.check_if_path_or_subpath_is_moved( - location, - InitializationRequiringAction::Use, - (place.as_ref(), span), - flow_state, - ); - } - Operand::Constant(_) => {} - } - } - - /// Checks whether a borrow of this place is invalidated when the function - /// exits - #[instrument(level = "debug", skip(self))] - fn check_for_invalidation_at_exit( - &mut self, - location: Location, - borrow: &BorrowData<'tcx>, - span: Span, - ) { - let place = borrow.borrowed_place; - let mut root_place = PlaceRef { local: place.local, projection: &[] }; - - // FIXME(nll-rfc#40): do more precise destructor tracking here. For now - // we just know that all locals are dropped at function exit (otherwise - // we'll have a memory leak) and assume that all statics have a destructor. - // - // FIXME: allow thread-locals to borrow other thread locals? - - let (might_be_alive, will_be_dropped) = - if self.body.local_decls[root_place.local].is_ref_to_thread_local() { - // Thread-locals might be dropped after the function exits - // We have to dereference the outer reference because - // borrows don't conflict behind shared references. - root_place.projection = TyCtxtConsts::DEREF_PROJECTION; - (true, true) - } else { - (false, self.locals_are_invalidated_at_exit) - }; - - if !will_be_dropped { - debug!("place_is_invalidated_at_exit({:?}) - won't be dropped", place); - return; - } - - let sd = if might_be_alive { Deep } else { Shallow(None) }; - - if places_conflict::borrow_conflicts_with_place( - self.infcx.tcx, - self.body, - place, - borrow.kind, - root_place, - sd, - places_conflict::PlaceConflictBias::Overlap, - ) { - debug!("check_for_invalidation_at_exit({:?}): INVALID", place); - // FIXME: should be talking about the region lifetime instead - // of just a span here. - let span = self.infcx.tcx.sess.source_map().end_point(span); - self.report_borrowed_value_does_not_live_long_enough( - location, - borrow, - (place, span), - None, - ) - } - } - - /// Reports an error if this is a borrow of local data. - /// This is called for all Yield expressions on movable coroutines - fn check_for_local_borrow(&mut self, borrow: &BorrowData<'tcx>, yield_span: Span) { - debug!("check_for_local_borrow({:?})", borrow); - - if borrow_of_local_data(borrow.borrowed_place) { - let err = self.cannot_borrow_across_coroutine_yield( - self.retrieve_borrow_spans(borrow).var_or_use(), - yield_span, - ); - - self.buffer_error(err); - } - } - - fn check_activations(&mut self, location: Location, span: Span, flow_state: &Flows<'cx, 'tcx>) { - // Two-phase borrow support: For each activation that is newly - // generated at this statement, check if it interferes with - // another borrow. - let borrow_set = self.borrow_set.clone(); - for &borrow_index in borrow_set.activations_at_location(location) { - let borrow = &borrow_set[borrow_index]; - - // only mutable borrows should be 2-phase - assert!(match borrow.kind { - BorrowKind::Shared | BorrowKind::Fake => false, - BorrowKind::Mut { .. } => true, - }); - - self.access_place( - location, - (borrow.borrowed_place, span), - (Deep, Activation(WriteKind::MutableBorrow(borrow.kind), borrow_index)), - LocalMutationIsAllowed::No, - flow_state, - ); - // We do not need to call `check_if_path_or_subpath_is_moved` - // again, as we already called it when we made the - // initial reservation. - } - } - - fn check_movable_place(&mut self, location: Location, place: Place<'tcx>) { - use IllegalMoveOriginKind::*; - - let body = self.body; - let tcx = self.infcx.tcx; - let mut place_ty = PlaceTy::from_ty(body.local_decls[place.local].ty); - for (place_ref, elem) in place.iter_projections() { - match elem { - ProjectionElem::Deref => match place_ty.ty.kind() { - ty::Ref(..) | ty::RawPtr(..) => { - self.move_errors.push(MoveError::new( - place, - location, - BorrowedContent { - target_place: place_ref.project_deeper(&[elem], tcx), - }, - )); - return; - } - ty::Adt(adt, _) => { - if !adt.is_box() { - bug!("Adt should be a box type when Place is deref"); - } - } - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Foreign(_) - | ty::Str - | ty::Array(_, _) - | ty::Slice(_) - | ty::FnDef(_, _) - | ty::FnPtr(_) - | ty::Dynamic(_, _, _) - | ty::Closure(_, _) - | ty::CoroutineClosure(_, _) - | ty::Coroutine(_, _) - | ty::CoroutineWitness(..) - | ty::Never - | ty::Tuple(_) - | ty::Alias(_, _) - | ty::Param(_) - | ty::Bound(_, _) - | ty::Infer(_) - | ty::Error(_) - | ty::Placeholder(_) => { - bug!("When Place is Deref it's type shouldn't be {place_ty:#?}") - } - }, - ProjectionElem::Field(_, _) => match place_ty.ty.kind() { - ty::Adt(adt, _) => { - if adt.has_dtor(tcx) { - self.move_errors.push(MoveError::new( - place, - location, - InteriorOfTypeWithDestructor { container_ty: place_ty.ty }, - )); - return; - } - } - ty::Closure(..) - | ty::CoroutineClosure(..) - | ty::Coroutine(_, _) - | ty::Tuple(_) => (), - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Foreign(_) - | ty::Str - | ty::Array(_, _) - | ty::Slice(_) - | ty::RawPtr(_, _) - | ty::Ref(_, _, _) - | ty::FnDef(_, _) - | ty::FnPtr(_) - | ty::Dynamic(_, _, _) - | ty::CoroutineWitness(..) - | ty::Never - | ty::Alias(_, _) - | ty::Param(_) - | ty::Bound(_, _) - | ty::Infer(_) - | ty::Error(_) - | ty::Placeholder(_) => bug!( - "When Place contains ProjectionElem::Field it's type shouldn't be {place_ty:#?}" - ), - }, - ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { - match place_ty.ty.kind() { - ty::Slice(_) => { - self.move_errors.push(MoveError::new( - place, - location, - InteriorOfSliceOrArray { ty: place_ty.ty, is_index: false }, - )); - return; - } - ty::Array(_, _) => (), - _ => bug!("Unexpected type {:#?}", place_ty.ty), - } - } - ProjectionElem::Index(_) => match place_ty.ty.kind() { - ty::Array(..) | ty::Slice(..) => { - self.move_errors.push(MoveError::new( - place, - location, - InteriorOfSliceOrArray { ty: place_ty.ty, is_index: true }, - )); - return; - } - _ => bug!("Unexpected type {place_ty:#?}"), - }, - // `OpaqueCast`: only transmutes the type, so no moves there. - // `Downcast` : only changes information about a `Place` without moving. - // `Subtype` : only transmutes the type, so no moves. - // So it's safe to skip these. - ProjectionElem::OpaqueCast(_) - | ProjectionElem::Subtype(_) - | ProjectionElem::Downcast(_, _) => (), - } - - place_ty = place_ty.projection_ty(tcx, elem); - } - } - - fn check_if_full_path_is_moved( - &mut self, - location: Location, - desired_action: InitializationRequiringAction, - place_span: (PlaceRef<'tcx>, Span), - flow_state: &Flows<'cx, 'tcx>, - ) { - let maybe_uninits = &flow_state.uninits; - - // Bad scenarios: - // - // 1. Move of `a.b.c`, use of `a.b.c` - // 2. Move of `a.b.c`, use of `a.b.c.d` (without first reinitializing `a.b.c.d`) - // 3. Uninitialized `(a.b.c: &_)`, use of `*a.b.c`; note that with - // partial initialization support, one might have `a.x` - // initialized but not `a.b`. - // - // OK scenarios: - // - // 4. Move of `a.b.c`, use of `a.b.d` - // 5. Uninitialized `a.x`, initialized `a.b`, use of `a.b` - // 6. Copied `(a.b: &_)`, use of `*(a.b).c`; note that `a.b` - // must have been initialized for the use to be sound. - // 7. Move of `a.b.c` then reinit of `a.b.c.d`, use of `a.b.c.d` - - // The dataflow tracks shallow prefixes distinctly (that is, - // field-accesses on P distinctly from P itself), in order to - // track substructure initialization separately from the whole - // structure. - // - // E.g., when looking at (*a.b.c).d, if the closest prefix for - // which we have a MovePath is `a.b`, then that means that the - // initialization state of `a.b` is all we need to inspect to - // know if `a.b.c` is valid (and from that we infer that the - // dereference and `.d` access is also valid, since we assume - // `a.b.c` is assigned a reference to an initialized and - // well-formed record structure.) - - // Therefore, if we seek out the *closest* prefix for which we - // have a MovePath, that should capture the initialization - // state for the place scenario. - // - // This code covers scenarios 1, 2, and 3. - - debug!("check_if_full_path_is_moved place: {:?}", place_span.0); - let (prefix, mpi) = self.move_path_closest_to(place_span.0); - if maybe_uninits.contains(mpi) { - self.report_use_of_moved_or_uninitialized( - location, - desired_action, - (prefix, place_span.0, place_span.1), - mpi, - ); - } // Only query longest prefix with a MovePath, not further - // ancestors; dataflow recurs on children when parents - // move (to support partial (re)inits). - // - // (I.e., querying parents breaks scenario 7; but may want - // to do such a query based on partial-init feature-gate.) - } - - /// Subslices correspond to multiple move paths, so we iterate through the - /// elements of the base array. For each element we check - /// - /// * Does this element overlap with our slice. - /// * Is any part of it uninitialized. - fn check_if_subslice_element_is_moved( - &mut self, - location: Location, - desired_action: InitializationRequiringAction, - place_span: (PlaceRef<'tcx>, Span), - maybe_uninits: &ChunkedBitSet, - from: u64, - to: u64, - ) { - if let Some(mpi) = self.move_path_for_place(place_span.0) { - let move_paths = &self.move_data.move_paths; - - let root_path = &move_paths[mpi]; - for (child_mpi, child_move_path) in root_path.children(move_paths) { - let last_proj = child_move_path.place.projection.last().unwrap(); - if let ProjectionElem::ConstantIndex { offset, from_end, .. } = last_proj { - debug_assert!(!from_end, "Array constant indexing shouldn't be `from_end`."); - - if (from..to).contains(offset) { - let uninit_child = - self.move_data.find_in_move_path_or_its_descendants(child_mpi, |mpi| { - maybe_uninits.contains(mpi) - }); - - if let Some(uninit_child) = uninit_child { - self.report_use_of_moved_or_uninitialized( - location, - desired_action, - (place_span.0, place_span.0, place_span.1), - uninit_child, - ); - return; // don't bother finding other problems. - } - } - } - } - } - } - - fn check_if_path_or_subpath_is_moved( - &mut self, - location: Location, - desired_action: InitializationRequiringAction, - place_span: (PlaceRef<'tcx>, Span), - flow_state: &Flows<'cx, 'tcx>, - ) { - let maybe_uninits = &flow_state.uninits; - - // Bad scenarios: - // - // 1. Move of `a.b.c`, use of `a` or `a.b` - // partial initialization support, one might have `a.x` - // initialized but not `a.b`. - // 2. All bad scenarios from `check_if_full_path_is_moved` - // - // OK scenarios: - // - // 3. Move of `a.b.c`, use of `a.b.d` - // 4. Uninitialized `a.x`, initialized `a.b`, use of `a.b` - // 5. Copied `(a.b: &_)`, use of `*(a.b).c`; note that `a.b` - // must have been initialized for the use to be sound. - // 6. Move of `a.b.c` then reinit of `a.b.c.d`, use of `a.b.c.d` - - self.check_if_full_path_is_moved(location, desired_action, place_span, flow_state); - - if let Some((place_base, ProjectionElem::Subslice { from, to, from_end: false })) = - place_span.0.last_projection() - { - let place_ty = place_base.ty(self.body(), self.infcx.tcx); - if let ty::Array(..) = place_ty.ty.kind() { - self.check_if_subslice_element_is_moved( - location, - desired_action, - (place_base, place_span.1), - maybe_uninits, - from, - to, - ); - return; - } - } - - // A move of any shallow suffix of `place` also interferes - // with an attempt to use `place`. This is scenario 3 above. - // - // (Distinct from handling of scenarios 1+2+4 above because - // `place` does not interfere with suffixes of its prefixes, - // e.g., `a.b.c` does not interfere with `a.b.d`) - // - // This code covers scenario 1. - - debug!("check_if_path_or_subpath_is_moved place: {:?}", place_span.0); - if let Some(mpi) = self.move_path_for_place(place_span.0) { - let uninit_mpi = self - .move_data - .find_in_move_path_or_its_descendants(mpi, |mpi| maybe_uninits.contains(mpi)); - - if let Some(uninit_mpi) = uninit_mpi { - self.report_use_of_moved_or_uninitialized( - location, - desired_action, - (place_span.0, place_span.0, place_span.1), - uninit_mpi, - ); - return; // don't bother finding other problems. - } - } - } - - /// Currently MoveData does not store entries for all places in - /// the input MIR. For example it will currently filter out - /// places that are Copy; thus we do not track places of shared - /// reference type. This routine will walk up a place along its - /// prefixes, searching for a foundational place that *is* - /// tracked in the MoveData. - /// - /// An Err result includes a tag indicated why the search failed. - /// Currently this can only occur if the place is built off of a - /// static variable, as we do not track those in the MoveData. - fn move_path_closest_to(&mut self, place: PlaceRef<'tcx>) -> (PlaceRef<'tcx>, MovePathIndex) { - match self.move_data.rev_lookup.find(place) { - LookupResult::Parent(Some(mpi)) | LookupResult::Exact(mpi) => { - (self.move_data.move_paths[mpi].place.as_ref(), mpi) - } - LookupResult::Parent(None) => panic!("should have move path for every Local"), - } - } - - fn move_path_for_place(&mut self, place: PlaceRef<'tcx>) -> Option { - // If returns None, then there is no move path corresponding - // to a direct owner of `place` (which means there is nothing - // that borrowck tracks for its analysis). - - match self.move_data.rev_lookup.find(place) { - LookupResult::Parent(_) => None, - LookupResult::Exact(mpi) => Some(mpi), - } - } - - fn check_if_assigned_path_is_moved( - &mut self, - location: Location, - (place, span): (Place<'tcx>, Span), - flow_state: &Flows<'cx, 'tcx>, - ) { - debug!("check_if_assigned_path_is_moved place: {:?}", place); - - // None case => assigning to `x` does not require `x` be initialized. - for (place_base, elem) in place.iter_projections().rev() { - match elem { - ProjectionElem::Index(_/*operand*/) | - ProjectionElem::Subtype(_) | - ProjectionElem::OpaqueCast(_) | - ProjectionElem::ConstantIndex { .. } | - // assigning to P[i] requires P to be valid. - ProjectionElem::Downcast(_/*adt_def*/, _/*variant_idx*/) => - // assigning to (P->variant) is okay if assigning to `P` is okay - // - // FIXME: is this true even if P is an adt with a dtor? - { } - - // assigning to (*P) requires P to be initialized - ProjectionElem::Deref => { - self.check_if_full_path_is_moved( - location, InitializationRequiringAction::Use, - (place_base, span), flow_state); - // (base initialized; no need to - // recur further) - break; - } - - ProjectionElem::Subslice { .. } => { - panic!("we don't allow assignments to subslices, location: {location:?}"); - } - - ProjectionElem::Field(..) => { - // if type of `P` has a dtor, then - // assigning to `P.f` requires `P` itself - // be already initialized - let tcx = self.infcx.tcx; - let base_ty = place_base.ty(self.body(), tcx).ty; - match base_ty.kind() { - ty::Adt(def, _) if def.has_dtor(tcx) => { - self.check_if_path_or_subpath_is_moved( - location, InitializationRequiringAction::Assignment, - (place_base, span), flow_state); - - // (base initialized; no need to - // recur further) - break; - } - - // Once `let s; s.x = V; read(s.x);`, - // is allowed, remove this match arm. - ty::Adt(..) | ty::Tuple(..) => { - check_parent_of_field(self, location, place_base, span, flow_state); - } - - _ => {} - } - } - } - } - - fn check_parent_of_field<'cx, 'tcx>( - this: &mut MirBorrowckCtxt<'cx, 'tcx>, - location: Location, - base: PlaceRef<'tcx>, - span: Span, - flow_state: &Flows<'cx, 'tcx>, - ) { - // rust-lang/rust#21232: Until Rust allows reads from the - // initialized parts of partially initialized structs, we - // will, starting with the 2018 edition, reject attempts - // to write to structs that are not fully initialized. - // - // In other words, *until* we allow this: - // - // 1. `let mut s; s.x = Val; read(s.x);` - // - // we will for now disallow this: - // - // 2. `let mut s; s.x = Val;` - // - // and also this: - // - // 3. `let mut s = ...; drop(s); s.x=Val;` - // - // This does not use check_if_path_or_subpath_is_moved, - // because we want to *allow* reinitializations of fields: - // e.g., want to allow - // - // `let mut s = ...; drop(s.x); s.x=Val;` - // - // This does not use check_if_full_path_is_moved on - // `base`, because that would report an error about the - // `base` as a whole, but in this scenario we *really* - // want to report an error about the actual thing that was - // moved, which may be some prefix of `base`. - - // Shallow so that we'll stop at any dereference; we'll - // report errors about issues with such bases elsewhere. - let maybe_uninits = &flow_state.uninits; - - // Find the shortest uninitialized prefix you can reach - // without going over a Deref. - let mut shortest_uninit_seen = None; - for prefix in this.prefixes(base, PrefixSet::Shallow) { - let Some(mpi) = this.move_path_for_place(prefix) else { continue }; - - if maybe_uninits.contains(mpi) { - debug!( - "check_parent_of_field updating shortest_uninit_seen from {:?} to {:?}", - shortest_uninit_seen, - Some((prefix, mpi)) - ); - shortest_uninit_seen = Some((prefix, mpi)); - } else { - debug!("check_parent_of_field {:?} is definitely initialized", (prefix, mpi)); - } - } - - if let Some((prefix, mpi)) = shortest_uninit_seen { - // Check for a reassignment into an uninitialized field of a union (for example, - // after a move out). In this case, do not report an error here. There is an - // exception, if this is the first assignment into the union (that is, there is - // no move out from an earlier location) then this is an attempt at initialization - // of the union - we should error in that case. - let tcx = this.infcx.tcx; - if base.ty(this.body(), tcx).ty.is_union() { - if this.move_data.path_map[mpi].iter().any(|moi| { - this.move_data.moves[*moi].source.is_predecessor_of(location, this.body) - }) { - return; - } - } - - this.report_use_of_moved_or_uninitialized( - location, - InitializationRequiringAction::PartialAssignment, - (prefix, base, span), - mpi, - ); - - // rust-lang/rust#21232, #54499, #54986: during period where we reject - // partial initialization, do not complain about unnecessary `mut` on - // an attempt to do a partial initialization. - this.used_mut.insert(base.local); - } - } - } - - /// Checks the permissions for the given place and read or write kind - /// - /// Returns `true` if an error is reported. - fn check_access_permissions( - &mut self, - (place, span): (Place<'tcx>, Span), - kind: ReadOrWrite, - is_local_mutation_allowed: LocalMutationIsAllowed, - flow_state: &Flows<'cx, 'tcx>, - location: Location, - ) -> bool { - debug!( - "check_access_permissions({:?}, {:?}, is_local_mutation_allowed: {:?})", - place, kind, is_local_mutation_allowed - ); - - let error_access; - let the_place_err; - - match kind { - Reservation(WriteKind::MutableBorrow(BorrowKind::Mut { kind: mut_borrow_kind })) - | Write(WriteKind::MutableBorrow(BorrowKind::Mut { kind: mut_borrow_kind })) => { - let is_local_mutation_allowed = match mut_borrow_kind { - // `ClosureCapture` is used for mutable variable with an immutable binding. - // This is only behaviour difference between `ClosureCapture` and mutable borrows. - MutBorrowKind::ClosureCapture => LocalMutationIsAllowed::Yes, - MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow => { - is_local_mutation_allowed - } - }; - match self.is_mutable(place.as_ref(), is_local_mutation_allowed) { - Ok(root_place) => { - self.add_used_mut(root_place, flow_state); - return false; - } - Err(place_err) => { - error_access = AccessKind::MutableBorrow; - the_place_err = place_err; - } - } - } - Reservation(WriteKind::Mutate) | Write(WriteKind::Mutate) => { - match self.is_mutable(place.as_ref(), is_local_mutation_allowed) { - Ok(root_place) => { - self.add_used_mut(root_place, flow_state); - return false; - } - Err(place_err) => { - error_access = AccessKind::Mutate; - the_place_err = place_err; - } - } - } - - Reservation( - WriteKind::Move - | WriteKind::Replace - | WriteKind::StorageDeadOrDrop - | WriteKind::MutableBorrow(BorrowKind::Shared) - | WriteKind::MutableBorrow(BorrowKind::Fake), - ) - | Write( - WriteKind::Move - | WriteKind::Replace - | WriteKind::StorageDeadOrDrop - | WriteKind::MutableBorrow(BorrowKind::Shared) - | WriteKind::MutableBorrow(BorrowKind::Fake), - ) => { - if self.is_mutable(place.as_ref(), is_local_mutation_allowed).is_err() - && !self.has_buffered_diags() - { - // rust-lang/rust#46908: In pure NLL mode this code path should be - // unreachable, but we use `span_delayed_bug` because we can hit this when - // dereferencing a non-Copy raw pointer *and* have `-Ztreat-err-as-bug` - // enabled. We don't want to ICE for that case, as other errors will have - // been emitted (#52262). - self.dcx().span_delayed_bug( - span, - format!( - "Accessing `{place:?}` with the kind `{kind:?}` shouldn't be possible", - ), - ); - } - return false; - } - Activation(..) => { - // permission checks are done at Reservation point. - return false; - } - Read( - ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake) - | ReadKind::Copy, - ) => { - // Access authorized - return false; - } - } - - // rust-lang/rust#21232, #54986: during period where we reject - // partial initialization, do not complain about mutability - // errors except for actual mutation (as opposed to an attempt - // to do a partial initialization). - let previously_initialized = self.is_local_ever_initialized(place.local, flow_state); - - // at this point, we have set up the error reporting state. - if let Some(init_index) = previously_initialized { - if let (AccessKind::Mutate, Some(_)) = (error_access, place.as_local()) { - // If this is a mutate access to an immutable local variable with no projections - // report the error as an illegal reassignment - let init = &self.move_data.inits[init_index]; - let assigned_span = init.span(self.body); - self.report_illegal_reassignment((place, span), assigned_span, place); - } else { - self.report_mutability_error(place, span, the_place_err, error_access, location) - } - true - } else { - false - } - } - - fn is_local_ever_initialized( - &self, - local: Local, - flow_state: &Flows<'cx, 'tcx>, - ) -> Option { - let mpi = self.move_data.rev_lookup.find_local(local)?; - let ii = &self.move_data.init_path_map[mpi]; - ii.into_iter().find(|&&index| flow_state.ever_inits.contains(index)).copied() - } - - /// Adds the place into the used mutable variables set - fn add_used_mut(&mut self, root_place: RootPlace<'tcx>, flow_state: &Flows<'cx, 'tcx>) { - match root_place { - RootPlace { place_local: local, place_projection: [], is_local_mutation_allowed } => { - // If the local may have been initialized, and it is now currently being - // mutated, then it is justified to be annotated with the `mut` - // keyword, since the mutation may be a possible reassignment. - if is_local_mutation_allowed != LocalMutationIsAllowed::Yes - && self.is_local_ever_initialized(local, flow_state).is_some() - { - self.used_mut.insert(local); - } - } - RootPlace { - place_local: _, - place_projection: _, - is_local_mutation_allowed: LocalMutationIsAllowed::Yes, - } => {} - RootPlace { - place_local, - place_projection: place_projection @ [.., _], - is_local_mutation_allowed: _, - } => { - if let Some(field) = self.is_upvar_field_projection(PlaceRef { - local: place_local, - projection: place_projection, - }) { - self.used_mut_upvars.push(field); - } - } - } - } - - /// Whether this value can be written or borrowed mutably. - /// Returns the root place if the place passed in is a projection. - fn is_mutable( - &self, - place: PlaceRef<'tcx>, - is_local_mutation_allowed: LocalMutationIsAllowed, - ) -> Result, PlaceRef<'tcx>> { - debug!("is_mutable: place={:?}, is_local...={:?}", place, is_local_mutation_allowed); - match place.last_projection() { - None => { - let local = &self.body.local_decls[place.local]; - match local.mutability { - Mutability::Not => match is_local_mutation_allowed { - LocalMutationIsAllowed::Yes => Ok(RootPlace { - place_local: place.local, - place_projection: place.projection, - is_local_mutation_allowed: LocalMutationIsAllowed::Yes, - }), - LocalMutationIsAllowed::ExceptUpvars => Ok(RootPlace { - place_local: place.local, - place_projection: place.projection, - is_local_mutation_allowed: LocalMutationIsAllowed::ExceptUpvars, - }), - LocalMutationIsAllowed::No => Err(place), - }, - Mutability::Mut => Ok(RootPlace { - place_local: place.local, - place_projection: place.projection, - is_local_mutation_allowed, - }), - } - } - Some((place_base, elem)) => { - match elem { - ProjectionElem::Deref => { - let base_ty = place_base.ty(self.body(), self.infcx.tcx).ty; - - // Check the kind of deref to decide - match base_ty.kind() { - ty::Ref(_, _, mutbl) => { - match mutbl { - // Shared borrowed data is never mutable - hir::Mutability::Not => Err(place), - // Mutably borrowed data is mutable, but only if we have a - // unique path to the `&mut` - hir::Mutability::Mut => { - let mode = match self.is_upvar_field_projection(place) { - Some(field) - if self.upvars[field.index()].is_by_ref() => - { - is_local_mutation_allowed - } - _ => LocalMutationIsAllowed::Yes, - }; - - self.is_mutable(place_base, mode) - } - } - } - ty::RawPtr(_, mutbl) => { - match mutbl { - // `*const` raw pointers are not mutable - hir::Mutability::Not => Err(place), - // `*mut` raw pointers are always mutable, regardless of - // context. The users have to check by themselves. - hir::Mutability::Mut => Ok(RootPlace { - place_local: place.local, - place_projection: place.projection, - is_local_mutation_allowed, - }), - } - } - // `Box` owns its content, so mutable if its location is mutable - _ if base_ty.is_box() => { - self.is_mutable(place_base, is_local_mutation_allowed) - } - // Deref should only be for reference, pointers or boxes - _ => bug!("Deref of unexpected type: {:?}", base_ty), - } - } - // All other projections are owned by their base path, so mutable if - // base path is mutable - ProjectionElem::Field(..) - | ProjectionElem::Index(..) - | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. } - | ProjectionElem::Subtype(..) - | ProjectionElem::OpaqueCast { .. } - | ProjectionElem::Downcast(..) => { - let upvar_field_projection = self.is_upvar_field_projection(place); - if let Some(field) = upvar_field_projection { - let upvar = &self.upvars[field.index()]; - debug!( - "is_mutable: upvar.mutability={:?} local_mutation_is_allowed={:?} \ - place={:?}, place_base={:?}", - upvar, is_local_mutation_allowed, place, place_base - ); - match (upvar.mutability, is_local_mutation_allowed) { - ( - Mutability::Not, - LocalMutationIsAllowed::No - | LocalMutationIsAllowed::ExceptUpvars, - ) => Err(place), - (Mutability::Not, LocalMutationIsAllowed::Yes) - | (Mutability::Mut, _) => { - // Subtle: this is an upvar - // reference, so it looks like - // `self.foo` -- we want to double - // check that the location `*self` - // is mutable (i.e., this is not a - // `Fn` closure). But if that - // check succeeds, we want to - // *blame* the mutability on - // `place` (that is, - // `self.foo`). This is used to - // propagate the info about - // whether mutability declarations - // are used outwards, so that we register - // the outer variable as mutable. Otherwise a - // test like this fails to record the `mut` - // as needed: - // - // ``` - // fn foo(_f: F) { } - // fn main() { - // let var = Vec::new(); - // foo(move || { - // var.push(1); - // }); - // } - // ``` - let _ = - self.is_mutable(place_base, is_local_mutation_allowed)?; - Ok(RootPlace { - place_local: place.local, - place_projection: place.projection, - is_local_mutation_allowed, - }) - } - } - } else { - self.is_mutable(place_base, is_local_mutation_allowed) - } - } - } - } - } - } - - /// If `place` is a field projection, and the field is being projected from a closure type, - /// then returns the index of the field being projected. Note that this closure will always - /// be `self` in the current MIR, because that is the only time we directly access the fields - /// of a closure type. - fn is_upvar_field_projection(&self, place_ref: PlaceRef<'tcx>) -> Option { - path_utils::is_upvar_field_projection(self.infcx.tcx, &self.upvars, place_ref, self.body()) - } - - fn dominators(&self) -> &Dominators { - // `BasicBlocks` computes dominators on-demand and caches them. - self.body.basic_blocks.dominators() - } -} - -mod diags { - use rustc_errors::ErrorGuaranteed; - - use super::*; - - enum BufferedDiag<'tcx> { - Error(Diag<'tcx>), - NonError(Diag<'tcx, ()>), - } - - impl<'tcx> BufferedDiag<'tcx> { - fn sort_span(&self) -> Span { - match self { - BufferedDiag::Error(diag) => diag.sort_span, - BufferedDiag::NonError(diag) => diag.sort_span, - } - } - } - - pub struct BorrowckDiags<'tcx> { - /// This field keeps track of move errors that are to be reported for given move indices. - /// - /// There are situations where many errors can be reported for a single move out (see - /// #53807) and we want only the best of those errors. - /// - /// The `report_use_of_moved_or_uninitialized` function checks this map and replaces the - /// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of - /// the `Place` of the previous most diagnostic. This happens instead of buffering the - /// error. Once all move errors have been reported, any diagnostics in this map are added - /// to the buffer to be emitted. - /// - /// `BTreeMap` is used to preserve the order of insertions when iterating. This is necessary - /// when errors in the map are being re-added to the error buffer so that errors with the - /// same primary span come out in a consistent order. - buffered_move_errors: BTreeMap, (PlaceRef<'tcx>, Diag<'tcx>)>, - - buffered_mut_errors: FxIndexMap, usize)>, - - /// Buffer of diagnostics to be reported. A mixture of error and non-error diagnostics. - buffered_diags: Vec>, - } - - impl<'tcx> BorrowckDiags<'tcx> { - pub fn new() -> Self { - BorrowckDiags { - buffered_move_errors: BTreeMap::new(), - buffered_mut_errors: Default::default(), - buffered_diags: Default::default(), - } - } - - pub fn buffer_error(&mut self, diag: Diag<'tcx>) { - self.buffered_diags.push(BufferedDiag::Error(diag)); - } - - pub fn buffer_non_error(&mut self, diag: Diag<'tcx, ()>) { - self.buffered_diags.push(BufferedDiag::NonError(diag)); - } - } - - impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { - pub fn buffer_error(&mut self, diag: Diag<'tcx>) { - self.diags.buffer_error(diag); - } - - pub fn buffer_non_error(&mut self, diag: Diag<'tcx, ()>) { - self.diags.buffer_non_error(diag); - } - - pub fn buffer_move_error( - &mut self, - move_out_indices: Vec, - place_and_err: (PlaceRef<'tcx>, Diag<'tcx>), - ) -> bool { - if let Some((_, diag)) = - self.diags.buffered_move_errors.insert(move_out_indices, place_and_err) - { - // Cancel the old diagnostic so we don't ICE - diag.cancel(); - false - } else { - true - } - } - - pub fn get_buffered_mut_error(&mut self, span: Span) -> Option<(Diag<'tcx>, usize)> { - // FIXME(#120456) - is `swap_remove` correct? - self.diags.buffered_mut_errors.swap_remove(&span) - } - - pub fn buffer_mut_error(&mut self, span: Span, diag: Diag<'tcx>, count: usize) { - self.diags.buffered_mut_errors.insert(span, (diag, count)); - } - - pub fn emit_errors(&mut self) -> Option { - let mut res = None; - - // Buffer any move errors that we collected and de-duplicated. - for (_, (_, diag)) in std::mem::take(&mut self.diags.buffered_move_errors) { - // We have already set tainted for this error, so just buffer it. - self.diags.buffered_diags.push(BufferedDiag::Error(diag)); - } - for (_, (mut diag, count)) in std::mem::take(&mut self.diags.buffered_mut_errors) { - if count > 10 { - #[allow(rustc::diagnostic_outside_of_impl)] - #[allow(rustc::untranslatable_diagnostic)] - diag.note(format!("...and {} other attempted mutable borrows", count - 10)); - } - self.diags.buffered_diags.push(BufferedDiag::Error(diag)); - } - - if !self.diags.buffered_diags.is_empty() { - self.diags.buffered_diags.sort_by_key(|buffered_diag| buffered_diag.sort_span()); - for buffered_diag in self.diags.buffered_diags.drain(..) { - match buffered_diag { - BufferedDiag::Error(diag) => res = Some(diag.emit()), - BufferedDiag::NonError(diag) => diag.emit(), - } - } - } - - res - } - - pub(crate) fn has_buffered_diags(&self) -> bool { - self.diags.buffered_diags.is_empty() - } - - pub fn has_move_error( - &self, - move_out_indices: &[MoveOutIndex], - ) -> Option<&(PlaceRef<'tcx>, Diag<'tcx>)> { - self.diags.buffered_move_errors.get(move_out_indices) - } - } -} - -/// The degree of overlap between 2 places for borrow-checking. -enum Overlap { - /// The places might partially overlap - in this case, we give - /// up and say that they might conflict. This occurs when - /// different fields of a union are borrowed. For example, - /// if `u` is a union, we have no way of telling how disjoint - /// `u.a.x` and `a.b.y` are. - Arbitrary, - /// The places have the same type, and are either completely disjoint - /// or equal - i.e., they can't "partially" overlap as can occur with - /// unions. This is the "base case" on which we recur for extensions - /// of the place. - EqualOrDisjoint, - /// The places are disjoint, so we know all extensions of them - /// will also be disjoint. - Disjoint, -} +);;}}_=>propagate_closure_used_mut_place(self,place),}}Operand::Constant(..)=>{} +}}fn consume_operand(&mut self,location:Location,(operand,span):(&'cx Operand,Span),flow_state:&Flows<'cx,'tcx>,){match*operand{Operand::Copy(place)=>{; +self.access_place(location,(((place,span))),(((Deep,((Read(ReadKind::Copy)))))), +LocalMutationIsAllowed::No,flow_state,);;self.check_if_path_or_subpath_is_moved( +location,InitializationRequiringAction::Use,(place.as_ref(),span),flow_state,);; +}Operand::Move(place)=>{{;};self.check_movable_place(location,place);();();self. +access_place(location,((((place,span)))),(( (Deep,((Write(WriteKind::Move)))))), +LocalMutationIsAllowed::Yes,flow_state,);;self.check_if_path_or_subpath_is_moved +(location,InitializationRequiringAction::Use,(place. as_ref(),span),flow_state,) +;let _=||();}Operand::Constant(_)=>{}}}#[instrument(level="debug",skip(self))]fn +check_for_invalidation_at_exit(&mut self,location:Location,borrow:&BorrowData,span:Span,){;let place=borrow.borrowed_place;;let mut root_place=PlaceRef{ +local:place.local,projection:&[]};;;let(might_be_alive,will_be_dropped)=if self. +body.local_decls[root_place.local].is_ref_to_thread_local(){let _=();root_place. +projection=TyCtxtConsts::DEREF_PROJECTION;let _=();(true,true)}else{(false,self. +locals_are_invalidated_at_exit)};let _=||();if!will_be_dropped{if true{};debug!( +"place_is_invalidated_at_exit({:?}) - won't be dropped",place);;;return;}let sd= +if might_be_alive{Deep}else{Shallow(None)};((),());let _=();if places_conflict:: +borrow_conflicts_with_place(self.infcx.tcx,self.body,place,borrow.kind,//*&*&(); +root_place,sd,places_conflict::PlaceConflictBias::Overlap,){loop{break;};debug!( +"check_for_invalidation_at_exit({:?}): INVALID",place);;let span=self.infcx.tcx. +sess.source_map().end_point(span);if true{};if true{};if true{};let _=||();self. +report_borrowed_value_does_not_live_long_enough(location,borrow,( (place,span)), +None,)}}fn check_for_local_borrow(&mut self,borrow:&BorrowData<'tcx>,yield_span +:Span){3;debug!("check_for_local_borrow({:?})",borrow);;if borrow_of_local_data( +borrow.borrowed_place){3;let err=self.cannot_borrow_across_coroutine_yield(self. +retrieve_borrow_spans(borrow).var_or_use(),yield_span,);;self.buffer_error(err); +}}fn check_activations(&mut self,location :Location,span:Span,flow_state:&Flows< +'cx,'tcx>){({});let borrow_set=self.borrow_set.clone();({});for&borrow_index in +borrow_set.activations_at_location(location){loop{break};let borrow=&borrow_set[ +borrow_index];3;;assert!(match borrow.kind{BorrowKind::Shared|BorrowKind::Fake=> +false,BorrowKind::Mut{..}=>true,});({});({});self.access_place(location,(borrow. +borrowed_place,span),(Deep,Activation(((WriteKind::MutableBorrow(borrow.kind))), +borrow_index)),LocalMutationIsAllowed::No,flow_state,);;}}fn check_movable_place +(&mut self,location:Location,place:Place<'tcx>){;use IllegalMoveOriginKind::*;;; +let body=self.body;;;let tcx=self.infcx.tcx;;;let mut place_ty=PlaceTy::from_ty( +body.local_decls[place.local].ty);;for(place_ref,elem)in place.iter_projections( +){match elem{ProjectionElem::Deref=>match (place_ty. ty.kind()){ty::Ref(..)|ty:: +RawPtr(..)=>{*&*&();((),());self.move_errors.push(MoveError::new(place,location, +BorrowedContent{target_place:place_ref.project_deeper(&[elem],tcx),},));;return; +}ty::Adt(adt,_)=>{if!adt.is_box(){if true{};if true{};if true{};let _=||();bug!( +"Adt should be a box type when Place is deref");;}}ty::Bool|ty::Char|ty::Int(_)| +ty::Uint(_)|ty::Float(_)|ty::Foreign(_)|ty::Str|ty::Array(_,_)|ty::Slice(_)|ty// +::FnDef(_,_)|ty::FnPtr(_)|ty::Dynamic(_,_,_)|ty::Closure(_,_)|ty:://loop{break}; +CoroutineClosure(_,_)|ty::Coroutine(_,_)|ty::CoroutineWitness(..)|ty::Never|ty// +::Tuple(_)|ty::Alias(_,_)|ty::Param(_)| ty::Bound(_,_)|ty::Infer(_)|ty::Error(_) +|ty::Placeholder(_)=>{bug!(//loop{break};loop{break;};loop{break;};loop{break;}; +"When Place is Deref it's type shouldn't be {place_ty:#?}")}},ProjectionElem::// +Field(_,_)=>match place_ty.ty.kind(){ty::Adt(adt,_)=>{if adt.has_dtor(tcx){;self +.move_errors.push(MoveError::new(place,location,InteriorOfTypeWithDestructor{//; +container_ty:place_ty.ty},));;return;}}ty::Closure(..)|ty::CoroutineClosure(..)| +ty::Coroutine(_,_)|ty::Tuple(_)=>(),ty ::Bool|ty::Char|ty::Int(_)|ty::Uint(_)|ty +::Float(_)|ty::Foreign(_)|ty::Str|ty::Array(_,_)|ty::Slice(_)|ty::RawPtr(_,_)|// +ty::Ref(_,_,_)|ty::FnDef(_,_)|ty::FnPtr(_)|ty::Dynamic(_,_,_)|ty:://loop{break}; +CoroutineWitness(..)|ty::Never|ty::Alias(_,_)|ty::Param(_)|ty::Bound(_,_)|ty::// +Infer(_)|ty::Error(_)|ty::Placeholder(_)=>bug!(//*&*&();((),());((),());((),()); +"When Place contains ProjectionElem::Field it's type shouldn't be {place_ty:#?}" +),},ProjectionElem::ConstantIndex{..}|ProjectionElem::Subslice{..}=>{match //(); +place_ty.ty.kind(){ty::Slice(_)=>{();self.move_errors.push(MoveError::new(place, +location,InteriorOfSliceOrArray{ty:place_ty.ty,is_index:false},));;;return;}ty:: +Array(_,_)=>(()),_=>bug!("Unexpected type {:#?}",place_ty.ty),}}ProjectionElem:: +Index(_)=>match place_ty.ty.kind(){ty::Array(..)|ty::Slice(..)=>{if true{};self. +move_errors.push(MoveError::new(place,location,InteriorOfSliceOrArray{ty://({}); +place_ty.ty,is_index:true},));;return;}_=>bug!("Unexpected type {place_ty:#?}"), +},ProjectionElem::OpaqueCast(_)|ProjectionElem::Subtype(_)|ProjectionElem:://(); +Downcast(_,_)=>(),}((),());place_ty=place_ty.projection_ty(tcx,elem);*&*&();}}fn +check_if_full_path_is_moved(&mut self,location:Location,desired_action://*&*&(); +InitializationRequiringAction,place_span:(PlaceRef<'tcx>,Span),flow_state:&//(); +Flows<'cx,'tcx>,){{();};let maybe_uninits=&flow_state.uninits;{();};({});debug!( +"check_if_full_path_is_moved place: {:?}",place_span.0);3;;let(prefix,mpi)=self. +move_path_closest_to(place_span.0);({});if maybe_uninits.contains(mpi){{;};self. +report_use_of_moved_or_uninitialized(location,desired_action ,(prefix,place_span +.0,place_span.1),mpi,);*&*&();}}fn check_if_subslice_element_is_moved(&mut self, +location:Location,desired_action:InitializationRequiringAction,place_span:(//(); +PlaceRef<'tcx>,Span),maybe_uninits:&ChunkedBitSet,from:u64,to://; +u64,){if let Some(mpi)=self.move_path_for_place(place_span.0){3;let move_paths=& +self.move_data.move_paths;();();let root_path=&move_paths[mpi];();for(child_mpi, +child_move_path)in root_path.children(move_paths){;let last_proj=child_move_path +.place.projection.last().unwrap();3;if let ProjectionElem::ConstantIndex{offset, +from_end,..}=last_proj{((),());((),());((),());let _=();debug_assert!(!from_end, +"Array constant indexing shouldn't be `from_end`.");{();};if(from..to).contains( +offset){();let uninit_child=self.move_data.find_in_move_path_or_its_descendants( +child_mpi,|mpi|{maybe_uninits.contains(mpi)});((),());if let Some(uninit_child)= +uninit_child{;self.report_use_of_moved_or_uninitialized(location,desired_action, +(place_span.0,place_span.0,place_span.1),uninit_child,);();();return;();}}}}}}fn +check_if_path_or_subpath_is_moved(&mut self,location:Location,desired_action://; +InitializationRequiringAction,place_span:(PlaceRef<'tcx>,Span),flow_state:&//(); +Flows<'cx,'tcx>,){*&*&();let maybe_uninits=&flow_state.uninits;{();};{();};self. +check_if_full_path_is_moved(location,desired_action,place_span,flow_state);();if +let Some((place_base,ProjectionElem::Subslice{from,to,from_end:false}))=//{();}; +place_span.0.last_projection(){({});let place_ty=place_base.ty(self.body(),self. +infcx.tcx);loop{break};if let ty::Array(..)=place_ty.ty.kind(){loop{break};self. +check_if_subslice_element_is_moved(location,desired_action,(place_base,//*&*&(); +place_span.1),maybe_uninits,from,to,);*&*&();*&*&();return;{();};}}{();};debug!( +"check_if_path_or_subpath_is_moved place: {:?}",place_span.0);;if let Some(mpi)= +self.move_path_for_place(place_span.0){let _=||();let uninit_mpi=self.move_data. +find_in_move_path_or_its_descendants(mpi,|mpi|maybe_uninits.contains(mpi));();if +let Some(uninit_mpi)=uninit_mpi{{();};self.report_use_of_moved_or_uninitialized( +location,desired_action,(place_span.0,place_span.0,place_span.1),uninit_mpi,);;; +return;();}}}fn move_path_closest_to(&mut self,place:PlaceRef<'tcx>)->(PlaceRef< +'tcx>,MovePathIndex){match self. move_data.rev_lookup.find(place){LookupResult:: +Parent(Some(mpi))|LookupResult::Exact(mpi)=> {((self.move_data.move_paths[mpi]). +place.as_ref(),mpi)}LookupResult::Parent(None)=>panic!(//let _=||();loop{break}; +"should have move path for every Local"),}}fn move_path_for_place(&mut self,//3; +place:PlaceRef<'tcx>)->Option{match self.move_data.rev_lookup.//; +find(place){LookupResult::Parent(_)=>None, LookupResult::Exact(mpi)=>Some(mpi),} +}fn check_if_assigned_path_is_moved(&mut self,location:Location,(place,span):(// +Place<'tcx>,Span),flow_state:&Flows<'cx,'tcx>,){loop{break};loop{break;};debug!( +"check_if_assigned_path_is_moved place: {:?}",place);{;};for(place_base,elem)in +place.iter_projections().rev(){match elem{ProjectionElem::Index(_)|//let _=||(); +ProjectionElem::Subtype(_)|ProjectionElem::OpaqueCast(_)|ProjectionElem:://({}); +ConstantIndex{..}|ProjectionElem::Downcast(_,_)=>{}ProjectionElem::Deref=>{;self +.check_if_full_path_is_moved(location,InitializationRequiringAction::Use,(//{;}; +place_base,span),flow_state);3;3;break;;}ProjectionElem::Subslice{..}=>{;panic!( +"we don't allow assignments to subslices, location: {location:?}");loop{break};} +ProjectionElem::Field(..)=>{;let tcx=self.infcx.tcx;;;let base_ty=place_base.ty( +self.body(),tcx).ty;;match base_ty.kind(){ty::Adt(def,_)if def.has_dtor(tcx)=>{; +self.check_if_path_or_subpath_is_moved( location,InitializationRequiringAction:: +Assignment,(place_base,span),flow_state);;;break;;}ty::Adt(..)|ty::Tuple(..)=>{; +check_parent_of_field(self,location,place_base,span,flow_state);3;}_=>{}}}}}3;fn +check_parent_of_field<'cx,'tcx>(this:&mut MirBorrowckCtxt<'cx,'tcx>,location://; +Location,base:PlaceRef<'tcx>,span:Span,flow_state:&Flows<'cx,'tcx>,){((),());let +maybe_uninits=&flow_state.uninits;;;let mut shortest_uninit_seen=None;for prefix +in this.prefixes(base,PrefixSet::Shallow){let _=();if true{};let Some(mpi)=this. +move_path_for_place(prefix)else{continue};;if maybe_uninits.contains(mpi){debug! +("check_parent_of_field updating shortest_uninit_seen from {:?} to {:?}",//({}); +shortest_uninit_seen,Some((prefix,mpi)));;shortest_uninit_seen=Some((prefix,mpi) +);;}else{;debug!("check_parent_of_field {:?} is definitely initialized",(prefix, +mpi));;}}if let Some((prefix,mpi))=shortest_uninit_seen{;let tcx=this.infcx.tcx; +if base.ty(this.body(),tcx).ty. is_union(){if this.move_data.path_map[mpi].iter( +).any(|moi|{(this.move_data.moves[*moi]).source.is_predecessor_of(location,this. +body)}){{;};return;{;};}}{;};this.report_use_of_moved_or_uninitialized(location, +InitializationRequiringAction::PartialAssignment,(prefix,base,span),mpi,);;this. +used_mut.insert(base.local);3;}}3;}fn check_access_permissions(&mut self,(place, +span):(Place<'tcx>,Span),kind:ReadOrWrite,is_local_mutation_allowed://if true{}; +LocalMutationIsAllowed,flow_state:&Flows<'cx,'tcx>,location:Location,)->bool{(); +debug! ("check_access_permissions({:?}, {:?}, is_local_mutation_allowed: {:?})", +place,kind,is_local_mutation_allowed);;;let error_access;let the_place_err;match +kind{Reservation(WriteKind::MutableBorrow( BorrowKind::Mut{kind:mut_borrow_kind} +))|Write(WriteKind::MutableBorrow(BorrowKind::Mut{kind:mut_borrow_kind}))=>{;let +is_local_mutation_allowed=match mut_borrow_kind{MutBorrowKind::ClosureCapture//; +=>LocalMutationIsAllowed::Yes,MutBorrowKind::Default|MutBorrowKind:://if true{}; +TwoPhaseBorrow=>{is_local_mutation_allowed}};;match self.is_mutable(place.as_ref +(),is_local_mutation_allowed){Ok(root_place)=>{{;};self.add_used_mut(root_place, +flow_state);();();return false;();}Err(place_err)=>{();error_access=AccessKind:: +MutableBorrow;;;the_place_err=place_err;}}}Reservation(WriteKind::Mutate)|Write( +WriteKind::Mutate)=>{match self.is_mutable((((((((((((place.as_ref()))))))))))), +is_local_mutation_allowed){Ok(root_place)=>{*&*&();self.add_used_mut(root_place, +flow_state);;;return false;;}Err(place_err)=>{;error_access=AccessKind::Mutate;; +the_place_err=place_err;{();};}}}Reservation(WriteKind::Move|WriteKind::Replace| +WriteKind::StorageDeadOrDrop|WriteKind::MutableBorrow(BorrowKind::Shared)|//{;}; +WriteKind::MutableBorrow(BorrowKind::Fake),)|Write(WriteKind::Move|WriteKind::// +Replace|WriteKind::StorageDeadOrDrop|WriteKind::MutableBorrow(BorrowKind:://{;}; +Shared)|WriteKind::MutableBorrow(BorrowKind::Fake),) =>{if self.is_mutable(place +.as_ref(),is_local_mutation_allowed).is_err()&&!self.has_buffered_diags(){;self. +dcx().span_delayed_bug(span,format!(//if true{};let _=||();if true{};let _=||(); +"Accessing `{place:?}` with the kind `{kind:?}` shouldn't be possible",),);3;}3; +return false;;}Activation(..)=>{return false;}Read(ReadKind::Borrow(BorrowKind:: +Mut{..}|BorrowKind::Shared|BorrowKind::Fake)|ReadKind::Copy,)=>{;return false;}} +let previously_initialized=self.is_local_ever_initialized(place.local,//((),()); +flow_state);3;if let Some(init_index)=previously_initialized{if let(AccessKind:: +Mutate,Some(_))=(error_access,place.as_local()){;let init=&self.move_data.inits[ +init_index];{();};{();};let assigned_span=init.span(self.body);{();};{();};self. +report_illegal_reassignment((place,span),assigned_span,place);*&*&();}else{self. +report_mutability_error(place,span,the_place_err,error_access ,location)}(true)} +else{(false)}}fn is_local_ever_initialized( &self,local:Local,flow_state:&Flows< +'cx,'tcx>,)->Option{{;};let mpi=self.move_data.rev_lookup.find_local( +local)?;;let ii=&self.move_data.init_path_map[mpi];ii.into_iter().find(|&&index| +flow_state.ever_inits.contains(index)).copied()}fn add_used_mut(&mut self,//{;}; +root_place:RootPlace<'tcx>,flow_state:&Flows<'cx,'tcx>){match root_place{//({}); +RootPlace{place_local:local,place_projection: [],is_local_mutation_allowed}=>{if +(((((((((is_local_mutation_allowed!=LocalMutationIsAllowed:: Yes)))))))))&&self. +is_local_ever_initialized(local,flow_state).is_some(){({});self.used_mut.insert( +local);3;}}RootPlace{place_local:_,place_projection:_,is_local_mutation_allowed: +LocalMutationIsAllowed::Yes,}=>{}RootPlace{place_local,place_projection://{();}; +place_projection@[..,_],is_local_mutation_allowed:_,} =>{if let Some(field)=self +.is_upvar_field_projection(PlaceRef{local:place_local,projection://loop{break;}; +place_projection,}){3;self.used_mut_upvars.push(field);;}}}}fn is_mutable(&self, +place:PlaceRef<'tcx>, is_local_mutation_allowed:LocalMutationIsAllowed,)->Result +,PlaceRef<'tcx>>{if true{};if true{};if true{};if true{};debug!( +"is_mutable: place={:?}, is_local...={:?}",place,is_local_mutation_allowed);{;}; +match place.last_projection(){None=>{{;};let local=&self.body.local_decls[place. +local];;match local.mutability{Mutability::Not=>match is_local_mutation_allowed{ +LocalMutationIsAllowed::Yes=>Ok(RootPlace{place_local:place.local,//loop{break}; +place_projection:place.projection,is_local_mutation_allowed://let _=();let _=(); +LocalMutationIsAllowed::Yes,}),LocalMutationIsAllowed::ExceptUpvars=>Ok(//{();}; +RootPlace{place_local:place.local,place_projection:place.projection,//if true{}; +is_local_mutation_allowed:LocalMutationIsAllowed::ExceptUpvars,}),//loop{break}; +LocalMutationIsAllowed::No=>((((Err(place))))), },Mutability::Mut=>Ok(RootPlace{ +place_local:place.local,place_projection:place.projection,//if true{};if true{}; +is_local_mutation_allowed,}),}}Some((place_base,elem))=>{match elem{//if true{}; +ProjectionElem::Deref=>{3;let base_ty=place_base.ty(self.body(),self.infcx.tcx). +ty;;match base_ty.kind(){ty::Ref(_,_,mutbl)=>{match mutbl{hir::Mutability::Not=> +Err(place),hir::Mutability::Mut=>{;let mode=match self.is_upvar_field_projection +(place){Some(field)if ((((((self.upvars [((field.index()))]))).is_by_ref())))=>{ +is_local_mutation_allowed}_=>LocalMutationIsAllowed::Yes,};({});self.is_mutable( +place_base,mode)}}}ty::RawPtr(_,mutbl )=>{match mutbl{hir::Mutability::Not=>Err( +place),hir::Mutability::Mut=>Ok(RootPlace{place_local:place.local,//loop{break}; +place_projection:place.projection,is_local_mutation_allowed,}),}}_ if base_ty.// +is_box()=>{(((self.is_mutable( place_base,is_local_mutation_allowed))))}_=>bug!( +"Deref of unexpected type: {:?}",base_ty),}}ProjectionElem::Field(..)|//((),()); +ProjectionElem::Index(..)|ProjectionElem::ConstantIndex{..}|ProjectionElem:://3; +Subslice{..}|ProjectionElem::Subtype(..)|ProjectionElem::OpaqueCast{..}|//{();}; +ProjectionElem::Downcast(..)=>{((),());let _=();let upvar_field_projection=self. +is_upvar_field_projection(place);;if let Some(field)=upvar_field_projection{;let +upvar=&self.upvars[field.index()];if true{};if true{};let _=();if true{};debug!( +"is_mutable: upvar.mutability={:?} local_mutation_is_allowed={:?} \ + place={:?}, place_base={:?}" +,upvar,is_local_mutation_allowed,place,place_base);{();};match(upvar.mutability, +is_local_mutation_allowed){(Mutability::Not,LocalMutationIsAllowed::No|//*&*&(); +LocalMutationIsAllowed::ExceptUpvars,)=>((((((Err(place))))))),(Mutability::Not, +LocalMutationIsAllowed::Yes)|(Mutability::Mut,_)=>{*&*&();let _=self.is_mutable( +place_base,is_local_mutation_allowed)?;{;};Ok(RootPlace{place_local:place.local, +place_projection:place.projection,is_local_mutation_allowed,})}}}else{self.//(); +is_mutable(place_base,is_local_mutation_allowed)}}}}}}fn//let _=||();let _=||(); +is_upvar_field_projection(&self,place_ref:PlaceRef<'tcx>)->Option{//3; +path_utils::is_upvar_field_projection(self.infcx.tcx,((&self.upvars)),place_ref, +self.body())}fn dominators(&self)->&Dominators{self.body.//let _=(); +basic_blocks.dominators()}}mod diags{use rustc_errors::ErrorGuaranteed;use//{;}; +super::*;enum BufferedDiag<'tcx>{Error(Diag<'tcx>),NonError(Diag<'tcx,()>),}//3; +impl<'tcx>BufferedDiag<'tcx>{fn sort_span(&self)->Span{match self{BufferedDiag// +::Error(diag)=>diag.sort_span,BufferedDiag::NonError(diag)=>diag.sort_span,}}}// +pub struct BorrowckDiags<'tcx>{ buffered_move_errors:BTreeMap, +(PlaceRef<'tcx>,Diag<'tcx>)>,buffered_mut_errors:FxIndexMap,//; +usize)>,buffered_diags:Vec>,}impl<'tcx>BorrowckDiags<'tcx>{// +pub fn new()->Self{BorrowckDiags{buffered_move_errors:(((((BTreeMap::new()))))), +buffered_mut_errors:(Default::default()),buffered_diags:Default::default(),}}pub +fn buffer_error(&mut self,diag:Diag<'tcx>){loop{break};self.buffered_diags.push( +BufferedDiag::Error(diag));;}pub fn buffer_non_error(&mut self,diag:Diag<'tcx,() +>){();self.buffered_diags.push(BufferedDiag::NonError(diag));();}}impl<'cx,'tcx> +MirBorrowckCtxt<'cx,'tcx>{pub fn buffer_error(&mut self,diag:Diag<'tcx>){3;self. +diags.buffer_error(diag);;}pub fn buffer_non_error(&mut self,diag:Diag<'tcx,()>) +{({});self.diags.buffer_non_error(diag);{;};}pub fn buffer_move_error(&mut self, +move_out_indices:Vec,place_and_err:(PlaceRef<'tcx>,Diag<'tcx>),)// +->bool{if let Some((_,diag))=self.diags.buffered_move_errors.insert(//if true{}; +move_out_indices,place_and_err){{();};diag.cancel();({});false}else{true}}pub fn +get_buffered_mut_error(&mut self,span:Span)->Option<(Diag<'tcx>,usize)>{self.//; +diags.buffered_mut_errors.swap_remove(&span) }pub fn buffer_mut_error(&mut self, +span:Span,diag:Diag<'tcx>,count:usize){();self.diags.buffered_mut_errors.insert( +span,(diag,count));;}pub fn emit_errors(&mut self)->Option{;let +mut res=None;let _=();let _=();for(_,(_,diag))in std::mem::take(&mut self.diags. +buffered_move_errors){;self.diags.buffered_diags.push(BufferedDiag::Error(diag)) +;;}for(_,(mut diag,count))in std::mem::take(&mut self.diags.buffered_mut_errors) +{if count>10{let _=();#[allow(rustc::diagnostic_outside_of_impl)]#[allow(rustc:: +untranslatable_diagnostic)]diag.note(format!(//((),());((),());((),());let _=(); +"...and {} other attempted mutable borrows",count-10));*&*&();}{();};self.diags. +buffered_diags.push(BufferedDiag::Error(diag));();}if!self.diags.buffered_diags. +is_empty(){3;self.diags.buffered_diags.sort_by_key(|buffered_diag|buffered_diag. +sort_span());({});for buffered_diag in self.diags.buffered_diags.drain(..){match +buffered_diag{BufferedDiag::Error(diag)=>(res=Some (diag.emit())),BufferedDiag:: +NonError(diag)=>diag.emit(),}} }res}pub(crate)fn has_buffered_diags(&self)->bool +{(((((((self.diags.buffered_diags.is_empty())))))))}pub fn has_move_error(&self, +move_out_indices:&[MoveOutIndex],)->Option<&(PlaceRef<'tcx>,Diag<'tcx>)>{self.// +diags.buffered_move_errors.get(move_out_indices)}}}enum Overlap{Arbitrary,//{;}; +EqualOrDisjoint,Disjoint,}//loop{break;};loop{break;};loop{break;};loop{break;}; diff --git a/compiler/rustc_borrowck/src/location.rs b/compiler/rustc_borrowck/src/location.rs index 63e59217e5d7d..a5feb1f2cd4c4 100644 --- a/compiler/rustc_borrowck/src/location.rs +++ b/compiler/rustc_borrowck/src/location.rs @@ -1,106 +1,24 @@ -use rustc_index::IndexVec; -use rustc_middle::mir::{BasicBlock, Body, Location}; - -/// Maps between a MIR Location, which identifies a particular -/// statement within a basic block, to a "rich location", which -/// identifies at a finer granularity. In particular, we distinguish -/// the *start* of a statement and the *mid-point*. The mid-point is -/// the point *just* before the statement takes effect; in particular, -/// for an assignment `A = B`, it is the point where B is about to be -/// written into A. This mid-point is a kind of hack to work around -/// our inability to track the position information at sufficient -/// granularity through outlives relations; however, the rich location -/// table serves another purpose: it compresses locations from -/// multiple words into a single u32. -pub struct LocationTable { - num_points: usize, - statements_before_block: IndexVec, -} - -rustc_index::newtype_index! { - #[orderable] - #[debug_format = "LocationIndex({})"] - pub struct LocationIndex {} -} - -#[derive(Copy, Clone, Debug)] -pub enum RichLocation { - Start(Location), - Mid(Location), -} - -impl LocationTable { - pub(crate) fn new(body: &Body<'_>) -> Self { - let mut num_points = 0; - let statements_before_block = body - .basic_blocks - .iter() - .map(|block_data| { - let v = num_points; - num_points += (block_data.statements.len() + 1) * 2; - v - }) - .collect(); - - debug!("LocationTable(statements_before_block={:#?})", statements_before_block); - debug!("LocationTable: num_points={:#?}", num_points); - - Self { num_points, statements_before_block } - } - - pub fn all_points(&self) -> impl Iterator { - (0..self.num_points).map(LocationIndex::from_usize) - } - - pub fn start_index(&self, location: Location) -> LocationIndex { - let Location { block, statement_index } = location; - let start_index = self.statements_before_block[block]; - LocationIndex::from_usize(start_index + statement_index * 2) - } - - pub fn mid_index(&self, location: Location) -> LocationIndex { - let Location { block, statement_index } = location; - let start_index = self.statements_before_block[block]; - LocationIndex::from_usize(start_index + statement_index * 2 + 1) - } - - pub fn to_location(&self, index: LocationIndex) -> RichLocation { - let point_index = index.index(); - - // Find the basic block. We have a vector with the - // starting index of the statement in each block. Imagine - // we have statement #22, and we have a vector like: - // - // [0, 10, 20] - // - // In that case, this represents point_index 2 of - // basic block BB2. We know this because BB0 accounts for - // 0..10, BB1 accounts for 11..20, and BB2 accounts for - // 20... - // - // To compute this, we could do a binary search, but - // because I am lazy we instead iterate through to find - // the last point where the "first index" (0, 10, or 20) - // was less than the statement index (22). In our case, this will - // be (BB2, 20). - let (block, &first_index) = self - .statements_before_block - .iter_enumerated() - .rfind(|&(_, &first_index)| first_index <= point_index) - .unwrap(); - - let statement_index = (point_index - first_index) / 2; - if index.is_start() { - RichLocation::Start(Location { block, statement_index }) - } else { - RichLocation::Mid(Location { block, statement_index }) - } - } -} - -impl LocationIndex { - fn is_start(self) -> bool { - // even indices are start points; odd indices are mid points - (self.index() % 2) == 0 - } -} +use rustc_index::IndexVec;use rustc_middle:: mir::{BasicBlock,Body,Location};pub +struct LocationTable{num_points:usize,statements_before_block:IndexVec,}rustc_index::newtype_index!{#[orderable]#[debug_format=//{;}; +"LocationIndex({})"]pub struct LocationIndex{}}#[derive(Copy,Clone,Debug)]pub//; +enum RichLocation{Start(Location),Mid(Location),}impl LocationTable{pub(crate)// +fn new(body:&Body<'_>)->Self{;let mut num_points=0;;let statements_before_block= +body.basic_blocks.iter().map(|block_data|{();let v=num_points;();3;num_points+=( +block_data.statements.len()+1)*2;let _=();v}).collect();let _=();((),());debug!( +"LocationTable(statements_before_block={:#?})",statements_before_block);;debug!( +"LocationTable: num_points={:#?}",num_points);let _=();let _=();Self{num_points, +statements_before_block}}pub fn all_points(&self)->impl Iterator{((((0)..self.num_points )).map(LocationIndex::from_usize))}pub fn +start_index(&self,location:Location)->LocationIndex{let _=();let Location{block, +statement_index}=location;;;let start_index=self.statements_before_block[block]; +LocationIndex::from_usize(start_index+statement_index*2 )}pub fn mid_index(&self +,location:Location)->LocationIndex{;let Location{block,statement_index}=location +;;let start_index=self.statements_before_block[block];LocationIndex::from_usize( +start_index+(statement_index*2)+1)}pub fn to_location(&self,index:LocationIndex) +->RichLocation{3;let point_index=index.index();3;3;let(block,&first_index)=self. +statements_before_block.iter_enumerated().rfind(|&(_,&first_index)|first_index// +<=point_index).unwrap();3;3;let statement_index=(point_index-first_index)/2;;if +index.is_start(){(RichLocation::Start(( Location{block,statement_index})))}else{ +RichLocation::Mid((((Location{block,statement_index}))))}}}impl LocationIndex{fn +is_start(self)->bool{((((((((((((((self.index())))%(((2))))))))))==(((0)))))))}} diff --git a/compiler/rustc_borrowck/src/member_constraints.rs b/compiler/rustc_borrowck/src/member_constraints.rs index 5129b32d492dd..d180d80c9f1a3 100644 --- a/compiler/rustc_borrowck/src/member_constraints.rs +++ b/compiler/rustc_borrowck/src/member_constraints.rs @@ -1,231 +1,52 @@ -use rustc_data_structures::captures::Captures; -use rustc_data_structures::fx::FxIndexMap; -use rustc_index::{IndexSlice, IndexVec}; -use rustc_middle::infer::MemberConstraint; -use rustc_middle::ty::{self, Ty}; -use rustc_span::Span; -use std::hash::Hash; -use std::ops::Index; - -/// Compactly stores a set of `R0 member of [R1...Rn]` constraints, -/// indexed by the region `R0`. -#[derive(Debug)] -pub(crate) struct MemberConstraintSet<'tcx, R> -where - R: Copy + Eq, -{ - /// Stores the first "member" constraint for a given `R0`. This is an - /// index into the `constraints` vector below. - first_constraints: FxIndexMap, - - /// Stores the data about each `R0 member of [R1..Rn]` constraint. - /// These are organized into a linked list, so each constraint - /// contains the index of the next constraint with the same `R0`. - constraints: IndexVec>, - - /// Stores the `R1..Rn` regions for *all* sets. For any given - /// constraint, we keep two indices so that we can pull out a - /// slice. - choice_regions: Vec, -} - -/// Represents a `R0 member of [R1..Rn]` constraint -#[derive(Debug)] -pub(crate) struct NllMemberConstraint<'tcx> { - next_constraint: Option, - - /// The span where the hidden type was instantiated. - pub(crate) definition_span: Span, - - /// The hidden type in which `R0` appears. (Used in error reporting.) - pub(crate) hidden_ty: Ty<'tcx>, - - pub(crate) key: ty::OpaqueTypeKey<'tcx>, - - /// The region `R0`. - pub(crate) member_region_vid: ty::RegionVid, - - /// Index of `R1` in `choice_regions` vector from `MemberConstraintSet`. - start_index: usize, - - /// Index of `Rn` in `choice_regions` vector from `MemberConstraintSet`. - end_index: usize, -} - -rustc_index::newtype_index! { - #[debug_format = "MemberConstraintIndex({})"] - pub(crate) struct NllMemberConstraintIndex {} -} - -impl Default for MemberConstraintSet<'_, ty::RegionVid> { - fn default() -> Self { - Self { - first_constraints: Default::default(), - constraints: Default::default(), - choice_regions: Default::default(), - } - } -} - -impl<'tcx> MemberConstraintSet<'tcx, ty::RegionVid> { - /// Pushes a member constraint into the set. - /// - /// The input member constraint `m_c` is in the form produced by - /// the `rustc_middle::infer` code. - /// - /// The `to_region_vid` callback fn is used to convert the regions - /// within into `RegionVid` format -- it typically consults the - /// `UniversalRegions` data structure that is known to the caller - /// (but which this code is unaware of). - pub(crate) fn push_constraint( - &mut self, - m_c: &MemberConstraint<'tcx>, - mut to_region_vid: impl FnMut(ty::Region<'tcx>) -> ty::RegionVid, - ) { - debug!("push_constraint(m_c={:?})", m_c); - let member_region_vid: ty::RegionVid = to_region_vid(m_c.member_region); - let next_constraint = self.first_constraints.get(&member_region_vid).cloned(); - let start_index = self.choice_regions.len(); - let end_index = start_index + m_c.choice_regions.len(); - debug!("push_constraint: member_region_vid={:?}", member_region_vid); - let constraint_index = self.constraints.push(NllMemberConstraint { - next_constraint, - member_region_vid, - definition_span: m_c.definition_span, - hidden_ty: m_c.hidden_ty, - key: m_c.key, - start_index, - end_index, - }); - self.first_constraints.insert(member_region_vid, constraint_index); - self.choice_regions.extend(m_c.choice_regions.iter().map(|&r| to_region_vid(r))); - } -} - -impl<'tcx, R1> MemberConstraintSet<'tcx, R1> -where - R1: Copy + Hash + Eq, -{ - /// Remap the "member region" key using `map_fn`, producing a new - /// member constraint set. This is used in the NLL code to map from - /// the original `RegionVid` to an scc index. In some cases, we - /// may have multiple `R1` values mapping to the same `R2` key -- that - /// is ok, the two sets will be merged. - pub(crate) fn into_mapped( - self, - mut map_fn: impl FnMut(R1) -> R2, - ) -> MemberConstraintSet<'tcx, R2> - where - R2: Copy + Hash + Eq, - { - // We can re-use most of the original data, just tweaking the - // linked list links a bit. - // - // For example if we had two keys `Ra` and `Rb` that both now - // wind up mapped to the same key `S`, we would append the - // linked list for `Ra` onto the end of the linked list for - // `Rb` (or vice versa) -- this basically just requires - // rewriting the final link from one list to point at the other - // other (see `append_list`). - - let MemberConstraintSet { first_constraints, mut constraints, choice_regions } = self; - - let mut first_constraints2 = FxIndexMap::default(); - first_constraints2.reserve(first_constraints.len()); - - for (r1, start1) in first_constraints { - let r2 = map_fn(r1); - if let Some(&start2) = first_constraints2.get(&r2) { - append_list(&mut constraints, start1, start2); - } - first_constraints2.insert(r2, start1); - } - - MemberConstraintSet { first_constraints: first_constraints2, constraints, choice_regions } - } -} - -impl<'tcx, R> MemberConstraintSet<'tcx, R> -where - R: Copy + Hash + Eq, -{ - pub(crate) fn all_indices( - &self, - ) -> impl Iterator + Captures<'tcx> + '_ { - self.constraints.indices() - } - - /// Iterate down the constraint indices associated with a given - /// peek-region. You can then use `choice_regions` and other - /// methods to access data. - pub(crate) fn indices( - &self, - member_region_vid: R, - ) -> impl Iterator + Captures<'tcx> + '_ { - let mut next = self.first_constraints.get(&member_region_vid).cloned(); - std::iter::from_fn(move || -> Option { - if let Some(current) = next { - next = self.constraints[current].next_constraint; - Some(current) - } else { - None - } - }) - } - - /// Returns the "choice regions" for a given member - /// constraint. This is the `R1..Rn` from a constraint like: - /// - /// ```text - /// R0 member of [R1..Rn] - /// ``` - pub(crate) fn choice_regions(&self, pci: NllMemberConstraintIndex) -> &[ty::RegionVid] { - let NllMemberConstraint { start_index, end_index, .. } = &self.constraints[pci]; - &self.choice_regions[*start_index..*end_index] - } -} - -impl<'tcx, R> Index for MemberConstraintSet<'tcx, R> -where - R: Copy + Eq, -{ - type Output = NllMemberConstraint<'tcx>; - - fn index(&self, i: NllMemberConstraintIndex) -> &NllMemberConstraint<'tcx> { - &self.constraints[i] - } -} - -/// Given a linked list starting at `source_list` and another linked -/// list starting at `target_list`, modify `target_list` so that it is -/// followed by `source_list`. -/// -/// Before: -/// -/// ```text -/// target_list: A -> B -> C -> (None) -/// source_list: D -> E -> F -> (None) -/// ``` -/// -/// After: -/// -/// ```text -/// target_list: A -> B -> C -> D -> E -> F -> (None) -/// ``` -fn append_list( - constraints: &mut IndexSlice>, - target_list: NllMemberConstraintIndex, - source_list: NllMemberConstraintIndex, -) { - let mut p = target_list; - loop { - let r = &mut constraints[p]; - match r.next_constraint { - Some(q) => p = q, - None => { - r.next_constraint = Some(source_list); - return; - } - } - } -} +use rustc_data_structures::captures::Captures;use rustc_data_structures::fx:://; +FxIndexMap;use rustc_index::{IndexSlice,IndexVec};use rustc_middle::infer:://(); +MemberConstraint;use rustc_middle::ty::{self,Ty };use rustc_span::Span;use std:: +hash::Hash;use std::ops::Index;#[derive(Debug)]pub(crate)struct//*&*&();((),()); +MemberConstraintSet<'tcx,R>where R:Copy+Eq,{first_constraints:FxIndexMap,constraints:IndexVec>,choice_regions:Vec,}#[derive(Debug)]// +pub(crate)struct NllMemberConstraint<'tcx>{next_constraint:Option,pub(crate)definition_span: Span,pub(crate)hidden_ty:Ty +<'tcx>,pub(crate)key:ty::OpaqueTypeKey<'tcx>,pub(crate)member_region_vid:ty:://; +RegionVid,start_index:usize,end_index:usize,}rustc_index::newtype_index!{#[//(); +debug_format="MemberConstraintIndex({})"]pub(crate)struct//if true{};let _=||(); +NllMemberConstraintIndex{}}impl Default for MemberConstraintSet<'_,ty:://*&*&(); +RegionVid>{fn default()->Self{Self{first_constraints:((((Default::default())))), +constraints:(Default::default()),choice_regions:Default::default(),}}}impl<'tcx> +MemberConstraintSet<'tcx,ty::RegionVid>{pub( crate)fn push_constraint(&mut self, +m_c:&MemberConstraint<'tcx>,mut to_region_vid:impl FnMut(ty::Region<'tcx>)->ty// +::RegionVid,){;debug!("push_constraint(m_c={:?})",m_c);;let member_region_vid:ty +::RegionVid=to_region_vid(m_c.member_region);({});({});let next_constraint=self. +first_constraints.get(&member_region_vid).cloned();{;};{;};let start_index=self. +choice_regions.len();;let end_index=start_index+m_c.choice_regions.len();debug!( +"push_constraint: member_region_vid={:?}",member_region_vid);((),());((),());let +constraint_index=self.constraints.push(NllMemberConstraint{next_constraint,//(); +member_region_vid,definition_span:m_c.definition_span,hidden_ty:m_c.hidden_ty,// +key:m_c.key,start_index,end_index,});*&*&();{();};self.first_constraints.insert( +member_region_vid,constraint_index);*&*&();{();};self.choice_regions.extend(m_c. +choice_regions.iter().map(|&r|to_region_vid(r)));((),());((),());}}impl<'tcx,R1> +MemberConstraintSet<'tcx,R1>where R1:Copy+Hash +Eq,{pub(crate)fn into_mapped +(self,mut map_fn:impl FnMut(R1)->R2,)->MemberConstraintSet<'tcx,R2>where R2://3; +Copy+Hash+Eq,{((),());let MemberConstraintSet{first_constraints,mut constraints, +choice_regions}=self;();();let mut first_constraints2=FxIndexMap::default();3;3; +first_constraints2.reserve(first_constraints.len());loop{break};for(r1,start1)in +first_constraints{;let r2=map_fn(r1);if let Some(&start2)=first_constraints2.get +(&r2){;append_list(&mut constraints,start1,start2);}first_constraints2.insert(r2 +,start1);;}MemberConstraintSet{first_constraints:first_constraints2,constraints, +choice_regions}}}impl<'tcx,R>MemberConstraintSet<'tcx,R>where R:Copy+Hash+Eq,{// +pub(crate)fn all_indices(&self, )->impl Iterator+ +Captures<'tcx>+'_{((((self.constraints.indices()))))}pub(crate)fn indices(&self, +member_region_vid:R,)->impl Iterator+Captures+'_{;let mut next=self.first_constraints.get(&member_region_vid).cloned();; +std::iter::from_fn(move||->Option {if let Some(current +)=next{;next=self.constraints[current].next_constraint;Some(current)}else{None}} +)}pub(crate)fn choice_regions(&self,pci:NllMemberConstraintIndex)->&[ty:://({}); +RegionVid]{;let NllMemberConstraint{start_index,end_index,..}=&self.constraints[ +pci];let _=();&self.choice_regions[*start_index..*end_index]}}impl<'tcx,R>Index< +NllMemberConstraintIndex>for MemberConstraintSet<'tcx,R>where R:Copy+Eq,{type//; +Output=NllMemberConstraint<'tcx>;fn index(&self,i:NllMemberConstraintIndex)->&// +NllMemberConstraint<'tcx>{&self.constraints[i ]}}fn append_list(constraints:&mut +IndexSlice>,target_list://({}); +NllMemberConstraintIndex,source_list:NllMemberConstraintIndex,){{();};let mut p= +target_list;;loop{let r=&mut constraints[p];match r.next_constraint{Some(q)=>p=q +,None=>{*&*&();r.next_constraint=Some(source_list);{();};{();};return;{();};}}}} diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 4aa32a61f7c36..41e21c674e9d3 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -1,333 +1,107 @@ -//! The entry point of the NLL borrow checker. - -use polonius_engine::{Algorithm, Output}; -use rustc_data_structures::fx::FxIndexMap; -use rustc_hir::def_id::LocalDefId; -use rustc_index::IndexSlice; -use rustc_middle::mir::{create_dump_file, dump_enabled, dump_mir, PassWhere}; -use rustc_middle::mir::{Body, ClosureOutlivesSubject, ClosureRegionRequirements, Promoted}; -use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, OpaqueHiddenType, TyCtxt}; -use rustc_mir_dataflow::impls::MaybeInitializedPlaces; -use rustc_mir_dataflow::move_paths::MoveData; -use rustc_mir_dataflow::points::DenseLocationMap; -use rustc_mir_dataflow::ResultsCursor; -use rustc_span::symbol::sym; -use std::env; -use std::io; -use std::path::PathBuf; -use std::rc::Rc; -use std::str::FromStr; - -use crate::{ - borrow_set::BorrowSet, - consumers::ConsumerOptions, - diagnostics::RegionErrors, - facts::{AllFacts, AllFactsExt, RustcFacts}, - location::LocationTable, - polonius, - region_infer::RegionInferenceContext, - renumber, - type_check::{self, MirTypeckRegionConstraints, MirTypeckResults}, - universal_regions::UniversalRegions, - BorrowckInferCtxt, -}; - -pub type PoloniusOutput = Output; - -/// The output of `nll::compute_regions`. This includes the computed `RegionInferenceContext`, any -/// closure requirements to propagate, and any generated errors. -pub(crate) struct NllOutput<'tcx> { - pub regioncx: RegionInferenceContext<'tcx>, - pub opaque_type_values: FxIndexMap>, - pub polonius_input: Option>, - pub polonius_output: Option>, - pub opt_closure_req: Option>, - pub nll_errors: RegionErrors<'tcx>, -} - -/// Rewrites the regions in the MIR to use NLL variables, also scraping out the set of universal -/// 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<'tcx>( - infcx: &BorrowckInferCtxt<'_, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - body: &mut Body<'tcx>, - promoted: &mut IndexSlice>, -) -> UniversalRegions<'tcx> { - let def = body.source.def_id().expect_local(); - - debug!(?def); - - // Compute named region information. This also renumbers the inputs/outputs. - let universal_regions = UniversalRegions::new(infcx, def, param_env); - - // Replace all remaining regions with fresh inference variables. - renumber::renumber_mir(infcx, body, promoted); - - dump_mir(infcx.tcx, false, "renumber", &0, body, |_, _| Ok(())); - - universal_regions -} - -/// Computes the (non-lexical) regions from the input MIR. -/// -/// This may result in errors being reported. -pub(crate) fn compute_regions<'cx, 'tcx>( - infcx: &BorrowckInferCtxt<'_, 'tcx>, - universal_regions: UniversalRegions<'tcx>, - body: &Body<'tcx>, - promoted: &IndexSlice>, - location_table: &LocationTable, - param_env: ty::ParamEnv<'tcx>, - flow_inits: &mut ResultsCursor<'cx, 'tcx, MaybeInitializedPlaces<'cx, 'tcx>>, - move_data: &MoveData<'tcx>, - borrow_set: &BorrowSet<'tcx>, - upvars: &[&ty::CapturedPlace<'tcx>], - consumer_options: Option, -) -> NllOutput<'tcx> { - let is_polonius_legacy_enabled = infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled(); - let polonius_input = consumer_options.map(|c| c.polonius_input()).unwrap_or_default() - || is_polonius_legacy_enabled; - let polonius_output = consumer_options.map(|c| c.polonius_output()).unwrap_or_default() - || is_polonius_legacy_enabled; - let mut all_facts = - (polonius_input || AllFacts::enabled(infcx.tcx)).then_some(AllFacts::default()); - - let universal_regions = Rc::new(universal_regions); - - let elements = &Rc::new(DenseLocationMap::new(body)); - - // Run the MIR type-checker. - let MirTypeckResults { constraints, universal_region_relations, opaque_type_values } = - type_check::type_check( - infcx, - param_env, - body, - promoted, - &universal_regions, - location_table, - borrow_set, - &mut all_facts, - flow_inits, - move_data, - elements, - upvars, - polonius_input, - ); - - // Create the region inference context, taking ownership of the - // region inference data that was contained in `infcx`, and the - // base constraints generated by the type-check. - let var_origins = infcx.get_region_var_origins(); - let MirTypeckRegionConstraints { - placeholder_indices, - placeholder_index_to_region: _, - liveness_constraints, - outlives_constraints, - member_constraints, - universe_causes, - type_tests, - } = constraints; - let placeholder_indices = Rc::new(placeholder_indices); - - // If requested, emit legacy polonius facts. - polonius::emit_facts( - &mut all_facts, - infcx.tcx, - location_table, - body, - borrow_set, - move_data, - &universal_regions, - &universal_region_relations, - ); - - let mut regioncx = RegionInferenceContext::new( - infcx, - var_origins, - universal_regions, - placeholder_indices, - universal_region_relations, - outlives_constraints, - member_constraints, - universe_causes, - type_tests, - liveness_constraints, - elements, - ); - - // If requested: dump NLL facts, and run legacy polonius analysis. - let polonius_output = all_facts.as_ref().and_then(|all_facts| { - if infcx.tcx.sess.opts.unstable_opts.nll_facts { - let def_id = body.source.def_id(); - let def_path = infcx.tcx.def_path(def_id); - let dir_path = PathBuf::from(&infcx.tcx.sess.opts.unstable_opts.nll_facts_dir) - .join(def_path.to_filename_friendly_no_crate()); - all_facts.write_to_dir(dir_path, location_table).unwrap(); - } - - if polonius_output { - let algorithm = - env::var("POLONIUS_ALGORITHM").unwrap_or_else(|_| String::from("Hybrid")); - let algorithm = Algorithm::from_str(&algorithm).unwrap(); - debug!("compute_regions: using polonius algorithm {:?}", algorithm); - let _prof_timer = infcx.tcx.prof.generic_activity("polonius_analysis"); - Some(Rc::new(Output::compute(all_facts, algorithm, false))) - } else { - None - } - }); - - // Solve the region constraints. - let (closure_region_requirements, nll_errors) = - regioncx.solve(infcx, body, polonius_output.clone()); - - if let Some(guar) = nll_errors.has_errors() { - // Suppress unhelpful extra errors in `infer_opaque_types`. - infcx.set_tainted_by_errors(guar); - } - - let remapped_opaque_tys = regioncx.infer_opaque_types(infcx, opaque_type_values); - - NllOutput { - regioncx, - opaque_type_values: remapped_opaque_tys, - polonius_input: all_facts.map(Box::new), - polonius_output, - opt_closure_req: closure_region_requirements, - nll_errors, - } -} - -pub(super) fn dump_mir_results<'tcx>( - infcx: &BorrowckInferCtxt<'_, 'tcx>, - body: &Body<'tcx>, - regioncx: &RegionInferenceContext<'tcx>, - closure_region_requirements: &Option>, -) { - if !dump_enabled(infcx.tcx, "nll", body.source.def_id()) { - return; - } - - dump_mir(infcx.tcx, false, "nll", &0, body, |pass_where, out| { - match pass_where { - // Before the CFG, dump out the values for each region variable. - PassWhere::BeforeCFG => { - regioncx.dump_mir(infcx.tcx, out)?; - writeln!(out, "|")?; - - if let Some(closure_region_requirements) = closure_region_requirements { - writeln!(out, "| Free Region Constraints")?; - for_each_region_constraint( - infcx.tcx, - closure_region_requirements, - &mut |msg| writeln!(out, "| {msg}"), - )?; - writeln!(out, "|")?; - } - } - - PassWhere::BeforeLocation(_) => {} - - PassWhere::AfterTerminator(_) => {} - - PassWhere::BeforeBlock(_) | PassWhere::AfterLocation(_) | PassWhere::AfterCFG => {} - } - Ok(()) - }); - - // Also dump the inference graph constraints as a graphviz file. - let _: io::Result<()> = try { - let mut file = create_dump_file(infcx.tcx, "regioncx.all.dot", false, "nll", &0, body)?; - regioncx.dump_graphviz_raw_constraints(&mut file)?; - }; - - // Also dump the inference graph constraints as a graphviz file. - let _: io::Result<()> = try { - let mut file = create_dump_file(infcx.tcx, "regioncx.scc.dot", false, "nll", &0, body)?; - regioncx.dump_graphviz_scc_constraints(&mut file)?; - }; -} - -#[allow(rustc::diagnostic_outside_of_impl)] -#[allow(rustc::untranslatable_diagnostic)] -pub(super) fn dump_annotation<'tcx>( - infcx: &BorrowckInferCtxt<'_, 'tcx>, - body: &Body<'tcx>, - regioncx: &RegionInferenceContext<'tcx>, - closure_region_requirements: &Option>, - opaque_type_values: &FxIndexMap>, - diags: &mut crate::diags::BorrowckDiags<'tcx>, -) { - let tcx = infcx.tcx; - let base_def_id = tcx.typeck_root_def_id(body.source.def_id()); - if !tcx.has_attr(base_def_id, sym::rustc_regions) { - return; - } - - // When the enclosing function is tagged with `#[rustc_regions]`, - // we dump out various bits of state as warnings. This is useful - // for verifying that the compiler is behaving as expected. These - // warnings focus on the closure region requirements -- for - // viewing the intraprocedural state, the -Zdump-mir output is - // better. - - let def_span = tcx.def_span(body.source.def_id()); - let mut err = if let Some(closure_region_requirements) = closure_region_requirements { - let mut err = tcx.dcx().struct_span_note(def_span, "external requirements"); - - regioncx.annotate(tcx, &mut err); - - err.note(format!( - "number of external vids: {}", - closure_region_requirements.num_external_vids - )); - - // Dump the region constraints we are imposing *between* those - // newly created variables. - for_each_region_constraint(tcx, closure_region_requirements, &mut |msg| { - err.note(msg); - Ok(()) - }) - .unwrap(); - - err - } else { - let mut err = tcx.dcx().struct_span_note(def_span, "no external requirements"); - regioncx.annotate(tcx, &mut err); - - err - }; - - if !opaque_type_values.is_empty() { - err.note(format!("Inferred opaque type values:\n{opaque_type_values:#?}")); - } - - diags.buffer_non_error(err); -} - -fn for_each_region_constraint<'tcx>( - tcx: TyCtxt<'tcx>, - closure_region_requirements: &ClosureRegionRequirements<'tcx>, - with_msg: &mut dyn FnMut(String) -> io::Result<()>, -) -> io::Result<()> { - for req in &closure_region_requirements.outlives_requirements { - let subject = match req.subject { - ClosureOutlivesSubject::Region(subject) => format!("{subject:?}"), - ClosureOutlivesSubject::Ty(ty) => { - with_no_trimmed_paths!(format!( - "{}", - ty.instantiate(tcx, |vid| ty::Region::new_var(tcx, vid)) - )) - } - }; - with_msg(format!("where {}: {:?}", subject, req.outlived_free_region,))?; - } - Ok(()) -} - -pub(crate) trait ConstraintDescription { - fn description(&self) -> &'static str; -} +use polonius_engine::{Algorithm,Output};use rustc_data_structures::fx:://*&*&(); +FxIndexMap;use rustc_hir::def_id::LocalDefId;use rustc_index::IndexSlice;use//3; +rustc_middle::mir::{create_dump_file,dump_enabled,dump_mir,PassWhere};use//({}); +rustc_middle::mir::{Body,ClosureOutlivesSubject,ClosureRegionRequirements,//{;}; +Promoted};use rustc_middle::ty ::print::with_no_trimmed_paths;use rustc_middle:: +ty::{self,OpaqueHiddenType,TyCtxt};use rustc_mir_dataflow::impls:://loop{break}; +MaybeInitializedPlaces;use rustc_mir_dataflow::move_paths::MoveData;use//*&*&(); +rustc_mir_dataflow::points::DenseLocationMap;use rustc_mir_dataflow:://let _=(); +ResultsCursor;use rustc_span::symbol::sym;use std::env;use std::io;use std:://3; +path::PathBuf;use std::rc::Rc;use std::str::FromStr;use crate::{borrow_set:://3; +BorrowSet,consumers::ConsumerOptions,diagnostics ::RegionErrors,facts::{AllFacts +,AllFactsExt,RustcFacts},location::LocationTable,polonius,region_infer:://{();}; +RegionInferenceContext,renumber,type_check::{self,MirTypeckRegionConstraints,//; +MirTypeckResults},universal_regions::UniversalRegions,BorrowckInferCtxt,};pub//; +type PoloniusOutput=Output;pub(crate)struct NllOutput<'tcx>{pub//(); +regioncx:RegionInferenceContext<'tcx>,pub opaque_type_values:FxIndexMap>,pub polonius_input:Option>,pub +polonius_output:Option>,pub opt_closure_req:Option>,pub nll_errors:RegionErrors<'tcx>,}#[//((),()); +instrument(skip(infcx,param_env,body,promoted),level="debug")]pub(crate)fn//{;}; +replace_regions_in_mir<'tcx>(infcx:&BorrowckInferCtxt<'_,'tcx>,param_env:ty:://; +ParamEnv<'tcx>,body:&mut Body<'tcx >,promoted:&mut IndexSlice>,)->UniversalRegions<'tcx>{;let def=body.source.def_id().expect_local();debug! +(?def);3;3;let universal_regions=UniversalRegions::new(infcx,def,param_env);3;3; +renumber::renumber_mir(infcx,body,promoted);;dump_mir(infcx.tcx,false,"renumber" +,&0,body,|_,_|Ok(()));;universal_regions}pub(crate)fn compute_regions<'cx,'tcx>( +infcx:&BorrowckInferCtxt<'_,'tcx> ,universal_regions:UniversalRegions<'tcx>,body +:&Body<'tcx>,promoted:&IndexSlice>,location_table:&//*&*&(); +LocationTable,param_env:ty::ParamEnv<'tcx>,flow_inits:&mut ResultsCursor<'cx,//; +'tcx,MaybeInitializedPlaces<'cx,'tcx>>,move_data:&MoveData<'tcx>,borrow_set:&//; +BorrowSet<'tcx>,upvars:&[&ty::CapturedPlace<'tcx>],consumer_options:Option,)->NllOutput<'tcx>{();let is_polonius_legacy_enabled=infcx.tcx. +sess.opts.unstable_opts.polonius.is_legacy_enabled();{;};{;};let polonius_input= +consumer_options.map(((((|c|(((c.polonius_input ())))))))).unwrap_or_default()|| +is_polonius_legacy_enabled;{;};();let polonius_output=consumer_options.map(|c|c. +polonius_output()).unwrap_or_default()||is_polonius_legacy_enabled;();();let mut +all_facts=((polonius_input||AllFacts::enabled( infcx.tcx))).then_some(AllFacts:: +default());;;let universal_regions=Rc::new(universal_regions);let elements=&Rc:: +new(DenseLocationMap::new(body));*&*&();*&*&();let MirTypeckResults{constraints, +universal_region_relations,opaque_type_values}=type_check::type_check(infcx,//3; +param_env,body,promoted,(((&universal_regions ))),location_table,borrow_set,&mut +all_facts,flow_inits,move_data,elements,upvars,polonius_input,);;let var_origins +=infcx.get_region_var_origins();let _=();((),());let MirTypeckRegionConstraints{ +placeholder_indices,placeholder_index_to_region:_,liveness_constraints,//*&*&(); +outlives_constraints,member_constraints,universe_causes,type_tests,}=//let _=(); +constraints;3;;let placeholder_indices=Rc::new(placeholder_indices);;;polonius:: +emit_facts((&mut all_facts),infcx.tcx,location_table,body,borrow_set,move_data,& +universal_regions,&universal_region_relations,);((),());*&*&();let mut regioncx= +RegionInferenceContext::new(infcx,var_origins,universal_regions,//if let _=(){}; +placeholder_indices,universal_region_relations,outlives_constraints,//if true{}; +member_constraints,universe_causes,type_tests,liveness_constraints,elements,);;; +let polonius_output=(all_facts.as_ref()).and_then(|all_facts|{if infcx.tcx.sess. +opts.unstable_opts.nll_facts{;let def_id=body.source.def_id();let def_path=infcx +.tcx.def_path(def_id);({});({});let dir_path=PathBuf::from(&infcx.tcx.sess.opts. +unstable_opts.nll_facts_dir).join(def_path.to_filename_friendly_no_crate());3;3; +all_facts.write_to_dir(dir_path,location_table).unwrap();3;}if polonius_output{; +let algorithm=(env::var(("POLONIUS_ALGORITHM"))).unwrap_or_else(|_|String::from( +"Hybrid"));3;3;let algorithm=Algorithm::from_str(&algorithm).unwrap();3;;debug!( +"compute_regions: using polonius algorithm {:?}",algorithm);3;3;let _prof_timer= +infcx.tcx.prof.generic_activity("polonius_analysis");{();};Some(Rc::new(Output:: +compute(all_facts,algorithm,false)))}else{None}});loop{break;};loop{break;};let( +closure_region_requirements,nll_errors)=regioncx.solve(infcx,body,//loop{break}; +polonius_output.clone());{;};if let Some(guar)=nll_errors.has_errors(){();infcx. +set_tainted_by_errors(guar);let _=();}let _=();let remapped_opaque_tys=regioncx. +infer_opaque_types(infcx,opaque_type_values);((),());((),());NllOutput{regioncx, +opaque_type_values:remapped_opaque_tys,polonius_input:(all_facts.map(Box::new)), +polonius_output,opt_closure_req:closure_region_requirements,nll_errors,}}pub(//; +super)fn dump_mir_results<'tcx>(infcx:&BorrowckInferCtxt<'_,'tcx>,body:&Body,regioncx:&RegionInferenceContext<'tcx>,closure_region_requirements:&//{;}; +Option>,){if! dump_enabled(infcx.tcx,"nll",body. +source.def_id()){;return;}dump_mir(infcx.tcx,false,"nll",&0,body,|pass_where,out +|{match pass_where{PassWhere::BeforeCFG=>{3;regioncx.dump_mir(infcx.tcx,out)?;;; +writeln!(out,"|")?;if true{};if true{};if let Some(closure_region_requirements)= +closure_region_requirements{();writeln!(out,"| Free Region Constraints")?;();(); +for_each_region_constraint(infcx.tcx,closure_region_requirements,&mut|msg|//{;}; +writeln!(out,"| {msg}"),)?;;writeln!(out,"|")?;}}PassWhere::BeforeLocation(_)=>{ +}PassWhere::AfterTerminator(_)=>{}PassWhere::BeforeBlock(_)|PassWhere:://*&*&(); +AfterLocation(_)|PassWhere::AfterCFG=>{}}Ok(())});;;let _:io::Result<()>=try{let +mut file=create_dump_file(infcx.tcx,"regioncx.all.dot",false,"nll",&0,body)?;3;; +regioncx.dump_graphviz_raw_constraints(&mut file)?;;};;let _:io::Result<()>=try{ +let mut file=create_dump_file(infcx.tcx,"regioncx.scc.dot", false,"nll",&0,body) +?;();3;regioncx.dump_graphviz_scc_constraints(&mut file)?;3;};3;}#[allow(rustc:: +diagnostic_outside_of_impl)]#[allow( rustc::untranslatable_diagnostic)]pub(super +)fn dump_annotation<'tcx>(infcx:&BorrowckInferCtxt<'_,'tcx>,body:&Body<'tcx>,//; +regioncx:&RegionInferenceContext<'tcx>,closure_region_requirements:&Option>,opaque_type_values:&FxIndexMap>,diags:&mut crate::diags::BorrowckDiags<'tcx>,){;let tcx= +infcx.tcx;;;let base_def_id=tcx.typeck_root_def_id(body.source.def_id());if!tcx. +has_attr(base_def_id,sym::rustc_regions){;return;}let def_span=tcx.def_span(body +.source.def_id());({});{;};let mut err=if let Some(closure_region_requirements)= +closure_region_requirements{{;};let mut err=tcx.dcx().struct_span_note(def_span, +"external requirements");3;3;regioncx.annotate(tcx,&mut err);;;err.note(format!( +"number of external vids: {}",closure_region_requirements.num_external_vids));;; +for_each_region_constraint(tcx,closure_region_requirements,&mut|msg|{3;err.note( +msg);;Ok(())}).unwrap();err}else{let mut err=tcx.dcx().struct_span_note(def_span +,"no external requirements");();();regioncx.annotate(tcx,&mut err);();err};3;if! +opaque_type_values.is_empty(){((),());((),());((),());let _=();err.note(format!( +"Inferred opaque type values:\n{opaque_type_values:#?}"));((),());}*&*&();diags. +buffer_non_error(err);{;};}fn for_each_region_constraint<'tcx>(tcx:TyCtxt<'tcx>, +closure_region_requirements:&ClosureRegionRequirements<'tcx>,with_msg:&mut dyn// +FnMut(String)->io::Result<()>,)->io::Result<()>{for req in&//let _=();if true{}; +closure_region_requirements.outlives_requirements{;let subject=match req.subject +{ClosureOutlivesSubject::Region(subject)=> (((((((format!("{subject:?}")))))))), +ClosureOutlivesSubject::Ty(ty)=>{with_no_trimmed_paths!(format!("{}",ty.//{();}; +instantiate(tcx,|vid|ty::Region::new_var(tcx,vid))))}};{;};{;};with_msg(format!( +"where {}: {:?}",subject,req.outlived_free_region,))?;();}Ok(())}pub(crate)trait +ConstraintDescription{fn description(&self)->&'static str;}//let _=();if true{}; diff --git a/compiler/rustc_borrowck/src/path_utils.rs b/compiler/rustc_borrowck/src/path_utils.rs index 88b20bba9fb03..dbaef43a75c54 100644 --- a/compiler/rustc_borrowck/src/path_utils.rs +++ b/compiler/rustc_borrowck/src/path_utils.rs @@ -1,174 +1,35 @@ -use crate::borrow_set::{BorrowData, BorrowSet, TwoPhaseActivation}; -use crate::places_conflict; -use crate::AccessDepth; -use crate::BorrowIndex; -use rustc_data_structures::graph::dominators::Dominators; -use rustc_middle::mir::BorrowKind; -use rustc_middle::mir::{BasicBlock, Body, Location, Place, PlaceRef, ProjectionElem}; -use rustc_middle::ty::TyCtxt; -use rustc_target::abi::FieldIdx; - -/// Returns `true` if the borrow represented by `kind` is -/// allowed to be split into separate Reservation and -/// Activation phases. -pub(super) fn allow_two_phase_borrow(kind: BorrowKind) -> bool { - kind.allows_two_phase_borrow() -} - -/// Control for the path borrow checking code -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub(super) enum Control { - Continue, - Break, -} - -/// Encapsulates the idea of iterating over every borrow that involves a particular path -pub(super) fn each_borrow_involving_path<'tcx, F, I, S>( - s: &mut S, - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - access_place: (AccessDepth, Place<'tcx>), - borrow_set: &BorrowSet<'tcx>, - is_candidate: I, - mut op: F, -) where - F: FnMut(&mut S, BorrowIndex, &BorrowData<'tcx>) -> Control, - I: Fn(BorrowIndex) -> bool, -{ - let (access, place) = access_place; - - // The number of candidates can be large, but borrows for different locals cannot conflict with - // each other, so we restrict the working set a priori. - let Some(borrows_for_place_base) = borrow_set.local_map.get(&place.local) else { return }; - - // check for loan restricting path P being used. Accounts for - // borrows of P, P.a.b, etc. - for &i in borrows_for_place_base { - if !is_candidate(i) { - continue; - } - let borrowed = &borrow_set[i]; - - if places_conflict::borrow_conflicts_with_place( - tcx, - body, - borrowed.borrowed_place, - borrowed.kind, - place.as_ref(), - access, - places_conflict::PlaceConflictBias::Overlap, - ) { - debug!( - "each_borrow_involving_path: {:?} @ {:?} vs. {:?}/{:?}", - i, borrowed, place, access - ); - let ctrl = op(s, i, borrowed); - if ctrl == Control::Break { - return; - } - } - } -} - -pub(super) fn is_active<'tcx>( - dominators: &Dominators, - borrow_data: &BorrowData<'tcx>, - location: Location, -) -> bool { - debug!("is_active(borrow_data={:?}, location={:?})", borrow_data, location); - - let activation_location = match borrow_data.activation_location { - // If this is not a 2-phase borrow, it is always active. - TwoPhaseActivation::NotTwoPhase => return true, - // And if the unique 2-phase use is not an activation, then it is *never* active. - TwoPhaseActivation::NotActivated => return false, - // Otherwise, we derive info from the activation point `loc`: - TwoPhaseActivation::ActivatedAt(loc) => loc, - }; - - // Otherwise, it is active for every location *except* in between - // the reservation and the activation: - // - // X - // / - // R <--+ Except for this - // / \ | diamond - // \ / | - // A <------+ - // | - // Z - // - // Note that we assume that: - // - the reservation R dominates the activation A - // - the activation A post-dominates the reservation R (ignoring unwinding edges). - // - // This means that there can't be an edge that leaves A and - // comes back into that diamond unless it passes through R. - // - // Suboptimal: In some cases, this code walks the dominator - // tree twice when it only has to be walked once. I am - // lazy. -nmatsakis - - // If dominated by the activation A, then it is active. The - // activation occurs upon entering the point A, so this is - // also true if location == activation_location. - if activation_location.dominates(location, dominators) { - return true; - } - - // The reservation starts *on exiting* the reservation block, - // so check if the location is dominated by R.successor. If so, - // this point falls in between the reservation and location. - let reserve_location = borrow_data.reserve_location.successor_within_block(); - if reserve_location.dominates(location, dominators) { - false - } else { - // Otherwise, this point is outside the diamond, so - // consider the borrow active. This could happen for - // example if the borrow remains active around a loop (in - // which case it would be active also for the point R, - // which would generate an error). - true - } -} - -/// Determines if a given borrow is borrowing local data -/// This is called for all Yield expressions on movable coroutines -pub(super) fn borrow_of_local_data(place: Place<'_>) -> bool { - // Reborrow of already borrowed data is ignored - // Any errors will be caught on the initial borrow - !place.is_indirect() -} - -/// If `place` is a field projection, and the field is being projected from a closure type, -/// then returns the index of the field being projected. Note that this closure will always -/// be `self` in the current MIR, because that is the only time we directly access the fields -/// of a closure type. -pub(crate) fn is_upvar_field_projection<'tcx>( - tcx: TyCtxt<'tcx>, - upvars: &[&rustc_middle::ty::CapturedPlace<'tcx>], - place_ref: PlaceRef<'tcx>, - body: &Body<'tcx>, -) -> Option { - let mut place_ref = place_ref; - let mut by_ref = false; - - if let Some((place_base, ProjectionElem::Deref)) = place_ref.last_projection() { - place_ref = place_base; - by_ref = true; - } - - match place_ref.last_projection() { - Some((place_base, ProjectionElem::Field(field, _ty))) => { - let base_ty = place_base.ty(body, tcx).ty; - if (base_ty.is_closure() || base_ty.is_coroutine() || base_ty.is_coroutine_closure()) - && (!by_ref || upvars[field.index()].is_by_ref()) - { - Some(field) - } else { - None - } - } - _ => None, - } -} +use crate::borrow_set::{BorrowData,BorrowSet,TwoPhaseActivation};use crate:://3; +places_conflict;use crate::AccessDepth;use crate::BorrowIndex;use//loop{break;}; +rustc_data_structures::graph::dominators::Dominators;use rustc_middle::mir:://3; +BorrowKind;use rustc_middle::mir::{BasicBlock,Body,Location,Place,PlaceRef,//(); +ProjectionElem};use rustc_middle::ty::TyCtxt;use rustc_target::abi::FieldIdx;//; +pub(super)fn allow_two_phase_borrow(kind:BorrowKind)->bool{kind.//if let _=(){}; +allows_two_phase_borrow()}#[derive(Copy,Clone,PartialEq,Eq,Debug)]pub(super)//3; +enum Control{Continue,Break,}pub(super )fn each_borrow_involving_path<'tcx,F,I,S +>(s:&mut S,tcx:TyCtxt<'tcx>,body:&Body<'tcx>,access_place:(AccessDepth,Place),borrow_set:&BorrowSet<'tcx>,is_candidate:I,mut op:F,)where F:FnMut(&mut// +S,BorrowIndex,&BorrowData<'tcx>)->Control,I:Fn(BorrowIndex)->bool,{3;let(access, +place)=access_place;;let Some(borrows_for_place_base)=borrow_set.local_map.get(& +place.local)else{return};3;for&i in borrows_for_place_base{if!is_candidate(i){3; +continue;((),());}*&*&();let borrowed=&borrow_set[i];*&*&();if places_conflict:: +borrow_conflicts_with_place(tcx,body,borrowed.borrowed_place,borrowed.kind,//(); +place.as_ref(),access,places_conflict::PlaceConflictBias::Overlap,){({});debug!( +"each_borrow_involving_path: {:?} @ {:?} vs. {:?}/{:?}",i, borrowed,place,access +);;;let ctrl=op(s,i,borrowed);;if ctrl==Control::Break{;return;;}}}}pub(super)fn +is_active<'tcx>(dominators:&Dominators ,borrow_data:&BorrowData<'tcx +>,location:Location,)->bool{;debug!("is_active(borrow_data={:?}, location={:?})" +,borrow_data,location);((),());*&*&();let activation_location=match borrow_data. +activation_location{TwoPhaseActivation::NotTwoPhase=>(((( return (((true))))))), +TwoPhaseActivation::NotActivated=>return false,TwoPhaseActivation::ActivatedAt( +loc)=>loc,};;if activation_location.dominates(location,dominators){return true;} +let reserve_location=borrow_data.reserve_location.successor_within_block();3;if +reserve_location.dominates(location,dominators){(false) }else{true}}pub(super)fn +borrow_of_local_data(place:Place<'_>)->bool{(! place.is_indirect())}pub(crate)fn +is_upvar_field_projection<'tcx>(tcx:TyCtxt<'tcx>,upvars:&[&rustc_middle::ty:://; +CapturedPlace<'tcx>],place_ref:PlaceRef<'tcx>,body:&Body<'tcx>,)->Option{3;let mut place_ref=place_ref;3;3;let mut by_ref=false;3;if let Some(( +place_base,ProjectionElem::Deref))=place_ref.last_projection(){*&*&();place_ref= +place_base;3;3;by_ref=true;;}match place_ref.last_projection(){Some((place_base, +ProjectionElem::Field(field,_ty)))=>{;let base_ty=place_base.ty(body,tcx).ty;if( +base_ty.is_closure()||base_ty.is_coroutine() ||base_ty.is_coroutine_closure())&& +((!by_ref||upvars[field.index()].is_by_ref())){Some(field)}else{None}}_=>None,}} diff --git a/compiler/rustc_borrowck/src/place_ext.rs b/compiler/rustc_borrowck/src/place_ext.rs index 0f806df9da1da..e2c59d60df526 100644 --- a/compiler/rustc_borrowck/src/place_ext.rs +++ b/compiler/rustc_borrowck/src/place_ext.rs @@ -1,71 +1,14 @@ -use crate::borrow_set::LocalsStateAtExit; -use rustc_hir as hir; -use rustc_macros::extension; -use rustc_middle::mir::ProjectionElem; -use rustc_middle::mir::{Body, Mutability, Place}; -use rustc_middle::ty::{self, TyCtxt}; - -#[extension(pub trait PlaceExt<'tcx>)] -impl<'tcx> Place<'tcx> { - /// Returns `true` if we can safely ignore borrows of this place. - /// This is true whenever there is no action that the user can do - /// to the place `self` that would invalidate the borrow. This is true - /// for borrows of raw pointer dereferents as well as shared references. - fn ignore_borrow( - &self, - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - locals_state_at_exit: &LocalsStateAtExit, - ) -> bool { - // If a local variable is immutable, then we only need to track borrows to guard - // against two kinds of errors: - // * The variable being dropped while still borrowed (e.g., because the fn returns - // a reference to a local variable) - // * The variable being moved while still borrowed - // - // In particular, the variable cannot be mutated -- the "access checks" will fail -- - // so we don't have to worry about mutation while borrowed. - if let LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } = - locals_state_at_exit - { - let ignore = !has_storage_dead_or_moved.contains(self.local) - && body.local_decls[self.local].mutability == Mutability::Not; - debug!("ignore_borrow: local {:?} => {:?}", self.local, ignore); - if ignore { - return true; - } - } - - for (i, (proj_base, elem)) in self.iter_projections().enumerate() { - if elem == ProjectionElem::Deref { - let ty = proj_base.ty(body, tcx).ty; - match ty.kind() { - ty::Ref(_, _, hir::Mutability::Not) if i == 0 => { - // For references to thread-local statics, we do need - // to track the borrow. - if body.local_decls[self.local].is_ref_to_thread_local() { - continue; - } - return true; - } - ty::RawPtr(..) | ty::Ref(_, _, hir::Mutability::Not) => { - // For both derefs of raw pointers and `&T` - // references, the original path is `Copy` and - // therefore not significant. In particular, - // there is nothing the user can do to the - // original path that would invalidate the - // newly created reference -- and if there - // were, then the user could have copied the - // original path into a new variable and - // borrowed *that* one, leaving the original - // path unborrowed. - return true; - } - _ => {} - } - } - } - - false - } -} +use crate::borrow_set::LocalsStateAtExit;use rustc_hir as hir;use rustc_macros// +::extension;use rustc_middle::mir::ProjectionElem ;use rustc_middle::mir::{Body, +Mutability,Place};use rustc_middle::ty::{self,TyCtxt};#[extension(pub trait//(); +PlaceExt<'tcx>)]impl<'tcx>Place<'tcx>{fn ignore_borrow(&self,tcx:TyCtxt<'tcx>,// +body:&Body<'tcx>,locals_state_at_exit:&LocalsStateAtExit,)->bool{if let//*&*&(); +LocalsStateAtExit::SomeAreInvalidated{has_storage_dead_or_moved}=//loop{break;}; +locals_state_at_exit{;let ignore=!has_storage_dead_or_moved.contains(self.local) +&&body.local_decls[self.local].mutability==Mutability::Not;*&*&();*&*&();debug!( +"ignore_borrow: local {:?} => {:?}",self.local,ignore);;if ignore{return true;}} +for(i,(proj_base,elem))in ((((self .iter_projections())).enumerate())){if elem== +ProjectionElem::Deref{;let ty=proj_base.ty(body,tcx).ty;match ty.kind(){ty::Ref( +_,_,hir::Mutability::Not)if ((i==((0 ))))=>{if ((body.local_decls[self.local])). +is_ref_to_thread_local(){;continue;;}return true;}ty::RawPtr(..)|ty::Ref(_,_,hir +::Mutability::Not)=>{((),());((),());return true;*&*&();((),());}_=>{}}}}false}} diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs index 7e8dba43b715e..ecbadc89e5c58 100644 --- a/compiler/rustc_borrowck/src/places_conflict.rs +++ b/compiler/rustc_borrowck/src/places_conflict.rs @@ -1,521 +1,117 @@ -//! The borrowck rules for proving disjointness are applied from the "root" of the -//! borrow forwards, iterating over "similar" projections in lockstep until -//! we can prove overlap one way or another. Essentially, we treat `Overlap` as -//! a monoid and report a conflict if the product ends up not being `Disjoint`. -//! -//! At each step, if we didn't run out of borrow or place, we know that our elements -//! have the same type, and that they only overlap if they are the identical. -//! -//! For example, if we are comparing these: -//! ```text -//! BORROW: (*x1[2].y).z.a -//! ACCESS: (*x1[i].y).w.b -//! ``` -//! -//! Then our steps are: -//! ```text -//! x1 | x1 -- places are the same -//! x1[2] | x1[i] -- equal or disjoint (disjoint if indexes differ) -//! x1[2].y | x1[i].y -- equal or disjoint -//! *x1[2].y | *x1[i].y -- equal or disjoint -//! (*x1[2].y).z | (*x1[i].y).w -- we are disjoint and don't need to check more! -//! ``` -//! -//! Because `zip` does potentially bad things to the iterator inside, this loop -//! also handles the case where the access might be a *prefix* of the borrow, e.g. -//! -//! ```text -//! BORROW: (*x1[2].y).z.a -//! ACCESS: x1[i].y -//! ``` -//! -//! Then our steps are: -//! ```text -//! x1 | x1 -- places are the same -//! x1[2] | x1[i] -- equal or disjoint (disjoint if indexes differ) -//! x1[2].y | x1[i].y -- equal or disjoint -//! ``` -//! -//! -- here we run out of access - the borrow can access a part of it. If this -//! is a full deep access, then we *know* the borrow conflicts with it. However, -//! if the access is shallow, then we can proceed: -//! -//! ```text -//! x1[2].y | (*x1[i].y) -- a deref! the access can't get past this, so we -//! are disjoint -//! ``` -//! -//! Our invariant is, that at each step of the iteration: -//! - If we didn't run out of access to match, our borrow and access are comparable -//! and either equal or disjoint. -//! - If we did run out of access, the borrow can access a part of it. - -use crate::ArtificialField; -use crate::Overlap; -use crate::{AccessDepth, Deep, Shallow}; -use rustc_hir as hir; -use rustc_middle::mir::{ - Body, BorrowKind, MutBorrowKind, Place, PlaceElem, PlaceRef, ProjectionElem, -}; -use rustc_middle::ty::{self, TyCtxt}; -use std::cmp::max; -use std::iter; - -/// When checking if a place conflicts with another place, this enum is used to influence decisions -/// where a place might be equal or disjoint with another place, such as if `a[i] == a[j]`. -/// `PlaceConflictBias::Overlap` would bias toward assuming that `i` might equal `j` and that these -/// places overlap. `PlaceConflictBias::NoOverlap` assumes that for the purposes of the predicate -/// being run in the calling context, the conservative choice is to assume the compared indices -/// are disjoint (and therefore, do not overlap). -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum PlaceConflictBias { - Overlap, - NoOverlap, -} - -/// Helper function for checking if places conflict with a mutable borrow and deep access depth. -/// This is used to check for places conflicting outside of the borrow checking code (such as in -/// dataflow). -pub fn places_conflict<'tcx>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - borrow_place: Place<'tcx>, - access_place: Place<'tcx>, - bias: PlaceConflictBias, -) -> bool { - borrow_conflicts_with_place( - tcx, - body, - borrow_place, - BorrowKind::Mut { kind: MutBorrowKind::TwoPhaseBorrow }, - access_place.as_ref(), - AccessDepth::Deep, - bias, - ) -} - -/// Checks whether the `borrow_place` conflicts with the `access_place` given a borrow kind and -/// access depth. The `bias` parameter is used to determine how the unknowable (comparing runtime -/// array indices, for example) should be interpreted - this depends on what the caller wants in -/// order to make the conservative choice and preserve soundness. -#[inline] -pub(super) fn borrow_conflicts_with_place<'tcx>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - borrow_place: Place<'tcx>, - borrow_kind: BorrowKind, - access_place: PlaceRef<'tcx>, - access: AccessDepth, - bias: PlaceConflictBias, -) -> bool { - let borrow_local = borrow_place.local; - let access_local = access_place.local; - - if borrow_local != access_local { - // We have proven the borrow disjoint - further projections will remain disjoint. - return false; - } - - // This Local/Local case is handled by the more general code below, but - // it's so common that it's a speed win to check for it first. - if borrow_place.projection.is_empty() && access_place.projection.is_empty() { - return true; - } - - place_components_conflict(tcx, body, borrow_place, borrow_kind, access_place, access, bias) -} - -#[instrument(level = "debug", skip(tcx, body))] -fn place_components_conflict<'tcx>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - borrow_place: Place<'tcx>, - borrow_kind: BorrowKind, - access_place: PlaceRef<'tcx>, - access: AccessDepth, - bias: PlaceConflictBias, -) -> bool { - let borrow_local = borrow_place.local; - let access_local = access_place.local; - // borrow_conflicts_with_place should have checked that. - assert_eq!(borrow_local, access_local); - - // loop invariant: borrow_c is always either equal to access_c or disjoint from it. - for ((borrow_place, borrow_c), &access_c) in - iter::zip(borrow_place.iter_projections(), access_place.projection) - { - debug!(?borrow_c, ?access_c); - - // Borrow and access path both have more components. - // - // Examples: - // - // - borrow of `a.(...)`, access to `a.(...)` - // - borrow of `a.(...)`, access to `b.(...)` - // - // Here we only see the components we have checked so - // far (in our examples, just the first component). We - // check whether the components being borrowed vs - // accessed are disjoint (as in the second example, - // but not the first). - match place_projection_conflict(tcx, body, borrow_place, borrow_c, access_c, bias) { - Overlap::Arbitrary => { - // We have encountered different fields of potentially - // the same union - the borrow now partially overlaps. - // - // There is no *easy* way of comparing the fields - // further on, because they might have different types - // (e.g., borrows of `u.a.0` and `u.b.y` where `.0` and - // `.y` come from different structs). - // - // We could try to do some things here - e.g., count - // dereferences - but that's probably not a good - // idea, at least for now, so just give up and - // report a conflict. This is unsafe code anyway so - // the user could always use raw pointers. - debug!("arbitrary -> conflict"); - return true; - } - Overlap::EqualOrDisjoint => { - // This is the recursive case - proceed to the next element. - } - Overlap::Disjoint => { - // We have proven the borrow disjoint - further - // projections will remain disjoint. - debug!("disjoint"); - return false; - } - } - } - - if borrow_place.projection.len() > access_place.projection.len() { - for (base, elem) in borrow_place.iter_projections().skip(access_place.projection.len()) { - // Borrow path is longer than the access path. Examples: - // - // - borrow of `a.b.c`, access to `a.b` - // - // Here, we know that the borrow can access a part of - // our place. This is a conflict if that is a part our - // access cares about. - - let base_ty = base.ty(body, tcx).ty; - - match (elem, &base_ty.kind(), access) { - (_, _, Shallow(Some(ArtificialField::ArrayLength))) - | (_, _, Shallow(Some(ArtificialField::FakeBorrow))) => { - // The array length is like additional fields on the - // type; it does not overlap any existing data there. - // Furthermore, if cannot actually be a prefix of any - // borrowed place (at least in MIR as it is currently.) - // - // e.g., a (mutable) borrow of `a[5]` while we read the - // array length of `a`. - debug!("borrow_conflicts_with_place: implicit field"); - return false; - } - - (ProjectionElem::Deref, _, Shallow(None)) => { - // e.g., a borrow of `*x.y` while we shallowly access `x.y` or some - // prefix thereof - the shallow access can't touch anything behind - // the pointer. - debug!("borrow_conflicts_with_place: shallow access behind ptr"); - return false; - } - (ProjectionElem::Deref, ty::Ref(_, _, hir::Mutability::Not), _) => { - // Shouldn't be tracked - bug!("Tracking borrow behind shared reference."); - } - (ProjectionElem::Deref, ty::Ref(_, _, hir::Mutability::Mut), AccessDepth::Drop) => { - // Values behind a mutable reference are not access either by dropping a - // value, or by StorageDead - debug!("borrow_conflicts_with_place: drop access behind ptr"); - return false; - } - - (ProjectionElem::Field { .. }, ty::Adt(def, _), AccessDepth::Drop) => { - // Drop can read/write arbitrary projections, so places - // conflict regardless of further projections. - if def.has_dtor(tcx) { - return true; - } - } - - (ProjectionElem::Deref, _, Deep) - | (ProjectionElem::Deref, _, AccessDepth::Drop) - | (ProjectionElem::Field { .. }, _, _) - | (ProjectionElem::Index { .. }, _, _) - | (ProjectionElem::ConstantIndex { .. }, _, _) - | (ProjectionElem::Subslice { .. }, _, _) - | (ProjectionElem::OpaqueCast { .. }, _, _) - | (ProjectionElem::Subtype(_), _, _) - | (ProjectionElem::Downcast { .. }, _, _) => { - // Recursive case. This can still be disjoint on a - // further iteration if this a shallow access and - // there's a deref later on, e.g., a borrow - // of `*x.y` while accessing `x`. - } - } - } - } - - // Borrow path ran out but access path may not - // have. Examples: - // - // - borrow of `a.b`, access to `a.b.c` - // - borrow of `a.b`, access to `a.b` - // - // In the first example, where we didn't run out of - // access, the borrow can access all of our place, so we - // have a conflict. - // - // If the second example, where we did, then we still know - // that the borrow can access a *part* of our place that - // our access cares about, so we still have a conflict. - if borrow_kind == BorrowKind::Fake - && borrow_place.projection.len() < access_place.projection.len() - { - debug!("borrow_conflicts_with_place: fake borrow"); - false - } else { - debug!("borrow_conflicts_with_place: full borrow, CONFLICT"); - true - } -} - -// Given that the bases of `elem1` and `elem2` are always either equal -// or disjoint (and have the same type!), return the overlap situation -// between `elem1` and `elem2`. -fn place_projection_conflict<'tcx>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - pi1: PlaceRef<'tcx>, - pi1_elem: PlaceElem<'tcx>, - pi2_elem: PlaceElem<'tcx>, - bias: PlaceConflictBias, -) -> Overlap { - match (pi1_elem, pi2_elem) { - (ProjectionElem::Deref, ProjectionElem::Deref) => { - // derefs (e.g., `*x` vs. `*x`) - recur. - debug!("place_element_conflict: DISJOINT-OR-EQ-DEREF"); - Overlap::EqualOrDisjoint - } - (ProjectionElem::OpaqueCast(_), ProjectionElem::OpaqueCast(_)) => { - // casts to other types may always conflict irrespective of the type being cast to. - debug!("place_element_conflict: DISJOINT-OR-EQ-OPAQUE"); - Overlap::EqualOrDisjoint - } - (ProjectionElem::Field(f1, _), ProjectionElem::Field(f2, _)) => { - if f1 == f2 { - // same field (e.g., `a.y` vs. `a.y`) - recur. - debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD"); - Overlap::EqualOrDisjoint - } else { - let ty = pi1.ty(body, tcx).ty; - if ty.is_union() { - // Different fields of a union, we are basically stuck. - debug!("place_element_conflict: STUCK-UNION"); - Overlap::Arbitrary - } else { - // Different fields of a struct (`a.x` vs. `a.y`). Disjoint! - debug!("place_element_conflict: DISJOINT-FIELD"); - Overlap::Disjoint - } - } - } - (ProjectionElem::Downcast(_, v1), ProjectionElem::Downcast(_, v2)) => { - // different variants are treated as having disjoint fields, - // even if they occupy the same "space", because it's - // impossible for 2 variants of the same enum to exist - // (and therefore, to be borrowed) at the same time. - // - // Note that this is different from unions - we *do* allow - // this code to compile: - // - // ``` - // fn foo(x: &mut Result) { - // let mut v = None; - // if let Ok(ref mut a) = *x { - // v = Some(a); - // } - // // here, you would *think* that the - // // *entirety* of `x` would be borrowed, - // // but in fact only the `Ok` variant is, - // // so the `Err` variant is *entirely free*: - // if let Err(ref mut a) = *x { - // v = Some(a); - // } - // drop(v); - // } - // ``` - if v1 == v2 { - debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD"); - Overlap::EqualOrDisjoint - } else { - debug!("place_element_conflict: DISJOINT-FIELD"); - Overlap::Disjoint - } - } - ( - ProjectionElem::Index(..), - ProjectionElem::Index(..) - | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. }, - ) - | ( - ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. }, - ProjectionElem::Index(..), - ) => { - // Array indexes (`a[0]` vs. `a[i]`). These can either be disjoint - // (if the indexes differ) or equal (if they are the same). - match bias { - PlaceConflictBias::Overlap => { - // If we are biased towards overlapping, then this is the recursive - // case that gives "equal *or* disjoint" its meaning. - debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-INDEX"); - Overlap::EqualOrDisjoint - } - PlaceConflictBias::NoOverlap => { - // If we are biased towards no overlapping, then this is disjoint. - debug!("place_element_conflict: DISJOINT-ARRAY-INDEX"); - Overlap::Disjoint - } - } - } - ( - ProjectionElem::ConstantIndex { offset: o1, min_length: _, from_end: false }, - ProjectionElem::ConstantIndex { offset: o2, min_length: _, from_end: false }, - ) - | ( - ProjectionElem::ConstantIndex { offset: o1, min_length: _, from_end: true }, - ProjectionElem::ConstantIndex { offset: o2, min_length: _, from_end: true }, - ) => { - if o1 == o2 { - debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX"); - Overlap::EqualOrDisjoint - } else { - debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX"); - Overlap::Disjoint - } - } - ( - ProjectionElem::ConstantIndex { - offset: offset_from_begin, - min_length: min_length1, - from_end: false, - }, - ProjectionElem::ConstantIndex { - offset: offset_from_end, - min_length: min_length2, - from_end: true, - }, - ) - | ( - ProjectionElem::ConstantIndex { - offset: offset_from_end, - min_length: min_length1, - from_end: true, - }, - ProjectionElem::ConstantIndex { - offset: offset_from_begin, - min_length: min_length2, - from_end: false, - }, - ) => { - // both patterns matched so it must be at least the greater of the two - let min_length = max(min_length1, min_length2); - // `offset_from_end` can be in range `[1..min_length]`, 1 indicates the last - // element (like -1 in Python) and `min_length` the first. - // Therefore, `min_length - offset_from_end` gives the minimal possible - // offset from the beginning - if offset_from_begin >= min_length - offset_from_end { - debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-FE"); - Overlap::EqualOrDisjoint - } else { - debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-FE"); - Overlap::Disjoint - } - } - ( - ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }, - ProjectionElem::Subslice { from, to, from_end: false }, - ) - | ( - ProjectionElem::Subslice { from, to, from_end: false }, - ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }, - ) => { - if (from..to).contains(&offset) { - debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE"); - Overlap::EqualOrDisjoint - } else { - debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE"); - Overlap::Disjoint - } - } - ( - ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }, - ProjectionElem::Subslice { from, .. }, - ) - | ( - ProjectionElem::Subslice { from, .. }, - ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }, - ) => { - if offset >= from { - debug!("place_element_conflict: DISJOINT-OR-EQ-SLICE-CONSTANT-INDEX-SUBSLICE"); - Overlap::EqualOrDisjoint - } else { - debug!("place_element_conflict: DISJOINT-SLICE-CONSTANT-INDEX-SUBSLICE"); - Overlap::Disjoint - } - } - ( - ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true }, - ProjectionElem::Subslice { to, from_end: true, .. }, - ) - | ( - ProjectionElem::Subslice { to, from_end: true, .. }, - ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true }, - ) => { - if offset > to { - debug!( - "place_element_conflict: \ +use crate::ArtificialField;use crate::Overlap;use crate::{AccessDepth,Deep,//(); +Shallow};use rustc_hir as hir;use rustc_middle::mir::{Body,BorrowKind,//((),()); +MutBorrowKind,Place,PlaceElem,PlaceRef,ProjectionElem ,};use rustc_middle::ty::{ +self,TyCtxt};use std::cmp::max;use std::iter;#[derive(Copy,Clone,Debug,Eq,//{;}; +PartialEq)]pub enum PlaceConflictBias{ Overlap,NoOverlap,}pub fn places_conflict +<'tcx>(tcx:TyCtxt<'tcx>,body:& Body<'tcx>,borrow_place:Place<'tcx>,access_place: +Place<'tcx>,bias:PlaceConflictBias, )->bool{borrow_conflicts_with_place(tcx,body +,borrow_place,BorrowKind::Mut{kind :MutBorrowKind::TwoPhaseBorrow},access_place. +as_ref(),AccessDepth::Deep,bias,)}#[inline]pub(super)fn//let _=||();loop{break}; +borrow_conflicts_with_place<'tcx>(tcx:TyCtxt<'tcx>,body:&Body<'tcx>,//if true{}; +borrow_place:Place<'tcx>,borrow_kind:BorrowKind,access_place:PlaceRef<'tcx>,//3; +access:AccessDepth,bias:PlaceConflictBias,)->bool{;let borrow_local=borrow_place +.local;;let access_local=access_place.local;if borrow_local!=access_local{return +false;3;}if borrow_place.projection.is_empty()&&access_place.projection.is_empty +(){3;return true;3;}place_components_conflict(tcx,body,borrow_place,borrow_kind, +access_place,access,bias)}#[instrument(level="debug",skip(tcx,body))]fn//*&*&(); +place_components_conflict<'tcx>(tcx:TyCtxt<'tcx> ,body:&Body<'tcx>,borrow_place: +Place<'tcx>,borrow_kind:BorrowKind,access_place:PlaceRef<'tcx>,access://((),()); +AccessDepth,bias:PlaceConflictBias,)->bool{;let borrow_local=borrow_place.local; +let access_local=access_place.local;;assert_eq!(borrow_local,access_local);for(( +borrow_place,borrow_c),&access_c)in iter::zip((borrow_place.iter_projections()), +access_place.projection){let _=||();debug!(?borrow_c,?access_c);if true{};match +place_projection_conflict(tcx,body,borrow_place, borrow_c,access_c,bias){Overlap +::Arbitrary=>{();debug!("arbitrary -> conflict");();();return true;();}Overlap:: +EqualOrDisjoint=>{}Overlap::Disjoint=>{;debug!("disjoint");;;return false;}}}if +borrow_place.projection.len()>(access_place.projection.len ()){for(base,elem)in +borrow_place.iter_projections().skip(access_place.projection.len()){;let base_ty +=base.ty(body,tcx).ty;({});match(elem,&base_ty.kind(),access){(_,_,Shallow(Some( +ArtificialField::ArrayLength)))|(_, _,Shallow(Some(ArtificialField::FakeBorrow)) +)=>{3;debug!("borrow_conflicts_with_place: implicit field");3;3;return false;;}( +ProjectionElem::Deref,_,Shallow(None))=>{((),());((),());((),());((),());debug!( +"borrow_conflicts_with_place: shallow access behind ptr");();3;return false;3;}( +ProjectionElem::Deref,ty::Ref(_,_,hir::Mutability::Not),_)=>{if let _=(){};bug!( +"Tracking borrow behind shared reference.");;}(ProjectionElem::Deref,ty::Ref(_,_ +,hir::Mutability::Mut),AccessDepth::Drop)=>{if let _=(){};*&*&();((),());debug!( +"borrow_conflicts_with_place: drop access behind ptr");{;};();return false;();}( +ProjectionElem::Field{..},ty::Adt(def,_),AccessDepth::Drop)=>{if def.has_dtor(// +tcx){();return true;3;}}(ProjectionElem::Deref,_,Deep)|(ProjectionElem::Deref,_, +AccessDepth::Drop)|(ProjectionElem::Field{..}, _,_)|(ProjectionElem::Index{..},_ +,_)|(ProjectionElem::ConstantIndex{..},_,_ )|(ProjectionElem::Subslice{..},_,_)| +(ProjectionElem::OpaqueCast{..},_,_)|(ProjectionElem::Subtype(_),_,_)|(//*&*&(); +ProjectionElem::Downcast{..},_,_)=>{}}}}if (((borrow_kind==BorrowKind::Fake)))&& +borrow_place.projection.len()(tcx:TyCtxt<'tcx>, body:&Body<'tcx>,pi1:PlaceRef< +'tcx>,pi1_elem:PlaceElem<'tcx>, pi2_elem:PlaceElem<'tcx>,bias:PlaceConflictBias, +)->Overlap{match(((pi1_elem,pi2_elem ))){(ProjectionElem::Deref,ProjectionElem:: +Deref)=>{{;};debug!("place_element_conflict: DISJOINT-OR-EQ-DEREF");();Overlap:: +EqualOrDisjoint}(ProjectionElem::OpaqueCast(_) ,ProjectionElem::OpaqueCast(_))=> +{*&*&();debug!("place_element_conflict: DISJOINT-OR-EQ-OPAQUE");*&*&();Overlap:: +EqualOrDisjoint}(ProjectionElem::Field(f1,_),ProjectionElem ::Field(f2,_))=>{if +f1==f2{({});debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD");{;};Overlap:: +EqualOrDisjoint}else{();let ty=pi1.ty(body,tcx).ty;();if ty.is_union(){3;debug!( +"place_element_conflict: STUCK-UNION");({});Overlap::Arbitrary}else{({});debug!( +"place_element_conflict: DISJOINT-FIELD");;Overlap::Disjoint}}}(ProjectionElem:: +Downcast(_,v1),ProjectionElem::Downcast(_,v2))=>{if v1==v2{if let _=(){};debug!( +"place_element_conflict: DISJOINT-OR-EQ-FIELD");;Overlap::EqualOrDisjoint}else{; +debug!("place_element_conflict: DISJOINT-FIELD");let _=||();Overlap::Disjoint}}( +ProjectionElem::Index(..),ProjectionElem::Index(..)|ProjectionElem:://if true{}; +ConstantIndex{..}|ProjectionElem::Subslice{ ..},)|(ProjectionElem::ConstantIndex +{..}|ProjectionElem::Subslice{..},ProjectionElem::Index(..),)=>{match bias{//(); +PlaceConflictBias::Overlap=>{let _=||();let _=||();let _=||();let _=||();debug!( +"place_element_conflict: DISJOINT-OR-EQ-ARRAY-INDEX");;Overlap::EqualOrDisjoint} +PlaceConflictBias::NoOverlap=>{if true{};let _=||();if true{};let _=||();debug!( +"place_element_conflict: DISJOINT-ARRAY-INDEX");let _=||();Overlap::Disjoint}}}( +ProjectionElem::ConstantIndex{offset:o1,min_length:_,from_end:false},//let _=(); +ProjectionElem::ConstantIndex{offset:o2,min_length:_,from_end:false},)|(//{();}; +ProjectionElem::ConstantIndex{offset:o1,min_length:_,from_end:true},//if true{}; +ProjectionElem::ConstantIndex{offset:o2,min_length:_, from_end:true},)=>{if o1== +o2{{;};debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX");(); +Overlap::EqualOrDisjoint}else{if true{};let _=||();let _=||();let _=||();debug!( +"place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX");();Overlap::Disjoint}}( +ProjectionElem::ConstantIndex{offset:offset_from_begin,min_length:min_length1,// +from_end:false,},ProjectionElem::ConstantIndex{offset:offset_from_end,//((),()); +min_length:min_length2,from_end:true,} ,)|(ProjectionElem::ConstantIndex{offset: +offset_from_end,min_length:min_length1,from_end:true,},ProjectionElem:://*&*&(); +ConstantIndex{offset:offset_from_begin,min_length: min_length2,from_end:false,}, +)=>{({});let min_length=max(min_length1,min_length2);({});if offset_from_begin>= +min_length-offset_from_end{let _=||();loop{break};let _=||();loop{break};debug!( +"place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-FE");({});Overlap:: +EqualOrDisjoint}else{loop{break;};loop{break;};loop{break;};loop{break;};debug!( +"place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-FE");;Overlap::Disjoint}} +(ProjectionElem::ConstantIndex{offset,min_length:_,from_end:false},//let _=||(); +ProjectionElem::Subslice{from,to,from_end:false},)|(ProjectionElem::Subslice{//; +from,to,from_end:false},ProjectionElem::ConstantIndex{offset,min_length:_,//{;}; +from_end:false},)=>{if(from..to).contains(&offset){let _=||();let _=||();debug!( +"place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE");;Overlap +::EqualOrDisjoint}else{loop{break};loop{break;};loop{break};loop{break;};debug!( +"place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE");({});Overlap:: +Disjoint}}(ProjectionElem::ConstantIndex{offset,min_length:_,from_end:false},//; +ProjectionElem::Subslice{from,..},)|(ProjectionElem::Subslice{from,..},//*&*&(); +ProjectionElem::ConstantIndex{offset,min_length:_,from_end :false},)=>{if offset +>=from{((),());((),());((),());let _=();((),());((),());((),());let _=();debug!( +"place_element_conflict: DISJOINT-OR-EQ-SLICE-CONSTANT-INDEX-SUBSLICE");;Overlap +::EqualOrDisjoint}else{loop{break};loop{break;};loop{break};loop{break;};debug!( +"place_element_conflict: DISJOINT-SLICE-CONSTANT-INDEX-SUBSLICE");({});Overlap:: +Disjoint}}(ProjectionElem::ConstantIndex{offset,min_length:_,from_end:true},//3; +ProjectionElem::Subslice{to,from_end:true,..},)|(ProjectionElem::Subslice{to,//; +from_end:true,..},ProjectionElem::ConstantIndex{offset,min_length:_,from_end://; +true},)=>{if offset>to{loop{break};loop{break;};loop{break};loop{break;};debug!( +"place_element_conflict: \ DISJOINT-OR-EQ-SLICE-CONSTANT-INDEX-SUBSLICE-FE" - ); - Overlap::EqualOrDisjoint - } else { - debug!("place_element_conflict: DISJOINT-SLICE-CONSTANT-INDEX-SUBSLICE-FE"); - Overlap::Disjoint - } - } - ( - ProjectionElem::Subslice { from: f1, to: t1, from_end: false }, - ProjectionElem::Subslice { from: f2, to: t2, from_end: false }, - ) => { - if f2 >= t1 || f1 >= t2 { - debug!("place_element_conflict: DISJOINT-ARRAY-SUBSLICES"); - Overlap::Disjoint - } else { - debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-SUBSLICES"); - Overlap::EqualOrDisjoint - } - } - (ProjectionElem::Subslice { .. }, ProjectionElem::Subslice { .. }) => { - debug!("place_element_conflict: DISJOINT-OR-EQ-SLICE-SUBSLICES"); - Overlap::EqualOrDisjoint - } - ( - ProjectionElem::Deref - | ProjectionElem::Field(..) - | ProjectionElem::Index(..) - | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subtype(_) - | ProjectionElem::OpaqueCast { .. } - | ProjectionElem::Subslice { .. } - | ProjectionElem::Downcast(..), - _, - ) => bug!( - "mismatched projections in place_element_conflict: {:?} and {:?}", - pi1_elem, - pi2_elem - ), - } -} +);if true{};let _=||();Overlap::EqualOrDisjoint}else{if true{};if true{};debug!( +"place_element_conflict: DISJOINT-SLICE-CONSTANT-INDEX-SUBSLICE-FE");3;Overlap:: +Disjoint}}(ProjectionElem::Subslice{from:f1,to:t1,from_end:false},//loop{break}; +ProjectionElem::Subslice{from:f2,to:t2,from_end:false},)=>{if f2>=t1||f1>=t2{(); +debug!("place_element_conflict: DISJOINT-ARRAY-SUBSLICES");();Overlap::Disjoint} +else{;debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-SUBSLICES");Overlap:: +EqualOrDisjoint}}(ProjectionElem::Subslice{..},ProjectionElem::Subslice{..})=>{; +debug!("place_element_conflict: DISJOINT-OR-EQ-SLICE-SUBSLICES");{();};Overlap:: +EqualOrDisjoint}(ProjectionElem::Deref| ProjectionElem::Field(..)|ProjectionElem +::Index(..)|ProjectionElem::ConstantIndex{..}|ProjectionElem::Subtype(_)|//({}); +ProjectionElem::OpaqueCast{..}|ProjectionElem::Subslice{..}|ProjectionElem:://3; +Downcast(..),_,)=>bug!(//loop{break;};if let _=(){};if let _=(){};if let _=(){}; +"mismatched projections in place_element_conflict: {:?} and {:?}",pi1_elem,//(); +pi2_elem),}}//((),());((),());((),());let _=();((),());((),());((),());let _=(); diff --git a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs index 956de1dec9b2b..3d881a077ff43 100644 --- a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs +++ b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs @@ -1,422 +1,118 @@ -use rustc_data_structures::graph::dominators::Dominators; -use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{self, BasicBlock, Body, Location, NonDivergingIntrinsic, Place, Rvalue}; -use rustc_middle::mir::{BorrowKind, Mutability, Operand}; -use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind}; -use rustc_middle::mir::{Statement, StatementKind}; -use rustc_middle::ty::TyCtxt; - -use crate::{ - borrow_set::BorrowSet, facts::AllFacts, location::LocationTable, path_utils::*, AccessDepth, - Activation, ArtificialField, BorrowIndex, Deep, LocalMutationIsAllowed, Read, ReadKind, - ReadOrWrite, Reservation, Shallow, Write, WriteKind, -}; - -/// Emit `loan_invalidated_at` facts. -pub(super) fn emit_loan_invalidations<'tcx>( - tcx: TyCtxt<'tcx>, - all_facts: &mut AllFacts, - location_table: &LocationTable, - body: &Body<'tcx>, - borrow_set: &BorrowSet<'tcx>, -) { - let dominators = body.basic_blocks.dominators(); - let mut visitor = - LoanInvalidationsGenerator { all_facts, borrow_set, tcx, location_table, body, dominators }; - visitor.visit_body(body); -} - -struct LoanInvalidationsGenerator<'cx, 'tcx> { - tcx: TyCtxt<'tcx>, - all_facts: &'cx mut AllFacts, - location_table: &'cx LocationTable, - body: &'cx Body<'tcx>, - dominators: &'cx Dominators, - borrow_set: &'cx BorrowSet<'tcx>, -} - -/// Visits the whole MIR and generates `invalidates()` facts. -/// Most of the code implementing this was stolen from `borrow_check/mod.rs`. -impl<'cx, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'cx, 'tcx> { - fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { - self.check_activations(location); - - match &statement.kind { - StatementKind::Assign(box (lhs, rhs)) => { - self.consume_rvalue(location, rhs); - - self.mutate_place(location, *lhs, Shallow(None)); - } - StatementKind::FakeRead(box (_, _)) => { - // Only relevant for initialized/liveness/safety checks. - } - StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => { - self.consume_operand(location, op); - } - StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping { - src, - dst, - count, - })) => { - self.consume_operand(location, src); - self.consume_operand(location, dst); - self.consume_operand(location, count); - } - // Only relevant for mir typeck - StatementKind::AscribeUserType(..) - // Only relevant for liveness and unsafeck - | StatementKind::PlaceMention(..) - // Doesn't have any language semantics - | StatementKind::Coverage(..) - // Does not actually affect borrowck - | StatementKind::StorageLive(..) => {} - StatementKind::StorageDead(local) => { - self.access_place( - location, - Place::from(*local), - (Shallow(None), Write(WriteKind::StorageDeadOrDrop)), - LocalMutationIsAllowed::Yes, - ); - } - StatementKind::ConstEvalCounter - | StatementKind::Nop - | StatementKind::Retag { .. } - | StatementKind::Deinit(..) - | StatementKind::SetDiscriminant { .. } => { - bug!("Statement not allowed in this MIR phase") - } - } - - self.super_statement(statement, location); - } - - fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { - self.check_activations(location); - - match &terminator.kind { - TerminatorKind::SwitchInt { discr, targets: _ } => { - self.consume_operand(location, discr); - } - TerminatorKind::Drop { place: drop_place, target: _, unwind: _, replace } => { - let write_kind = - if *replace { WriteKind::Replace } else { WriteKind::StorageDeadOrDrop }; - self.access_place( - location, - *drop_place, - (AccessDepth::Drop, Write(write_kind)), - LocalMutationIsAllowed::Yes, - ); - } - TerminatorKind::Call { - func, - args, - destination, - target: _, - unwind: _, - call_source: _, - fn_span: _, - } => { - self.consume_operand(location, func); - for arg in args { - self.consume_operand(location, &arg.node); - } - self.mutate_place(location, *destination, Deep); - } - TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => { - self.consume_operand(location, cond); - use rustc_middle::mir::AssertKind; - if let AssertKind::BoundsCheck { len, index } = &**msg { - self.consume_operand(location, len); - self.consume_operand(location, index); - } - } - TerminatorKind::Yield { value, resume, resume_arg, drop: _ } => { - self.consume_operand(location, value); - - // Invalidate all borrows of local places - let borrow_set = self.borrow_set; - let resume = self.location_table.start_index(resume.start_location()); - for (i, data) in borrow_set.iter_enumerated() { - if borrow_of_local_data(data.borrowed_place) { - self.all_facts.loan_invalidated_at.push((resume, i)); - } - } - - self.mutate_place(location, *resume_arg, Deep); - } - TerminatorKind::UnwindResume - | TerminatorKind::Return - | TerminatorKind::CoroutineDrop => { - // Invalidate all borrows of local places - let borrow_set = self.borrow_set; - let start = self.location_table.start_index(location); - for (i, data) in borrow_set.iter_enumerated() { - if borrow_of_local_data(data.borrowed_place) { - self.all_facts.loan_invalidated_at.push((start, i)); - } - } - } - TerminatorKind::InlineAsm { - template: _, - operands, - options: _, - line_spans: _, - targets: _, - unwind: _, - } => { - for op in operands { - match op { - InlineAsmOperand::In { reg: _, value } => { - self.consume_operand(location, value); - } - InlineAsmOperand::Out { reg: _, late: _, place, .. } => { - if let &Some(place) = place { - self.mutate_place(location, place, Shallow(None)); - } - } - InlineAsmOperand::InOut { reg: _, late: _, in_value, out_place } => { - self.consume_operand(location, in_value); - if let &Some(out_place) = out_place { - self.mutate_place(location, out_place, Shallow(None)); - } - } - InlineAsmOperand::Const { value: _ } - | InlineAsmOperand::SymFn { value: _ } - | InlineAsmOperand::SymStatic { def_id: _ } - | InlineAsmOperand::Label { target_index: _ } => {} - } - } - } - TerminatorKind::Goto { target: _ } - | TerminatorKind::UnwindTerminate(_) - | TerminatorKind::Unreachable - | TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ } - | TerminatorKind::FalseUnwind { real_target: _, unwind: _ } => { - // no data used, thus irrelevant to borrowck - } - } - - self.super_terminator(terminator, location); - } -} - -impl<'cx, 'tcx> LoanInvalidationsGenerator<'cx, 'tcx> { - /// Simulates mutation of a place. - fn mutate_place(&mut self, location: Location, place: Place<'tcx>, kind: AccessDepth) { - self.access_place( - location, - place, - (kind, Write(WriteKind::Mutate)), - LocalMutationIsAllowed::ExceptUpvars, - ); - } - - /// Simulates consumption of an operand. - fn consume_operand(&mut self, location: Location, operand: &Operand<'tcx>) { - match *operand { - Operand::Copy(place) => { - self.access_place( - location, - place, - (Deep, Read(ReadKind::Copy)), - LocalMutationIsAllowed::No, - ); - } - Operand::Move(place) => { - self.access_place( - location, - place, - (Deep, Write(WriteKind::Move)), - LocalMutationIsAllowed::Yes, - ); - } - Operand::Constant(_) => {} - } - } - - // Simulates consumption of an rvalue - fn consume_rvalue(&mut self, location: Location, rvalue: &Rvalue<'tcx>) { - match rvalue { - &Rvalue::Ref(_ /*rgn*/, bk, place) => { - let access_kind = match bk { - BorrowKind::Fake => { - (Shallow(Some(ArtificialField::FakeBorrow)), Read(ReadKind::Borrow(bk))) - } - BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))), - BorrowKind::Mut { .. } => { - let wk = WriteKind::MutableBorrow(bk); - if allow_two_phase_borrow(bk) { - (Deep, Reservation(wk)) - } else { - (Deep, Write(wk)) - } - } - }; - - self.access_place(location, place, access_kind, LocalMutationIsAllowed::No); - } - - &Rvalue::AddressOf(mutability, place) => { - let access_kind = match mutability { - Mutability::Mut => ( - Deep, - Write(WriteKind::MutableBorrow(BorrowKind::Mut { - kind: mir::MutBorrowKind::Default, - })), - ), - Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))), - }; - - self.access_place(location, place, access_kind, LocalMutationIsAllowed::No); - } - - Rvalue::ThreadLocalRef(_) => {} - - Rvalue::Use(operand) - | Rvalue::Repeat(operand, _) - | Rvalue::UnaryOp(_ /*un_op*/, operand) - | Rvalue::Cast(_ /*cast_kind*/, operand, _ /*ty*/) - | Rvalue::ShallowInitBox(operand, _ /*ty*/) => self.consume_operand(location, operand), - - &Rvalue::CopyForDeref(place) => { - let op = &Operand::Copy(place); - self.consume_operand(location, op); - } - - &(Rvalue::Len(place) | Rvalue::Discriminant(place)) => { - let af = match rvalue { - Rvalue::Len(..) => Some(ArtificialField::ArrayLength), - Rvalue::Discriminant(..) => None, - _ => unreachable!(), - }; - self.access_place( - location, - place, - (Shallow(af), Read(ReadKind::Copy)), - LocalMutationIsAllowed::No, - ); - } - - Rvalue::BinaryOp(_bin_op, box (operand1, operand2)) - | Rvalue::CheckedBinaryOp(_bin_op, box (operand1, operand2)) => { - self.consume_operand(location, operand1); - self.consume_operand(location, operand2); - } - - Rvalue::NullaryOp(_op, _ty) => {} - - Rvalue::Aggregate(_, operands) => { - for operand in operands { - self.consume_operand(location, operand); - } - } - } - } - - /// Simulates an access to a place. - fn access_place( - &mut self, - location: Location, - place: Place<'tcx>, - kind: (AccessDepth, ReadOrWrite), - _is_local_mutation_allowed: LocalMutationIsAllowed, - ) { - let (sd, rw) = kind; - // note: not doing check_access_permissions checks because they don't generate invalidates - self.check_access_for_conflict(location, place, sd, rw); - } - - fn check_access_for_conflict( - &mut self, - location: Location, - place: Place<'tcx>, - sd: AccessDepth, - rw: ReadOrWrite, - ) { - debug!( - "check_access_for_conflict(location={:?}, place={:?}, sd={:?}, rw={:?})", - location, place, sd, rw, - ); - each_borrow_involving_path( - self, - self.tcx, - self.body, - (sd, place), - self.borrow_set, - |_| true, - |this, borrow_index, borrow| { - match (rw, borrow.kind) { - // Obviously an activation is compatible with its own - // reservation (or even prior activating uses of same - // borrow); so don't check if they interfere. - // - // NOTE: *reservations* do conflict with themselves; - // thus aren't injecting unsoundness w/ this check.) - (Activation(_, activating), _) if activating == borrow_index => { - // Activating a borrow doesn't generate any invalidations, since we - // have already taken the reservation - } - - (Read(_), BorrowKind::Fake | BorrowKind::Shared) - | (Read(ReadKind::Borrow(BorrowKind::Fake)), BorrowKind::Mut { .. }) => { - // Reads don't invalidate shared or shallow borrows - } - - (Read(_), BorrowKind::Mut { .. }) => { - // Reading from mere reservations of mutable-borrows is OK. - if !is_active(this.dominators, borrow, location) { - // If the borrow isn't active yet, reads don't invalidate it - assert!(allow_two_phase_borrow(borrow.kind)); - return Control::Continue; - } - - // Unique and mutable borrows are invalidated by reads from any - // involved path - this.emit_loan_invalidated_at(borrow_index, location); - } - - (Reservation(_) | Activation(_, _) | Write(_), _) => { - // unique or mutable borrows are invalidated by writes. - // Reservations count as writes since we need to check - // that activating the borrow will be OK - // FIXME(bob_twinkles) is this actually the right thing to do? - this.emit_loan_invalidated_at(borrow_index, location); - } - } - Control::Continue - }, - ); - } - - /// Generates a new `loan_invalidated_at(L, B)` fact. - fn emit_loan_invalidated_at(&mut self, b: BorrowIndex, l: Location) { - let lidx = self.location_table.start_index(l); - self.all_facts.loan_invalidated_at.push((lidx, b)); - } - - fn check_activations(&mut self, location: Location) { - // Two-phase borrow support: For each activation that is newly - // generated at this statement, check if it interferes with - // another borrow. - for &borrow_index in self.borrow_set.activations_at_location(location) { - let borrow = &self.borrow_set[borrow_index]; - - // only mutable borrows should be 2-phase - assert!(match borrow.kind { - BorrowKind::Shared | BorrowKind::Fake => false, - BorrowKind::Mut { .. } => true, - }); - - self.access_place( - location, - borrow.borrowed_place, - (Deep, Activation(WriteKind::MutableBorrow(borrow.kind), borrow_index)), - LocalMutationIsAllowed::No, - ); - - // We do not need to call `check_if_path_or_subpath_is_moved` - // again, as we already called it when we made the - // initial reservation. - } - } -} +use rustc_data_structures::graph::dominators::Dominators;use rustc_middle::mir// +::visit::Visitor;use rustc_middle::mir::{self,BasicBlock,Body,Location,//*&*&(); +NonDivergingIntrinsic,Place,Rvalue};use rustc_middle::mir::{BorrowKind,//*&*&(); +Mutability,Operand};use rustc_middle::mir::{InlineAsmOperand,Terminator,//{();}; +TerminatorKind};use rustc_middle::mir::{Statement,StatementKind};use//if true{}; +rustc_middle::ty::TyCtxt;use crate::{borrow_set::BorrowSet,facts::AllFacts,//(); +location::LocationTable,path_utils::*,AccessDepth,Activation,ArtificialField,//; +BorrowIndex,Deep,LocalMutationIsAllowed,Read,ReadKind,ReadOrWrite,Reservation,// +Shallow,Write,WriteKind,};pub(super )fn emit_loan_invalidations<'tcx>(tcx:TyCtxt +<'tcx>,all_facts:&mut AllFacts,location_table:&LocationTable,body:&Body<'tcx>,// +borrow_set:&BorrowSet<'tcx>,){;let dominators=body.basic_blocks.dominators();let +mut visitor=LoanInvalidationsGenerator{all_facts,borrow_set,tcx,location_table// +,body,dominators};;;visitor.visit_body(body);}struct LoanInvalidationsGenerator< +'cx,'tcx>{tcx:TyCtxt<'tcx>,all_facts:&'cx mut AllFacts,location_table:&'cx//{;}; +LocationTable,body:&'cx Body<'tcx>,dominators:&'cx Dominators,//{;}; +borrow_set:&'cx BorrowSet<'tcx>,}impl<'cx,'tcx>Visitor<'tcx>for//*&*&();((),()); +LoanInvalidationsGenerator<'cx,'tcx>{fn visit_statement(&mut self,statement:&//; +Statement<'tcx>,location:Location){();self.check_activations(location);();match& +statement.kind{StatementKind::Assign(box(lhs,rhs))=>{*&*&();self.consume_rvalue( +location,rhs);;;self.mutate_place(location,*lhs,Shallow(None));;}StatementKind:: +FakeRead(box(_,_))=>{}StatementKind::Intrinsic(box NonDivergingIntrinsic:://{;}; +Assume(op))=>{3;self.consume_operand(location,op);;}StatementKind::Intrinsic(box +NonDivergingIntrinsic::CopyNonOverlapping(mir:: CopyNonOverlapping{src,dst,count +,}))=>{;self.consume_operand(location,src);;;self.consume_operand(location,dst); +self.consume_operand(location,count);*&*&();}StatementKind::AscribeUserType(..)| +StatementKind::PlaceMention(..)|StatementKind::Coverage(..)|StatementKind:://(); +StorageLive(..)=>{}StatementKind::StorageDead(local)=>{*&*&();self.access_place( +location,Place::from(*local), (Shallow(None),Write(WriteKind::StorageDeadOrDrop) +),LocalMutationIsAllowed::Yes,);3;}StatementKind::ConstEvalCounter|StatementKind +::Nop|StatementKind::Retag{..}|StatementKind::Deinit(..)|StatementKind:://{();}; +SetDiscriminant{..}=>{bug!("Statement not allowed in this MIR phase")}}{;};self. +super_statement(statement,location);;}fn visit_terminator(&mut self,terminator:& +Terminator<'tcx>,location:Location){();self.check_activations(location);3;match& +terminator.kind{TerminatorKind::SwitchInt{discr,targets:_}=>{if let _=(){};self. +consume_operand(location,discr);;}TerminatorKind::Drop{place:drop_place,target:_ +,unwind:_,replace}=>{let _=();let write_kind=if*replace{WriteKind::Replace}else{ +WriteKind::StorageDeadOrDrop};({});({});self.access_place(location,*drop_place,( +AccessDepth::Drop,Write(write_kind)),LocalMutationIsAllowed::Yes,);loop{break};} +TerminatorKind::Call{func,args,destination,target:_,unwind:_,call_source:_,//(); +fn_span:_,}=>{();self.consume_operand(location,func);();for arg in args{();self. +consume_operand(location,&arg.node);3;};self.mutate_place(location,*destination, +Deep);3;}TerminatorKind::Assert{cond,expected:_,msg,target:_,unwind:_}=>{3;self. +consume_operand(location,cond);();();use rustc_middle::mir::AssertKind;();if let +AssertKind::BoundsCheck{len,index}=&**msg{;self.consume_operand(location,len);;; +self.consume_operand(location,index);{();};}}TerminatorKind::Yield{value,resume, +resume_arg,drop:_}=>{;self.consume_operand(location,value);;let borrow_set=self. +borrow_set;;let resume=self.location_table.start_index(resume.start_location()); +for(i,data)in ((((borrow_set.iter_enumerated())))){if borrow_of_local_data(data. +borrowed_place){3;self.all_facts.loan_invalidated_at.push((resume,i));3;}};self. +mutate_place(location,*resume_arg,Deep);if true{};}TerminatorKind::UnwindResume| +TerminatorKind::Return|TerminatorKind::CoroutineDrop=>{({});let borrow_set=self. +borrow_set;;;let start=self.location_table.start_index(location);;for(i,data)in +borrow_set.iter_enumerated(){if borrow_of_local_data(data.borrowed_place){;self. +all_facts.loan_invalidated_at.push((start,i));({});}}}TerminatorKind::InlineAsm{ +template:_,operands,options:_,line_spans:_,targets:_,unwind:_,}=>{for op in//(); +operands{match op{InlineAsmOperand::In{reg:_,value}=>{({});self.consume_operand( +location,value);{;};}InlineAsmOperand::Out{reg:_,late:_,place,..}=>{if let&Some( +place)=place{;self.mutate_place(location,place,Shallow(None));}}InlineAsmOperand +::InOut{reg:_,late:_,in_value,out_place}=>{*&*&();self.consume_operand(location, +in_value);;if let&Some(out_place)=out_place{self.mutate_place(location,out_place +,Shallow(None));({});}}InlineAsmOperand::Const{value:_}|InlineAsmOperand::SymFn{ +value:_}|InlineAsmOperand::SymStatic{def_id:_}|InlineAsmOperand::Label{//*&*&(); +target_index:_}=>{}}}}TerminatorKind::Goto{target:_}|TerminatorKind:://let _=(); +UnwindTerminate(_)|TerminatorKind::Unreachable|TerminatorKind::FalseEdge{//({}); +real_target:_,imaginary_target:_}|TerminatorKind::FalseUnwind{real_target:_,//3; +unwind:_}=>{}}{;};self.super_terminator(terminator,location);();}}impl<'cx,'tcx> +LoanInvalidationsGenerator<'cx,'tcx>{fn mutate_place(&mut self,location://{();}; +Location,place:Place<'tcx>,kind:AccessDepth){;self.access_place(location,place,( +kind,Write(WriteKind::Mutate)),LocalMutationIsAllowed::ExceptUpvars,);*&*&();}fn +consume_operand(&mut self,location:Location,operand:&Operand<'tcx>){match*//{;}; +operand{Operand::Copy(place)=>{({});self.access_place(location,place,(Deep,Read( +ReadKind::Copy)),LocalMutationIsAllowed::No,);();}Operand::Move(place)=>{3;self. +access_place(location,place,(((((((Deep,(((((Write(WriteKind::Move))))))))))))), +LocalMutationIsAllowed::Yes,);;}Operand::Constant(_)=>{}}}fn consume_rvalue(&mut +self,location:Location,rvalue:&Rvalue<'tcx>){match rvalue{&Rvalue::Ref(_,bk,//3; +place)=>{loop{break;};let access_kind=match bk{BorrowKind::Fake=>{(Shallow(Some( +ArtificialField::FakeBorrow)),Read(ReadKind::Borrow (bk)))}BorrowKind::Shared=>( +Deep,Read(ReadKind::Borrow(bk))),BorrowKind::Mut{..}=>{*&*&();let wk=WriteKind:: +MutableBorrow(bk);();if allow_two_phase_borrow(bk){(Deep,Reservation(wk))}else{( +Deep,Write(wk))}}};((),());((),());self.access_place(location,place,access_kind, +LocalMutationIsAllowed::No);({});}&Rvalue::AddressOf(mutability,place)=>{{;};let +access_kind=match mutability{Mutability::Mut=>(Deep,Write(WriteKind:://let _=(); +MutableBorrow(BorrowKind::Mut{kind:mir::MutBorrowKind:: Default,})),),Mutability +::Not=>(Deep,Read(ReadKind::Borrow(BorrowKind::Shared))),};3;;self.access_place( +location,place,access_kind,LocalMutationIsAllowed::No);;}Rvalue::ThreadLocalRef( +_)=>{}Rvalue::Use(operand)|Rvalue:: Repeat(operand,_)|Rvalue::UnaryOp(_,operand) +|Rvalue::Cast(_,operand,_)|Rvalue::ShallowInitBox(operand,_)=>self.//let _=||(); +consume_operand(location,operand),&Rvalue::CopyForDeref(place)=>{*&*&();let op=& +Operand::Copy(place);;;self.consume_operand(location,op);;}&(Rvalue::Len(place)| +Rvalue::Discriminant(place))=>{*&*&();let af=match rvalue{Rvalue::Len(..)=>Some( +ArtificialField::ArrayLength),Rvalue::Discriminant(..) =>None,_=>unreachable!(), +};({});({});self.access_place(location,place,(Shallow(af),Read(ReadKind::Copy)), +LocalMutationIsAllowed::No,);;}Rvalue::BinaryOp(_bin_op,box(operand1,operand2))| +Rvalue::CheckedBinaryOp(_bin_op,box(operand1,operand2))=>{;self.consume_operand( +location,operand1);;;self.consume_operand(location,operand2);}Rvalue::NullaryOp( +_op,_ty)=>{}Rvalue::Aggregate(_,operands)=>{for operand in operands{*&*&();self. +consume_operand(location,operand);*&*&();}}}}fn access_place(&mut self,location: +Location,place:Place<'tcx>,kind:(AccessDepth,ReadOrWrite),//if true{};if true{}; +_is_local_mutation_allowed:LocalMutationIsAllowed,){();let(sd,rw)=kind;3;3;self. +check_access_for_conflict(location,place,sd,rw);;}fn check_access_for_conflict(& +mut self,location:Location,place:Place<'tcx>,sd:AccessDepth,rw:ReadOrWrite,){(); +debug! ("check_access_for_conflict(location={:?}, place={:?}, sd={:?}, rw={:?})" +,location,place,sd,rw,);;each_borrow_involving_path(self,self.tcx,self.body,(sd, +place),self.borrow_set,|_|true, |this,borrow_index,borrow|{match(rw,borrow.kind) +{(Activation(_,activating),_)if activating==borrow_index=>{}(Read(_),BorrowKind +::Fake|BorrowKind::Shared)|(Read( ReadKind::Borrow(BorrowKind::Fake)),BorrowKind +::Mut{..})=>{}(Read(_),BorrowKind::Mut{..})=>{if!is_active(this.dominators,//(); +borrow,location){;assert!(allow_two_phase_borrow(borrow.kind));;return Control:: +Continue;;}this.emit_loan_invalidated_at(borrow_index,location);}(Reservation(_) +|Activation(_,_)|Write(_),_)=>{{();};this.emit_loan_invalidated_at(borrow_index, +location);();}}Control::Continue},);();}fn emit_loan_invalidated_at(&mut self,b: +BorrowIndex,l:Location){();let lidx=self.location_table.start_index(l);3;3;self. +all_facts.loan_invalidated_at.push((lidx,b));();}fn check_activations(&mut self, +location:Location){for&borrow_index in self.borrow_set.activations_at_location( +location){;let borrow=&self.borrow_set[borrow_index];;assert!(match borrow.kind{ +BorrowKind::Shared|BorrowKind::Fake=>false,BorrowKind::Mut{..}=>true,});3;;self. +access_place(location,borrow.borrowed_place,(Deep,Activation(WriteKind:://{();}; +MutableBorrow(borrow.kind),borrow_index)),LocalMutationIsAllowed::No,);{();};}}} diff --git a/compiler/rustc_borrowck/src/polonius/loan_kills.rs b/compiler/rustc_borrowck/src/polonius/loan_kills.rs index 53adad5561e60..c0142621c6b2d 100644 --- a/compiler/rustc_borrowck/src/polonius/loan_kills.rs +++ b/compiler/rustc_borrowck/src/polonius/loan_kills.rs @@ -1,145 +1,49 @@ -use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{ - Body, Local, Location, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, - Terminator, TerminatorKind, -}; -use rustc_middle::ty::TyCtxt; - -use crate::{borrow_set::BorrowSet, facts::AllFacts, location::LocationTable, places_conflict}; - -/// Emit `loan_killed_at` and `cfg_edge` facts at the same time. -pub(super) fn emit_loan_kills<'tcx>( - tcx: TyCtxt<'tcx>, - all_facts: &mut AllFacts, - location_table: &LocationTable, - body: &Body<'tcx>, - borrow_set: &BorrowSet<'tcx>, -) { - let mut visitor = LoanKillsGenerator { borrow_set, tcx, location_table, all_facts, body }; - for (bb, data) in body.basic_blocks.iter_enumerated() { - visitor.visit_basic_block_data(bb, data); - } -} - -struct LoanKillsGenerator<'cx, 'tcx> { - tcx: TyCtxt<'tcx>, - all_facts: &'cx mut AllFacts, - location_table: &'cx LocationTable, - borrow_set: &'cx BorrowSet<'tcx>, - body: &'cx Body<'tcx>, -} - -impl<'cx, 'tcx> Visitor<'tcx> for LoanKillsGenerator<'cx, 'tcx> { - fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { - // Also record CFG facts here. - self.all_facts.cfg_edge.push(( - self.location_table.start_index(location), - self.location_table.mid_index(location), - )); - - self.all_facts.cfg_edge.push(( - self.location_table.mid_index(location), - self.location_table.start_index(location.successor_within_block()), - )); - - // If there are borrows on this now dead local, we need to record them as `killed`. - if let StatementKind::StorageDead(local) = statement.kind { - self.record_killed_borrows_for_local(local, location); - } - - self.super_statement(statement, location); - } - - fn visit_assign(&mut self, place: &Place<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) { - // When we see `X = ...`, then kill borrows of - // `(*X).foo` and so forth. - self.record_killed_borrows_for_place(*place, location); - self.super_assign(place, rvalue, location); - } - - fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { - // Also record CFG facts here. - self.all_facts.cfg_edge.push(( - self.location_table.start_index(location), - self.location_table.mid_index(location), - )); - - let successor_blocks = terminator.successors(); - self.all_facts.cfg_edge.reserve(successor_blocks.size_hint().0); - for successor_block in successor_blocks { - self.all_facts.cfg_edge.push(( - self.location_table.mid_index(location), - self.location_table.start_index(successor_block.start_location()), - )); - } - - // A `Call` terminator's return value can be a local which has borrows, - // so we need to record those as `killed` as well. - if let TerminatorKind::Call { destination, .. } = terminator.kind { - self.record_killed_borrows_for_place(destination, location); - } - - self.super_terminator(terminator, location); - } -} - -impl<'tcx> LoanKillsGenerator<'_, 'tcx> { - /// Records the borrows on the specified place as `killed`. For example, when assigning to a - /// local, or on a call's return destination. - fn record_killed_borrows_for_place(&mut self, place: Place<'tcx>, location: Location) { - // Depending on the `Place` we're killing: - // - if it's a local, or a single deref of a local, - // we kill all the borrows on the local. - // - if it's a deeper projection, we have to filter which - // of the borrows are killed: the ones whose `borrowed_place` - // conflicts with the `place`. - match place.as_ref() { - PlaceRef { local, projection: &[] } - | PlaceRef { local, projection: &[ProjectionElem::Deref] } => { - debug!( - "Recording `killed` facts for borrows of local={:?} at location={:?}", - local, location - ); - - self.record_killed_borrows_for_local(local, location); - } - - PlaceRef { local, projection: &[.., _] } => { - // Kill conflicting borrows of the innermost local. - debug!( - "Recording `killed` facts for borrows of \ - innermost projected local={:?} at location={:?}", - local, location - ); - - if let Some(borrow_indices) = self.borrow_set.local_map.get(&local) { - for &borrow_index in borrow_indices { - let places_conflict = places_conflict::places_conflict( - self.tcx, - self.body, - self.borrow_set[borrow_index].borrowed_place, - place, - places_conflict::PlaceConflictBias::NoOverlap, - ); - - if places_conflict { - let location_index = self.location_table.mid_index(location); - self.all_facts.loan_killed_at.push((borrow_index, location_index)); - } - } - } - } - } - } - - /// Records the borrows on the specified local as `killed`. - fn record_killed_borrows_for_local(&mut self, local: Local, location: Location) { - if let Some(borrow_indices) = self.borrow_set.local_map.get(&local) { - let location_index = self.location_table.mid_index(location); - self.all_facts.loan_killed_at.reserve(borrow_indices.len()); - for &borrow_index in borrow_indices { - self.all_facts.loan_killed_at.push((borrow_index, location_index)); - } - } - } -} +use rustc_middle::mir::visit::Visitor;use rustc_middle::mir::{Body,Local,//({}); +Location,Place,PlaceRef,ProjectionElem,Rvalue,Statement,StatementKind,//((),()); +Terminator,TerminatorKind,};use rustc_middle:: ty::TyCtxt;use crate::{borrow_set +::BorrowSet,facts::AllFacts,location:: LocationTable,places_conflict};pub(super) +fn emit_loan_kills<'tcx>(tcx:TyCtxt<'tcx>,all_facts:&mut AllFacts,//loop{break}; +location_table:&LocationTable,body:&Body<'tcx>,borrow_set:&BorrowSet<'tcx>,){(); +let mut visitor=LoanKillsGenerator{ borrow_set,tcx,location_table,all_facts,body +};if true{};for(bb,data)in body.basic_blocks.iter_enumerated(){let _=();visitor. +visit_basic_block_data(bb,data);{();};}}struct LoanKillsGenerator<'cx,'tcx>{tcx: +TyCtxt<'tcx>,all_facts:&'cx mut AllFacts,location_table:&'cx LocationTable,//(); +borrow_set:&'cx BorrowSet<'tcx>,body:&'cx Body<'tcx>,}impl<'cx,'tcx>Visitorfor LoanKillsGenerator<'cx,'tcx>{fn visit_statement(&mut self,statement:&// +Statement<'tcx>,location:Location){if true{};self.all_facts.cfg_edge.push((self. +location_table.start_index(location),self. location_table.mid_index(location),)) +;3;3;self.all_facts.cfg_edge.push((self.location_table.mid_index(location),self. +location_table.start_index(location.successor_within_block()),));let _=();if let +StatementKind::StorageDead(local)=statement.kind{loop{break;};loop{break;};self. +record_killed_borrows_for_local(local,location);;}self.super_statement(statement +,location);3;}fn visit_assign(&mut self,place:&Place<'tcx>,rvalue:&Rvalue<'tcx>, +location:Location){;self.record_killed_borrows_for_place(*place,location);;self. +super_assign(place,rvalue,location);;}fn visit_terminator(&mut self,terminator:& +Terminator<'tcx>,location:Location){let _=();self.all_facts.cfg_edge.push((self. +location_table.start_index(location),self. location_table.mid_index(location),)) +;;;let successor_blocks=terminator.successors();self.all_facts.cfg_edge.reserve( +successor_blocks.size_hint().0);3;for successor_block in successor_blocks{;self. +all_facts.cfg_edge.push(((((((self.location_table.mid_index(location)))))),self. +location_table.start_index(successor_block.start_location()),));let _=();}if let +TerminatorKind::Call{destination,..}=terminator.kind{let _=||();let _=||();self. +record_killed_borrows_for_place(destination,location);3;};self.super_terminator( +terminator,location);((),());let _=();}}impl<'tcx>LoanKillsGenerator<'_,'tcx>{fn +record_killed_borrows_for_place(&mut self,place: Place<'tcx>,location:Location){ +match place.as_ref(){PlaceRef{local, projection:&[]}|PlaceRef{local,projection:& +[ProjectionElem::Deref]}=>{let _=||();loop{break};let _=||();loop{break};debug!( +"Recording `killed` facts for borrows of local={:?} at location={:?}",local,//3; +location);;self.record_killed_borrows_for_local(local,location);}PlaceRef{local, +projection:&[..,_]}=>{loop{break};loop{break;};loop{break;};loop{break;};debug!( +"Recording `killed` facts for borrows of \ + innermost projected local={:?} at location={:?}" +,local,location);{;};if let Some(borrow_indices)=self.borrow_set.local_map.get(& +local){for&borrow_index in borrow_indices{;let places_conflict=places_conflict:: +places_conflict(self.tcx,self.body, self.borrow_set[borrow_index].borrowed_place +,place,places_conflict::PlaceConflictBias::NoOverlap,);3;if places_conflict{;let +location_index=self.location_table.mid_index(location);({});({});self.all_facts. +loan_killed_at.push((borrow_index,location_index));if true{};let _=||();}}}}}}fn +record_killed_borrows_for_local(&mut self,local: Local,location:Location){if let +Some(borrow_indices)=self.borrow_set.local_map.get(&local){3;let location_index= +self.location_table.mid_index(location);;;self.all_facts.loan_killed_at.reserve( +borrow_indices.len());{;};for&borrow_index in borrow_indices{{;};self.all_facts. +loan_killed_at.push((borrow_index,location_index));loop{break};loop{break;};}}}} diff --git a/compiler/rustc_borrowck/src/polonius/mod.rs b/compiler/rustc_borrowck/src/polonius/mod.rs index 40126d50d57e6..370ff000b8618 100644 --- a/compiler/rustc_borrowck/src/polonius/mod.rs +++ b/compiler/rustc_borrowck/src/polonius/mod.rs @@ -1,188 +1,55 @@ -//! Functions dedicated to fact generation for the `-Zpolonius=legacy` datalog implementation. -//! -//! Will be removed in the future, once the in-tree `-Zpolonius=next` implementation reaches feature -//! parity. - -use rustc_middle::mir::{Body, LocalKind, Location, START_BLOCK}; -use rustc_middle::ty::TyCtxt; -use rustc_mir_dataflow::move_paths::{InitKind, InitLocation, MoveData}; - -use crate::borrow_set::BorrowSet; -use crate::facts::AllFacts; -use crate::location::LocationTable; -use crate::type_check::free_region_relations::UniversalRegionRelations; -use crate::universal_regions::UniversalRegions; - -mod loan_invalidations; -mod loan_kills; - -/// When requested, emit most of the facts needed by polonius: -/// - moves and assignments -/// - universal regions and their relations -/// - CFG points and edges -/// - loan kills -/// - loan invalidations -/// -/// The rest of the facts are emitted during typeck and liveness. -pub(crate) fn emit_facts<'tcx>( - all_facts: &mut Option, - tcx: TyCtxt<'tcx>, - location_table: &LocationTable, - body: &Body<'tcx>, - borrow_set: &BorrowSet<'tcx>, - move_data: &MoveData<'_>, - universal_regions: &UniversalRegions<'_>, - universal_region_relations: &UniversalRegionRelations<'_>, -) { - let Some(all_facts) = all_facts else { - // We don't do anything if there are no facts to fill. - return; - }; - let _prof_timer = tcx.prof.generic_activity("polonius_fact_generation"); - emit_move_facts(all_facts, move_data, location_table, body); - emit_universal_region_facts( - all_facts, - borrow_set, - &universal_regions, - &universal_region_relations, - ); - emit_cfg_and_loan_kills_facts(all_facts, tcx, location_table, body, borrow_set); - emit_loan_invalidations_facts(all_facts, tcx, location_table, body, borrow_set); -} - -/// Emit facts needed for move/init analysis: moves and assignments. -fn emit_move_facts( - all_facts: &mut AllFacts, - move_data: &MoveData<'_>, - location_table: &LocationTable, - body: &Body<'_>, -) { - all_facts - .path_is_var - .extend(move_data.rev_lookup.iter_locals_enumerated().map(|(l, r)| (r, l))); - - for (child, move_path) in move_data.move_paths.iter_enumerated() { - if let Some(parent) = move_path.parent { - all_facts.child_path.push((child, parent)); - } - } - - let fn_entry_start = - location_table.start_index(Location { block: START_BLOCK, statement_index: 0 }); - - // initialized_at - for init in move_data.inits.iter() { - match init.location { - InitLocation::Statement(location) => { - let block_data = &body[location.block]; - let is_terminator = location.statement_index == block_data.statements.len(); - - if is_terminator && init.kind == InitKind::NonPanicPathOnly { - // We are at the terminator of an init that has a panic path, - // and where the init should not happen on panic - - for successor in block_data.terminator().successors() { - if body[successor].is_cleanup { - continue; - } - - // The initialization happened in (or rather, when arriving at) - // the successors, but not in the unwind block. - let first_statement = Location { block: successor, statement_index: 0 }; - all_facts - .path_assigned_at_base - .push((init.path, location_table.start_index(first_statement))); - } - } else { - // In all other cases, the initialization just happens at the - // midpoint, like any other effect. - all_facts - .path_assigned_at_base - .push((init.path, location_table.mid_index(location))); - } - } - // Arguments are initialized on function entry - InitLocation::Argument(local) => { - assert!(body.local_kind(local) == LocalKind::Arg); - all_facts.path_assigned_at_base.push((init.path, fn_entry_start)); - } - } - } - - for (local, path) in move_data.rev_lookup.iter_locals_enumerated() { - if body.local_kind(local) != LocalKind::Arg { - // Non-arguments start out deinitialised; we simulate this with an - // initial move: - all_facts.path_moved_at_base.push((path, fn_entry_start)); - } - } - - // moved_out_at - // deinitialisation is assumed to always happen! - all_facts - .path_moved_at_base - .extend(move_data.moves.iter().map(|mo| (mo.path, location_table.mid_index(mo.source)))); -} - -/// Emit universal regions facts, and their relations. -fn emit_universal_region_facts( - all_facts: &mut AllFacts, - borrow_set: &BorrowSet<'_>, - universal_regions: &UniversalRegions<'_>, - universal_region_relations: &UniversalRegionRelations<'_>, -) { - // 1: universal regions are modeled in Polonius as a pair: - // - the universal region vid itself. - // - a "placeholder loan" associated to this universal region. Since they don't exist in - // the `borrow_set`, their `BorrowIndex` are synthesized as the universal region index - // added to the existing number of loans, as if they succeeded them in the set. - // - all_facts.universal_region.extend(universal_regions.universal_regions()); - let borrow_count = borrow_set.len(); - debug!( - "emit_universal_region_facts: polonius placeholders, num_universals={}, borrow_count={}", - universal_regions.len(), - borrow_count - ); - - for universal_region in universal_regions.universal_regions() { - let universal_region_idx = universal_region.index(); - let placeholder_loan_idx = borrow_count + universal_region_idx; - all_facts.placeholder.push((universal_region, placeholder_loan_idx.into())); - } - - // 2: the universal region relations `outlives` constraints are emitted as - // `known_placeholder_subset` facts. - for (fr1, fr2) in universal_region_relations.known_outlives() { - if fr1 != fr2 { - debug!( - "emit_universal_region_facts: emitting polonius `known_placeholder_subset` \ - fr1={:?}, fr2={:?}", - fr1, fr2 - ); - all_facts.known_placeholder_subset.push((fr1, fr2)); - } - } -} - -/// Emit facts about loan invalidations. -fn emit_loan_invalidations_facts<'tcx>( - all_facts: &mut AllFacts, - tcx: TyCtxt<'tcx>, - location_table: &LocationTable, - body: &Body<'tcx>, - borrow_set: &BorrowSet<'tcx>, -) { - loan_invalidations::emit_loan_invalidations(tcx, all_facts, location_table, body, borrow_set); -} - -/// Emit facts about CFG points and edges, as well as locations where loans are killed. -fn emit_cfg_and_loan_kills_facts<'tcx>( - all_facts: &mut AllFacts, - tcx: TyCtxt<'tcx>, - location_table: &LocationTable, - body: &Body<'tcx>, - borrow_set: &BorrowSet<'tcx>, -) { - loan_kills::emit_loan_kills(tcx, all_facts, location_table, body, borrow_set); -} +use rustc_middle::mir::{Body,LocalKind ,Location,START_BLOCK};use rustc_middle:: +ty::TyCtxt;use rustc_mir_dataflow:: move_paths::{InitKind,InitLocation,MoveData} +;use crate::borrow_set::BorrowSet;use crate::facts::AllFacts;use crate:://{();}; +location::LocationTable;use crate::type_check::free_region_relations:://((),()); +UniversalRegionRelations;use crate::universal_regions::UniversalRegions;mod//(); +loan_invalidations;mod loan_kills;pub(crate)fn emit_facts<'tcx>(all_facts:&mut// +Option,tcx:TyCtxt<'tcx> ,location_table:&LocationTable,body:&Body<'tcx +>,borrow_set:&BorrowSet<'tcx>,move_data:&MoveData<'_>,universal_regions:&//({}); +UniversalRegions<'_>,universal_region_relations: &UniversalRegionRelations<'_>,) +{3;let Some(all_facts)=all_facts else{3;return;3;};3;3;let _prof_timer=tcx.prof. +generic_activity("polonius_fact_generation");({});{;};emit_move_facts(all_facts, +move_data,location_table,body);;emit_universal_region_facts(all_facts,borrow_set +,&universal_regions,&universal_region_relations,);;emit_cfg_and_loan_kills_facts +(all_facts,tcx,location_table,body,borrow_set);3;;emit_loan_invalidations_facts( +all_facts,tcx,location_table,body,borrow_set);();}fn emit_move_facts(all_facts:& +mut AllFacts,move_data:&MoveData<'_>,location_table:&LocationTable,body:&Body,){;all_facts.path_is_var.extend(move_data.rev_lookup.iter_locals_enumerated( +).map(|(l,r)|(r,l)));*&*&();((),());for(child,move_path)in move_data.move_paths. +iter_enumerated(){if let Some(parent)=move_path.parent{{;};all_facts.child_path. +push((child,parent));;}};let fn_entry_start=location_table.start_index(Location{ +block:START_BLOCK,statement_index:0});3;for init in move_data.inits.iter(){match +init.location{InitLocation::Statement(location)=>{;let block_data=&body[location +.block];;let is_terminator=location.statement_index==block_data.statements.len() +;{();};if is_terminator&&init.kind==InitKind::NonPanicPathOnly{for successor in +block_data.terminator().successors(){if body[successor].is_cleanup{;continue;;}; +let first_statement=Location{block:successor,statement_index:0};();();all_facts. +path_assigned_at_base.push((init.path,location_table.start_index(//loop{break;}; +first_statement)));();}}else{();all_facts.path_assigned_at_base.push((init.path, +location_table.mid_index(location)));;}}InitLocation::Argument(local)=>{assert!( +body.local_kind(local)==LocalKind::Arg);;;all_facts.path_assigned_at_base.push(( +init.path,fn_entry_start));let _=||();}}}for(local,path)in move_data.rev_lookup. +iter_locals_enumerated(){if body.local_kind(local)!=LocalKind::Arg{();all_facts. +path_moved_at_base.push((path,fn_entry_start));;}};all_facts.path_moved_at_base. +extend(((move_data.moves.iter())).map( |mo|(mo.path,location_table.mid_index(mo. +source))));;}fn emit_universal_region_facts(all_facts:&mut AllFacts,borrow_set:& +BorrowSet<'_>,universal_regions:&UniversalRegions<'_>,//loop{break};loop{break}; +universal_region_relations:&UniversalRegionRelations<'_>,){let _=||();all_facts. +universal_region.extend(universal_regions.universal_regions());;let borrow_count +=borrow_set.len();if let _=(){};if let _=(){};loop{break;};if let _=(){};debug!( +"emit_universal_region_facts: polonius placeholders, num_universals={}, borrow_count={}" +,universal_regions.len(),borrow_count);((),());let _=();for universal_region in +universal_regions.universal_regions(){;let universal_region_idx=universal_region +.index();;;let placeholder_loan_idx=borrow_count+universal_region_idx;all_facts. +placeholder.push((universal_region,placeholder_loan_idx.into()));3;}for(fr1,fr2) +in universal_region_relations.known_outlives(){if fr1!=fr2{if let _=(){};debug!( +"emit_universal_region_facts: emitting polonius `known_placeholder_subset` \ + fr1={:?}, fr2={:?}" +,fr1,fr2);({});({});all_facts.known_placeholder_subset.push((fr1,fr2));{;};}}}fn +emit_loan_invalidations_facts<'tcx>(all_facts:&mut AllFacts,tcx:TyCtxt<'tcx>,//; +location_table:&LocationTable,body:&Body<'tcx>,borrow_set:&BorrowSet<'tcx>,){(); +loan_invalidations::emit_loan_invalidations(tcx,all_facts,location_table,body,// +borrow_set);;}fn emit_cfg_and_loan_kills_facts<'tcx>(all_facts:&mut AllFacts,tcx +:TyCtxt<'tcx>,location_table:&LocationTable,body:&Body<'tcx>,borrow_set:&//({}); +BorrowSet<'tcx>,){;loan_kills::emit_loan_kills(tcx,all_facts,location_table,body +,borrow_set);((),());((),());((),());let _=();((),());((),());((),());let _=();} diff --git a/compiler/rustc_borrowck/src/prefixes.rs b/compiler/rustc_borrowck/src/prefixes.rs index 8a3a089d0eeba..7d6cad7ad1b33 100644 --- a/compiler/rustc_borrowck/src/prefixes.rs +++ b/compiler/rustc_borrowck/src/prefixes.rs @@ -1,102 +1,20 @@ -//! From the NLL RFC: -//! "Shallow prefixes are found by stripping away fields, but stop at -//! any dereference. So: writing a path like `a` is illegal if `a.b` -//! is borrowed. But: writing `a` is legal if `*a` is borrowed, -//! whether or not `a` is a shared or mutable reference. [...] " - -use super::MirBorrowckCtxt; - -use rustc_middle::mir::{PlaceRef, ProjectionElem}; - -pub trait IsPrefixOf<'tcx> { - fn is_prefix_of(&self, other: PlaceRef<'tcx>) -> bool; -} - -impl<'tcx> IsPrefixOf<'tcx> for PlaceRef<'tcx> { - fn is_prefix_of(&self, other: PlaceRef<'tcx>) -> bool { - self.local == other.local - && self.projection.len() <= other.projection.len() - && self.projection == &other.projection[..self.projection.len()] - } -} - -pub(super) struct Prefixes<'tcx> { - kind: PrefixSet, - next: Option>, -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub(super) enum PrefixSet { - /// Doesn't stop until it returns the base case (a Local or - /// Static prefix). - All, - /// Stops at any dereference. - Shallow, -} - -impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { - /// Returns an iterator over the prefixes of `place` - /// (inclusive) from longest to smallest, potentially - /// terminating the iteration early based on `kind`. - pub(super) fn prefixes(&self, place_ref: PlaceRef<'tcx>, kind: PrefixSet) -> Prefixes<'tcx> { - Prefixes { next: Some(place_ref), kind } - } -} - -impl<'tcx> Iterator for Prefixes<'tcx> { - type Item = PlaceRef<'tcx>; - fn next(&mut self) -> Option { - let mut cursor = self.next?; - - // Post-processing `place`: Enqueue any remaining - // work. Also, `place` may not be a prefix itself, but - // may hold one further down (e.g., we never return - // downcasts here, but may return a base of a downcast). - - 'cursor: loop { - match cursor.last_projection() { - None => { - self.next = None; - return Some(cursor); - } - Some((cursor_base, elem)) => { - match elem { - ProjectionElem::Field(_ /*field*/, _ /*ty*/) => { - // FIXME: add union handling - self.next = Some(cursor_base); - return Some(cursor); - } - ProjectionElem::Downcast(..) - | ProjectionElem::Subslice { .. } - | ProjectionElem::OpaqueCast { .. } - | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Index(_) => { - cursor = cursor_base; - continue 'cursor; - } - ProjectionElem::Subtype(..) => { - panic!("Subtype projection is not allowed before borrow check") - } - ProjectionElem::Deref => { - match self.kind { - PrefixSet::Shallow => { - // Shallow prefixes are found by stripping away - // fields, but stop at *any* dereference. - // So we can just stop the traversal now. - self.next = None; - return Some(cursor); - } - PrefixSet::All => { - // All prefixes: just blindly enqueue the base - // of the projection. - self.next = Some(cursor_base); - return Some(cursor); - } - } - } - } - } - } - } - } -} +use super::MirBorrowckCtxt;use rustc_middle ::mir::{PlaceRef,ProjectionElem};pub +trait IsPrefixOf<'tcx>{fn is_prefix_of(&self,other:PlaceRef<'tcx>)->bool;}impl// +<'tcx>IsPrefixOf<'tcx>for PlaceRef<'tcx>{fn is_prefix_of(&self,other:PlaceRef)->bool{self.local==other.local&&self.projection.len()<=other.projection.// +len()&&self.projection==&other.projection[..self.projection.len()]}}pub(super)// +struct Prefixes<'tcx>{kind:PrefixSet,next: Option>,}#[derive(Copy +,Clone,PartialEq,Eq,Debug)]pub(super) enum PrefixSet{All,Shallow,}impl<'cx,'tcx> +MirBorrowckCtxt<'cx,'tcx>{pub(super)fn prefixes(&self,place_ref:PlaceRef<'tcx>, +kind:PrefixSet)->Prefixes<'tcx>{Prefixes{next :Some(place_ref),kind}}}impl<'tcx> +Iterator for Prefixes<'tcx>{type Item=PlaceRef <'tcx>;fn next(&mut self)->Option +{((),());let mut cursor=self.next?;*&*&();'cursor:loop{match cursor. +last_projection(){None=>{;self.next=None;return Some(cursor);}Some((cursor_base, +elem))=>{match elem{ProjectionElem::Field(_,_)=>{;self.next=Some(cursor_base);;; +return Some(cursor);;}ProjectionElem::Downcast(..)|ProjectionElem::Subslice{..}| +ProjectionElem::OpaqueCast{..}| ProjectionElem::ConstantIndex{..}|ProjectionElem +::Index(_)=>{;cursor=cursor_base;continue 'cursor;}ProjectionElem::Subtype(..)=> +{panic!( "Subtype projection is not allowed before borrow check")}ProjectionElem +::Deref=>{match self.kind{PrefixSet::Shallow=>{3;self.next=None;3;3;return Some( +cursor);;}PrefixSet::All=>{self.next=Some(cursor_base);return Some(cursor);}}}}} +}}}}//let _=();let _=();let _=();if true{};let _=();let _=();let _=();if true{}; diff --git a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs index 53541b33c41d1..5b62d5dffffae 100644 --- a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs +++ b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs @@ -1,89 +1,25 @@ -//! As part of generating the regions, if you enable `-Zdump-mir=nll`, -//! we will generate an annotated copy of the MIR that includes the -//! state of region inference. This code handles emitting the region -//! context internal state. - -use super::{OutlivesConstraint, RegionInferenceContext}; -use crate::type_check::Locations; -use rustc_infer::infer::NllRegionVariableOrigin; -use rustc_middle::ty::TyCtxt; -use std::io::{self, Write}; - -// Room for "'_#NNNNr" before things get misaligned. -// Easy enough to fix if this ever doesn't seem like -// enough. -const REGION_WIDTH: usize = 8; - -impl<'tcx> RegionInferenceContext<'tcx> { - /// Write out our state into the `.mir` files. - pub(crate) fn dump_mir(&self, tcx: TyCtxt<'tcx>, out: &mut dyn Write) -> io::Result<()> { - writeln!(out, "| Free Region Mapping")?; - - for region in self.regions() { - if let NllRegionVariableOrigin::FreeRegion = self.definitions[region].origin { - let classification = self.universal_regions.region_classification(region).unwrap(); - let outlived_by = self.universal_region_relations.regions_outlived_by(region); - writeln!( - out, - "| {r:rw$?} | {c:cw$?} | {ob:?}", - r = region, - rw = REGION_WIDTH, - c = classification, - cw = 8, // "External" at most - ob = outlived_by - )?; - } - } - - writeln!(out, "|")?; - writeln!(out, "| Inferred Region Values")?; - for region in self.regions() { - writeln!( - out, - "| {r:rw$?} | {ui:4?} | {v}", - r = region, - rw = REGION_WIDTH, - ui = self.region_universe(region), - v = self.region_value_str(region), - )?; - } - - writeln!(out, "|")?; - writeln!(out, "| Inference Constraints")?; - self.for_each_constraint(tcx, &mut |msg| writeln!(out, "| {msg}"))?; - - Ok(()) - } - - /// Debugging aid: Invokes the `with_msg` callback repeatedly with - /// our internal region constraints. These are dumped into the - /// -Zdump-mir file so that we can figure out why the region - /// inference resulted in the values that it did when debugging. - fn for_each_constraint( - &self, - tcx: TyCtxt<'tcx>, - with_msg: &mut dyn FnMut(&str) -> io::Result<()>, - ) -> io::Result<()> { - for region in self.definitions.indices() { - let value = self.liveness_constraints.pretty_print_live_points(region); - if value != "{}" { - with_msg(&format!("{region:?} live at {value}"))?; - } - } - - let mut constraints: Vec<_> = self.constraints.outlives().iter().collect(); - constraints.sort_by_key(|c| (c.sup, c.sub)); - for constraint in &constraints { - let OutlivesConstraint { sup, sub, locations, category, span, .. } = constraint; - let (name, arg) = match locations { - Locations::All(span) => { - ("All", tcx.sess.source_map().span_to_embeddable_string(*span)) - } - Locations::Single(loc) => ("Single", format!("{loc:?}")), - }; - with_msg(&format!("{sup:?}: {sub:?} due to {category:?} at {name}({arg}) ({span:?}"))?; - } - - Ok(()) - } -} +use super::{OutlivesConstraint,RegionInferenceContext};use crate::type_check::// +Locations;use rustc_infer::infer::NllRegionVariableOrigin;use rustc_middle::ty// +::TyCtxt;use std::io::{self,Write};const REGION_WIDTH:usize=((((8))));impl<'tcx> +RegionInferenceContext<'tcx>{pub(crate)fn dump_mir( &self,tcx:TyCtxt<'tcx>,out:& +mut dyn Write)->io::Result<()>{{;};writeln!(out,"| Free Region Mapping")?;();for +region in (((self.regions()))) {if let NllRegionVariableOrigin::FreeRegion=self. +definitions[region].origin{let _=||();let classification=self.universal_regions. +region_classification(region).unwrap();if true{};if true{};let outlived_by=self. +universal_region_relations.regions_outlived_by(region);{();};{();};writeln!(out, +"| {r:rw$?} | {c:cw$?} | {ob:?}",r=region,rw= REGION_WIDTH,c=classification,cw=8 +,ob=outlived_by)?;;}}writeln!(out,"|")?;writeln!(out,"| Inferred Region Values") +?;();for region in self.regions(){3;writeln!(out,"| {r:rw$?} | {ui:4?} | {v}",r= +region,rw=REGION_WIDTH,ui=self. region_universe(region),v=self.region_value_str( +region),)?;;};writeln!(out,"|")?;;writeln!(out,"| Inference Constraints")?;self. +for_each_constraint(tcx,&mut|msg|writeln!(out,"| {msg}"))?;loop{break};Ok(())}fn +for_each_constraint(&self,tcx:TyCtxt<'tcx>,with_msg:&mut dyn FnMut(&str)->io::// +Result<()>,)->io::Result<()>{for region in self.definitions.indices(){;let value +=self.liveness_constraints.pretty_print_live_points(region);();if value!="{}"{3; +with_msg(&format!("{region:?} live at {value}"))?;;}}let mut constraints:Vec<_>= +self.constraints.outlives().iter().collect();;constraints.sort_by_key(|c|(c.sup, +c.sub));;for constraint in&constraints{let OutlivesConstraint{sup,sub,locations, +category,span,..}=constraint;;let(name,arg)=match locations{Locations::All(span) +=>{(("All",tcx.sess.source_map( ).span_to_embeddable_string(*span)))}Locations:: +Single(loc)=>("Single",format!("{loc:?}")),};let _=();((),());with_msg(&format!( +"{sup:?}: {sub:?} due to {category:?} at {name}({arg}) ({span:?}"))?;3;}Ok(())}} diff --git a/compiler/rustc_borrowck/src/region_infer/graphviz.rs b/compiler/rustc_borrowck/src/region_infer/graphviz.rs index c103ba3c40709..81a38c1d32b68 100644 --- a/compiler/rustc_borrowck/src/region_infer/graphviz.rs +++ b/compiler/rustc_borrowck/src/region_infer/graphviz.rs @@ -1,139 +1,47 @@ -//! This module provides linkage between RegionInferenceContext and -//! `rustc_graphviz` traits, specialized to attaching borrowck analysis -//! data to rendered labels. - -use std::borrow::Cow; -use std::io::{self, Write}; - -use super::*; -use rustc_graphviz as dot; - -impl<'tcx> RegionInferenceContext<'tcx> { - /// Write out the region constraint graph. - pub(crate) fn dump_graphviz_raw_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> { - dot::render(&RawConstraints { regioncx: self }, &mut w) - } - - /// Write out the region constraint graph. - pub(crate) fn dump_graphviz_scc_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> { - let mut nodes_per_scc: IndexVec = - self.constraint_sccs.all_sccs().map(|_| Vec::new()).collect(); - - for region in self.definitions.indices() { - let scc = self.constraint_sccs.scc(region); - nodes_per_scc[scc].push(region); - } - - dot::render(&SccConstraints { regioncx: self, nodes_per_scc }, &mut w) - } -} - -struct RawConstraints<'a, 'tcx> { - regioncx: &'a RegionInferenceContext<'tcx>, -} - -impl<'a, 'this, 'tcx> dot::Labeller<'this> for RawConstraints<'a, 'tcx> { - type Node = RegionVid; - type Edge = OutlivesConstraint<'tcx>; - - fn graph_id(&'this self) -> dot::Id<'this> { - dot::Id::new("RegionInferenceContext").unwrap() - } - fn node_id(&'this self, n: &RegionVid) -> dot::Id<'this> { - dot::Id::new(format!("r{}", n.index())).unwrap() - } - fn node_shape(&'this self, _node: &RegionVid) -> Option> { - Some(dot::LabelText::LabelStr(Cow::Borrowed("box"))) - } - fn node_label(&'this self, n: &RegionVid) -> dot::LabelText<'this> { - dot::LabelText::LabelStr(format!("{n:?}").into()) - } - fn edge_label(&'this self, e: &OutlivesConstraint<'tcx>) -> dot::LabelText<'this> { - dot::LabelText::LabelStr(format!("{:?}", e.locations).into()) - } -} - -impl<'a, 'this, 'tcx> dot::GraphWalk<'this> for RawConstraints<'a, 'tcx> { - type Node = RegionVid; - type Edge = OutlivesConstraint<'tcx>; - - fn nodes(&'this self) -> dot::Nodes<'this, RegionVid> { - let vids: Vec = self.regioncx.definitions.indices().collect(); - vids.into() - } - fn edges(&'this self) -> dot::Edges<'this, OutlivesConstraint<'tcx>> { - (&self.regioncx.constraints.outlives().raw[..]).into() - } - - // Render `a: b` as `a -> b`, indicating the flow - // of data during inference. - - fn source(&'this self, edge: &OutlivesConstraint<'tcx>) -> RegionVid { - edge.sup - } - - fn target(&'this self, edge: &OutlivesConstraint<'tcx>) -> RegionVid { - edge.sub - } -} - -struct SccConstraints<'a, 'tcx> { - regioncx: &'a RegionInferenceContext<'tcx>, - nodes_per_scc: IndexVec>, -} - -impl<'a, 'this, 'tcx> dot::Labeller<'this> for SccConstraints<'a, 'tcx> { - type Node = ConstraintSccIndex; - type Edge = (ConstraintSccIndex, ConstraintSccIndex); - - fn graph_id(&'this self) -> dot::Id<'this> { - dot::Id::new("RegionInferenceContext".to_string()).unwrap() - } - fn node_id(&'this self, n: &ConstraintSccIndex) -> dot::Id<'this> { - dot::Id::new(format!("r{}", n.index())).unwrap() - } - fn node_shape(&'this self, _node: &ConstraintSccIndex) -> Option> { - Some(dot::LabelText::LabelStr(Cow::Borrowed("box"))) - } - fn node_label(&'this self, n: &ConstraintSccIndex) -> dot::LabelText<'this> { - let nodes = &self.nodes_per_scc[*n]; - dot::LabelText::LabelStr(format!("{n:?} = {nodes:?}").into()) - } -} - -impl<'a, 'this, 'tcx> dot::GraphWalk<'this> for SccConstraints<'a, 'tcx> { - type Node = ConstraintSccIndex; - type Edge = (ConstraintSccIndex, ConstraintSccIndex); - - fn nodes(&'this self) -> dot::Nodes<'this, ConstraintSccIndex> { - let vids: Vec = self.regioncx.constraint_sccs.all_sccs().collect(); - vids.into() - } - fn edges(&'this self) -> dot::Edges<'this, (ConstraintSccIndex, ConstraintSccIndex)> { - let edges: Vec<_> = self - .regioncx - .constraint_sccs - .all_sccs() - .flat_map(|scc_a| { - self.regioncx - .constraint_sccs - .successors(scc_a) - .iter() - .map(move |&scc_b| (scc_a, scc_b)) - }) - .collect(); - - edges.into() - } - - // Render `a: b` as `a -> b`, indicating the flow - // of data during inference. - - fn source(&'this self, edge: &(ConstraintSccIndex, ConstraintSccIndex)) -> ConstraintSccIndex { - edge.0 - } - - fn target(&'this self, edge: &(ConstraintSccIndex, ConstraintSccIndex)) -> ConstraintSccIndex { - edge.1 - } -} +use std::borrow::Cow;use std::io::{self,Write};use super::*;use rustc_graphviz// +as dot;impl<'tcx>RegionInferenceContext<'tcx>{pub(crate)fn//if true{};if true{}; +dump_graphviz_raw_constraints(&self,mut w:&mut dyn Write)->io::Result<()>{dot:: +render(((((&((((RawConstraints{regioncx:self})))))))),(((&mut w))))}pub(crate)fn +dump_graphviz_scc_constraints(&self,mut w:&mut dyn Write)->io::Result<()>{();let +mut nodes_per_scc:IndexVec =self.constraint_sccs.all_sccs( +).map(|_|Vec::new()).collect();;for region in self.definitions.indices(){let scc +=self.constraint_sccs.scc(region);;nodes_per_scc[scc].push(region);}dot::render( +&SccConstraints{regioncx:self,nodes_per_scc}, &mut w)}}struct RawConstraints<'a, +'tcx>{regioncx:&'a RegionInferenceContext<'tcx>,}impl<'a,'this,'tcx>dot:://({}); +Labeller<'this>for RawConstraints<'a,'tcx>{type Node=RegionVid;type Edge=//({}); +OutlivesConstraint<'tcx>;fn graph_id(&'this self)-> dot::Id<'this>{dot::Id::new( +"RegionInferenceContext").unwrap()}fn node_id(&'this self,n:&RegionVid)->dot::// +Id<'this>{(dot::Id::new(format!("r{}",n.index())).unwrap())}fn node_shape(&'this +self,_node:&RegionVid)->Option>{Some(dot::LabelText:://(); +LabelStr((Cow::Borrowed("box"))))}fn node_label(&'this self,n:&RegionVid)->dot:: +LabelText<'this>{((dot::LabelText::LabelStr(((( format!("{n:?}")).into())))))}fn +edge_label(&'this self,e:&OutlivesConstraint<'tcx>)->dot::LabelText<'this>{dot// +::LabelText::LabelStr((format!("{:?}",e.locations).into()))}}impl<'a,'this,'tcx> +dot::GraphWalk<'this>for RawConstraints<'a, 'tcx>{type Node=RegionVid;type Edge= +OutlivesConstraint<'tcx>;fn nodes(&'this self)->dot::Nodes<'this,RegionVid>{;let +vids:Vec=self.regioncx.definitions.indices().collect();3;vids.into()} +fn edges(&'this self)->dot::Edges<'this,OutlivesConstraint<'tcx>>{(&self.//({}); +regioncx.constraints.outlives().raw[..]).into()}fn source(&'this self,edge:&//3; +OutlivesConstraint<'tcx>)->RegionVid{edge.sup}fn target(&'this self,edge:&//{;}; +OutlivesConstraint<'tcx>)->RegionVid{edge.sub}}struct SccConstraints<'a,'tcx>{// +regioncx:&'a RegionInferenceContext<'tcx>,nodes_per_scc:IndexVec>,}impl<'a,'this,'tcx>dot::Labeller<'this>for// +SccConstraints<'a,'tcx>{type Node=ConstraintSccIndex;type Edge=(//if let _=(){}; +ConstraintSccIndex,ConstraintSccIndex);fn graph_id(& 'this self)->dot::Id<'this> +{(dot::Id::new("RegionInferenceContext".to_string()).unwrap())}fn node_id(&'this +self,n:&ConstraintSccIndex)->dot::Id<'this>{ dot::Id::new(format!("r{}",n.index( +))).unwrap()}fn node_shape( &'this self,_node:&ConstraintSccIndex)->Option>{(Some((dot::LabelText::LabelStr( (Cow::Borrowed("box"))))))}fn +node_label(&'this self,n:&ConstraintSccIndex)->dot::LabelText<'this>{;let nodes= +&self.nodes_per_scc[*n];3;dot::LabelText::LabelStr(format!("{n:?} = {nodes:?}"). +into())}}impl<'a,'this,'tcx>dot::GraphWalk<'this>for SccConstraints<'a,'tcx>{//; +type Node=ConstraintSccIndex;type Edge=(ConstraintSccIndex,ConstraintSccIndex); +fn nodes(&'this self)->dot::Nodes<'this,ConstraintSccIndex>{*&*&();let vids:Vec< +ConstraintSccIndex>=self.regioncx.constraint_sccs.all_sccs().collect();{;};vids. +into()}fn edges(&'this self)->dot::Edges<'this,(ConstraintSccIndex,//let _=||(); +ConstraintSccIndex)>{;let edges:Vec<_>=self.regioncx.constraint_sccs.all_sccs(). +flat_map(|scc_a|{((self.regioncx.constraint_sccs.successors(scc_a)).iter()).map( +move|&scc_b|(scc_a,scc_b))}).collect();;edges.into()}fn source(&'this self,edge: +&(ConstraintSccIndex,ConstraintSccIndex))->ConstraintSccIndex {edge.0}fn target( +&'this self,edge:& (ConstraintSccIndex,ConstraintSccIndex))->ConstraintSccIndex{ +edge.1}}//((),());let _=();let _=();let _=();((),());let _=();let _=();let _=(); diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 599f7dd18c3ea..97d941beb5781 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -1,2304 +1,561 @@ -use std::collections::VecDeque; -use std::rc::Rc; - -use rustc_data_structures::binary_search_util; -use rustc_data_structures::frozen::Frozen; -use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; -use rustc_data_structures::graph::scc::Sccs; -use rustc_errors::Diag; -use rustc_hir::def_id::CRATE_DEF_ID; -use rustc_index::{IndexSlice, IndexVec}; -use rustc_infer::infer::outlives::test_type_match; -use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq}; -use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin}; -use rustc_middle::mir::{ - BasicBlock, Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureOutlivesSubjectTy, - ClosureRegionRequirements, ConstraintCategory, Local, Location, ReturnConstraint, - TerminatorKind, -}; -use rustc_middle::traits::ObligationCause; -use rustc_middle::traits::ObligationCauseCode; -use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable}; -use rustc_mir_dataflow::points::DenseLocationMap; -use rustc_span::Span; - -use crate::constraints::graph::{self, NormalConstraintGraph, RegionGraph}; -use crate::dataflow::BorrowIndex; -use crate::{ - constraints::{ConstraintSccIndex, OutlivesConstraint, OutlivesConstraintSet}, - diagnostics::{RegionErrorKind, RegionErrors, UniverseInfo}, - member_constraints::{MemberConstraintSet, NllMemberConstraintIndex}, - nll::PoloniusOutput, - region_infer::reverse_sccs::ReverseSccGraph, - region_infer::values::{ - LivenessValues, PlaceholderIndices, RegionElement, RegionValues, ToElementIndex, - }, - type_check::{free_region_relations::UniversalRegionRelations, Locations}, - universal_regions::UniversalRegions, - BorrowckInferCtxt, -}; - -mod dump_mir; -mod graphviz; -mod opaque_types; -mod reverse_sccs; - -pub mod values; - -pub struct RegionInferenceContext<'tcx> { - pub var_infos: VarInfos, - - /// Contains the definition for every region variable. Region - /// variables are identified by their index (`RegionVid`). The - /// definition contains information about where the region came - /// from as well as its final inferred value. - definitions: IndexVec>, - - /// The liveness constraints added to each region. For most - /// regions, these start out empty and steadily grow, though for - /// each universally quantified region R they start out containing - /// the entire CFG and `end(R)`. - liveness_constraints: LivenessValues, - - /// The outlives constraints computed by the type-check. - constraints: Frozen>, - - /// The constraint-set, but in graph form, making it easy to traverse - /// the constraints adjacent to a particular region. Used to construct - /// the SCC (see `constraint_sccs`) and for error reporting. - constraint_graph: Frozen, - - /// The SCC computed from `constraints` and the constraint - /// graph. We have an edge from SCC A to SCC B if `A: B`. Used to - /// compute the values of each region. - constraint_sccs: Rc>, - - /// Reverse of the SCC constraint graph -- i.e., an edge `A -> B` exists if - /// `B: A`. This is used to compute the universal regions that are required - /// to outlive a given SCC. Computed lazily. - rev_scc_graph: Option, - - /// The "R0 member of [R1..Rn]" constraints, indexed by SCC. - member_constraints: Rc>, - - /// Records the member constraints that we applied to each scc. - /// This is useful for error reporting. Once constraint - /// propagation is done, this vector is sorted according to - /// `member_region_scc`. - member_constraints_applied: Vec, - - /// Map universe indexes to information on why we created it. - universe_causes: FxIndexMap>, - - /// Contains the minimum universe of any variable within the same - /// SCC. We will ensure that no SCC contains values that are not - /// visible from this index. - scc_universes: IndexVec, - - /// Contains the "representative" region of each SCC. - /// It is defined as the one with the minimal RegionVid, favoring - /// free regions, then placeholders, then existential regions. - /// - /// It is a hacky way to manage checking regions for equality, - /// since we can 'canonicalize' each region to the representative - /// of its SCC and be sure that -- if they have the same repr -- - /// they *must* be equal (though not having the same repr does not - /// mean they are unequal). - scc_representatives: IndexVec, - - /// The final inferred values of the region variables; we compute - /// one value per SCC. To get the value for any given *region*, - /// you first find which scc it is a part of. - scc_values: RegionValues, - - /// Type constraints that we check after solving. - type_tests: Vec>, - - /// Information about the universally quantified regions in scope - /// on this function. - universal_regions: Rc>, - - /// Information about how the universally quantified regions in - /// scope on this function relate to one another. - universal_region_relations: Frozen>, -} - -/// Each time that `apply_member_constraint` is successful, it appends -/// one of these structs to the `member_constraints_applied` field. -/// This is used in error reporting to trace out what happened. -/// -/// The way that `apply_member_constraint` works is that it effectively -/// adds a new lower bound to the SCC it is analyzing: so you wind up -/// with `'R: 'O` where `'R` is the pick-region and `'O` is the -/// minimal viable option. -#[derive(Debug)] -pub(crate) struct AppliedMemberConstraint { - /// The SCC that was affected. (The "member region".) - /// - /// The vector if `AppliedMemberConstraint` elements is kept sorted - /// by this field. - pub(crate) member_region_scc: ConstraintSccIndex, - - /// The "best option" that `apply_member_constraint` found -- this was - /// added as an "ad-hoc" lower-bound to `member_region_scc`. - pub(crate) min_choice: ty::RegionVid, - - /// The "member constraint index" -- we can find out details about - /// the constraint from - /// `set.member_constraints[member_constraint_index]`. - pub(crate) member_constraint_index: NllMemberConstraintIndex, -} - -#[derive(Debug)] -pub(crate) struct RegionDefinition<'tcx> { - /// What kind of variable is this -- a free region? existential - /// variable? etc. (See the `NllRegionVariableOrigin` for more - /// info.) - pub(crate) origin: NllRegionVariableOrigin, - - /// Which universe is this region variable defined in? This is - /// most often `ty::UniverseIndex::ROOT`, but when we encounter - /// forall-quantifiers like `for<'a> { 'a = 'b }`, we would create - /// the variable for `'a` in a fresh universe that extends ROOT. - pub(crate) universe: ty::UniverseIndex, - - /// If this is 'static or an early-bound region, then this is - /// `Some(X)` where `X` is the name of the region. - pub(crate) external_name: Option>, -} - -/// N.B., the variants in `Cause` are intentionally ordered. Lower -/// values are preferred when it comes to error messages. Do not -/// reorder willy nilly. -#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] -pub(crate) enum Cause { - /// point inserted because Local was live at the given Location - LiveVar(Local, Location), - - /// point inserted because Local was dropped at the given Location - DropVar(Local, Location), -} - -/// A "type test" corresponds to an outlives constraint between a type -/// and a lifetime, like `T: 'x` or `::Bar: 'x`. They are -/// translated from the `Verify` region constraints in the ordinary -/// inference context. -/// -/// These sorts of constraints are handled differently than ordinary -/// constraints, at least at present. During type checking, the -/// `InferCtxt::process_registered_region_obligations` method will -/// attempt to convert a type test like `T: 'x` into an ordinary -/// outlives constraint when possible (for example, `&'a T: 'b` will -/// be converted into `'a: 'b` and registered as a `Constraint`). -/// -/// In some cases, however, there are outlives relationships that are -/// not converted into a region constraint, but rather into one of -/// these "type tests". The distinction is that a type test does not -/// influence the inference result, but instead just examines the -/// values that we ultimately inferred for each region variable and -/// checks that they meet certain extra criteria. If not, an error -/// can be issued. -/// -/// One reason for this is that these type tests typically boil down -/// to a check like `'a: 'x` where `'a` is a universally quantified -/// region -- and therefore not one whose value is really meant to be -/// *inferred*, precisely (this is not always the case: one can have a -/// type test like `>::Bar: 'x`, where `'?0` is an -/// inference variable). Another reason is that these type tests can -/// involve *disjunction* -- that is, they can be satisfied in more -/// than one way. -/// -/// For more information about this translation, see -/// `InferCtxt::process_registered_region_obligations` and -/// `InferCtxt::type_must_outlive` in `rustc_infer::infer::InferCtxt`. -#[derive(Clone, Debug)] -pub struct TypeTest<'tcx> { - /// The type `T` that must outlive the region. - pub generic_kind: GenericKind<'tcx>, - - /// The region `'x` that the type must outlive. - pub lower_bound: RegionVid, - - /// The span to blame. - pub span: Span, - - /// A test which, if met by the region `'x`, proves that this type - /// constraint is satisfied. - pub verify_bound: VerifyBound<'tcx>, -} - -/// When we have an unmet lifetime constraint, we try to propagate it outward (e.g. to a closure -/// environment). If we can't, it is an error. -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -enum RegionRelationCheckResult { - Ok, - Propagated, - Error, -} - -#[derive(Clone, PartialEq, Eq, Debug)] -enum Trace<'tcx> { - StartRegion, - FromOutlivesConstraint(OutlivesConstraint<'tcx>), - NotVisited, -} - -#[derive(Clone, PartialEq, Eq, Debug)] -pub enum ExtraConstraintInfo { - PlaceholderFromPredicate(Span), -} - -#[instrument(skip(infcx, sccs), level = "debug")] -fn sccs_info<'cx, 'tcx>( - infcx: &'cx BorrowckInferCtxt<'cx, 'tcx>, - sccs: Rc>, -) { - use crate::renumber::RegionCtxt; - - let var_to_origin = infcx.reg_var_to_origin.borrow(); - - let mut var_to_origin_sorted = var_to_origin.clone().into_iter().collect::>(); - var_to_origin_sorted.sort_by_key(|vto| vto.0); - - let mut reg_vars_to_origins_str = "region variables to origins:\n".to_string(); - for (reg_var, origin) in var_to_origin_sorted.into_iter() { - reg_vars_to_origins_str.push_str(&format!("{reg_var:?}: {origin:?}\n")); - } - debug!("{}", reg_vars_to_origins_str); - - let num_components = sccs.scc_data().ranges().len(); - let mut components = vec![FxIndexSet::default(); num_components]; - - for (reg_var_idx, scc_idx) in sccs.scc_indices().iter().enumerate() { - let reg_var = ty::RegionVid::from_usize(reg_var_idx); - let origin = var_to_origin.get(®_var).unwrap_or_else(|| &RegionCtxt::Unknown); - components[scc_idx.as_usize()].insert((reg_var, *origin)); - } - - let mut components_str = "strongly connected components:".to_string(); - for (scc_idx, reg_vars_origins) in components.iter().enumerate() { - let regions_info = reg_vars_origins.clone().into_iter().collect::>(); - components_str.push_str(&format!( - "{:?}: {:?},\n)", - ConstraintSccIndex::from_usize(scc_idx), - regions_info, - )) - } - debug!("{}", components_str); - - // calculate the best representative for each component - let components_representatives = components - .into_iter() - .enumerate() - .map(|(scc_idx, region_ctxts)| { - let repr = region_ctxts - .into_iter() - .map(|reg_var_origin| reg_var_origin.1) - .max_by(|x, y| x.preference_value().cmp(&y.preference_value())) - .unwrap(); - - (ConstraintSccIndex::from_usize(scc_idx), repr) - }) - .collect::>(); - - let mut scc_node_to_edges = FxIndexMap::default(); - for (scc_idx, repr) in components_representatives.iter() { - let edges_range = sccs.scc_data().ranges()[*scc_idx].clone(); - let edges = &sccs.scc_data().all_successors()[edges_range]; - let edge_representatives = - edges.iter().map(|scc_idx| components_representatives[scc_idx]).collect::>(); - scc_node_to_edges.insert((scc_idx, repr), edge_representatives); - } - - debug!("SCC edges {:#?}", scc_node_to_edges); -} - -impl<'tcx> RegionInferenceContext<'tcx> { - /// Creates a new region inference context with a total of - /// `num_region_variables` valid inference variables; the first N - /// of those will be constant regions representing the free - /// regions defined in `universal_regions`. - /// - /// The `outlives_constraints` and `type_tests` are an initial set - /// of constraints produced by the MIR type check. - pub(crate) fn new<'cx>( - _infcx: &BorrowckInferCtxt<'cx, 'tcx>, - var_infos: VarInfos, - universal_regions: Rc>, - placeholder_indices: Rc, - universal_region_relations: Frozen>, - outlives_constraints: OutlivesConstraintSet<'tcx>, - member_constraints_in: MemberConstraintSet<'tcx, RegionVid>, - universe_causes: FxIndexMap>, - type_tests: Vec>, - liveness_constraints: LivenessValues, - elements: &Rc, - ) -> Self { - debug!("universal_regions: {:#?}", universal_regions); - debug!("outlives constraints: {:#?}", outlives_constraints); - debug!("placeholder_indices: {:#?}", placeholder_indices); - debug!("type tests: {:#?}", type_tests); - - // Create a RegionDefinition for each inference variable. - let definitions: IndexVec<_, _> = var_infos - .iter() - .map(|info| RegionDefinition::new(info.universe, info.origin)) - .collect(); - - let constraints = Frozen::freeze(outlives_constraints); - let constraint_graph = Frozen::freeze(constraints.graph(definitions.len())); - let fr_static = universal_regions.fr_static; - let constraint_sccs = Rc::new(constraints.compute_sccs(&constraint_graph, fr_static)); - - if cfg!(debug_assertions) { - sccs_info(_infcx, constraint_sccs.clone()); - } - - let mut scc_values = - RegionValues::new(elements, universal_regions.len(), &placeholder_indices); - - for region in liveness_constraints.regions() { - let scc = constraint_sccs.scc(region); - scc_values.merge_liveness(scc, region, &liveness_constraints); - } - - let scc_universes = Self::compute_scc_universes(&constraint_sccs, &definitions); - - let scc_representatives = Self::compute_scc_representatives(&constraint_sccs, &definitions); - - let member_constraints = - Rc::new(member_constraints_in.into_mapped(|r| constraint_sccs.scc(r))); - - let mut result = Self { - var_infos, - definitions, - liveness_constraints, - constraints, - constraint_graph, - constraint_sccs, - rev_scc_graph: None, - member_constraints, - member_constraints_applied: Vec::new(), - universe_causes, - scc_universes, - scc_representatives, - scc_values, - type_tests, - universal_regions, - universal_region_relations, - }; - - result.init_free_and_bound_regions(); - - result - } - - /// Each SCC is the combination of many region variables which - /// have been equated. Therefore, we can associate a universe with - /// each SCC which is minimum of all the universes of its - /// constituent regions -- this is because whatever value the SCC - /// takes on must be a value that each of the regions within the - /// SCC could have as well. This implies that the SCC must have - /// the minimum, or narrowest, universe. - fn compute_scc_universes( - constraint_sccs: &Sccs, - definitions: &IndexSlice>, - ) -> IndexVec { - let num_sccs = constraint_sccs.num_sccs(); - let mut scc_universes = IndexVec::from_elem_n(ty::UniverseIndex::MAX, num_sccs); - - debug!("compute_scc_universes()"); - - // For each region R in universe U, ensure that the universe for the SCC - // that contains R is "no bigger" than U. This effectively sets the universe - // for each SCC to be the minimum of the regions within. - for (region_vid, region_definition) in definitions.iter_enumerated() { - let scc = constraint_sccs.scc(region_vid); - let scc_universe = &mut scc_universes[scc]; - let scc_min = std::cmp::min(region_definition.universe, *scc_universe); - if scc_min != *scc_universe { - *scc_universe = scc_min; - debug!( - "compute_scc_universes: lowered universe of {scc:?} to {scc_min:?} \ - because it contains {region_vid:?} in {region_universe:?}", - scc = scc, - scc_min = scc_min, - region_vid = region_vid, - region_universe = region_definition.universe, - ); - } - } - - // Walk each SCC `A` and `B` such that `A: B` - // and ensure that universe(A) can see universe(B). - // - // This serves to enforce the 'empty/placeholder' hierarchy - // (described in more detail on `RegionKind`): - // - // ``` - // static -----+ - // | | - // empty(U0) placeholder(U1) - // | / - // empty(U1) - // ``` - // - // In particular, imagine we have variables R0 in U0 and R1 - // created in U1, and constraints like this; - // - // ``` - // R1: !1 // R1 outlives the placeholder in U1 - // R1: R0 // R1 outlives R0 - // ``` - // - // Here, we wish for R1 to be `'static`, because it - // cannot outlive `placeholder(U1)` and `empty(U0)` any other way. - // - // Thanks to this loop, what happens is that the `R1: R0` - // constraint lowers the universe of `R1` to `U0`, which in turn - // means that the `R1: !1` constraint will (later) cause - // `R1` to become `'static`. - for scc_a in constraint_sccs.all_sccs() { - for &scc_b in constraint_sccs.successors(scc_a) { - let scc_universe_a = scc_universes[scc_a]; - let scc_universe_b = scc_universes[scc_b]; - let scc_universe_min = std::cmp::min(scc_universe_a, scc_universe_b); - if scc_universe_a != scc_universe_min { - scc_universes[scc_a] = scc_universe_min; - - debug!( - "compute_scc_universes: lowered universe of {scc_a:?} to {scc_universe_min:?} \ - because {scc_a:?}: {scc_b:?} and {scc_b:?} is in universe {scc_universe_b:?}", - scc_a = scc_a, - scc_b = scc_b, - scc_universe_min = scc_universe_min, - scc_universe_b = scc_universe_b - ); - } - } - } - - debug!("compute_scc_universes: scc_universe = {:#?}", scc_universes); - - scc_universes - } - - /// For each SCC, we compute a unique `RegionVid`. See the - /// `scc_representatives` field of `RegionInferenceContext` for - /// more details. - fn compute_scc_representatives( - constraints_scc: &Sccs, - definitions: &IndexSlice>, - ) -> IndexVec { - let num_sccs = constraints_scc.num_sccs(); - let mut scc_representatives = IndexVec::from_elem_n(RegionVid::MAX, num_sccs); - - // Iterate over all RegionVids *in-order* and pick the least RegionVid as the - // representative of its SCC. This naturally prefers free regions over others. - for (vid, def) in definitions.iter_enumerated() { - let repr = &mut scc_representatives[constraints_scc.scc(vid)]; - if *repr == ty::RegionVid::MAX { - *repr = vid; - } else if matches!(def.origin, NllRegionVariableOrigin::Placeholder(_)) - && matches!(definitions[*repr].origin, NllRegionVariableOrigin::Existential { .. }) - { - // Pick placeholders over existentials even if they have a greater RegionVid. - *repr = vid; - } - } - - scc_representatives - } - - /// Initializes the region variables for each universally - /// quantified region (lifetime parameter). The first N variables - /// always correspond to the regions appearing in the function - /// signature (both named and anonymous) and where-clauses. This - /// function iterates over those regions and initializes them with - /// minimum values. - /// - /// For example: - /// ``` - /// fn foo<'a, 'b>( /* ... */ ) where 'a: 'b { /* ... */ } - /// ``` - /// would initialize two variables like so: - /// ```ignore (illustrative) - /// R0 = { CFG, R0 } // 'a - /// R1 = { CFG, R0, R1 } // 'b - /// ``` - /// Here, R0 represents `'a`, and it contains (a) the entire CFG - /// and (b) any universally quantified regions that it outlives, - /// which in this case is just itself. R1 (`'b`) in contrast also - /// outlives `'a` and hence contains R0 and R1. - fn init_free_and_bound_regions(&mut self) { - // Update the names (if any) - // This iterator has unstable order but we collect it all into an IndexVec - for (external_name, variable) in self.universal_regions.named_universal_regions() { - debug!( - "init_universal_regions: region {:?} has external name {:?}", - variable, external_name - ); - self.definitions[variable].external_name = Some(external_name); - } - - for variable in self.definitions.indices() { - let scc = self.constraint_sccs.scc(variable); - - match self.definitions[variable].origin { - NllRegionVariableOrigin::FreeRegion => { - // For each free, universally quantified region X: - - // Add all nodes in the CFG to liveness constraints - self.liveness_constraints.add_all_points(variable); - self.scc_values.add_all_points(scc); - - // Add `end(X)` into the set for X. - self.scc_values.add_element(scc, variable); - } - - NllRegionVariableOrigin::Placeholder(placeholder) => { - // Each placeholder region is only visible from - // its universe `ui` and its extensions. So we - // can't just add it into `scc` unless the - // universe of the scc can name this region. - let scc_universe = self.scc_universes[scc]; - if scc_universe.can_name(placeholder.universe) { - self.scc_values.add_element(scc, placeholder); - } else { - debug!( - "init_free_and_bound_regions: placeholder {:?} is \ - not compatible with universe {:?} of its SCC {:?}", - placeholder, scc_universe, scc, - ); - self.add_incompatible_universe(scc); - } - } - - NllRegionVariableOrigin::Existential { .. } => { - // For existential, regions, nothing to do. - } - } - } - } - - /// Returns an iterator over all the region indices. - pub fn regions(&self) -> impl Iterator + 'tcx { - self.definitions.indices() - } - - /// Given a universal region in scope on the MIR, returns the - /// corresponding index. - /// - /// (Panics if `r` is not a registered universal region.) - pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid { - self.universal_regions.to_region_vid(r) - } - - /// Returns an iterator over all the outlives constraints. - pub fn outlives_constraints(&self) -> impl Iterator> + '_ { - self.constraints.outlives().iter().copied() - } - - /// Adds annotations for `#[rustc_regions]`; see `UniversalRegions::annotate`. - pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diag<'_, ()>) { - self.universal_regions.annotate(tcx, err) - } - - /// Returns `true` if the region `r` contains the point `p`. - /// - /// Panics if called before `solve()` executes, - pub(crate) fn region_contains(&self, r: RegionVid, p: impl ToElementIndex) -> bool { - let scc = self.constraint_sccs.scc(r); - self.scc_values.contains(scc, p) - } - - /// Returns the lowest statement index in `start..=end` which is not contained by `r`. - /// - /// Panics if called before `solve()` executes. - pub(crate) fn first_non_contained_inclusive( - &self, - r: RegionVid, - block: BasicBlock, - start: usize, - end: usize, - ) -> Option { - let scc = self.constraint_sccs.scc(r); - self.scc_values.first_non_contained_inclusive(scc, block, start, end) - } - - /// Returns access to the value of `r` for debugging purposes. - pub(crate) fn region_value_str(&self, r: RegionVid) -> String { - let scc = self.constraint_sccs.scc(r); - self.scc_values.region_value_str(scc) - } - - pub(crate) fn placeholders_contained_in<'a>( - &'a self, - r: RegionVid, - ) -> impl Iterator + 'a { - let scc = self.constraint_sccs.scc(r); - self.scc_values.placeholders_contained_in(scc) - } - - /// Returns access to the value of `r` for debugging purposes. - pub(crate) fn region_universe(&self, r: RegionVid) -> ty::UniverseIndex { - let scc = self.constraint_sccs.scc(r); - self.scc_universes[scc] - } - - /// Once region solving has completed, this function will return the member constraints that - /// were applied to the value of a given SCC `scc`. See `AppliedMemberConstraint`. - pub(crate) fn applied_member_constraints( - &self, - scc: ConstraintSccIndex, - ) -> &[AppliedMemberConstraint] { - binary_search_util::binary_search_slice( - &self.member_constraints_applied, - |applied| applied.member_region_scc, - &scc, - ) - } - - /// Performs region inference and report errors if we see any - /// unsatisfiable constraints. If this is a closure, returns the - /// region requirements to propagate to our creator, if any. - #[instrument(skip(self, infcx, body, polonius_output), level = "debug")] - pub(super) fn solve( - &mut self, - infcx: &InferCtxt<'tcx>, - body: &Body<'tcx>, - polonius_output: Option>, - ) -> (Option>, RegionErrors<'tcx>) { - let mir_def_id = body.source.def_id(); - self.propagate_constraints(); - - let mut errors_buffer = RegionErrors::new(infcx.tcx); - - // If this is a closure, we can propagate unsatisfied - // `outlives_requirements` to our creator, so create a vector - // to store those. Otherwise, we'll pass in `None` to the - // functions below, which will trigger them to report errors - // eagerly. - let mut outlives_requirements = infcx.tcx.is_typeck_child(mir_def_id).then(Vec::new); - - self.check_type_tests(infcx, outlives_requirements.as_mut(), &mut errors_buffer); - - debug!(?errors_buffer); - debug!(?outlives_requirements); - - // In Polonius mode, the errors about missing universal region relations are in the output - // and need to be emitted or propagated. Otherwise, we need to check whether the - // constraints were too strong, and if so, emit or propagate those errors. - if infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled() { - self.check_polonius_subset_errors( - outlives_requirements.as_mut(), - &mut errors_buffer, - polonius_output.expect("Polonius output is unavailable despite `-Z polonius`"), - ); - } else { - self.check_universal_regions(outlives_requirements.as_mut(), &mut errors_buffer); - } - - debug!(?errors_buffer); - - if errors_buffer.is_empty() { - self.check_member_constraints(infcx, &mut errors_buffer); - } - - debug!(?errors_buffer); - - let outlives_requirements = outlives_requirements.unwrap_or_default(); - - if outlives_requirements.is_empty() { - (None, errors_buffer) - } else { - let num_external_vids = self.universal_regions.num_global_and_external_regions(); - ( - Some(ClosureRegionRequirements { num_external_vids, outlives_requirements }), - errors_buffer, - ) - } - } - - /// Propagate the region constraints: this will grow the values - /// for each region variable until all the constraints are - /// satisfied. Note that some values may grow **too** large to be - /// feasible, but we check this later. - #[instrument(skip(self), level = "debug")] - fn propagate_constraints(&mut self) { - debug!("constraints={:#?}", { - let mut constraints: Vec<_> = self.outlives_constraints().collect(); - constraints.sort_by_key(|c| (c.sup, c.sub)); - constraints - .into_iter() - .map(|c| (c, self.constraint_sccs.scc(c.sup), self.constraint_sccs.scc(c.sub))) - .collect::>() - }); - - // To propagate constraints, we walk the DAG induced by the - // SCC. For each SCC, we visit its successors and compute - // their values, then we union all those values to get our - // own. - let constraint_sccs = self.constraint_sccs.clone(); - for scc in constraint_sccs.all_sccs() { - self.compute_value_for_scc(scc); - } - - // Sort the applied member constraints so we can binary search - // through them later. - self.member_constraints_applied.sort_by_key(|applied| applied.member_region_scc); - } - - /// Computes the value of the SCC `scc_a`, which has not yet been - /// computed, by unioning the values of its successors. - /// Assumes that all successors have been computed already - /// (which is assured by iterating over SCCs in dependency order). - #[instrument(skip(self), level = "debug")] - fn compute_value_for_scc(&mut self, scc_a: ConstraintSccIndex) { - let constraint_sccs = self.constraint_sccs.clone(); - - // Walk each SCC `B` such that `A: B`... - for &scc_b in constraint_sccs.successors(scc_a) { - debug!(?scc_b); - - // ...and add elements from `B` into `A`. One complication - // arises because of universes: If `B` contains something - // that `A` cannot name, then `A` can only contain `B` if - // it outlives static. - if self.universe_compatible(scc_b, scc_a) { - // `A` can name everything that is in `B`, so just - // merge the bits. - self.scc_values.add_region(scc_a, scc_b); - } else { - self.add_incompatible_universe(scc_a); - } - } - - // Now take member constraints into account. - let member_constraints = self.member_constraints.clone(); - for m_c_i in member_constraints.indices(scc_a) { - self.apply_member_constraint(scc_a, m_c_i, member_constraints.choice_regions(m_c_i)); - } - - debug!(value = ?self.scc_values.region_value_str(scc_a)); - } - - /// Invoked for each `R0 member of [R1..Rn]` constraint. - /// - /// `scc` is the SCC containing R0, and `choice_regions` are the - /// `R1..Rn` regions -- they are always known to be universal - /// regions (and if that's not true, we just don't attempt to - /// enforce the constraint). - /// - /// The current value of `scc` at the time the method is invoked - /// is considered a *lower bound*. If possible, we will modify - /// the constraint to set it equal to one of the option regions. - /// If we make any changes, returns true, else false. - /// - /// This function only adds the member constraints to the region graph, - /// it does not check them. They are later checked in - /// `check_member_constraints` after the region graph has been computed. - #[instrument(skip(self, member_constraint_index), level = "debug")] - fn apply_member_constraint( - &mut self, - scc: ConstraintSccIndex, - member_constraint_index: NllMemberConstraintIndex, - choice_regions: &[ty::RegionVid], - ) { - // Lazily compute the reverse graph, we'll need it later. - self.compute_reverse_scc_graph(); - - // Create a mutable vector of the options. We'll try to winnow - // them down. - let mut choice_regions: Vec = choice_regions.to_vec(); - - // Convert to the SCC representative: sometimes we have inference - // variables in the member constraint that wind up equated with - // universal regions. The scc representative is the minimal numbered - // one from the corresponding scc so it will be the universal region - // if one exists. - for c_r in &mut choice_regions { - let scc = self.constraint_sccs.scc(*c_r); - *c_r = self.scc_representatives[scc]; - } - - // If the member region lives in a higher universe, we currently choose - // the most conservative option by leaving it unchanged. - if self.scc_universes[scc] != ty::UniverseIndex::ROOT { - return; - } - debug_assert!( - self.scc_values.placeholders_contained_in(scc).next().is_none(), - "scc {:?} in a member constraint has placeholder value: {:?}", - scc, - self.scc_values.region_value_str(scc), - ); - - // The existing value for `scc` is a lower-bound. This will - // consist of some set `{P} + {LB}` of points `{P}` and - // lower-bound free regions `{LB}`. As each choice region `O` - // is a free region, it will outlive the points. But we can - // only consider the option `O` if `O: LB`. - choice_regions.retain(|&o_r| { - self.scc_values - .universal_regions_outlived_by(scc) - .all(|lb| self.universal_region_relations.outlives(o_r, lb)) - }); - debug!(?choice_regions, "after lb"); - - // Now find all the *upper bounds* -- that is, each UB is a - // free region that must outlive the member region `R0` (`UB: - // R0`). Therefore, we need only keep an option `O` if `UB: O` - // for all UB. - let universal_region_relations = &self.universal_region_relations; - for ub in self.rev_scc_graph.as_ref().unwrap().upper_bounds(scc) { - debug!(?ub); - choice_regions.retain(|&o_r| universal_region_relations.outlives(ub, o_r)); - } - debug!(?choice_regions, "after ub"); - - // At this point we can pick any member of `choice_regions`, but to avoid potential - // non-determinism we will pick the *unique minimum* choice. - // - // Because universal regions are only partially ordered (i.e, not every two regions are - // comparable), we will ignore any region that doesn't compare to all others when picking - // the minimum choice. - // For example, consider `choice_regions = ['static, 'a, 'b, 'c, 'd, 'e]`, where - // `'static: 'a, 'static: 'b, 'a: 'c, 'b: 'c, 'c: 'd, 'c: 'e`. - // `['d, 'e]` are ignored because they do not compare - the same goes for `['a, 'b]`. - let totally_ordered_subset = choice_regions.iter().copied().filter(|&r1| { - choice_regions.iter().all(|&r2| { - self.universal_region_relations.outlives(r1, r2) - || self.universal_region_relations.outlives(r2, r1) - }) - }); - // Now we're left with `['static, 'c]`. Pick `'c` as the minimum! - let Some(min_choice) = totally_ordered_subset.reduce(|r1, r2| { - let r1_outlives_r2 = self.universal_region_relations.outlives(r1, r2); - let r2_outlives_r1 = self.universal_region_relations.outlives(r2, r1); - match (r1_outlives_r2, r2_outlives_r1) { - (true, true) => r1.min(r2), - (true, false) => r2, - (false, true) => r1, - (false, false) => bug!("incomparable regions in total order"), - } - }) else { - debug!("no unique minimum choice"); - return; - }; - - let min_choice_scc = self.constraint_sccs.scc(min_choice); - debug!(?min_choice, ?min_choice_scc); - if self.scc_values.add_region(scc, min_choice_scc) { - self.member_constraints_applied.push(AppliedMemberConstraint { - member_region_scc: scc, - min_choice, - member_constraint_index, - }); - } - } - - /// Returns `true` if all the elements in the value of `scc_b` are nameable - /// in `scc_a`. Used during constraint propagation, and only once - /// the value of `scc_b` has been computed. - fn universe_compatible(&self, scc_b: ConstraintSccIndex, scc_a: ConstraintSccIndex) -> bool { - let universe_a = self.scc_universes[scc_a]; - - // Quick check: if scc_b's declared universe is a subset of - // scc_a's declared universe (typically, both are ROOT), then - // it cannot contain any problematic universe elements. - if universe_a.can_name(self.scc_universes[scc_b]) { - return true; - } - - // Otherwise, we have to iterate over the universe elements in - // B's value, and check whether all of them are nameable - // from universe_a - self.scc_values.placeholders_contained_in(scc_b).all(|p| universe_a.can_name(p.universe)) - } - - /// Extend `scc` so that it can outlive some placeholder region - /// from a universe it can't name; at present, the only way for - /// this to be true is if `scc` outlives `'static`. This is - /// actually stricter than necessary: ideally, we'd support bounds - /// like `for<'a: 'b>` that might then allow us to approximate - /// `'a` with `'b` and not `'static`. But it will have to do for - /// now. - fn add_incompatible_universe(&mut self, scc: ConstraintSccIndex) { - debug!("add_incompatible_universe(scc={:?})", scc); - - let fr_static = self.universal_regions.fr_static; - self.scc_values.add_all_points(scc); - self.scc_values.add_element(scc, fr_static); - } - - /// Once regions have been propagated, this method is used to see - /// whether the "type tests" produced by typeck were satisfied; - /// type tests encode type-outlives relationships like `T: - /// 'a`. See `TypeTest` for more details. - fn check_type_tests( - &self, - infcx: &InferCtxt<'tcx>, - mut propagated_outlives_requirements: Option<&mut Vec>>, - errors_buffer: &mut RegionErrors<'tcx>, - ) { - let tcx = infcx.tcx; - - // Sometimes we register equivalent type-tests that would - // result in basically the exact same error being reported to - // the user. Avoid that. - let mut deduplicate_errors = FxIndexSet::default(); - - for type_test in &self.type_tests { - debug!("check_type_test: {:?}", type_test); - - let generic_ty = type_test.generic_kind.to_ty(tcx); - if self.eval_verify_bound( - infcx, - generic_ty, - type_test.lower_bound, - &type_test.verify_bound, - ) { - continue; - } - - if let Some(propagated_outlives_requirements) = &mut propagated_outlives_requirements { - if self.try_promote_type_test(infcx, type_test, propagated_outlives_requirements) { - continue; - } - } - - // Type-test failed. Report the error. - let erased_generic_kind = infcx.tcx.erase_regions(type_test.generic_kind); - - // Skip duplicate-ish errors. - if deduplicate_errors.insert(( - erased_generic_kind, - type_test.lower_bound, - type_test.span, - )) { - debug!( - "check_type_test: reporting error for erased_generic_kind={:?}, \ +use std::collections::VecDeque;use std::rc::Rc;use rustc_data_structures:://{;}; +binary_search_util;use rustc_data_structures::frozen::Frozen;use//if let _=(){}; +rustc_data_structures::fx::{FxIndexMap,FxIndexSet};use rustc_data_structures::// +graph::scc::Sccs;use rustc_errors:: Diag;use rustc_hir::def_id::CRATE_DEF_ID;use +rustc_index::{IndexSlice,IndexVec};use rustc_infer::infer::outlives:://let _=(); +test_type_match;use rustc_infer::infer::region_constraints::{GenericKind,//({}); +VarInfos,VerifyBound,VerifyIfEq};use rustc_infer::infer::{InferCtxt,//if true{}; +NllRegionVariableOrigin,RegionVariableOrigin};use rustc_middle::mir::{//((),()); +BasicBlock,Body,ClosureOutlivesRequirement,ClosureOutlivesSubject,//loop{break}; +ClosureOutlivesSubjectTy,ClosureRegionRequirements,ConstraintCategory,Local,//3; +Location,ReturnConstraint,TerminatorKind,};use rustc_middle::traits:://let _=(); +ObligationCause;use rustc_middle::traits::ObligationCauseCode;use rustc_middle// +::ty::{self,RegionVid,Ty,TyCtxt,TypeFoldable};use rustc_mir_dataflow::points::// +DenseLocationMap;use rustc_span::Span;use crate::constraints::graph::{self,//(); +NormalConstraintGraph,RegionGraph};use crate ::dataflow::BorrowIndex;use crate:: +{constraints::{ConstraintSccIndex,OutlivesConstraint,OutlivesConstraintSet},//3; +diagnostics::{RegionErrorKind,RegionErrors,UniverseInfo},member_constraints::{// +MemberConstraintSet,NllMemberConstraintIndex},nll::PoloniusOutput,region_infer// +::reverse_sccs::ReverseSccGraph,region_infer::values::{LivenessValues,//((),()); +PlaceholderIndices,RegionElement,RegionValues,ToElementIndex,},type_check::{//3; +free_region_relations::UniversalRegionRelations,Locations},universal_regions::// +UniversalRegions,BorrowckInferCtxt,};mod dump_mir;mod graphviz;mod opaque_types +;mod reverse_sccs;pub mod values;pub struct RegionInferenceContext<'tcx>{pub//3; +var_infos:VarInfos,definitions:IndexVec>,//{;}; +liveness_constraints:LivenessValues,constraints:Frozen>,constraint_graph:Frozen,constraint_sccs:Rc>,rev_scc_graph:Option,//let _=(); +member_constraints:Rc>,//if true{}; +member_constraints_applied:Vec,universe_causes://{();}; +FxIndexMap>,scc_universes:IndexVec,scc_representatives:IndexVec,scc_values:RegionValues,// +type_tests:Vec>,universal_regions:Rc>,//3; +universal_region_relations:Frozen>,}#[derive(//3; +Debug)]pub(crate)struct AppliedMemberConstraint{pub(crate)member_region_scc://3; +ConstraintSccIndex,pub(crate)min_choice:ty::RegionVid,pub(crate)//if let _=(){}; +member_constraint_index:NllMemberConstraintIndex,}#[derive(Debug)]pub(crate)//3; +struct RegionDefinition<'tcx>{pub(crate)origin:NllRegionVariableOrigin,pub(//(); +crate)universe:ty::UniverseIndex,pub( crate)external_name:Option>,}#[derive(Copy,Clone,Debug,PartialOrd ,Ord,PartialEq,Eq)]pub(crate)enum Cause +{LiveVar(Local,Location),DropVar(Local,Location),}#[derive(Clone,Debug)]pub//(); +struct TypeTest<'tcx>{pub generic_kind:GenericKind<'tcx>,pub lower_bound://({}); +RegionVid,pub span:Span,pub verify_bound: VerifyBound<'tcx>,}#[derive(Clone,Copy +,Debug,Eq,PartialEq)]enum RegionRelationCheckResult{Ok,Propagated,Error,}#[//(); +derive(Clone,PartialEq,Eq,Debug)]enum Trace<'tcx>{StartRegion,//((),());((),()); +FromOutlivesConstraint(OutlivesConstraint<'tcx>),NotVisited,}#[derive(Clone,//3; +PartialEq,Eq,Debug)]pub enum ExtraConstraintInfo{PlaceholderFromPredicate(Span) +,}#[instrument(skip(infcx,sccs),level="debug")]fn sccs_info<'cx,'tcx>(infcx:&//; +'cx BorrowckInferCtxt<'cx,'tcx>,sccs:Rc>,){3; +use crate::renumber::RegionCtxt;();();let var_to_origin=infcx.reg_var_to_origin. +borrow();;let mut var_to_origin_sorted=var_to_origin.clone().into_iter().collect +::>();{;};{;};var_to_origin_sorted.sort_by_key(|vto|vto.0);{;};();let mut +reg_vars_to_origins_str="region variables to origins:\n".to_string();*&*&();for( +reg_var,origin)in var_to_origin_sorted.into_iter(){({});reg_vars_to_origins_str. +push_str(&format!("{reg_var:?}: {origin:?}\n"));if true{};}let _=();debug!("{}", +reg_vars_to_origins_str);;;let num_components=sccs.scc_data().ranges().len();let +mut components=vec![FxIndexSet::default();num_components];{();};for(reg_var_idx, +scc_idx)in sccs.scc_indices().iter().enumerate(){{;};let reg_var=ty::RegionVid:: +from_usize(reg_var_idx);;;let origin=var_to_origin.get(®_var).unwrap_or_else( +||&RegionCtxt::Unknown);;components[scc_idx.as_usize()].insert((reg_var,*origin) +);3;}3;let mut components_str="strongly connected components:".to_string();;for( +scc_idx,reg_vars_origins)in components.iter().enumerate(){({});let regions_info= +reg_vars_origins.clone().into_iter().collect::>();((),());components_str. +push_str(&format!("{:?}: {:?},\n)",ConstraintSccIndex::from_usize(scc_idx),//(); +regions_info,))}3;debug!("{}",components_str);3;;let components_representatives= +components.into_iter().enumerate().map(|(scc_idx,region_ctxts)|{*&*&();let repr= +region_ctxts.into_iter().map((|reg_var_origin|reg_var_origin.1 )).max_by(|x,y|x. +preference_value().cmp(&y.preference_value())).unwrap();();(ConstraintSccIndex:: +from_usize(scc_idx),repr)}).collect::>();((),());((),());let mut +scc_node_to_edges=FxIndexMap::default();if true{};if true{};for(scc_idx,repr)in +components_representatives.iter(){{;};let edges_range=sccs.scc_data().ranges()[* +scc_idx].clone();;;let edges=&sccs.scc_data().all_successors()[edges_range];;let +edge_representatives=(((edges.iter()))).map(|scc_idx|components_representatives[ +scc_idx]).collect::>();({});({});scc_node_to_edges.insert((scc_idx,repr), +edge_representatives);;};debug!("SCC edges {:#?}",scc_node_to_edges);}impl<'tcx> +RegionInferenceContext<'tcx>{pub(crate)fn new<'cx>(_infcx:&BorrowckInferCtxt,var_infos:VarInfos,universal_regions:Rc>,//{;}; +placeholder_indices:Rc,universal_region_relations:Frozen>, outlives_constraints:OutlivesConstraintSet<'tcx +>,member_constraints_in:MemberConstraintSet<'tcx,RegionVid>,universe_causes://3; +FxIndexMap>,type_tests:Vec> +,liveness_constraints:LivenessValues,elements:&Rc,)->Self{{;}; +debug!("universal_regions: {:#?}",universal_regions);if true{};if true{};debug!( +"outlives constraints: {:#?}",outlives_constraints);let _=||();if true{};debug!( +"placeholder_indices: {:#?}",placeholder_indices);3;;debug!("type tests: {:#?}", +type_tests);{();};({});let definitions:IndexVec<_,_>=var_infos.iter().map(|info| +RegionDefinition::new(info.universe,info.origin)).collect();3;3;let constraints= +Frozen::freeze(outlives_constraints);{;};();let constraint_graph=Frozen::freeze( +constraints.graph(definitions.len()));;let fr_static=universal_regions.fr_static +;{;};{;};let constraint_sccs=Rc::new(constraints.compute_sccs(&constraint_graph, +fr_static));;if cfg!(debug_assertions){sccs_info(_infcx,constraint_sccs.clone()) +;{;};}();let mut scc_values=RegionValues::new(elements,universal_regions.len(),& +placeholder_indices);();for region in liveness_constraints.regions(){();let scc= +constraint_sccs.scc(region);*&*&();*&*&();scc_values.merge_liveness(scc,region,& +liveness_constraints);({});}({});let scc_universes=Self::compute_scc_universes(& +constraint_sccs,&definitions);if true{};if true{};let scc_representatives=Self:: +compute_scc_representatives(&constraint_sccs,&definitions);let _=();let _=();let +member_constraints=Rc::new(member_constraints_in .into_mapped(|r|constraint_sccs +.scc(r)));{;};();let mut result=Self{var_infos,definitions,liveness_constraints, +constraints,constraint_graph,constraint_sccs,rev_scc_graph:None,//if let _=(){}; +member_constraints,member_constraints_applied:(((Vec:: new()))),universe_causes, +scc_universes,scc_representatives,scc_values,type_tests,universal_regions,//{;}; +universal_region_relations,};3;3;result.init_free_and_bound_regions();;result}fn +compute_scc_universes(constraint_sccs:&Sccs,//{;}; +definitions:&IndexSlice>,)->IndexVec{;let num_sccs=constraint_sccs.num_sccs();; +let mut scc_universes=IndexVec::from_elem_n(ty::UniverseIndex::MAX,num_sccs);3;; +debug!("compute_scc_universes()");if true{};for(region_vid,region_definition)in +definitions.iter_enumerated(){();let scc=constraint_sccs.scc(region_vid);3;3;let +scc_universe=&mut scc_universes[scc];let _=();((),());let scc_min=std::cmp::min( +region_definition.universe,*scc_universe);{();};if scc_min!=*scc_universe{({});* +scc_universe=scc_min;loop{break;};loop{break;};loop{break;};loop{break;};debug!( +"compute_scc_universes: lowered universe of {scc:?} to {scc_min:?} \ + because it contains {region_vid:?} in {region_universe:?}" +,scc=scc,scc_min=scc_min,region_vid=region_vid,region_universe=//*&*&();((),()); +region_definition.universe,);({});}}for scc_a in constraint_sccs.all_sccs(){for& +scc_b in constraint_sccs.successors(scc_a){{;};let scc_universe_a=scc_universes[ +scc_a];;;let scc_universe_b=scc_universes[scc_b];let scc_universe_min=std::cmp:: +min(scc_universe_a,scc_universe_b);({});if scc_universe_a!=scc_universe_min{{;}; +scc_universes[scc_a]=scc_universe_min;let _=();let _=();((),());let _=();debug!( +"compute_scc_universes: lowered universe of {scc_a:?} to {scc_universe_min:?} \ + because {scc_a:?}: {scc_b:?} and {scc_b:?} is in universe {scc_universe_b:?}" +,scc_a=scc_a,scc_b=scc_b,scc_universe_min=scc_universe_min,scc_universe_b=//{;}; +scc_universe_b);{;};}}}{;};debug!("compute_scc_universes: scc_universe = {:#?}", +scc_universes);();scc_universes}fn compute_scc_representatives(constraints_scc:& +Sccs,definitions:&IndexSlice>,)->IndexVec{*&*&();let +num_sccs=constraints_scc.num_sccs();();();let mut scc_representatives=IndexVec:: +from_elem_n(RegionVid::MAX,num_sccs);;for(vid,def)in definitions.iter_enumerated +(){3;let repr=&mut scc_representatives[constraints_scc.scc(vid)];3;if*repr==ty:: +RegionVid::MAX{;*repr=vid;}else if matches!(def.origin,NllRegionVariableOrigin:: +Placeholder(_))&&matches!(definitions[*repr].origin,NllRegionVariableOrigin:://; +Existential{..}){;*repr=vid;}}scc_representatives}fn init_free_and_bound_regions +(&mut self){for(external_name,variable)in self.universal_regions.//loop{break;}; +named_universal_regions(){let _=||();loop{break};loop{break};loop{break};debug!( +"init_universal_regions: region {:?} has external name {:?}",variable,//((),()); +external_name);;;self.definitions[variable].external_name=Some(external_name);;} +for variable in self.definitions.indices(){{;};let scc=self.constraint_sccs.scc( +variable);({});match self.definitions[variable].origin{NllRegionVariableOrigin:: +FreeRegion=>{;self.liveness_constraints.add_all_points(variable);self.scc_values +.add_all_points(scc);{();};({});self.scc_values.add_element(scc,variable);({});} +NllRegionVariableOrigin::Placeholder(placeholder)=>{{();};let scc_universe=self. +scc_universes[scc];({});if scc_universe.can_name(placeholder.universe){{;};self. +scc_values.add_element(scc,placeholder);if let _=(){};}else{loop{break;};debug!( +"init_free_and_bound_regions: placeholder {:?} is \ + not compatible with universe {:?} of its SCC {:?}" +,placeholder,scc_universe,scc,);{;};();self.add_incompatible_universe(scc);();}} +NllRegionVariableOrigin::Existential{..}=>{}}}}pub fn regions(&self)->impl//{;}; +Iterator+'tcx{self.definitions .indices()}pub fn to_region_vid(& +self,r:ty::Region<'tcx>)->RegionVid {self.universal_regions.to_region_vid(r)}pub +fn outlives_constraints(&self)->impl Iterator>+//; +'_{self.constraints.outlives().iter() .copied()}pub(crate)fn annotate(&self,tcx: +TyCtxt<'tcx>,err:&mut Diag<'_,() >){self.universal_regions.annotate(tcx,err)}pub +(crate)fn region_contains(&self,r:RegionVid,p:impl ToElementIndex)->bool{{;};let +scc=self.constraint_sccs.scc(r);{;};self.scc_values.contains(scc,p)}pub(crate)fn +first_non_contained_inclusive(&self,r:RegionVid,block:BasicBlock,start:usize,//; +end:usize,)->Option{;let scc=self.constraint_sccs.scc(r);self.scc_values. +first_non_contained_inclusive(scc,block,start,end)}pub(crate)fn//*&*&();((),()); +region_value_str(&self,r:RegionVid)->String{;let scc=self.constraint_sccs.scc(r) +;3;self.scc_values.region_value_str(scc)}pub(crate)fn placeholders_contained_in< +'a>(&'a self,r:RegionVid,)->impl Iterator+'a{{;};let +scc=self.constraint_sccs.scc(r);;self.scc_values.placeholders_contained_in(scc)} +pub(crate)fn region_universe(&self,r:RegionVid)->ty::UniverseIndex{;let scc=self +.constraint_sccs.scc(r);if true{};if true{};self.scc_universes[scc]}pub(crate)fn +applied_member_constraints(&self,scc:ConstraintSccIndex,)->&[//((),());let _=(); +AppliedMemberConstraint]{binary_search_util::binary_search_slice(&self.//*&*&(); +member_constraints_applied,((|applied|applied.member_region_scc)) ,((&scc)),)}#[ +instrument(skip(self,infcx,body,polonius_output),level="debug")]pub(super)fn//3; +solve(&mut self,infcx:&InferCtxt<'tcx >,body:&Body<'tcx>,polonius_output:Option< +Rc>,)->(Option>,RegionErrors){;let mir_def_id=body.source.def_id();self.propagate_constraints();let mut +errors_buffer=RegionErrors::new(infcx.tcx);;;let mut outlives_requirements=infcx +.tcx.is_typeck_child(mir_def_id).then(Vec::new);3;3;self.check_type_tests(infcx, +outlives_requirements.as_mut(),&mut errors_buffer);;debug!(?errors_buffer);debug +!(?outlives_requirements);((),());if infcx.tcx.sess.opts.unstable_opts.polonius. +is_legacy_enabled(){{;};self.check_polonius_subset_errors(outlives_requirements. +as_mut(),((((((((((((((&mut errors_buffer)))))))))))))),polonius_output.expect( +"Polonius output is unavailable despite `-Z polonius`"),);{();};}else{({});self. +check_universal_regions(outlives_requirements.as_mut(),&mut errors_buffer);3;}3; +debug!(?errors_buffer);loop{break};if errors_buffer.is_empty(){loop{break};self. +check_member_constraints(infcx,&mut errors_buffer);;};debug!(?errors_buffer);let +outlives_requirements=outlives_requirements.unwrap_or_default();loop{break;};if +outlives_requirements.is_empty(){(None,errors_buffer)}else{let _=();let _=();let +num_external_vids=self.universal_regions.num_global_and_external_regions();{;};( +Some((((ClosureRegionRequirements{num_external_vids ,outlives_requirements})))), +errors_buffer,)}}#[instrument(skip(self),level="debug")]fn//if true{};if true{}; +propagate_constraints(&mut self){loop{break};debug!("constraints={:#?}",{let mut +constraints:Vec<_>=self.outlives_constraints().collect();constraints.//let _=(); +sort_by_key(|c|(c.sup,c.sub));constraints.into_iter().map(|c|(c,self.//let _=(); +constraint_sccs.scc(c.sup),self.constraint_sccs.scc( c.sub))).collect::>( +)});;let constraint_sccs=self.constraint_sccs.clone();for scc in constraint_sccs +.all_sccs(){;self.compute_value_for_scc(scc);;};self.member_constraints_applied. +sort_by_key(|applied|applied.member_region_scc);;}#[instrument(skip(self),level= +"debug")]fn compute_value_for_scc(&mut self,scc_a:ConstraintSccIndex){*&*&();let +constraint_sccs=self.constraint_sccs.clone();{();};for&scc_b in constraint_sccs. +successors(scc_a){;debug!(?scc_b);if self.universe_compatible(scc_b,scc_a){self. +scc_values.add_region(scc_a,scc_b);;}else{self.add_incompatible_universe(scc_a); +}}({});let member_constraints=self.member_constraints.clone();({});for m_c_i in +member_constraints.indices(scc_a){({});self.apply_member_constraint(scc_a,m_c_i, +member_constraints.choice_regions(m_c_i));{;};}();debug!(value=?self.scc_values. +region_value_str(scc_a));;}#[instrument(skip(self,member_constraint_index),level +="debug")]fn apply_member_constraint(&mut self,scc:ConstraintSccIndex,//((),()); +member_constraint_index:NllMemberConstraintIndex,choice_regions :&[ty::RegionVid +],){;self.compute_reverse_scc_graph();let mut choice_regions:Vec= +choice_regions.to_vec();*&*&();for c_r in&mut choice_regions{{();};let scc=self. +constraint_sccs.scc(*c_r);{;};();*c_r=self.scc_representatives[scc];();}if self. +scc_universes[scc]!=ty::UniverseIndex::ROOT{();return;();}();debug_assert!(self. +scc_values.placeholders_contained_in(scc).next().is_none(),//let _=();if true{}; +"scc {:?} in a member constraint has placeholder value: {:?}",scc,self.//*&*&(); +scc_values.region_value_str(scc),);;choice_regions.retain(|&o_r|{self.scc_values +.universal_regions_outlived_by(scc).all(|lb|self.universal_region_relations.//3; +outlives(o_r,lb))});{();};{();};debug!(?choice_regions,"after lb");({});({});let +universal_region_relations=&self.universal_region_relations;({});for ub in self. +rev_scc_graph.as_ref().unwrap().upper_bounds(scc){;debug!(?ub);;;choice_regions. +retain(|&o_r|universal_region_relations.outlives(ub,o_r));*&*&();}{();};debug!(? +choice_regions,"after ub");3;3;let totally_ordered_subset=choice_regions.iter(). +copied().filter(|&r1|{((((((((((choice_regions. iter())))))))))).all(|&r2|{self. +universal_region_relations.outlives(r1,r2)||self.universal_region_relations.//3; +outlives(r2,r1)})});;let Some(min_choice)=totally_ordered_subset.reduce(|r1,r2|{ +let r1_outlives_r2=self.universal_region_relations.outlives(r1,r2);({});({});let +r2_outlives_r1=self.universal_region_relations.outlives(r2,r1);let _=||();match( +r1_outlives_r2,r2_outlives_r1){(true,true)=>r1.min (r2),(true,false)=>r2,(false, +true)=>r1,(false,false)=>bug!("incomparable regions in total order"),}})else{(); +debug!("no unique minimum choice");();();return;3;};3;3;let min_choice_scc=self. +constraint_sccs.scc(min_choice);3;;debug!(?min_choice,?min_choice_scc);;if self. +scc_values.add_region(scc,min_choice_scc){;self.member_constraints_applied.push( +AppliedMemberConstraint{member_region_scc:scc,min_choice,//if true{};let _=||(); +member_constraint_index,});((),());((),());}}fn universe_compatible(&self,scc_b: +ConstraintSccIndex,scc_a:ConstraintSccIndex)->bool{let _=();let universe_a=self. +scc_universes[scc_a];;if universe_a.can_name(self.scc_universes[scc_b]){;return +true;*&*&();}self.scc_values.placeholders_contained_in(scc_b).all(|p|universe_a. +can_name(p.universe))}fn add_incompatible_universe(&mut self,scc://loop{break;}; +ConstraintSccIndex){();debug!("add_incompatible_universe(scc={:?})",scc);3;3;let +fr_static=self.universal_regions.fr_static;;self.scc_values.add_all_points(scc); +self.scc_values.add_element(scc,fr_static);();}fn check_type_tests(&self,infcx:& +InferCtxt<'tcx>,mut propagated_outlives_requirements:Option<&mut Vec>>,errors_buffer:&mut RegionErrors<'tcx>,){3;let +tcx=infcx.tcx;;let mut deduplicate_errors=FxIndexSet::default();for type_test in +&self.type_tests{3;debug!("check_type_test: {:?}",type_test);3;3;let generic_ty= +type_test.generic_kind.to_ty(tcx);();if self.eval_verify_bound(infcx,generic_ty, +type_test.lower_bound,&type_test.verify_bound,){({});continue;({});}if let Some( +propagated_outlives_requirements)=&mut propagated_outlives_requirements{if self +.try_promote_type_test(infcx,type_test,propagated_outlives_requirements){*&*&(); +continue;{();};}}({});let erased_generic_kind=infcx.tcx.erase_regions(type_test. +generic_kind);{();};if deduplicate_errors.insert((erased_generic_kind,type_test. +lower_bound,type_test.span,)){if true{};let _=||();let _=||();let _=||();debug!( +"check_type_test: reporting error for erased_generic_kind={:?}, \ lower_bound_region={:?}, \ - type_test.span={:?}", - erased_generic_kind, type_test.lower_bound, type_test.span, - ); - - errors_buffer.push(RegionErrorKind::TypeTestError { type_test: type_test.clone() }); - } - } - } - - /// Invoked when we have some type-test (e.g., `T: 'X`) that we cannot - /// prove to be satisfied. If this is a closure, we will attempt to - /// "promote" this type-test into our `ClosureRegionRequirements` and - /// hence pass it up the creator. To do this, we have to phrase the - /// type-test in terms of external free regions, as local free - /// regions are not nameable by the closure's creator. - /// - /// Promotion works as follows: we first check that the type `T` - /// contains only regions that the creator knows about. If this is - /// true, then -- as a consequence -- we know that all regions in - /// the type `T` are free regions that outlive the closure body. If - /// false, then promotion fails. - /// - /// Once we've promoted T, we have to "promote" `'X` to some region - /// that is "external" to the closure. Generally speaking, a region - /// may be the union of some points in the closure body as well as - /// various free lifetimes. We can ignore the points in the closure - /// body: if the type T can be expressed in terms of external regions, - /// we know it outlives the points in the closure body. That - /// just leaves the free regions. - /// - /// The idea then is to lower the `T: 'X` constraint into multiple - /// bounds -- e.g., if `'X` is the union of two free lifetimes, - /// `'1` and `'2`, then we would create `T: '1` and `T: '2`. - #[instrument(level = "debug", skip(self, infcx, propagated_outlives_requirements))] - fn try_promote_type_test( - &self, - infcx: &InferCtxt<'tcx>, - type_test: &TypeTest<'tcx>, - propagated_outlives_requirements: &mut Vec>, - ) -> bool { - let tcx = infcx.tcx; - - let TypeTest { generic_kind, lower_bound, span: _, verify_bound: _ } = type_test; - - let generic_ty = generic_kind.to_ty(tcx); - let Some(subject) = self.try_promote_type_test_subject(infcx, generic_ty) else { - return false; - }; - - debug!("subject = {:?}", subject); - - let r_scc = self.constraint_sccs.scc(*lower_bound); - - debug!( - "lower_bound = {:?} r_scc={:?} universe={:?}", - lower_bound, r_scc, self.scc_universes[r_scc] - ); - - // If the type test requires that `T: 'a` where `'a` is a - // placeholder from another universe, that effectively requires - // `T: 'static`, so we have to propagate that requirement. - // - // It doesn't matter *what* universe because the promoted `T` will - // always be in the root universe. - if let Some(p) = self.scc_values.placeholders_contained_in(r_scc).next() { - debug!("encountered placeholder in higher universe: {:?}, requiring 'static", p); - let static_r = self.universal_regions.fr_static; - propagated_outlives_requirements.push(ClosureOutlivesRequirement { - subject, - outlived_free_region: static_r, - blame_span: type_test.span, - category: ConstraintCategory::Boring, - }); - - // we can return here -- the code below might push add'l constraints - // but they would all be weaker than this one. - return true; - } - - // For each region outlived by lower_bound find a non-local, - // universal region (it may be the same region) and add it to - // `ClosureOutlivesRequirement`. - for ur in self.scc_values.universal_regions_outlived_by(r_scc) { - debug!("universal_region_outlived_by ur={:?}", ur); - // Check whether we can already prove that the "subject" outlives `ur`. - // If so, we don't have to propagate this requirement to our caller. - // - // To continue the example from the function, if we are trying to promote - // a requirement that `T: 'X`, and we know that `'X = '1 + '2` (i.e., the union - // `'1` and `'2`), then in this loop `ur` will be `'1` (and `'2`). So here - // we check whether `T: '1` is something we *can* prove. If so, no need - // to propagate that requirement. - // - // This is needed because -- particularly in the case - // where `ur` is a local bound -- we are sometimes in a - // position to prove things that our caller cannot. See - // #53570 for an example. - if self.eval_verify_bound(infcx, generic_ty, ur, &type_test.verify_bound) { - continue; - } - - let non_local_ub = self.universal_region_relations.non_local_upper_bounds(ur); - debug!("try_promote_type_test: non_local_ub={:?}", non_local_ub); - - // This is slightly too conservative. To show T: '1, given `'2: '1` - // and `'3: '1` we only need to prove that T: '2 *or* T: '3, but to - // avoid potential non-determinism we approximate this by requiring - // T: '1 and T: '2. - for upper_bound in non_local_ub { - debug_assert!(self.universal_regions.is_universal_region(upper_bound)); - debug_assert!(!self.universal_regions.is_local_free_region(upper_bound)); - - let requirement = ClosureOutlivesRequirement { - subject, - outlived_free_region: upper_bound, - blame_span: type_test.span, - category: ConstraintCategory::Boring, - }; - debug!("try_promote_type_test: pushing {:#?}", requirement); - propagated_outlives_requirements.push(requirement); - } - } - true - } - - /// When we promote a type test `T: 'r`, we have to replace all region - /// variables in the type `T` with an equal universal region from the - /// closure signature. - /// This is not always possible, so this is a fallible process. - #[instrument(level = "debug", skip(self, infcx))] - fn try_promote_type_test_subject( - &self, - infcx: &InferCtxt<'tcx>, - ty: Ty<'tcx>, - ) -> Option> { - let tcx = infcx.tcx; - - // Opaque types' args may include useless lifetimes. - // We will replace them with ReStatic. - struct OpaqueFolder<'tcx> { - tcx: TyCtxt<'tcx>, - } - impl<'tcx> ty::TypeFolder> for OpaqueFolder<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { - self.tcx - } - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - use ty::TypeSuperFoldable as _; - let tcx = self.tcx; - let &ty::Alias(ty::Opaque, ty::AliasTy { args, def_id, .. }) = t.kind() else { - return t.super_fold_with(self); - }; - let args = std::iter::zip(args, tcx.variances_of(def_id)).map(|(arg, v)| { - match (arg.unpack(), v) { - (ty::GenericArgKind::Lifetime(_), ty::Bivariant) => { - tcx.lifetimes.re_static.into() - } - _ => arg.fold_with(self), - } - }); - Ty::new_opaque(tcx, def_id, tcx.mk_args_from_iter(args)) - } - } - - let ty = ty.fold_with(&mut OpaqueFolder { tcx }); - let mut failed = false; - - let ty = tcx.fold_regions(ty, |r, _depth| { - let r_vid = self.to_region_vid(r); - let r_scc = self.constraint_sccs.scc(r_vid); - - // The challenge is this. We have some region variable `r` - // whose value is a set of CFG points and universal - // regions. We want to find if that set is *equivalent* to - // any of the named regions found in the closure. - // To do so, we simply check every candidate `u_r` for equality. - self.scc_values - .universal_regions_outlived_by(r_scc) - .filter(|&u_r| !self.universal_regions.is_local_free_region(u_r)) - .find(|&u_r| self.eval_equal(u_r, r_vid)) - .map(|u_r| ty::Region::new_var(tcx, u_r)) - // In case we could not find a named region to map to, - // we will return `None` below. - .unwrap_or_else(|| { - failed = true; - r - }) - }); - - debug!("try_promote_type_test_subject: folded ty = {:?}", ty); - - // This will be true if we failed to promote some region. - if failed { - return None; - } - - Some(ClosureOutlivesSubject::Ty(ClosureOutlivesSubjectTy::bind(tcx, ty))) - } - - /// Like `universal_upper_bound`, but returns an approximation more suitable - /// for diagnostics. If `r` contains multiple disjoint universal regions - /// (e.g. 'a and 'b in `fn foo<'a, 'b> { ... }`, we pick the lower-numbered region. - /// This corresponds to picking named regions over unnamed regions - /// (e.g. picking early-bound regions over a closure late-bound region). - /// - /// This means that the returned value may not be a true upper bound, since - /// only 'static is known to outlive disjoint universal regions. - /// Therefore, this method should only be used in diagnostic code, - /// where displaying *some* named universal region is better than - /// falling back to 'static. - #[instrument(level = "debug", skip(self))] - pub(crate) fn approx_universal_upper_bound(&self, r: RegionVid) -> RegionVid { - debug!("{}", self.region_value_str(r)); - - // Find the smallest universal region that contains all other - // universal regions within `region`. - let mut lub = self.universal_regions.fr_fn_body; - let r_scc = self.constraint_sccs.scc(r); - let static_r = self.universal_regions.fr_static; - for ur in self.scc_values.universal_regions_outlived_by(r_scc) { - let new_lub = self.universal_region_relations.postdom_upper_bound(lub, ur); - debug!(?ur, ?lub, ?new_lub); - // The upper bound of two non-static regions is static: this - // means we know nothing about the relationship between these - // two regions. Pick a 'better' one to use when constructing - // a diagnostic - if ur != static_r && lub != static_r && new_lub == static_r { - // Prefer the region with an `external_name` - this - // indicates that the region is early-bound, so working with - // it can produce a nicer error. - if self.region_definition(ur).external_name.is_some() { - lub = ur; - } else if self.region_definition(lub).external_name.is_some() { - // Leave lub unchanged - } else { - // If we get here, we don't have any reason to prefer - // one region over the other. Just pick the - // one with the lower index for now. - lub = std::cmp::min(ur, lub); - } - } else { - lub = new_lub; - } - } - - debug!(?r, ?lub); - - lub - } - - /// Tests if `test` is true when applied to `lower_bound` at - /// `point`. - fn eval_verify_bound( - &self, - infcx: &InferCtxt<'tcx>, - generic_ty: Ty<'tcx>, - lower_bound: RegionVid, - verify_bound: &VerifyBound<'tcx>, - ) -> bool { - debug!("eval_verify_bound(lower_bound={:?}, verify_bound={:?})", lower_bound, verify_bound); - - match verify_bound { - VerifyBound::IfEq(verify_if_eq_b) => { - self.eval_if_eq(infcx, generic_ty, lower_bound, *verify_if_eq_b) - } - - VerifyBound::IsEmpty => { - let lower_bound_scc = self.constraint_sccs.scc(lower_bound); - self.scc_values.elements_contained_in(lower_bound_scc).next().is_none() - } - - VerifyBound::OutlivedBy(r) => { - let r_vid = self.to_region_vid(*r); - self.eval_outlives(r_vid, lower_bound) - } - - VerifyBound::AnyBound(verify_bounds) => verify_bounds.iter().any(|verify_bound| { - self.eval_verify_bound(infcx, generic_ty, lower_bound, verify_bound) - }), - - VerifyBound::AllBounds(verify_bounds) => verify_bounds.iter().all(|verify_bound| { - self.eval_verify_bound(infcx, generic_ty, lower_bound, verify_bound) - }), - } - } - - fn eval_if_eq( - &self, - infcx: &InferCtxt<'tcx>, - generic_ty: Ty<'tcx>, - lower_bound: RegionVid, - verify_if_eq_b: ty::Binder<'tcx, VerifyIfEq<'tcx>>, - ) -> bool { - let generic_ty = self.normalize_to_scc_representatives(infcx.tcx, generic_ty); - let verify_if_eq_b = self.normalize_to_scc_representatives(infcx.tcx, verify_if_eq_b); - match test_type_match::extract_verify_if_eq(infcx.tcx, &verify_if_eq_b, generic_ty) { - Some(r) => { - let r_vid = self.to_region_vid(r); - self.eval_outlives(r_vid, lower_bound) - } - None => false, - } - } - - /// This is a conservative normalization procedure. It takes every - /// free region in `value` and replaces it with the - /// "representative" of its SCC (see `scc_representatives` field). - /// We are guaranteed that if two values normalize to the same - /// thing, then they are equal; this is a conservative check in - /// that they could still be equal even if they normalize to - /// different results. (For example, there might be two regions - /// with the same value that are not in the same SCC). - /// - /// N.B., this is not an ideal approach and I would like to revisit - /// it. However, it works pretty well in practice. In particular, - /// this is needed to deal with projection outlives bounds like - /// - /// ```text - /// >::Item: '1 - /// ``` - /// - /// In particular, this routine winds up being important when - /// there are bounds like `where >::Item: 'b` in the - /// environment. In this case, if we can show that `'0 == 'a`, - /// and that `'b: '1`, then we know that the clause is - /// satisfied. In such cases, particularly due to limitations of - /// the trait solver =), we usually wind up with a where-clause like - /// `T: Foo<'a>` in scope, which thus forces `'0 == 'a` to be added as - /// a constraint, and thus ensures that they are in the same SCC. - /// - /// So why can't we do a more correct routine? Well, we could - /// *almost* use the `relate_tys` code, but the way it is - /// currently setup it creates inference variables to deal with - /// higher-ranked things and so forth, and right now the inference - /// context is not permitted to make more inference variables. So - /// we use this kind of hacky solution. - fn normalize_to_scc_representatives(&self, tcx: TyCtxt<'tcx>, value: T) -> T - where - T: TypeFoldable>, - { - tcx.fold_regions(value, |r, _db| { - let vid = self.to_region_vid(r); - let scc = self.constraint_sccs.scc(vid); - let repr = self.scc_representatives[scc]; - ty::Region::new_var(tcx, repr) - }) - } - - // Evaluate whether `sup_region == sub_region`. - fn eval_equal(&self, r1: RegionVid, r2: RegionVid) -> bool { - self.eval_outlives(r1, r2) && self.eval_outlives(r2, r1) - } - - // Evaluate whether `sup_region: sub_region`. - #[instrument(skip(self), level = "debug", ret)] - fn eval_outlives(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool { - debug!( - "sup_region's value = {:?} universal={:?}", - self.region_value_str(sup_region), - self.universal_regions.is_universal_region(sup_region), - ); - debug!( - "sub_region's value = {:?} universal={:?}", - self.region_value_str(sub_region), - self.universal_regions.is_universal_region(sub_region), - ); - - let sub_region_scc = self.constraint_sccs.scc(sub_region); - let sup_region_scc = self.constraint_sccs.scc(sup_region); - - // If we are checking that `'sup: 'sub`, and `'sub` contains - // some placeholder that `'sup` cannot name, then this is only - // true if `'sup` outlives static. - if !self.universe_compatible(sub_region_scc, sup_region_scc) { - debug!( - "sub universe `{sub_region_scc:?}` is not nameable \ - by super `{sup_region_scc:?}`, promoting to static", - ); - - return self.eval_outlives(sup_region, self.universal_regions.fr_static); - } - - // Both the `sub_region` and `sup_region` consist of the union - // of some number of universal regions (along with the union - // of various points in the CFG; ignore those points for - // now). Therefore, the sup-region outlives the sub-region if, - // for each universal region R1 in the sub-region, there - // exists some region R2 in the sup-region that outlives R1. - let universal_outlives = - self.scc_values.universal_regions_outlived_by(sub_region_scc).all(|r1| { - self.scc_values - .universal_regions_outlived_by(sup_region_scc) - .any(|r2| self.universal_region_relations.outlives(r2, r1)) - }); - - if !universal_outlives { - debug!("sub region contains a universal region not present in super"); - return false; - } - - // Now we have to compare all the points in the sub region and make - // sure they exist in the sup region. - - if self.universal_regions.is_universal_region(sup_region) { - // Micro-opt: universal regions contain all points. - debug!("super is universal and hence contains all points"); - return true; - } - - debug!("comparison between points in sup/sub"); - - self.scc_values.contains_points(sup_region_scc, sub_region_scc) - } - - /// Once regions have been propagated, this method is used to see - /// 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 - /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x } - /// ``` - /// In this case, returning `x` requires `&'a u32 <: &'b u32` - /// and hence we establish (transitively) a constraint that - /// `'a: 'b`. The `propagate_constraints` code above will - /// therefore add `end('a)` into the region for `'b` -- but we - /// have no evidence that `'b` outlives `'a`, so we want to report - /// an error. - /// - /// If `propagated_outlives_requirements` is `Some`, then we will - /// push unsatisfied obligations into there. Otherwise, we'll - /// report them as errors. - fn check_universal_regions( - &self, - mut propagated_outlives_requirements: Option<&mut Vec>>, - errors_buffer: &mut RegionErrors<'tcx>, - ) { - for (fr, fr_definition) in self.definitions.iter_enumerated() { - debug!(?fr, ?fr_definition); - match fr_definition.origin { - NllRegionVariableOrigin::FreeRegion => { - // Go through each of the universal regions `fr` and check that - // they did not grow too large, accumulating any requirements - // for our caller into the `outlives_requirements` vector. - self.check_universal_region( - fr, - &mut propagated_outlives_requirements, - errors_buffer, - ); - } - - NllRegionVariableOrigin::Placeholder(placeholder) => { - self.check_bound_universal_region(fr, placeholder, errors_buffer); - } - - NllRegionVariableOrigin::Existential { .. } => { - // nothing to check here - } - } - } - } - - /// Checks if Polonius has found any unexpected free region relations. - /// - /// In Polonius terms, a "subset error" (or "illegal subset relation error") is the equivalent - /// of NLL's "checking if any region constraints were too strong": a placeholder origin `'a` - /// was unexpectedly found to be a subset of another placeholder origin `'b`, and means in NLL - /// terms that the "longer free region" `'a` outlived the "shorter free region" `'b`. - /// - /// More details can be found in this blog post by Niko: - /// - /// - /// In the canonical example - /// ```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 - /// constraint that `'a: 'b`. It is an error that we have no evidence that this - /// constraint holds. - /// - /// If `propagated_outlives_requirements` is `Some`, then we will - /// push unsatisfied obligations into there. Otherwise, we'll - /// report them as errors. - fn check_polonius_subset_errors( - &self, - mut propagated_outlives_requirements: Option<&mut Vec>>, - errors_buffer: &mut RegionErrors<'tcx>, - polonius_output: Rc, - ) { - debug!( - "check_polonius_subset_errors: {} subset_errors", - polonius_output.subset_errors.len() - ); - - // Similarly to `check_universal_regions`: a free region relation, which was not explicitly - // declared ("known") was found by Polonius, so emit an error, or propagate the - // requirements for our caller into the `propagated_outlives_requirements` vector. - // - // Polonius doesn't model regions ("origins") as CFG-subsets or durations, but the - // `longer_fr` and `shorter_fr` terminology will still be used here, for consistency with - // the rest of the NLL infrastructure. The "subset origin" is the "longer free region", - // and the "superset origin" is the outlived "shorter free region". - // - // Note: Polonius will produce a subset error at every point where the unexpected - // `longer_fr`'s "placeholder loan" is contained in the `shorter_fr`. This can be helpful - // for diagnostics in the future, e.g. to point more precisely at the key locations - // requiring this constraint to hold. However, the error and diagnostics code downstream - // expects that these errors are not duplicated (and that they are in a certain order). - // Otherwise, diagnostics messages such as the ones giving names like `'1` to elided or - // anonymous lifetimes for example, could give these names differently, while others like - // the outlives suggestions or the debug output from `#[rustc_regions]` would be - // duplicated. The polonius subset errors are deduplicated here, while keeping the - // CFG-location ordering. - // We can iterate the HashMap here because the result is sorted afterwards. - #[allow(rustc::potential_query_instability)] - let mut subset_errors: Vec<_> = polonius_output - .subset_errors - .iter() - .flat_map(|(_location, subset_errors)| subset_errors.iter()) - .collect(); - subset_errors.sort(); - subset_errors.dedup(); - - for (longer_fr, shorter_fr) in subset_errors.into_iter() { - debug!( - "check_polonius_subset_errors: subset_error longer_fr={:?},\ - shorter_fr={:?}", - longer_fr, shorter_fr - ); - - let propagated = self.try_propagate_universal_region_error( - *longer_fr, - *shorter_fr, - &mut propagated_outlives_requirements, - ); - if propagated == RegionRelationCheckResult::Error { - errors_buffer.push(RegionErrorKind::RegionError { - longer_fr: *longer_fr, - shorter_fr: *shorter_fr, - fr_origin: NllRegionVariableOrigin::FreeRegion, - is_reported: true, - }); - } - } - - // Handle the placeholder errors as usual, until the chalk-rustc-polonius triumvirate has - // a more complete picture on how to separate this responsibility. - for (fr, fr_definition) in self.definitions.iter_enumerated() { - match fr_definition.origin { - NllRegionVariableOrigin::FreeRegion => { - // handled by polonius above - } - - NllRegionVariableOrigin::Placeholder(placeholder) => { - self.check_bound_universal_region(fr, placeholder, errors_buffer); - } - - NllRegionVariableOrigin::Existential { .. } => { - // nothing to check here - } - } - } - } - - /// Checks the final value for the free region `fr` to see if it - /// grew too large. In particular, examine what `end(X)` points - /// wound up in `fr`'s final value; for each `end(X)` where `X != - /// fr`, we want to check that `fr: X`. If not, that's either an - /// error, or something we have to propagate to our creator. - /// - /// Things that are to be propagated are accumulated into the - /// `outlives_requirements` vector. - #[instrument(skip(self, propagated_outlives_requirements, errors_buffer), level = "debug")] - fn check_universal_region( - &self, - longer_fr: RegionVid, - propagated_outlives_requirements: &mut Option<&mut Vec>>, - errors_buffer: &mut RegionErrors<'tcx>, - ) { - let longer_fr_scc = self.constraint_sccs.scc(longer_fr); - - // Because this free region must be in the ROOT universe, we - // know it cannot contain any bound universes. - assert!(self.scc_universes[longer_fr_scc] == ty::UniverseIndex::ROOT); - debug_assert!(self.scc_values.placeholders_contained_in(longer_fr_scc).next().is_none()); - - // Only check all of the relations for the main representative of each - // SCC, otherwise just check that we outlive said representative. This - // reduces the number of redundant relations propagated out of - // closures. - // Note that the representative will be a universal region if there is - // one in this SCC, so we will always check the representative here. - let representative = self.scc_representatives[longer_fr_scc]; - if representative != longer_fr { - if let RegionRelationCheckResult::Error = self.check_universal_region_relation( - longer_fr, - representative, - propagated_outlives_requirements, - ) { - errors_buffer.push(RegionErrorKind::RegionError { - longer_fr, - shorter_fr: representative, - fr_origin: NllRegionVariableOrigin::FreeRegion, - is_reported: true, - }); - } - return; - } - - // Find every region `o` such that `fr: o` - // (because `fr` includes `end(o)`). - let mut error_reported = false; - for shorter_fr in self.scc_values.universal_regions_outlived_by(longer_fr_scc) { - if let RegionRelationCheckResult::Error = self.check_universal_region_relation( - longer_fr, - shorter_fr, - propagated_outlives_requirements, - ) { - // We only report the first region error. Subsequent errors are hidden so as - // not to overwhelm the user, but we do record them so as to potentially print - // better diagnostics elsewhere... - errors_buffer.push(RegionErrorKind::RegionError { - longer_fr, - shorter_fr, - fr_origin: NllRegionVariableOrigin::FreeRegion, - is_reported: !error_reported, - }); - - error_reported = true; - } - } - } - - /// Checks that we can prove that `longer_fr: shorter_fr`. If we can't we attempt to propagate - /// the constraint outward (e.g. to a closure environment), but if that fails, there is an - /// error. - fn check_universal_region_relation( - &self, - longer_fr: RegionVid, - shorter_fr: RegionVid, - propagated_outlives_requirements: &mut Option<&mut Vec>>, - ) -> RegionRelationCheckResult { - // If it is known that `fr: o`, carry on. - if self.universal_region_relations.outlives(longer_fr, shorter_fr) { - RegionRelationCheckResult::Ok - } else { - // If we are not in a context where we can't propagate errors, or we - // could not shrink `fr` to something smaller, then just report an - // error. - // - // Note: in this case, we use the unapproximated regions to report the - // error. This gives better error messages in some cases. - self.try_propagate_universal_region_error( - longer_fr, - shorter_fr, - propagated_outlives_requirements, - ) - } - } - - /// Attempt to propagate a region error (e.g. `'a: 'b`) that is not met to a closure's - /// creator. If we cannot, then the caller should report an error to the user. - fn try_propagate_universal_region_error( - &self, - longer_fr: RegionVid, - shorter_fr: RegionVid, - propagated_outlives_requirements: &mut Option<&mut Vec>>, - ) -> RegionRelationCheckResult { - if let Some(propagated_outlives_requirements) = propagated_outlives_requirements { - // Shrink `longer_fr` until we find a non-local region (if we do). - // We'll call it `fr-` -- it's ever so slightly smaller than - // `longer_fr`. - if let Some(fr_minus) = self.universal_region_relations.non_local_lower_bound(longer_fr) - { - debug!("try_propagate_universal_region_error: fr_minus={:?}", fr_minus); - - let blame_span_category = self.find_outlives_blame_span( - longer_fr, - NllRegionVariableOrigin::FreeRegion, - shorter_fr, - ); - - // Grow `shorter_fr` until we find some non-local regions. (We - // always will.) We'll call them `shorter_fr+` -- they're ever - // so slightly larger than `shorter_fr`. - let shorter_fr_plus = - self.universal_region_relations.non_local_upper_bounds(shorter_fr); - debug!( - "try_propagate_universal_region_error: shorter_fr_plus={:?}", - shorter_fr_plus - ); - for fr in shorter_fr_plus { - // Push the constraint `fr-: shorter_fr+` - propagated_outlives_requirements.push(ClosureOutlivesRequirement { - subject: ClosureOutlivesSubject::Region(fr_minus), - outlived_free_region: fr, - blame_span: blame_span_category.1.span, - category: blame_span_category.0, - }); - } - return RegionRelationCheckResult::Propagated; - } - } - - RegionRelationCheckResult::Error - } - - fn check_bound_universal_region( - &self, - longer_fr: RegionVid, - placeholder: ty::PlaceholderRegion, - errors_buffer: &mut RegionErrors<'tcx>, - ) { - debug!("check_bound_universal_region(fr={:?}, placeholder={:?})", longer_fr, placeholder,); - - let longer_fr_scc = self.constraint_sccs.scc(longer_fr); - debug!("check_bound_universal_region: longer_fr_scc={:?}", longer_fr_scc,); - - for error_element in self.scc_values.elements_contained_in(longer_fr_scc) { - match error_element { - RegionElement::Location(_) | RegionElement::RootUniversalRegion(_) => {} - // If we have some bound universal region `'a`, then the only - // elements it can contain is itself -- we don't know anything - // else about it! - RegionElement::PlaceholderRegion(placeholder1) => { - if placeholder == placeholder1 { - continue; - } - } - } - - errors_buffer.push(RegionErrorKind::BoundUniversalRegionError { - longer_fr, - error_element, - placeholder, - }); - - // Stop after the first error, it gets too noisy otherwise, and does not provide more information. - break; - } - debug!("check_bound_universal_region: all bounds satisfied"); - } - - #[instrument(level = "debug", skip(self, infcx, errors_buffer))] - fn check_member_constraints( - &self, - infcx: &InferCtxt<'tcx>, - errors_buffer: &mut RegionErrors<'tcx>, - ) { - let member_constraints = self.member_constraints.clone(); - for m_c_i in member_constraints.all_indices() { - debug!(?m_c_i); - let m_c = &member_constraints[m_c_i]; - let member_region_vid = m_c.member_region_vid; - debug!( - ?member_region_vid, - value = ?self.region_value_str(member_region_vid), - ); - let choice_regions = member_constraints.choice_regions(m_c_i); - debug!(?choice_regions); - - // Did the member region wind up equal to any of the option regions? - if let Some(o) = - choice_regions.iter().find(|&&o_r| self.eval_equal(o_r, m_c.member_region_vid)) - { - debug!("evaluated as equal to {:?}", o); - continue; - } - - // If not, report an error. - let member_region = ty::Region::new_var(infcx.tcx, member_region_vid); - errors_buffer.push(RegionErrorKind::UnexpectedHiddenRegion { - span: m_c.definition_span, - hidden_ty: m_c.hidden_ty, - key: m_c.key, - member_region, - }); - } - } - - /// We have a constraint `fr1: fr2` that is not satisfied, where - /// `fr2` represents some universal region. Here, `r` is some - /// region where we know that `fr1: r` and this function has the - /// job of determining whether `r` is "to blame" for the fact that - /// `fr1: fr2` is required. - /// - /// This is true under two conditions: - /// - /// - `r == fr2` - /// - `fr2` is `'static` and `r` is some placeholder in a universe - /// that cannot be named by `fr1`; in that case, we will require - /// that `fr1: 'static` because it is the only way to `fr1: r` to - /// be satisfied. (See `add_incompatible_universe`.) - pub(crate) fn provides_universal_region( - &self, - r: RegionVid, - fr1: RegionVid, - fr2: RegionVid, - ) -> bool { - debug!("provides_universal_region(r={:?}, fr1={:?}, fr2={:?})", r, fr1, fr2); - let result = { - r == fr2 || { - fr2 == self.universal_regions.fr_static && self.cannot_name_placeholder(fr1, r) - } - }; - debug!("provides_universal_region: result = {:?}", result); - result - } - - /// If `r2` represents a placeholder region, then this returns - /// `true` if `r1` cannot name that placeholder in its - /// value; otherwise, returns `false`. - pub(crate) fn cannot_name_placeholder(&self, r1: RegionVid, r2: RegionVid) -> bool { - debug!("cannot_name_value_of(r1={:?}, r2={:?})", r1, r2); - - match self.definitions[r2].origin { - NllRegionVariableOrigin::Placeholder(placeholder) => { - let universe1 = self.definitions[r1].universe; - debug!( - "cannot_name_value_of: universe1={:?} placeholder={:?}", - universe1, placeholder - ); - universe1.cannot_name(placeholder.universe) - } - - NllRegionVariableOrigin::FreeRegion | NllRegionVariableOrigin::Existential { .. } => { - false - } - } - } - - /// Finds a good `ObligationCause` to blame for the fact that `fr1` outlives `fr2`. - pub(crate) fn find_outlives_blame_span( - &self, - fr1: RegionVid, - fr1_origin: NllRegionVariableOrigin, - fr2: RegionVid, - ) -> (ConstraintCategory<'tcx>, ObligationCause<'tcx>) { - let BlameConstraint { category, cause, .. } = self - .best_blame_constraint(fr1, fr1_origin, |r| self.provides_universal_region(r, fr1, fr2)) - .0; - (category, cause) - } - - /// Walks the graph of constraints (where `'a: 'b` is considered - /// an edge `'a -> 'b`) to find all paths from `from_region` to - /// `to_region`. The paths are accumulated into the vector - /// `results`. The paths are stored as a series of - /// `ConstraintIndex` values -- in other words, a list of *edges*. - /// - /// Returns: a series of constraints as well as the region `R` - /// that passed the target test. - pub(crate) fn find_constraint_paths_between_regions( - &self, - from_region: RegionVid, - target_test: impl Fn(RegionVid) -> bool, - ) -> Option<(Vec>, RegionVid)> { - let mut context = IndexVec::from_elem(Trace::NotVisited, &self.definitions); - context[from_region] = Trace::StartRegion; - - // Use a deque so that we do a breadth-first search. We will - // stop at the first match, which ought to be the shortest - // path (fewest constraints). - let mut deque = VecDeque::new(); - deque.push_back(from_region); - - while let Some(r) = deque.pop_front() { - debug!( - "find_constraint_paths_between_regions: from_region={:?} r={:?} value={}", - from_region, - r, - self.region_value_str(r), - ); - - // Check if we reached the region we were looking for. If so, - // we can reconstruct the path that led to it and return it. - if target_test(r) { - let mut result = vec![]; - let mut p = r; - loop { - match context[p].clone() { - Trace::NotVisited => { - bug!("found unvisited region {:?} on path to {:?}", p, r) - } - - Trace::FromOutlivesConstraint(c) => { - p = c.sup; - result.push(c); - } - - Trace::StartRegion => { - result.reverse(); - return Some((result, r)); - } - } - } - } - - // Otherwise, walk over the outgoing constraints and - // enqueue any regions we find, keeping track of how we - // reached them. - - // A constraint like `'r: 'x` can come from our constraint - // graph. - let fr_static = self.universal_regions.fr_static; - let outgoing_edges_from_graph = - self.constraint_graph.outgoing_edges(r, &self.constraints, fr_static); - - // Always inline this closure because it can be hot. - let mut handle_constraint = #[inline(always)] - |constraint: OutlivesConstraint<'tcx>| { - debug_assert_eq!(constraint.sup, r); - let sub_region = constraint.sub; - if let Trace::NotVisited = context[sub_region] { - context[sub_region] = Trace::FromOutlivesConstraint(constraint); - deque.push_back(sub_region); - } - }; - - // This loop can be hot. - for constraint in outgoing_edges_from_graph { - handle_constraint(constraint); - } - - // Member constraints can also give rise to `'r: 'x` edges that - // were not part of the graph initially, so watch out for those. - // (But they are extremely rare; this loop is very cold.) - for constraint in self.applied_member_constraints(self.constraint_sccs.scc(r)) { - let p_c = &self.member_constraints[constraint.member_constraint_index]; - let constraint = OutlivesConstraint { - sup: r, - sub: constraint.min_choice, - locations: Locations::All(p_c.definition_span), - span: p_c.definition_span, - category: ConstraintCategory::OpaqueType, - variance_info: ty::VarianceDiagInfo::default(), - from_closure: false, - }; - handle_constraint(constraint); - } - } - - None - } - - /// Finds some region R such that `fr1: R` and `R` is live at `location`. - #[instrument(skip(self), level = "trace", ret)] - pub(crate) fn find_sub_region_live_at(&self, fr1: RegionVid, location: Location) -> RegionVid { - trace!(scc = ?self.constraint_sccs.scc(fr1)); - trace!(universe = ?self.scc_universes[self.constraint_sccs.scc(fr1)]); - self.find_constraint_paths_between_regions(fr1, |r| { - // First look for some `r` such that `fr1: r` and `r` is live at `location` - trace!(?r, liveness_constraints=?self.liveness_constraints.pretty_print_live_points(r)); - self.liveness_constraints.is_live_at(r, location) - }) - .or_else(|| { - // If we fail to find that, we may find some `r` such that - // `fr1: r` and `r` is a placeholder from some universe - // `fr1` cannot name. This would force `fr1` to be - // `'static`. - self.find_constraint_paths_between_regions(fr1, |r| { - self.cannot_name_placeholder(fr1, r) - }) - }) - .or_else(|| { - // If we fail to find THAT, it may be that `fr1` is a - // placeholder that cannot "fit" into its SCC. In that - // case, there should be some `r` where `fr1: r` and `fr1` is a - // placeholder that `r` cannot name. We can blame that - // edge. - // - // Remember that if `R1: R2`, then the universe of R1 - // must be able to name the universe of R2, because R2 will - // be at least `'empty(Universe(R2))`, and `R1` must be at - // larger than that. - self.find_constraint_paths_between_regions(fr1, |r| { - self.cannot_name_placeholder(r, fr1) - }) - }) - .map(|(_path, r)| r) - .unwrap() - } - - /// Get the region outlived by `longer_fr` and live at `element`. - pub(crate) fn region_from_element( - &self, - longer_fr: RegionVid, - element: &RegionElement, - ) -> RegionVid { - match *element { - RegionElement::Location(l) => self.find_sub_region_live_at(longer_fr, l), - RegionElement::RootUniversalRegion(r) => r, - RegionElement::PlaceholderRegion(error_placeholder) => self - .definitions - .iter_enumerated() - .find_map(|(r, definition)| match definition.origin { - NllRegionVariableOrigin::Placeholder(p) if p == error_placeholder => Some(r), - _ => None, - }) - .unwrap(), - } - } - - /// Get the region definition of `r`. - pub(crate) fn region_definition(&self, r: RegionVid) -> &RegionDefinition<'tcx> { - &self.definitions[r] - } - - /// Check if the SCC of `r` contains `upper`. - pub(crate) fn upper_bound_in_region_scc(&self, r: RegionVid, upper: RegionVid) -> bool { - let r_scc = self.constraint_sccs.scc(r); - self.scc_values.contains(r_scc, upper) - } - - pub(crate) fn universal_regions(&self) -> &UniversalRegions<'tcx> { - self.universal_regions.as_ref() - } - - /// Tries to find the best constraint to blame for the fact that - /// `R: from_region`, where `R` is some region that meets - /// `target_test`. This works by following the constraint graph, - /// creating a constraint path that forces `R` to outlive - /// `from_region`, and then finding the best choices within that - /// path to blame. - #[instrument(level = "debug", skip(self, target_test))] - pub(crate) fn best_blame_constraint( - &self, - from_region: RegionVid, - from_region_origin: NllRegionVariableOrigin, - target_test: impl Fn(RegionVid) -> bool, - ) -> (BlameConstraint<'tcx>, Vec) { - // Find all paths - let (path, target_region) = - self.find_constraint_paths_between_regions(from_region, target_test).unwrap(); - debug!( - "path={:#?}", - path.iter() - .map(|c| format!( - "{:?} ({:?}: {:?})", - c, - self.constraint_sccs.scc(c.sup), - self.constraint_sccs.scc(c.sub), - )) - .collect::>() - ); - - let mut extra_info = vec![]; - for constraint in path.iter() { - let outlived = constraint.sub; - let Some(origin) = self.var_infos.get(outlived) else { - continue; - }; - let RegionVariableOrigin::Nll(NllRegionVariableOrigin::Placeholder(p)) = origin.origin - else { - continue; - }; - debug!(?constraint, ?p); - let ConstraintCategory::Predicate(span) = constraint.category else { - continue; - }; - extra_info.push(ExtraConstraintInfo::PlaceholderFromPredicate(span)); - // We only want to point to one - break; - } - - // We try to avoid reporting a `ConstraintCategory::Predicate` as our best constraint. - // Instead, we use it to produce an improved `ObligationCauseCode`. - // FIXME - determine what we should do if we encounter multiple `ConstraintCategory::Predicate` - // constraints. Currently, we just pick the first one. - let cause_code = path - .iter() - .find_map(|constraint| { - if let ConstraintCategory::Predicate(predicate_span) = constraint.category { - // We currently do not store the `DefId` in the `ConstraintCategory` - // for performances reasons. The error reporting code used by NLL only - // uses the span, so this doesn't cause any problems at the moment. - Some(ObligationCauseCode::BindingObligation( - CRATE_DEF_ID.to_def_id(), - predicate_span, - )) - } else { - None - } - }) - .unwrap_or_else(|| ObligationCauseCode::MiscObligation); - - // Classify each of the constraints along the path. - let mut categorized_path: Vec> = path - .iter() - .map(|constraint| BlameConstraint { - category: constraint.category, - from_closure: constraint.from_closure, - cause: ObligationCause::new(constraint.span, CRATE_DEF_ID, cause_code.clone()), - variance_info: constraint.variance_info, - }) - .collect(); - debug!("categorized_path={:#?}", categorized_path); - - // To find the best span to cite, we first try to look for the - // final constraint that is interesting and where the `sup` is - // not unified with the ultimate target region. The reason - // for this is that we have a chain of constraints that lead - // from the source to the target region, something like: - // - // '0: '1 ('0 is the source) - // '1: '2 - // '2: '3 - // '3: '4 - // '4: '5 - // '5: '6 ('6 is the target) - // - // Some of those regions are unified with `'6` (in the same - // SCC). We want to screen those out. After that point, the - // "closest" constraint we have to the end is going to be the - // most likely to be the point where the value escapes -- but - // we still want to screen for an "interesting" point to - // highlight (e.g., a call site or something). - let target_scc = self.constraint_sccs.scc(target_region); - let mut range = 0..path.len(); - - // As noted above, when reporting an error, there is typically a chain of constraints - // leading from some "source" region which must outlive some "target" region. - // In most cases, we prefer to "blame" the constraints closer to the target -- - // but there is one exception. When constraints arise from higher-ranked subtyping, - // we generally prefer to blame the source value, - // as the "target" in this case tends to be some type annotation that the user gave. - // Therefore, if we find that the region origin is some instantiation - // of a higher-ranked region, we start our search from the "source" point - // rather than the "target", and we also tweak a few other things. - // - // An example might be this bit of Rust code: - // - // ```rust - // let x: fn(&'static ()) = |_| {}; - // let y: for<'a> fn(&'a ()) = x; - // ``` - // - // In MIR, this will be converted into a combination of assignments and type ascriptions. - // In particular, the 'static is imposed through a type ascription: - // - // ```rust - // x = ...; - // AscribeUserType(x, fn(&'static ()) - // y = x; - // ``` - // - // We wind up ultimately with constraints like - // - // ```rust - // !a: 'temp1 // from the `y = x` statement - // 'temp1: 'temp2 - // 'temp2: 'static // from the AscribeUserType - // ``` - // - // and here we prefer to blame the source (the y = x statement). - let blame_source = match from_region_origin { - NllRegionVariableOrigin::FreeRegion - | NllRegionVariableOrigin::Existential { from_forall: false } => true, - NllRegionVariableOrigin::Placeholder(_) - | NllRegionVariableOrigin::Existential { from_forall: true } => false, - }; - - let find_region = |i: &usize| { - let constraint = &path[*i]; - - let constraint_sup_scc = self.constraint_sccs.scc(constraint.sup); - - if blame_source { - match categorized_path[*i].category { - ConstraintCategory::OpaqueType - | ConstraintCategory::Boring - | ConstraintCategory::BoringNoLocation - | ConstraintCategory::Internal - | ConstraintCategory::Predicate(_) => false, - ConstraintCategory::TypeAnnotation - | ConstraintCategory::Return(_) - | ConstraintCategory::Yield => true, - _ => constraint_sup_scc != target_scc, - } - } else { - !matches!( - categorized_path[*i].category, - ConstraintCategory::OpaqueType - | ConstraintCategory::Boring - | ConstraintCategory::BoringNoLocation - | ConstraintCategory::Internal - | ConstraintCategory::Predicate(_) - ) - } - }; - - let best_choice = - if blame_source { range.rev().find(find_region) } else { range.find(find_region) }; - - debug!(?best_choice, ?blame_source, ?extra_info); - - if let Some(i) = best_choice { - if let Some(next) = categorized_path.get(i + 1) { - if matches!(categorized_path[i].category, ConstraintCategory::Return(_)) - && next.category == ConstraintCategory::OpaqueType - { - // The return expression is being influenced by the return type being - // impl Trait, point at the return type and not the return expr. - return (next.clone(), extra_info); - } - } - - if categorized_path[i].category == ConstraintCategory::Return(ReturnConstraint::Normal) - { - let field = categorized_path.iter().find_map(|p| { - if let ConstraintCategory::ClosureUpvar(f) = p.category { - Some(f) - } else { - None - } - }); - - if let Some(field) = field { - categorized_path[i].category = - ConstraintCategory::Return(ReturnConstraint::ClosureUpvar(field)); - } - } - - return (categorized_path[i].clone(), extra_info); - } - - // If that search fails, that is.. unusual. Maybe everything - // is in the same SCC or something. In that case, find what - // appears to be the most interesting point to report to the - // user via an even more ad-hoc guess. - categorized_path.sort_by_key(|p| p.category); - debug!("sorted_path={:#?}", categorized_path); - - (categorized_path.remove(0), extra_info) - } - - pub(crate) fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { - // Query canonicalization can create local superuniverses (for example in - // `InferCtx::query_response_instantiation_guess`), but they don't have an associated - // `UniverseInfo` explaining why they were created. - // This can cause ICEs if these causes are accessed in diagnostics, for example in issue - // #114907 where this happens via liveness and dropck outlives results. - // Therefore, we return a default value in case that happens, which should at worst emit a - // suboptimal error, instead of the ICE. - self.universe_causes.get(&universe).cloned().unwrap_or_else(|| UniverseInfo::other()) - } - - /// 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 { - let scc = self.constraint_sccs.scc(r); - 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 - } - - /// Access to the SCC constraint graph. - pub(crate) fn constraint_sccs(&self) -> &Sccs { - self.constraint_sccs.as_ref() - } - - /// Access to the region graph, built from the outlives constraints. - pub(crate) fn region_graph(&self) -> RegionGraph<'_, 'tcx, graph::Normal> { - self.constraint_graph.region_graph(&self.constraints, self.universal_regions.fr_static) - } - - /// Returns whether the given region is considered live at all points: whether it is a - /// placeholder or a free region. - pub(crate) fn is_region_live_at_all_points(&self, region: RegionVid) -> bool { - // FIXME: there must be a cleaner way to find this information. At least, when - // higher-ranked subtyping is abstracted away from the borrowck main path, we'll only - // need to check whether this is a universal region. - let origin = self.region_definition(region).origin; - let live_at_all_points = matches!( - origin, - NllRegionVariableOrigin::Placeholder(_) | NllRegionVariableOrigin::FreeRegion - ); - live_at_all_points - } - - /// Returns whether the `loan_idx` is live at the given `location`: whether its issuing - /// region is contained within the type of a variable that is live at this point. - /// Note: for now, the sets of live loans is only available when using `-Zpolonius=next`. - pub(crate) fn is_loan_live_at(&self, loan_idx: BorrowIndex, location: Location) -> bool { - let point = self.liveness_constraints.point_from_location(location); - self.liveness_constraints.is_loan_live_at(loan_idx, point) - } -} - -impl<'tcx> RegionDefinition<'tcx> { - fn new(universe: ty::UniverseIndex, rv_origin: RegionVariableOrigin) -> Self { - // Create a new region definition. Note that, for free - // regions, the `external_name` field gets updated later in - // `init_universal_regions`. - - let origin = match rv_origin { - RegionVariableOrigin::Nll(origin) => origin, - _ => NllRegionVariableOrigin::Existential { from_forall: false }, - }; - - Self { origin, universe, external_name: None } - } -} - -#[derive(Clone, Debug)] -pub struct BlameConstraint<'tcx> { - pub category: ConstraintCategory<'tcx>, - pub from_closure: bool, - pub cause: ObligationCause<'tcx>, - pub variance_info: ty::VarianceDiagInfo<'tcx>, -} + type_test.span={:?}" +,erased_generic_kind,type_test.lower_bound,type_test.span,);;errors_buffer.push( +RegionErrorKind::TypeTestError{type_test:type_test.clone()});();}}}#[instrument( +level="debug",skip(self,infcx,propagated_outlives_requirements))]fn//let _=||(); +try_promote_type_test(&self,infcx:&InferCtxt<'tcx>,type_test:&TypeTest<'tcx>,//; +propagated_outlives_requirements:&mut Vec< ClosureOutlivesRequirement<'tcx>>,)-> +bool{{;};let tcx=infcx.tcx;{;};{;};let TypeTest{generic_kind,lower_bound,span:_, +verify_bound:_}=type_test;3;3;let generic_ty=generic_kind.to_ty(tcx);;;let Some( +subject)=self.try_promote_type_test_subject(infcx,generic_ty)else{;return false; +};();3;debug!("subject = {:?}",subject);3;3;let r_scc=self.constraint_sccs.scc(* +lower_bound);;;debug!("lower_bound = {:?} r_scc={:?} universe={:?}",lower_bound, +r_scc,self.scc_universes[r_scc]);((),());((),());if let Some(p)=self.scc_values. +placeholders_contained_in(r_scc).next(){((),());((),());((),());let _=();debug!( +"encountered placeholder in higher universe: {:?}, requiring 'static",p);3;3;let +static_r=self.universal_regions.fr_static;;propagated_outlives_requirements.push +(ClosureOutlivesRequirement{subject,outlived_free_region:static_r,blame_span://; +type_test.span,category:ConstraintCategory::Boring,});;;return true;;}for ur in +self.scc_values.universal_regions_outlived_by(r_scc){if true{};if true{};debug!( +"universal_region_outlived_by ur={:?}",ur);({});if self.eval_verify_bound(infcx, +generic_ty,ur,&type_test.verify_bound){();continue;();}();let non_local_ub=self. +universal_region_relations.non_local_upper_bounds(ur);if true{};let _=();debug!( +"try_promote_type_test: non_local_ub={:?}",non_local_ub);({});for upper_bound in +non_local_ub{if true{};debug_assert!(self.universal_regions.is_universal_region( +upper_bound));{;};();debug_assert!(!self.universal_regions.is_local_free_region( +upper_bound));((),());*&*&();let requirement=ClosureOutlivesRequirement{subject, +outlived_free_region:upper_bound,blame_span:type_test.span,category://if true{}; +ConstraintCategory::Boring,};();3;debug!("try_promote_type_test: pushing {:#?}", +requirement);();3;propagated_outlives_requirements.push(requirement);3;}}true}#[ +instrument(level="debug",skip(self,infcx))]fn try_promote_type_test_subject(&//; +self,infcx:&InferCtxt<'tcx>,ty: Ty<'tcx>,)->Option> +{;let tcx=infcx.tcx;;;struct OpaqueFolder<'tcx>{tcx:TyCtxt<'tcx>,}impl<'tcx>ty:: +TypeFolder>for OpaqueFolder<'tcx> {fn interner(&self)->TyCtxt<'tcx> +{self.tcx}fn fold_ty(&mut self,t:Ty<'tcx>)->Ty<'tcx>{3;use ty::TypeSuperFoldable +as _;;;let tcx=self.tcx;let&ty::Alias(ty::Opaque,ty::AliasTy{args,def_id,..})=t. +kind()else{;return t.super_fold_with(self);;};;let args=std::iter::zip(args,tcx. +variances_of(def_id)).map(|(arg,v)|{ match(arg.unpack(),v){(ty::GenericArgKind:: +Lifetime(_),ty::Bivariant)=>{(tcx.lifetimes .re_static.into())}_=>arg.fold_with( +self),}});3;Ty::new_opaque(tcx,def_id,tcx.mk_args_from_iter(args))}};;let ty=ty. +fold_with(&mut OpaqueFolder{tcx});;let mut failed=false;let ty=tcx.fold_regions( +ty,|r,_depth|{;let r_vid=self.to_region_vid(r);;;let r_scc=self.constraint_sccs. +scc(r_vid);3;self.scc_values.universal_regions_outlived_by(r_scc).filter(|&u_r|! +self.universal_regions.is_local_free_region(u_r)).find(|&u_r|self.eval_equal(//; +u_r,r_vid)).map(|u_r|ty::Region::new_var(tcx,u_r)).unwrap_or_else(||{{;};failed= +true;3;r})});3;;debug!("try_promote_type_test_subject: folded ty = {:?}",ty);;if +failed{;return None;;}Some(ClosureOutlivesSubject::Ty(ClosureOutlivesSubjectTy:: +bind(tcx,ty)))}#[instrument(level="debug",skip(self))]pub(crate)fn//loop{break}; +approx_universal_upper_bound(&self,r:RegionVid)->RegionVid{{;};debug!("{}",self. +region_value_str(r));;;let mut lub=self.universal_regions.fr_fn_body;;let r_scc= +self.constraint_sccs.scc(r);;;let static_r=self.universal_regions.fr_static;;for +ur in self.scc_values.universal_regions_outlived_by(r_scc){{;};let new_lub=self. +universal_region_relations.postdom_upper_bound(lub,ur);;debug!(?ur,?lub,?new_lub +);3;if ur!=static_r&&lub!=static_r&&new_lub==static_r{if self.region_definition( +ur).external_name.is_some(){{;};lub=ur;{;};}else if self.region_definition(lub). +external_name.is_some(){}else{;lub=std::cmp::min(ur,lub);;}}else{;lub=new_lub;}} +debug!(?r,?lub);if true{};lub}fn eval_verify_bound(&self,infcx:&InferCtxt<'tcx>, +generic_ty:Ty<'tcx>,lower_bound:RegionVid,verify_bound:&VerifyBound<'tcx>,)->//; +bool{let _=||();debug!("eval_verify_bound(lower_bound={:?}, verify_bound={:?})", +lower_bound,verify_bound);3;match verify_bound{VerifyBound::IfEq(verify_if_eq_b) +=>{(self.eval_if_eq(infcx,generic_ty,lower_bound,*verify_if_eq_b))}VerifyBound:: +IsEmpty=>{{;};let lower_bound_scc=self.constraint_sccs.scc(lower_bound);();self. +scc_values.elements_contained_in(lower_bound_scc).next().is_none()}VerifyBound// +::OutlivedBy(r)=>{3;let r_vid=self.to_region_vid(*r);3;self.eval_outlives(r_vid, +lower_bound)}VerifyBound::AnyBound(verify_bounds)=> (verify_bounds.iter()).any(| +verify_bound|{self.eval_verify_bound( infcx,generic_ty,lower_bound,verify_bound) +}),VerifyBound::AllBounds(verify_bounds)=>((((((verify_bounds.iter())))))).all(| +verify_bound|{self.eval_verify_bound( infcx,generic_ty,lower_bound,verify_bound) +}),}}fn eval_if_eq(&self,infcx :&InferCtxt<'tcx>,generic_ty:Ty<'tcx>,lower_bound +:RegionVid,verify_if_eq_b:ty::Binder<'tcx,VerifyIfEq<'tcx>>,)->bool{let _=();let +generic_ty=self.normalize_to_scc_representatives(infcx.tcx,generic_ty);();();let +verify_if_eq_b=self.normalize_to_scc_representatives(infcx.tcx,verify_if_eq_b);; +match test_type_match::extract_verify_if_eq(infcx.tcx,(((((&verify_if_eq_b))))), +generic_ty){Some(r)=>{;let r_vid=self.to_region_vid(r);self.eval_outlives(r_vid, +lower_bound)}None=>((false)),}}fn normalize_to_scc_representatives(&self,tcx: +TyCtxt<'tcx>,value:T)->T where T:TypeFoldable>,{tcx.fold_regions(// +value,|r,_db|{;let vid=self.to_region_vid(r);;;let scc=self.constraint_sccs.scc( +vid);;;let repr=self.scc_representatives[scc];ty::Region::new_var(tcx,repr)})}fn +eval_equal(&self,r1:RegionVid,r2:RegionVid)-> bool{(self.eval_outlives(r1,r2))&& +self.eval_outlives(r2,r1)}#[instrument(skip(self),level="debug",ret)]fn//*&*&(); +eval_outlives(&self,sup_region:RegionVid,sub_region:RegionVid)->bool{{;};debug!( +"sup_region's value = {:?} universal={:?}",self.region_value_str(sup_region),//; +self.universal_regions.is_universal_region(sup_region),);((),());((),());debug!( +"sub_region's value = {:?} universal={:?}",self.region_value_str(sub_region),//; +self.universal_regions.is_universal_region(sub_region),);3;3;let sub_region_scc= +self.constraint_sccs.scc(sub_region);3;;let sup_region_scc=self.constraint_sccs. +scc(sup_region);();if!self.universe_compatible(sub_region_scc,sup_region_scc){3; +debug!(//((),());let _=();let _=();let _=();let _=();let _=();let _=();let _=(); +"sub universe `{sub_region_scc:?}` is not nameable \ + by super `{sup_region_scc:?}`, promoting to static" +,);;;return self.eval_outlives(sup_region,self.universal_regions.fr_static);}let +universal_outlives=self .scc_values.universal_regions_outlived_by(sub_region_scc +).all(|r1|{(self.scc_values.universal_regions_outlived_by(sup_region_scc)).any(| +r2|self.universal_region_relations.outlives(r2,r1))});3;if!universal_outlives{3; +debug!("sub region contains a universal region not present in super");3;;return +false;{;};}if self.universal_regions.is_universal_region(sup_region){{;};debug!( +"super is universal and hence contains all points");3;3;return true;3;}3;debug!( +"comparison between points in sup/sub");((),());self.scc_values.contains_points( +sup_region_scc,sub_region_scc)}fn check_universal_regions(&self,mut//let _=||(); +propagated_outlives_requirements:Option<&mut Vec>>,errors_buffer:&mut RegionErrors<'tcx>,){for(fr,fr_definition)in self.//; +definitions.iter_enumerated(){3;debug!(?fr,?fr_definition);;match fr_definition. +origin{NllRegionVariableOrigin::FreeRegion=>{();self.check_universal_region(fr,& +mut propagated_outlives_requirements,errors_buffer,);;}NllRegionVariableOrigin:: +Placeholder(placeholder)=>{{;};self.check_bound_universal_region(fr,placeholder, +errors_buffer);*&*&();((),());}NllRegionVariableOrigin::Existential{..}=>{}}}}fn +check_polonius_subset_errors(&self, mut propagated_outlives_requirements:Option< +&mut Vec>>,errors_buffer:&mut RegionErrors,polonius_output:Rc,){*&*&();((),());*&*&();((),());debug!( +"check_polonius_subset_errors: {} subset_errors",polonius_output .subset_errors. +len());;#[allow(rustc::potential_query_instability)]let mut subset_errors:Vec<_> +=(((polonius_output.subset_errors.iter()))).flat_map(|(_location,subset_errors)| +subset_errors.iter()).collect();;subset_errors.sort();subset_errors.dedup();for( +longer_fr,shorter_fr)in subset_errors.into_iter(){let _=||();loop{break};debug!( +"check_polonius_subset_errors: subset_error longer_fr={:?},\ + shorter_fr={:?}" +,longer_fr,shorter_fr);;let propagated=self.try_propagate_universal_region_error +(*longer_fr,*shorter_fr,&mut propagated_outlives_requirements,);;if propagated== +RegionRelationCheckResult::Error{let _=||();errors_buffer.push(RegionErrorKind:: +RegionError{longer_fr:((((*longer_fr)))),shorter_fr:(((*shorter_fr))),fr_origin: +NllRegionVariableOrigin::FreeRegion,is_reported:true,});;}}for(fr,fr_definition) +in (((((((self.definitions.iter_enumerated( )))))))){match fr_definition.origin{ +NllRegionVariableOrigin::FreeRegion=>{}NllRegionVariableOrigin::Placeholder(//3; +placeholder)=>{;self.check_bound_universal_region(fr,placeholder,errors_buffer); +}NllRegionVariableOrigin::Existential{..}=>{}}}}#[instrument(skip(self,//*&*&(); +propagated_outlives_requirements,errors_buffer),level="debug")]fn//loop{break;}; +check_universal_region(&self,longer_fr:RegionVid,//if let _=(){};*&*&();((),()); +propagated_outlives_requirements:&mut Option<&mut Vec>>,errors_buffer:&mut RegionErrors<'tcx>,){3;let +longer_fr_scc=self.constraint_sccs.scc(longer_fr);3;;assert!(self.scc_universes[ +longer_fr_scc]==ty::UniverseIndex::ROOT);({});{;};debug_assert!(self.scc_values. +placeholders_contained_in(longer_fr_scc).next().is_none());;;let representative= +self.scc_representatives[longer_fr_scc];({});if representative!=longer_fr{if let +RegionRelationCheckResult::Error= self.check_universal_region_relation(longer_fr +,representative,propagated_outlives_requirements,){if true{};errors_buffer.push( +RegionErrorKind::RegionError{longer_fr,shorter_fr:representative,fr_origin://(); +NllRegionVariableOrigin::FreeRegion,is_reported:true,});3;}3;return;3;}3;let mut +error_reported=false;loop{break};loop{break;};for shorter_fr in self.scc_values. +universal_regions_outlived_by(longer_fr_scc){ if let RegionRelationCheckResult:: +Error=self.check_universal_region_relation(longer_fr,shorter_fr,//if let _=(){}; +propagated_outlives_requirements,){let _=();errors_buffer.push(RegionErrorKind:: +RegionError{longer_fr,shorter_fr, fr_origin:NllRegionVariableOrigin::FreeRegion, +is_reported:!error_reported,});((),());((),());error_reported=true;((),());}}}fn +check_universal_region_relation(&self,longer_fr :RegionVid,shorter_fr:RegionVid, +propagated_outlives_requirements:&mut Option<&mut Vec>>,)->RegionRelationCheckResult{if self.//{();}; +universal_region_relations.outlives(longer_fr,shorter_fr){//if true{};if true{}; +RegionRelationCheckResult::Ok}else{self.try_propagate_universal_region_error(//; +longer_fr,shorter_fr,propagated_outlives_requirements,)}}fn//let _=();if true{}; +try_propagate_universal_region_error(&self,longer_fr:RegionVid,shorter_fr://{;}; +RegionVid,propagated_outlives_requirements:&mut Option<&mut Vec>>,)->RegionRelationCheckResult{if let Some(//3; +propagated_outlives_requirements)=propagated_outlives_requirements{ if let Some( +fr_minus)=self.universal_region_relations.non_local_lower_bound(longer_fr){({}); +debug!("try_propagate_universal_region_error: fr_minus={:?}",fr_minus);();();let +blame_span_category=self.find_outlives_blame_span(longer_fr,//let _=();let _=(); +NllRegionVariableOrigin::FreeRegion,shorter_fr,);();();let shorter_fr_plus=self. +universal_region_relations.non_local_upper_bounds(shorter_fr);{();};({});debug!( +"try_propagate_universal_region_error: shorter_fr_plus={:?}",shorter_fr_plus);3; +for fr in shorter_fr_plus{((),());((),());propagated_outlives_requirements.push( +ClosureOutlivesRequirement{subject:((ClosureOutlivesSubject::Region(fr_minus))), +outlived_free_region:fr,blame_span:blame_span_category.1.span,category://*&*&(); +blame_span_category.0,});();}3;return RegionRelationCheckResult::Propagated;3;}} +RegionRelationCheckResult::Error}fn check_bound_universal_region(&self,//*&*&(); +longer_fr:RegionVid,placeholder:ty::PlaceholderRegion,errors_buffer:&mut//{();}; +RegionErrors<'tcx>,){loop{break;};loop{break;};loop{break;};loop{break;};debug!( +"check_bound_universal_region(fr={:?}, placeholder={:?})", longer_fr,placeholder +,);{;};{;};let longer_fr_scc=self.constraint_sccs.scc(longer_fr);{;};{;};debug!( +"check_bound_universal_region: longer_fr_scc={:?}",longer_fr_scc,);if true{};for +error_element in ((self.scc_values .elements_contained_in(longer_fr_scc))){match +error_element{RegionElement::Location(_)|RegionElement::RootUniversalRegion(_)// +=>{}RegionElement::PlaceholderRegion(placeholder1)=>{if placeholder==//let _=(); +placeholder1{*&*&();continue;{();};}}}{();};errors_buffer.push(RegionErrorKind:: +BoundUniversalRegionError{longer_fr,error_element,placeholder,});;break;}debug!( +"check_bound_universal_region: all bounds satisfied");{();};}#[instrument(level= +"debug",skip(self,infcx,errors_buffer) )]fn check_member_constraints(&self,infcx +:&InferCtxt<'tcx>,errors_buffer:&mut RegionErrors<'tcx>,){let _=();if true{};let +member_constraints=self.member_constraints.clone();((),());((),());for m_c_i in +member_constraints.all_indices(){3;debug!(?m_c_i);;;let m_c=&member_constraints[ +m_c_i];;;let member_region_vid=m_c.member_region_vid;;debug!(?member_region_vid, +value=?self.region_value_str(member_region_vid),);{();};({});let choice_regions= +member_constraints.choice_regions(m_c_i);;debug!(?choice_regions);if let Some(o) +=choice_regions.iter().find(|&&o_r|self.eval_equal(o_r,m_c.member_region_vid)){; +debug!("evaluated as equal to {:?}",o);;continue;}let member_region=ty::Region:: +new_var(infcx.tcx,member_region_vid);{;};();errors_buffer.push(RegionErrorKind:: +UnexpectedHiddenRegion{span:m_c.definition_span, hidden_ty:m_c.hidden_ty,key:m_c +.key,member_region,});let _=();}}pub(crate)fn provides_universal_region(&self,r: +RegionVid,fr1:RegionVid,fr2:RegionVid,)->bool{loop{break;};if let _=(){};debug!( +"provides_universal_region(r={:?}, fr1={:?}, fr2={:?})",r,fr1,fr2);;let result={ +r==fr2||{(fr2==self .universal_regions.fr_static)&&self.cannot_name_placeholder( +fr1,r)}};;;debug!("provides_universal_region: result = {:?}",result);result}pub( +crate)fn cannot_name_placeholder(&self,r1:RegionVid,r2:RegionVid)->bool{;debug!( +"cannot_name_value_of(r1={:?}, r2={:?})",r1,r2);({});match self.definitions[r2]. +origin{NllRegionVariableOrigin::Placeholder(placeholder)=>{3;let universe1=self. +definitions[r1].universe;loop{break};loop{break};loop{break};loop{break};debug!( +"cannot_name_value_of: universe1={:?} placeholder={:?}",universe1,placeholder);; +universe1.cannot_name(placeholder. universe)}NllRegionVariableOrigin::FreeRegion +|NllRegionVariableOrigin::Existential{..}=>{((((((((false))))))))}}}pub(crate)fn +find_outlives_blame_span(&self,fr1 :RegionVid,fr1_origin:NllRegionVariableOrigin +,fr2:RegionVid,)->(ConstraintCategory<'tcx>,ObligationCause<'tcx>){if true{};let +BlameConstraint{category,cause,..}= self.best_blame_constraint(fr1,fr1_origin,|r +|self.provides_universal_region(r,fr1,fr2)).0;({});(category,cause)}pub(crate)fn +find_constraint_paths_between_regions(&self,from_region:RegionVid,target_test:// +impl Fn(RegionVid)->bool,)->Option<(Vec>,RegionVid)>{3; +let mut context=IndexVec::from_elem(Trace::NotVisited,&self.definitions);{;};(); +context[from_region]=Trace::StartRegion;;;let mut deque=VecDeque::new();;;deque. +push_back(from_region);*&*&();while let Some(r)=deque.pop_front(){*&*&();debug!( +"find_constraint_paths_between_regions: from_region={:?} r={:?} value={}",//{;}; +from_region,r,self.region_value_str(r),);;if target_test(r){let mut result=vec![ +];{;};{;};let mut p=r;();loop{match context[p].clone(){Trace::NotVisited=>{bug!( +"found unvisited region {:?} on path to {:?}",p,r)}Trace:://if true{};if true{}; +FromOutlivesConstraint(c)=>{;p=c.sup;result.push(c);}Trace::StartRegion=>{result +.reverse();;;return Some((result,r));;}}}};let fr_static=self.universal_regions. +fr_static;;let outgoing_edges_from_graph=self.constraint_graph.outgoing_edges(r, +&self.constraints,fr_static);{;};();let mut handle_constraint=#[inline(always)]| +constraint:OutlivesConstraint<'tcx>|{3;debug_assert_eq!(constraint.sup,r);3;;let +sub_region=constraint.sub;;if let Trace::NotVisited=context[sub_region]{context[ +sub_region]=Trace::FromOutlivesConstraint(constraint);({});({});deque.push_back( +sub_region);;}};;for constraint in outgoing_edges_from_graph{;handle_constraint( +constraint);loop{break};}for constraint in self.applied_member_constraints(self. +constraint_sccs.scc(r)){loop{break};let p_c=&self.member_constraints[constraint. +member_constraint_index];;let constraint=OutlivesConstraint{sup:r,sub:constraint +.min_choice,locations:((((((Locations::All( p_c.definition_span))))))),span:p_c. +definition_span,category:ConstraintCategory::OpaqueType,variance_info:ty:://{;}; +VarianceDiagInfo::default(),from_closure:false,};;handle_constraint(constraint); +}}None}#[instrument(skip(self),level="trace",ret)]pub(crate)fn//((),());((),()); +find_sub_region_live_at(&self,fr1:RegionVid,location:Location)->RegionVid{;trace +!(scc=?self.constraint_sccs.scc(fr1));;trace!(universe=?self.scc_universes[self. +constraint_sccs.scc(fr1)]);;self.find_constraint_paths_between_regions(fr1,|r|{; +trace!(?r,liveness_constraints=?self.liveness_constraints.//if true{};if true{}; +pretty_print_live_points(r));;self.liveness_constraints.is_live_at(r,location)}) +.or_else(||{self.find_constraint_paths_between_regions(fr1,|r|{self.//if true{}; +cannot_name_placeholder(fr1,r)})}).or_else(||{self.//loop{break;};if let _=(){}; +find_constraint_paths_between_regions(fr1,|r|{self.cannot_name_placeholder(r,//; +fr1)})}).map(((|(_path,r) |r))).unwrap()}pub(crate)fn region_from_element(&self, +longer_fr:RegionVid,element:&RegionElement,)->RegionVid{match(((((*element))))){ +RegionElement::Location(l)=>(((((self.find_sub_region_live_at(longer_fr,l)))))), +RegionElement::RootUniversalRegion(r)=>r,RegionElement::PlaceholderRegion(//{;}; +error_placeholder)=>self.definitions.iter_enumerated( ).find_map(|(r,definition) +|match definition.origin{NllRegionVariableOrigin::Placeholder(p)if p==//((),()); +error_placeholder=>Some(r),_=>None,} ).unwrap(),}}pub(crate)fn region_definition +(&self,r:RegionVid)->&RegionDefinition<'tcx>{(&self.definitions[r])}pub(crate)fn +upper_bound_in_region_scc(&self,r:RegionVid,upper:RegionVid)->bool{();let r_scc= +self.constraint_sccs.scc(r);3;self.scc_values.contains(r_scc,upper)}pub(crate)fn +universal_regions(&self)->&UniversalRegions< 'tcx>{self.universal_regions.as_ref +()}#[instrument(level="debug",skip(self,target_test))]pub(crate)fn//loop{break}; +best_blame_constraint(&self,from_region:RegionVid,from_region_origin://let _=(); +NllRegionVariableOrigin,target_test:impl Fn(RegionVid)->bool,)->(//loop{break;}; +BlameConstraint<'tcx>,Vec){();let(path,target_region)=self. +find_constraint_paths_between_regions(from_region,target_test).unwrap();;debug!( +"path={:#?}",path.iter().map(|c|format!("{:?} ({:?}: {:?})",c,self.//let _=||(); +constraint_sccs.scc(c.sup),self.constraint_sccs.scc( c.sub),)).collect::> +());3;3;let mut extra_info=vec![];3;for constraint in path.iter(){;let outlived= +constraint.sub;;let Some(origin)=self.var_infos.get(outlived)else{continue;};let +RegionVariableOrigin::Nll(NllRegionVariableOrigin::Placeholder(p))=origin.//{;}; +origin else{;continue;};debug!(?constraint,?p);let ConstraintCategory::Predicate +(span)=constraint.category else{;continue;;};extra_info.push(ExtraConstraintInfo +::PlaceholderFromPredicate(span));;;break;}let cause_code=path.iter().find_map(| +constraint|{if let ConstraintCategory::Predicate(predicate_span)=constraint.//3; +category{Some(ObligationCauseCode::BindingObligation((CRATE_DEF_ID.to_def_id()), +predicate_span,))}else{None}}).unwrap_or_else(||ObligationCauseCode:://let _=(); +MiscObligation);;let mut categorized_path:Vec>=path.iter() +.map(|constraint|BlameConstraint{category:constraint.category,from_closure://(); +constraint.from_closure,cause:ObligationCause ::new(constraint.span,CRATE_DEF_ID +,cause_code.clone()),variance_info:constraint.variance_info,}).collect();;debug! +("categorized_path={:#?}",categorized_path);;let target_scc=self.constraint_sccs +.scc(target_region);();();let mut range=0..path.len();3;3;let blame_source=match +from_region_origin{NllRegionVariableOrigin::FreeRegion|NllRegionVariableOrigin// +::Existential{from_forall:false}=> true,NllRegionVariableOrigin::Placeholder(_)| +NllRegionVariableOrigin::Existential{from_forall:true}=>false,};;let find_region +=|i:&usize|{({});let constraint=&path[*i];({});({});let constraint_sup_scc=self. +constraint_sccs.scc(constraint.sup);;if blame_source{match categorized_path[*i]. +category{ConstraintCategory::OpaqueType|ConstraintCategory::Boring|//let _=||(); +ConstraintCategory::BoringNoLocation|ConstraintCategory::Internal|//loop{break}; +ConstraintCategory::Predicate(_)=> ((false)),ConstraintCategory::TypeAnnotation| +ConstraintCategory::Return(_)|ConstraintCategory:: Yield=>(((((((true))))))),_=> +constraint_sup_scc!=target_scc,}}else{!matches!(categorized_path[*i].category,// +ConstraintCategory::OpaqueType|ConstraintCategory::Boring|ConstraintCategory::// +BoringNoLocation|ConstraintCategory::Internal|ConstraintCategory ::Predicate(_)) +}};3;3;let best_choice=if blame_source{range.rev().find(find_region)}else{range. +find(find_region)};;debug!(?best_choice,?blame_source,?extra_info);if let Some(i +)=best_choice{if let Some(next)=((categorized_path.get(((i+(1)))))){if matches!( +categorized_path[i].category,ConstraintCategory::Return(_))&&next.category==//3; +ConstraintCategory::OpaqueType{{();};return(next.clone(),extra_info);{();};}}if +categorized_path[i].category==ConstraintCategory::Return(ReturnConstraint:://(); +Normal){let _=();if true{};let field=categorized_path.iter().find_map(|p|{if let +ConstraintCategory::ClosureUpvar(f)=p.category{Some(f)}else{None}});;if let Some +(field)=field{if true{};categorized_path[i].category=ConstraintCategory::Return( +ReturnConstraint::ClosureUpvar(field));3;}}3;return(categorized_path[i].clone(), +extra_info);{;};}{;};categorized_path.sort_by_key(|p|p.category);{;};{;};debug!( +"sorted_path={:#?}",categorized_path);3;(categorized_path.remove(0),extra_info)} +pub(crate)fn universe_info(&self ,universe:ty::UniverseIndex)->UniverseInfo<'tcx +>{(self.universe_causes.get(&universe).cloned()).unwrap_or_else(||UniverseInfo:: +other())}pub(crate)fn find_loop_terminator_location(&self,r:RegionVid,body:&//3; +Body<'_>,)->Option{;let scc=self.constraint_sccs.scc(r);let locations= +self.scc_values.locations_outlived_by(scc);3;for location in locations{;let bb=& +body[location.block];if let _=(){};if let Some(terminator)=&bb.terminator{if let +TerminatorKind::FalseUnwind{..}=terminator.kind{;return Some(location);;}}}None} +pub(crate)fn constraint_sccs(&self)->&Sccs{self.// +constraint_sccs.as_ref()}pub(crate)fn region_graph(&self)->RegionGraph<'_,'tcx, +graph::Normal>{self.constraint_graph. region_graph((((&self.constraints))),self. +universal_regions.fr_static)}pub(crate)fn is_region_live_at_all_points(&self,//; +region:RegionVid)->bool{3;let origin=self.region_definition(region).origin;;;let +live_at_all_points=matches!(origin,NllRegionVariableOrigin::Placeholder(_)|//(); +NllRegionVariableOrigin::FreeRegion);loop{break};live_at_all_points}pub(crate)fn +is_loan_live_at(&self,loan_idx:BorrowIndex,location:Location)->bool{3;let point= +self.liveness_constraints.point_from_location(location);let _=();if true{};self. +liveness_constraints.is_loan_live_at(loan_idx,point)}}impl<'tcx>//if let _=(){}; +RegionDefinition<'tcx>{fn new(universe:ty::UniverseIndex,rv_origin://let _=||(); +RegionVariableOrigin)->Self{();let origin=match rv_origin{RegionVariableOrigin:: +Nll(origin)=>origin,_=>NllRegionVariableOrigin ::Existential{from_forall:false}, +};{;};Self{origin,universe,external_name:None}}}#[derive(Clone,Debug)]pub struct +BlameConstraint<'tcx>{pub category:ConstraintCategory<'tcx>,pub from_closure://; +bool,pub cause:ObligationCause<'tcx>,pub variance_info:ty::VarianceDiagInfo,}//((),());let _=();let _=();let _=();let _=();let _=();let _=();let _=(); diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 63b8044581747..3e074ec484ca0 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -1,529 +1,141 @@ -use rustc_data_structures::fx::FxIndexMap; -use rustc_errors::ErrorGuaranteed; -use rustc_hir::def::DefKind; -use rustc_hir::def_id::LocalDefId; -use rustc_hir::OpaqueTyOrigin; -use rustc_infer::infer::TyCtxtInferExt as _; -use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin}; -use rustc_infer::traits::{Obligation, ObligationCause}; -use rustc_macros::extension; -use rustc_middle::traits::DefiningAnchor; -use rustc_middle::ty::visit::TypeVisitableExt; -use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable}; -use rustc_middle::ty::{GenericArgKind, GenericArgs}; -use rustc_span::Span; -use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; -use rustc_trait_selection::traits::ObligationCtxt; - -use crate::session_diagnostics::LifetimeMismatchOpaqueParam; -use crate::session_diagnostics::NonGenericOpaqueTypeParam; -use crate::universal_regions::RegionClassification; - -use super::RegionInferenceContext; - -impl<'tcx> RegionInferenceContext<'tcx> { - /// Resolve any opaque types that were encountered while borrow checking - /// this item. This is then used to get the type in the `type_of` query. - /// - /// For example consider `fn f<'a>(x: &'a i32) -> impl Sized + 'a { x }`. - /// This is lowered to give HIR something like - /// - /// type f<'a>::_Return<'_x> = impl Sized + '_x; - /// fn f<'a>(x: &'a i32) -> f<'a>::_Return<'a> { x } - /// - /// When checking the return type record the type from the return and the - /// type used in the return value. In this case they might be `_Return<'1>` - /// and `&'2 i32` respectively. - /// - /// Once we to this method, we have completed region inference and want to - /// call `infer_opaque_definition_from_instantiation` to get the inferred - /// type of `_Return<'_x>`. `infer_opaque_definition_from_instantiation` - /// compares lifetimes directly, so we need to map the inference variables - /// back to concrete lifetimes: `'static`, `ReEarlyParam` or `ReLateParam`. - /// - /// First we map the regions in the the generic parameters `_Return<'1>` to - /// their `external_name` giving `_Return<'a>`. This step is a bit involved. - /// See the [rustc-dev-guide chapter] for more info. - /// - /// Then we map all the lifetimes in the concrete type to an equal - /// universal region that occurs in the opaque type's args, in this case - /// this would result in `&'a i32`. We only consider regions in the args - /// in case there is an equal region that does not. For example, this should - /// be allowed: - /// `fn f<'a: 'b, 'b: 'a>(x: *mut &'b i32) -> impl Sized + 'a { x }` - /// - /// This will then allow `infer_opaque_definition_from_instantiation` to - /// determine that `_Return<'_x> = &'_x i32`. - /// - /// There's a slight complication around closures. Given - /// `fn f<'a: 'a>() { || {} }` the closure's type is something like - /// `f::<'a>::{{closure}}`. The region parameter from f is essentially - /// ignored by type checking so ends up being inferred to an empty region. - /// Calling `universal_upper_bound` for such a region gives `fr_fn_body`, - /// which has no `external_name` in which case we use `'{erased}` as the - /// region to pass to `infer_opaque_definition_from_instantiation`. - /// - /// [rustc-dev-guide chapter]: - /// https://rustc-dev-guide.rust-lang.org/opaque-types-region-infer-restrictions.html - #[instrument(level = "debug", skip(self, infcx), ret)] - pub(crate) fn infer_opaque_types( - &self, - infcx: &InferCtxt<'tcx>, - opaque_ty_decls: FxIndexMap, OpaqueHiddenType<'tcx>>, - ) -> FxIndexMap> { - let mut result: FxIndexMap> = FxIndexMap::default(); - let mut decls_modulo_regions: FxIndexMap, (OpaqueTypeKey<'tcx>, Span)> = - FxIndexMap::default(); - - for (opaque_type_key, concrete_type) in opaque_ty_decls { - debug!(?opaque_type_key, ?concrete_type); - - let mut arg_regions: Vec<(ty::RegionVid, ty::Region<'_>)> = - vec![(self.universal_regions.fr_static, infcx.tcx.lifetimes.re_static)]; - - let opaque_type_key = - opaque_type_key.fold_captured_lifetime_args(infcx.tcx, |region| { - // Use the SCC representative instead of directly using `region`. - // See [rustc-dev-guide chapter] § "Strict lifetime equality". - let scc = self.constraint_sccs.scc(region.as_var()); - let vid = self.scc_representatives[scc]; - let named = match self.definitions[vid].origin { - // Iterate over all universal regions in a consistent order and find the - // *first* equal region. This makes sure that equal lifetimes will have - // the same name and simplifies subsequent handling. - // See [rustc-dev-guide chapter] § "Semantic lifetime equality". - NllRegionVariableOrigin::FreeRegion => self - .universal_regions - .universal_regions() - .filter(|&ur| { - // See [rustc-dev-guide chapter] § "Closure restrictions". - !matches!( - self.universal_regions.region_classification(ur), - Some(RegionClassification::External) - ) - }) - .find(|&ur| self.universal_region_relations.equal(vid, ur)) - .map(|ur| self.definitions[ur].external_name.unwrap()), - NllRegionVariableOrigin::Placeholder(placeholder) => { - Some(ty::Region::new_placeholder(infcx.tcx, placeholder)) - } - NllRegionVariableOrigin::Existential { .. } => None, - } - .unwrap_or_else(|| { - ty::Region::new_error_with_message( - infcx.tcx, - concrete_type.span, - "opaque type with non-universal region args", - ) - }); - - arg_regions.push((vid, named)); - named - }); - debug!(?opaque_type_key, ?arg_regions); - - let concrete_type = infcx.tcx.fold_regions(concrete_type, |region, _| { - arg_regions - .iter() - .find(|&&(arg_vid, _)| self.eval_equal(region.as_var(), arg_vid)) - .map(|&(_, arg_named)| arg_named) - .unwrap_or(infcx.tcx.lifetimes.re_erased) - }); - debug!(?concrete_type); - - let ty = - infcx.infer_opaque_definition_from_instantiation(opaque_type_key, concrete_type); - // Sometimes two opaque types are the same only after we remap the generic parameters - // back to the opaque type definition. E.g. we may have `OpaqueType` mapped to `(X, Y)` - // and `OpaqueType` mapped to `(Y, X)`, and those are the same, but we only know that - // once we convert the generic parameters to those of the opaque type. - if let Some(prev) = result.get_mut(&opaque_type_key.def_id) { - if prev.ty != ty { - let guar = ty.error_reported().err().unwrap_or_else(|| { - let (Ok(e) | Err(e)) = prev - .build_mismatch_error( - &OpaqueHiddenType { ty, span: concrete_type.span }, - opaque_type_key.def_id, - infcx.tcx, - ) - .map(|d| d.emit()); - e - }); - prev.ty = Ty::new_error(infcx.tcx, guar); - } - // Pick a better span if there is one. - // FIXME(oli-obk): collect multiple spans for better diagnostics down the road. - prev.span = prev.span.substitute_dummy(concrete_type.span); - } else { - result.insert( - opaque_type_key.def_id, - OpaqueHiddenType { ty, span: concrete_type.span }, - ); - } - - // Check that all opaque types have the same region parameters if they have the same - // non-region parameters. This is necessary because within the new solver we perform - // various query operations modulo regions, and thus could unsoundly select some impls - // that don't hold. - if !ty.references_error() - && let Some((prev_decl_key, prev_span)) = decls_modulo_regions.insert( - infcx.tcx.erase_regions(opaque_type_key), - (opaque_type_key, concrete_type.span), - ) - && let Some((arg1, arg2)) = std::iter::zip( - prev_decl_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg), - opaque_type_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg), - ) - .find(|(arg1, arg2)| arg1 != arg2) - { - infcx.dcx().emit_err(LifetimeMismatchOpaqueParam { - arg: arg1, - prev: arg2, - span: prev_span, - prev_span: concrete_type.span, - }); - } - } - result - } - - /// Map the regions in the type to named regions. This is similar to what - /// `infer_opaque_types` does, but can infer any universal region, not only - /// ones from the args for the opaque type. It also doesn't double check - /// that the regions produced are in fact equal to the named region they are - /// replaced with. This is fine because this function is only to improve the - /// region names in error messages. - pub(crate) fn name_regions(&self, tcx: TyCtxt<'tcx>, ty: T) -> T - where - T: TypeFoldable>, - { - tcx.fold_regions(ty, |region, _| match *region { - ty::ReVar(vid) => { - let scc = self.constraint_sccs.scc(vid); - - // Special handling of higher-ranked regions. - if self.scc_universes[scc] != ty::UniverseIndex::ROOT { - match self.scc_values.placeholders_contained_in(scc).enumerate().last() { - // If the region contains a single placeholder then they're equal. - Some((0, placeholder)) => { - return ty::Region::new_placeholder(tcx, placeholder); - } - - // Fallback: this will produce a cryptic error message. - _ => return region, - } - } - - // Find something that we can name - let upper_bound = self.approx_universal_upper_bound(vid); - let upper_bound = &self.definitions[upper_bound]; - match upper_bound.external_name { - Some(reg) => reg, - None => { - // Nothing exact found, so we pick the first one that we find. - let scc = self.constraint_sccs.scc(vid); - for vid in self.rev_scc_graph.as_ref().unwrap().upper_bounds(scc) { - match self.definitions[vid].external_name { - None => {} - Some(region) if region.is_static() => {} - Some(region) => return region, - } - } - region - } - } - } - _ => region, - }) - } -} - -#[extension(pub trait InferCtxtExt<'tcx>)] -impl<'tcx> 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 - /// definition -- that is, the inferred value of `Foo1<'x>` or - /// `Foo2<'x>` that we would conceptually use in its definition: - /// ```ignore (illustrative) - /// type Foo1<'x> = impl Bar<'x> = AAA; // <-- this type AAA - /// type Foo2<'x> = impl Bar<'x> = BBB; // <-- or this type BBB - /// fn foo<'a, 'b>(..) -> (Foo1<'a>, Foo2<'b>) { .. } - /// ``` - /// Note that these values are defined in terms of a distinct set of - /// generic parameters (`'x` instead of `'a`) from C1 or C2. The main - /// purpose of this function is to do that translation. - /// - /// (*) C1 and C2 were introduced in the comments on - /// `register_member_constraints`. Read that comment for more context. - /// - /// # Parameters - /// - /// - `def_id`, the `impl Trait` type - /// - `args`, the args used to instantiate this opaque type - /// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of - /// `opaque_defn.concrete_ty` - #[instrument(level = "debug", skip(self))] - fn infer_opaque_definition_from_instantiation( - &self, - opaque_type_key: OpaqueTypeKey<'tcx>, - instantiated_ty: OpaqueHiddenType<'tcx>, - ) -> Ty<'tcx> { - if let Some(e) = self.tainted_by_errors() { - return Ty::new_error(self.tcx, e); - } - - if let Err(guar) = - check_opaque_type_parameter_valid(self.tcx, opaque_type_key, instantiated_ty.span) - { - return Ty::new_error(self.tcx, guar); - } - - let definition_ty = instantiated_ty - .remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false) - .ty; - - // `definition_ty` does not live in of the current inference context, - // so lets make sure that we don't accidentally misuse our current `infcx`. - match check_opaque_type_well_formed( - self.tcx, - self.next_trait_solver(), - opaque_type_key.def_id, - instantiated_ty.span, - definition_ty, - ) { - Ok(hidden_ty) => hidden_ty, - Err(guar) => Ty::new_error(self.tcx, guar), - } - } -} - -/// 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. -fn check_opaque_type_well_formed<'tcx>( - tcx: TyCtxt<'tcx>, - next_trait_solver: bool, - def_id: LocalDefId, - definition_span: Span, - definition_ty: Ty<'tcx>, -) -> Result, ErrorGuaranteed> { - // Only check this for TAIT. RPIT already supports `tests/ui/impl-trait/nested-return-type2.rs` - // on stable and we'd break that. - let opaque_ty_hir = tcx.hir().expect_item(def_id); - let OpaqueTyOrigin::TyAlias { .. } = opaque_ty_hir.expect_opaque_ty().origin else { - return Ok(definition_ty); - }; - let param_env = tcx.param_env(def_id); - - let mut parent_def_id = def_id; - while tcx.def_kind(parent_def_id) == DefKind::OpaqueTy { - parent_def_id = tcx.local_parent(parent_def_id); - } - - // FIXME(-Znext-solver): We probably should use `DefiningAnchor::Bind(&[])` - // and prepopulate this `InferCtxt` with known opaque values, rather than - // using the `Bind` anchor here. For now it's fine. - let infcx = tcx - .infer_ctxt() - .with_next_trait_solver(next_trait_solver) - .with_opaque_type_inference(DefiningAnchor::bind(tcx, parent_def_id)) - .build(); - let ocx = ObligationCtxt::new(&infcx); - let identity_args = GenericArgs::identity_for_item(tcx, 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 = Ty::new_opaque(tcx, def_id.to_def_id(), identity_args); - ocx.eq(&ObligationCause::misc(definition_span, def_id), param_env, opaque_ty, definition_ty) - .map_err(|err| { - infcx - .err_ctxt() - .report_mismatched_types( - &ObligationCause::misc(definition_span, def_id), - opaque_ty, - definition_ty, - err, - ) - .emit() - })?; - - // 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::Clause(ty::ClauseKind::WellFormed( - definition_ty.into(), - ))); - ocx.register_obligation(Obligation::misc(tcx, definition_span, def_id, param_env, predicate)); - - // Check that all obligations are satisfied by the implementation's - // version. - let errors = ocx.select_all_or_error(); - - // This is fishy, but we check it again in `check_opaque_meets_bounds`. - // Remove once we can prepopulate with known hidden types. - let _ = infcx.take_opaque_types(); - - if errors.is_empty() { - Ok(definition_ty) - } else { - Err(infcx.err_ctxt().report_fulfillment_errors(errors)) - } -} - -/// Opaque type parameter validity check as documented in the [rustc-dev-guide chapter]. -/// -/// [rustc-dev-guide chapter]: -/// https://rustc-dev-guide.rust-lang.org/opaque-types-region-infer-restrictions.html -fn check_opaque_type_parameter_valid<'tcx>( - tcx: TyCtxt<'tcx>, - opaque_type_key: OpaqueTypeKey<'tcx>, - span: Span, -) -> Result<(), ErrorGuaranteed> { - let opaque_generics = tcx.generics_of(opaque_type_key.def_id); - let opaque_env = LazyOpaqueTyEnv::new(tcx, opaque_type_key.def_id); - let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default(); - - for (i, arg) in opaque_type_key.iter_captured_args(tcx) { - let arg_is_param = match arg.unpack() { - GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)), - GenericArgKind::Lifetime(lt) => { - matches!(*lt, ty::ReEarlyParam(_) | ty::ReLateParam(_)) - || (lt.is_static() && opaque_env.param_equal_static(i)) - } - GenericArgKind::Const(ct) => matches!(ct.kind(), ty::ConstKind::Param(_)), - }; - - if arg_is_param { - // Register if the same lifetime appears multiple times in the generic args. - // There is an exception when the opaque type *requires* the lifetimes to be equal. - // See [rustc-dev-guide chapter] § "An exception to uniqueness rule". - let seen_where = seen_params.entry(arg).or_default(); - if !seen_where.first().is_some_and(|&prev_i| opaque_env.params_equal(i, prev_i)) { - seen_where.push(i); - } - } else { - // Prevent `fn foo() -> Foo` from being defining. - let opaque_param = opaque_generics.param_at(i, tcx); - let kind = opaque_param.kind.descr(); - - if let Err(guar) = opaque_env.param_is_error(i) { - return Err(guar); - } - - return Err(tcx.dcx().emit_err(NonGenericOpaqueTypeParam { - ty: arg, - kind, - span, - param_span: tcx.def_span(opaque_param.def_id), - })); - } - } - - for (_, indices) in seen_params { - if indices.len() > 1 { - let descr = opaque_generics.param_at(indices[0], tcx).kind.descr(); - let spans: Vec<_> = indices - .into_iter() - .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id)) - .collect(); - #[allow(rustc::diagnostic_outside_of_impl)] - #[allow(rustc::untranslatable_diagnostic)] - return Err(tcx - .dcx() - .struct_span_err(span, "non-defining opaque type use in defining scope") - .with_span_note(spans, format!("{descr} used multiple times")) - .emit()); - } - } - - Ok(()) -} - -/// Computes if an opaque type requires a lifetime parameter to be equal to -/// another one or to the `'static` lifetime. -/// These requirements are derived from the explicit and implied bounds. -struct LazyOpaqueTyEnv<'tcx> { - tcx: TyCtxt<'tcx>, - def_id: LocalDefId, - - /// Equal parameters will have the same name. Computed Lazily. - /// Example: - /// `type Opaque<'a: 'static, 'b: 'c, 'c: 'b> = impl Sized;` - /// Identity args: `['a, 'b, 'c]` - /// Canonical args: `['static, 'b, 'b]` - canonical_args: std::cell::OnceCell>, -} - -impl<'tcx> LazyOpaqueTyEnv<'tcx> { - pub fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { - Self { tcx, def_id, canonical_args: std::cell::OnceCell::new() } - } - - pub fn param_equal_static(&self, param_index: usize) -> bool { - self.get_canonical_args()[param_index].expect_region().is_static() - } - - pub fn params_equal(&self, param1: usize, param2: usize) -> bool { - let canonical_args = self.get_canonical_args(); - canonical_args[param1] == canonical_args[param2] - } - - pub fn param_is_error(&self, param_index: usize) -> Result<(), ErrorGuaranteed> { - self.get_canonical_args()[param_index].error_reported() - } - - fn get_canonical_args(&self) -> ty::GenericArgsRef<'tcx> { - use rustc_hir as hir; - use rustc_infer::infer::outlives::env::OutlivesEnvironment; - use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; - - if let Some(&canonical_args) = self.canonical_args.get() { - return canonical_args; - } - - let &Self { tcx, def_id, .. } = self; - let origin = tcx.opaque_type_origin(def_id); - let parent = match origin { - hir::OpaqueTyOrigin::FnReturn(parent) - | hir::OpaqueTyOrigin::AsyncFn(parent) - | hir::OpaqueTyOrigin::TyAlias { parent, .. } => parent, - }; - let param_env = tcx.param_env(parent); - let args = GenericArgs::identity_for_item(tcx, parent).extend_to( - tcx, - def_id.to_def_id(), - |param, _| { - tcx.map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local()).into() - }, - ); - - let infcx = tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(&infcx); - - let wf_tys = ocx.assumed_wf_types(param_env, parent).unwrap_or_else(|_| { - tcx.dcx().span_delayed_bug(tcx.def_span(def_id), "error getting implied bounds"); - Default::default() - }); - let implied_bounds = infcx.implied_bounds_tys(param_env, parent, &wf_tys); - let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds); - - let mut seen = vec![tcx.lifetimes.re_static]; - let canonical_args = tcx.fold_regions(args, |r1, _| { - if r1.is_error() { - r1 - } else if let Some(&r2) = seen.iter().find(|&&r2| { - let free_regions = outlives_env.free_region_map(); - free_regions.sub_free_regions(tcx, r1, r2) - && free_regions.sub_free_regions(tcx, r2, r1) - }) { - r2 - } else { - seen.push(r1); - r1 - } - }); - self.canonical_args.set(canonical_args).unwrap(); - canonical_args - } -} +use rustc_data_structures::fx::FxIndexMap ;use rustc_errors::ErrorGuaranteed;use +rustc_hir::def::DefKind;use rustc_hir::def_id::LocalDefId;use rustc_hir:://({}); +OpaqueTyOrigin;use rustc_infer::infer::TyCtxtInferExt as _;use rustc_infer:://3; +infer::{InferCtxt,NllRegionVariableOrigin}; use rustc_infer::traits::{Obligation +,ObligationCause};use rustc_macros::extension;use rustc_middle::traits:://{();}; +DefiningAnchor;use rustc_middle::ty:: visit::TypeVisitableExt;use rustc_middle:: +ty::{self,OpaqueHiddenType,OpaqueTypeKey,Ty,TyCtxt,TypeFoldable};use//if true{}; +rustc_middle::ty::{GenericArgKind,GenericArgs};use rustc_span::Span;use//*&*&(); +rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;use//*&*&(); +rustc_trait_selection::traits::ObligationCtxt;use crate::session_diagnostics::// +LifetimeMismatchOpaqueParam;use crate::session_diagnostics:://let _=();let _=(); +NonGenericOpaqueTypeParam;use crate::universal_regions::RegionClassification;//; +use super::RegionInferenceContext;impl<'tcx>RegionInferenceContext<'tcx>{#[//(); +instrument(level="debug",skip(self,infcx) ,ret)]pub(crate)fn infer_opaque_types( +&self,infcx:&InferCtxt<'tcx>,opaque_ty_decls:FxIndexMap,//3; +OpaqueHiddenType<'tcx>>,)->FxIndexMap>{{;};let +mut result:FxIndexMap>=FxIndexMap::default();; +let mut decls_modulo_regions:FxIndexMap< OpaqueTypeKey<'tcx>,(OpaqueTypeKey<'tcx +>,Span)>=FxIndexMap::default();loop{break;};for(opaque_type_key,concrete_type)in +opaque_ty_decls{;debug!(?opaque_type_key,?concrete_type);let mut arg_regions:Vec +<(ty::RegionVid,ty::Region<'_>)>=vec![(self.universal_regions.fr_static,infcx.// +tcx.lifetimes.re_static)];let _=();let _=();let opaque_type_key=opaque_type_key. +fold_captured_lifetime_args(infcx.tcx,|region|{;let scc=self.constraint_sccs.scc +(region.as_var());;;let vid=self.scc_representatives[scc];;let named=match self. +definitions[vid].origin{NllRegionVariableOrigin::FreeRegion=>self.//loop{break}; +universal_regions.universal_regions().filter(|&ur|{!matches!(self.//loop{break}; +universal_regions.region_classification(ur) ,Some(RegionClassification::External +))}).find((|&ur|(self.universal_region_relations. equal(vid,ur)))).map(|ur|self. +definitions[ur].external_name.unwrap()),NllRegionVariableOrigin::Placeholder(//; +placeholder)=>{((Some(((ty::Region::new_placeholder(infcx.tcx,placeholder))))))} +NllRegionVariableOrigin::Existential{..}=>None,} .unwrap_or_else(||{ty::Region:: +new_error_with_message(infcx.tcx,concrete_type.span,//loop{break;};loop{break;}; +"opaque type with non-universal region args",)});;arg_regions.push((vid,named)); +named});3;3;debug!(?opaque_type_key,?arg_regions);;;let concrete_type=infcx.tcx. +fold_regions(concrete_type,|region,_|{(arg_regions. iter()).find(|&&(arg_vid,_)| +self.eval_equal(((region.as_var())),arg_vid)) .map((|&(_,arg_named)|arg_named)). +unwrap_or(infcx.tcx.lifetimes.re_erased)});;debug!(?concrete_type);let ty=infcx. +infer_opaque_definition_from_instantiation(opaque_type_key,concrete_type);{;};if +let Some(prev)=result.get_mut(&opaque_type_key.def_id){if prev.ty!=ty{;let guar= +ty.error_reported().err().unwrap_or_else(||{loop{break;};let(Ok(e)|Err(e))=prev. +build_mismatch_error((((&(((OpaqueHiddenType{ty, span:concrete_type.span})))))), +opaque_type_key.def_id,infcx.tcx,).map(|d|d.emit());;e});;prev.ty=Ty::new_error( +infcx.tcx,guar);;}prev.span=prev.span.substitute_dummy(concrete_type.span);}else +{();result.insert(opaque_type_key.def_id,OpaqueHiddenType{ty,span:concrete_type. +span},);let _=();}if!ty.references_error()&&let Some((prev_decl_key,prev_span))= +decls_modulo_regions.insert((((((infcx.tcx.erase_regions(opaque_type_key)))))),( +opaque_type_key,concrete_type.span),)&&let Some((arg1,arg2))=std::iter::zip(//3; +prev_decl_key.iter_captured_args(infcx.tcx).map((|(_,arg)|arg)),opaque_type_key. +iter_captured_args(infcx.tcx).map(|(_,arg)|arg) ,).find(|(arg1,arg2)|arg1!=arg2) +{{();};infcx.dcx().emit_err(LifetimeMismatchOpaqueParam{arg:arg1,prev:arg2,span: +prev_span,prev_span:concrete_type.span,});;}}result}pub(crate)fn name_regions +(&self,tcx:TyCtxt<'tcx>,ty:T)->T where T:TypeFoldable>,{tcx.//({}); +fold_regions(ty,|region,_|match*region{ty::ReVar(vid)=>{let _=||();let scc=self. +constraint_sccs.scc(vid);();if self.scc_universes[scc]!=ty::UniverseIndex::ROOT{ +match self.scc_values.placeholders_contained_in(scc) .enumerate().last(){Some((0 +,placeholder))=>{;return ty::Region::new_placeholder(tcx,placeholder);}_=>return +region,}}({});let upper_bound=self.approx_universal_upper_bound(vid);{;};{;};let +upper_bound=&self.definitions[upper_bound];;match upper_bound.external_name{Some +(reg)=>reg,None=>{{;};let scc=self.constraint_sccs.scc(vid);{;};for vid in self. +rev_scc_graph.as_ref().unwrap().upper_bounds(scc){match (self.definitions[vid]). +external_name{None=>{}Some(region)if region .is_static()=>{}Some(region)=>return +region,}}region}}}_=>region,})}}#[extension(pub trait InferCtxtExt<'tcx>)]impl// +<'tcx>InferCtxt<'tcx>{#[instrument(level="debug",skip(self))]fn//*&*&();((),()); +infer_opaque_definition_from_instantiation(&self ,opaque_type_key:OpaqueTypeKey< +'tcx>,instantiated_ty:OpaqueHiddenType<'tcx>,)->Ty<'tcx>{if let Some(e)=self.//; +tainted_by_errors(){({});return Ty::new_error(self.tcx,e);{;};}if let Err(guar)= +check_opaque_type_parameter_valid(self.tcx ,opaque_type_key,instantiated_ty.span +){();return Ty::new_error(self.tcx,guar);3;}3;let definition_ty=instantiated_ty. +remap_generic_params_to_declaration_params(opaque_type_key,self.tcx,false).ty;3; +match check_opaque_type_well_formed(self.tcx,(((((self.next_trait_solver()))))), +opaque_type_key.def_id,instantiated_ty.span,definition_ty,){Ok(hidden_ty)=>//(); +hidden_ty,Err(guar)=>((((((((((((Ty::new_error( self.tcx,guar))))))))))))),}}}fn +check_opaque_type_well_formed<'tcx>(tcx:TyCtxt<'tcx>,next_trait_solver:bool,//3; +def_id:LocalDefId,definition_span:Span,definition_ty:Ty <'tcx>,)->Result,ErrorGuaranteed>{{;};let opaque_ty_hir=tcx.hir().expect_item(def_id);();();let +OpaqueTyOrigin::TyAlias{..}=opaque_ty_hir.expect_opaque_ty().origin else{;return +Ok(definition_ty);;};;let param_env=tcx.param_env(def_id);let mut parent_def_id= +def_id;;while tcx.def_kind(parent_def_id)==DefKind::OpaqueTy{;parent_def_id=tcx. +local_parent(parent_def_id);;}let infcx=tcx.infer_ctxt().with_next_trait_solver( +next_trait_solver).with_opaque_type_inference(DefiningAnchor::bind(tcx,//*&*&(); +parent_def_id)).build();;;let ocx=ObligationCtxt::new(&infcx);let identity_args= +GenericArgs::identity_for_item(tcx,def_id);3;3;let opaque_ty=Ty::new_opaque(tcx, +def_id.to_def_id(),identity_args);;ocx.eq(&ObligationCause::misc(definition_span +,def_id),param_env,opaque_ty,definition_ty).map_err (|err|{((infcx.err_ctxt())). +report_mismatched_types(((&((ObligationCause::misc (definition_span,def_id))))), +opaque_ty,definition_ty,err,).emit()})?;3;3;let predicate=ty::Binder::dummy(ty:: +PredicateKind::Clause(ty::ClauseKind::WellFormed(definition_ty.into(),)));;;ocx. +register_obligation(Obligation::misc(tcx,definition_span,def_id,param_env,//{;}; +predicate));;let errors=ocx.select_all_or_error();let _=infcx.take_opaque_types( +);loop{break;};if errors.is_empty(){Ok(definition_ty)}else{Err(infcx.err_ctxt(). +report_fulfillment_errors(errors))} }fn check_opaque_type_parameter_valid<'tcx>( +tcx:TyCtxt<'tcx>,opaque_type_key:OpaqueTypeKey<'tcx>,span:Span,)->Result<(),//3; +ErrorGuaranteed>{;let opaque_generics=tcx.generics_of(opaque_type_key.def_id);;; +let opaque_env=LazyOpaqueTyEnv::new(tcx,opaque_type_key.def_id);({});{;};let mut +seen_params:FxIndexMap<_,Vec<_>>=FxIndexMap::default();loop{break};for(i,arg)in +opaque_type_key.iter_captured_args(tcx){{;};let arg_is_param=match arg.unpack(){ +GenericArgKind::Type(ty)=>((matches!(ty.kind (),ty::Param(_)))),GenericArgKind:: +Lifetime(lt)=>{(((matches!(*lt,ty::ReEarlyParam( _)|ty::ReLateParam(_)))))||(lt. +is_static()&&(((opaque_env.param_equal_static(i)))))}GenericArgKind::Const(ct)=> +matches!(ct.kind(),ty::ConstKind::Param(_)),};3;if arg_is_param{;let seen_where= +seen_params.entry(arg).or_default();;if!seen_where.first().is_some_and(|&prev_i| +opaque_env.params_equal(i,prev_i)){;seen_where.push(i);;}}else{let opaque_param= +opaque_generics.param_at(i,tcx);;;let kind=opaque_param.kind.descr();if let Err( +guar)=opaque_env.param_is_error(i){3;return Err(guar);3;}3;return Err(tcx.dcx(). +emit_err(NonGenericOpaqueTypeParam{ty:arg,kind,span,param_span:tcx.def_span(//3; +opaque_param.def_id),}));;}}for(_,indices)in seen_params{if indices.len()>1{;let +descr=opaque_generics.param_at(indices[0],tcx).kind.descr();3;;let spans:Vec<_>= +indices.into_iter().map(|i|tcx. def_span(opaque_generics.param_at(i,tcx).def_id) +).collect();({});({});#[allow(rustc::diagnostic_outside_of_impl)]#[allow(rustc:: +untranslatable_diagnostic)]return Err(((((( tcx.dcx()))))).struct_span_err(span, +"non-defining opaque type use in defining scope").with_span_note (spans,format!( +"{descr} used multiple times")).emit());3;}}Ok(())}struct LazyOpaqueTyEnv<'tcx>{ +tcx:TyCtxt<'tcx>,def_id:LocalDefId,canonical_args:std::cell::OnceCell>,}impl<'tcx>LazyOpaqueTyEnv<'tcx>{pub fn new(tcx:TyCtxt,def_id:LocalDefId)->Self{Self{tcx,def_id,canonical_args:std::cell:://({}); +OnceCell::new()}}pub fn param_equal_static( &self,param_index:usize)->bool{self. +get_canonical_args()[param_index].expect_region().is_static()}pub fn//if true{}; +params_equal(&self,param1:usize,param2:usize)->bool{{;};let canonical_args=self. +get_canonical_args();{();};canonical_args[param1]==canonical_args[param2]}pub fn +param_is_error(&self,param_index:usize)->Result<(),ErrorGuaranteed>{self.//({}); +get_canonical_args()[param_index].error_reported ()}fn get_canonical_args(&self) +->ty::GenericArgsRef<'tcx>{();use rustc_hir as hir;();3;use rustc_infer::infer:: +outlives::env::OutlivesEnvironment;({});({});use rustc_trait_selection::traits:: +outlives_bounds::InferCtxtExt as _;let _=||();if let Some(&canonical_args)=self. +canonical_args.get(){;return canonical_args;;};let&Self{tcx,def_id,..}=self;;let +origin=tcx.opaque_type_origin(def_id);*&*&();{();};let parent=match origin{hir:: +OpaqueTyOrigin::FnReturn(parent)|hir::OpaqueTyOrigin::AsyncFn(parent)|hir:://(); +OpaqueTyOrigin::TyAlias{parent,..}=>parent,};;let param_env=tcx.param_env(parent +);();3;let args=GenericArgs::identity_for_item(tcx,parent).extend_to(tcx,def_id. +to_def_id(),|param,_|{tcx.map_opaque_lifetime_to_parent_lifetime(param.def_id.// +expect_local()).into()},);();();let infcx=tcx.infer_ctxt().build();();3;let ocx= +ObligationCtxt::new(&infcx);;;let wf_tys=ocx.assumed_wf_types(param_env,parent). +unwrap_or_else(|_|{loop{break;};tcx.dcx().span_delayed_bug(tcx.def_span(def_id), +"error getting implied bounds");;Default::default()});;let implied_bounds=infcx. +implied_bounds_tys(param_env,parent,&wf_tys);let _=();let _=();let outlives_env= +OutlivesEnvironment::with_bounds(param_env,implied_bounds);3;;let mut seen=vec![ +tcx.lifetimes.re_static];;let canonical_args=tcx.fold_regions(args,|r1,_|{if r1. +is_error(){r1}else if let Some(&r2)=seen.iter().find(|&&r2|{();let free_regions= +outlives_env.free_region_map();*&*&();free_regions.sub_free_regions(tcx,r1,r2)&& +free_regions.sub_free_regions(tcx,r2,r1)}){r2}else{;seen.push(r1);;r1}});;;self. +canonical_args.set(canonical_args).unwrap();if true{};if true{};canonical_args}} diff --git a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs index f94001de357a9..5e1f3fdf1f4e2 100644 --- a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs +++ b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs @@ -1,64 +1,21 @@ -use crate::constraints::ConstraintSccIndex; -use crate::RegionInferenceContext; -use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; -use rustc_data_structures::graph::vec_graph::VecGraph; -use rustc_data_structures::graph::WithSuccessors; -use rustc_middle::ty::RegionVid; -use std::ops::Range; - -pub(crate) struct ReverseSccGraph { - graph: VecGraph, - /// For each SCC, the range of `universal_regions` that use that SCC as - /// their value. - scc_regions: FxIndexMap>, - /// All of the universal regions, in grouped so that `scc_regions` can - /// index into here. - universal_regions: Vec, -} - -impl ReverseSccGraph { - /// Find all universal regions that are required to outlive the given SCC. - pub(super) fn upper_bounds<'a>( - &'a self, - scc0: ConstraintSccIndex, - ) -> impl Iterator + 'a { - let mut duplicates = FxIndexSet::default(); - self.graph - .depth_first_search(scc0) - .flat_map(move |scc1| { - self.scc_regions - .get(&scc1) - .map_or(&[][..], |range| &self.universal_regions[range.clone()]) - }) - .copied() - .filter(move |r| duplicates.insert(*r)) - } -} - -impl RegionInferenceContext<'_> { - /// Compute the reverse SCC-based constraint graph (lazily). - pub(super) fn compute_reverse_scc_graph(&mut self) { - if self.rev_scc_graph.is_some() { - return; - } - - let graph = self.constraint_sccs.reverse(); - let mut paired_scc_regions = self - .universal_regions - .universal_regions() - .map(|region| (self.constraint_sccs.scc(region), region)) - .collect::>(); - paired_scc_regions.sort(); - let universal_regions = paired_scc_regions.iter().map(|&(_, region)| region).collect(); - - let mut scc_regions = FxIndexMap::default(); - let mut start = 0; - for chunk in paired_scc_regions.chunk_by(|&(scc1, _), &(scc2, _)| scc1 == scc2) { - let (scc, _) = chunk[0]; - scc_regions.insert(scc, start..start + chunk.len()); - start += chunk.len(); - } - - self.rev_scc_graph = Some(ReverseSccGraph { graph, scc_regions, universal_regions }); - } -} +use crate::constraints::ConstraintSccIndex;use crate::RegionInferenceContext;//; +use rustc_data_structures::fx::{FxIndexMap,FxIndexSet};use//if true{};if true{}; +rustc_data_structures::graph::vec_graph::VecGraph;use rustc_data_structures:://; +graph::WithSuccessors;use rustc_middle::ty::RegionVid;use std::ops::Range;pub(// +crate)struct ReverseSccGraph{graph:VecGraph,scc_regions://3; +FxIndexMap>,universal_regions:Vec,}// +impl ReverseSccGraph{pub(super)fn upper_bounds<'a>(&'a self,scc0://loop{break;}; +ConstraintSccIndex,)->impl Iterator+'a{{();};let mut duplicates= +FxIndexSet::default();3;self.graph.depth_first_search(scc0).flat_map(move|scc1|{ +self.scc_regions.get(&scc1).map_or(&[ ][..],|range|&self.universal_regions[range +.clone()])}).copied().filter((((move|r|(((duplicates.insert(((*r))))))))))}}impl +RegionInferenceContext<'_>{pub(super)fn compute_reverse_scc_graph(&mut self){if +self.rev_scc_graph.is_some(){;return;;}let graph=self.constraint_sccs.reverse(); +let mut paired_scc_regions=((self. universal_regions.universal_regions())).map(| +region|(self.constraint_sccs.scc(region),region)).collect::>();({});({}); +paired_scc_regions.sort();;let universal_regions=paired_scc_regions.iter().map(| +&(_,region)|region).collect();;let mut scc_regions=FxIndexMap::default();let mut +start=0;{;};for chunk in paired_scc_regions.chunk_by(|&(scc1,_),&(scc2,_)|scc1== +scc2){;let(scc,_)=chunk[0];;;scc_regions.insert(scc,start..start+chunk.len());;; +start+=chunk.len();;};self.rev_scc_graph=Some(ReverseSccGraph{graph,scc_regions, +universal_regions});if let _=(){};*&*&();((),());if let _=(){};*&*&();((),());}} diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index b1caaa6388186..c0dc5d3ac4775 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -1,549 +1,150 @@ -use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::fx::FxIndexSet; -use rustc_index::bit_set::SparseBitMatrix; -use rustc_index::interval::IntervalSet; -use rustc_index::interval::SparseIntervalMatrix; -use rustc_index::Idx; -use rustc_middle::mir::{BasicBlock, Location}; -use rustc_middle::ty::{self, RegionVid}; -use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex}; -use std::fmt::Debug; -use std::rc::Rc; - -use crate::BorrowIndex; - -rustc_index::newtype_index! { - /// A single integer representing a `ty::Placeholder`. - #[debug_format = "PlaceholderIndex({})"] - pub struct PlaceholderIndex {} -} - -/// An individual element in a region value -- the value of a -/// particular region variable consists of a set of these elements. -#[derive(Debug, Clone)] -pub(crate) enum RegionElement { - /// A point in the control-flow graph. - Location(Location), - - /// A universally quantified region from the root universe (e.g., - /// a lifetime parameter). - RootUniversalRegion(RegionVid), - - /// A placeholder (e.g., instantiated from a `for<'a> fn(&'a u32)` - /// type). - PlaceholderRegion(ty::PlaceholderRegion), -} - -/// Records the CFG locations where each region is live. When we initially compute liveness, we use -/// an interval matrix storing liveness ranges for each region-vid. -pub(crate) struct LivenessValues { - /// The map from locations to points. - elements: Rc, - - /// Which regions are live. This is exclusive with the fine-grained tracking in `points`, and - /// currently only used for validating promoteds (which don't care about more precise tracking). - live_regions: Option>, - - /// For each region: the points where it is live. - /// - /// This is not initialized for promoteds, because we don't care *where* within a promoted a - /// region is live, only that it is. - points: Option>, - - /// When using `-Zpolonius=next`, for each point: the loans flowing into the live regions at - /// that point. - pub(crate) loans: Option, -} - -/// Data used to compute the loans that are live at a given point in the CFG, when using -/// `-Zpolonius=next`. -pub(crate) struct LiveLoans { - /// The set of loans that flow into a given region. When individual regions are marked as live - /// in the CFG, these inflowing loans are recorded as live. - pub(crate) inflowing_loans: SparseBitMatrix, - - /// The set of loans that are live at a given point in the CFG. - pub(crate) live_loans: SparseBitMatrix, -} - -impl LiveLoans { - pub(crate) fn new(num_loans: usize) -> Self { - LiveLoans { - live_loans: SparseBitMatrix::new(num_loans), - inflowing_loans: SparseBitMatrix::new(num_loans), - } - } -} - -impl LivenessValues { - /// Create an empty map of regions to locations where they're live. - pub(crate) fn with_specific_points(elements: Rc) -> Self { - LivenessValues { - live_regions: None, - points: Some(SparseIntervalMatrix::new(elements.num_points())), - elements, - loans: None, - } - } - - /// Create an empty map of regions to locations where they're live. - /// - /// Unlike `with_specific_points`, does not track exact locations where something is live, only - /// which regions are live. - pub(crate) fn without_specific_points(elements: Rc) -> Self { - LivenessValues { - live_regions: Some(Default::default()), - points: None, - elements, - loans: None, - } - } - - /// Iterate through each region that has a value in this set. - pub(crate) fn regions(&self) -> impl Iterator + '_ { - self.points.as_ref().expect("use with_specific_points").rows() - } - - /// Iterate through each region that has a value in this set. - // We are passing query instability implications to the caller. - #[rustc_lint_query_instability] - #[allow(rustc::potential_query_instability)] - pub(crate) fn live_regions_unordered(&self) -> impl Iterator + '_ { - self.live_regions.as_ref().unwrap().iter().copied() - } - - /// Records `region` as being live at the given `location`. - pub(crate) fn add_location(&mut self, region: RegionVid, location: Location) { - let point = self.elements.point_from_location(location); - debug!("LivenessValues::add_location(region={:?}, location={:?})", region, location); - if let Some(points) = &mut self.points { - points.insert(region, point); - } else { - if self.elements.point_in_range(point) { - self.live_regions.as_mut().unwrap().insert(region); - } - } - - // When available, record the loans flowing into this region as live at the given point. - if let Some(loans) = self.loans.as_mut() { - if let Some(inflowing) = loans.inflowing_loans.row(region) { - loans.live_loans.union_row(point, inflowing); - } - } - } - - /// Records `region` as being live at all the given `points`. - pub(crate) fn add_points(&mut self, region: RegionVid, points: &IntervalSet) { - debug!("LivenessValues::add_points(region={:?}, points={:?})", region, points); - if let Some(this) = &mut self.points { - this.union_row(region, points); - } else { - if points.iter().any(|point| self.elements.point_in_range(point)) { - self.live_regions.as_mut().unwrap().insert(region); - } - } - - // When available, record the loans flowing into this region as live at the given points. - if let Some(loans) = self.loans.as_mut() { - if let Some(inflowing) = loans.inflowing_loans.row(region) { - if !inflowing.is_empty() { - for point in points.iter() { - loans.live_loans.union_row(point, inflowing); - } - } - } - } - } - - /// Records `region` as being live at all the control-flow points. - pub(crate) fn add_all_points(&mut self, region: RegionVid) { - if let Some(points) = &mut self.points { - points.insert_all_into_row(region); - } else { - self.live_regions.as_mut().unwrap().insert(region); - } - } - - /// Returns whether `region` is marked live at the given `location`. - pub(crate) fn is_live_at(&self, region: RegionVid, location: Location) -> bool { - let point = self.elements.point_from_location(location); - if let Some(points) = &self.points { - points.row(region).is_some_and(|r| r.contains(point)) - } else { - unreachable!( - "Should be using LivenessValues::with_specific_points to ask whether live at a location" - ) - } - } - - /// Returns an iterator of all the points where `region` is live. - fn live_points(&self, region: RegionVid) -> impl Iterator + '_ { - let Some(points) = &self.points else { - unreachable!( - "Should be using LivenessValues::with_specific_points to ask whether live at a location" - ) - }; - points - .row(region) - .into_iter() - .flat_map(|set| set.iter()) - .take_while(|&p| self.elements.point_in_range(p)) - } - - /// For debugging purposes, returns a pretty-printed string of the points where the `region` is - /// live. - pub(crate) fn pretty_print_live_points(&self, region: RegionVid) -> String { - pretty_print_region_elements( - self.live_points(region).map(|p| RegionElement::Location(self.elements.to_location(p))), - ) - } - - #[inline] - pub(crate) fn point_from_location(&self, location: Location) -> PointIndex { - self.elements.point_from_location(location) - } - - /// When using `-Zpolonius=next`, returns whether the `loan_idx` is live at the given `point`. - pub(crate) fn is_loan_live_at(&self, loan_idx: BorrowIndex, point: PointIndex) -> bool { - self.loans - .as_ref() - .expect("Accessing live loans requires `-Zpolonius=next`") - .live_loans - .contains(point, loan_idx) - } -} - -/// Maps from `ty::PlaceholderRegion` values that are used in the rest of -/// rustc to the internal `PlaceholderIndex` values that are used in -/// NLL. -#[derive(Debug, Default)] -pub(crate) struct PlaceholderIndices { - indices: FxIndexSet, -} - -impl PlaceholderIndices { - /// Returns the `PlaceholderIndex` for the inserted `PlaceholderRegion` - pub(crate) fn insert(&mut self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex { - let (index, _) = self.indices.insert_full(placeholder); - index.into() - } - - pub(crate) fn lookup_index(&self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex { - self.indices.get_index_of(&placeholder).unwrap().into() - } - - pub(crate) fn lookup_placeholder( - &self, - placeholder: PlaceholderIndex, - ) -> ty::PlaceholderRegion { - self.indices[placeholder.index()] - } - - pub(crate) fn len(&self) -> usize { - self.indices.len() - } -} - -/// Stores the full values for a set of regions (in contrast to -/// `LivenessValues`, which only stores those points in the where a -/// region is live). The full value for a region may contain points in -/// the CFG, but also free regions as well as bound universe -/// placeholders. -/// -/// Example: -/// -/// ```text -/// fn foo(x: &'a u32) -> &'a u32 { -/// let y: &'0 u32 = x; // let's call this `'0` -/// y -/// } -/// ``` -/// -/// Here, the variable `'0` would contain the free region `'a`, -/// because (since it is returned) it must live for at least `'a`. But -/// it would also contain various points from within the function. -#[derive(Clone)] -pub(crate) struct RegionValues { - elements: Rc, - placeholder_indices: Rc, - points: SparseIntervalMatrix, - free_regions: SparseBitMatrix, - - /// Placeholders represent bound regions -- so something like `'a` - /// in `for<'a> fn(&'a u32)`. - placeholders: SparseBitMatrix, -} - -impl RegionValues { - /// Creates a new set of "region values" that tracks causal information. - /// Each of the regions in num_region_variables will be initialized with an - /// empty set of points and no causal information. - pub(crate) fn new( - elements: &Rc, - num_universal_regions: usize, - placeholder_indices: &Rc, - ) -> Self { - let num_placeholders = placeholder_indices.len(); - Self { - elements: elements.clone(), - points: SparseIntervalMatrix::new(elements.num_points()), - placeholder_indices: placeholder_indices.clone(), - free_regions: SparseBitMatrix::new(num_universal_regions), - placeholders: SparseBitMatrix::new(num_placeholders), - } - } - - /// Adds the given element to the value for the given region. Returns whether - /// the element is newly added (i.e., was not already present). - pub(crate) fn add_element(&mut self, r: N, elem: impl ToElementIndex) -> bool { - debug!("add(r={:?}, elem={:?})", r, elem); - elem.add_to_row(self, r) - } - - /// Adds all the control-flow points to the values for `r`. - pub(crate) fn add_all_points(&mut self, r: N) { - self.points.insert_all_into_row(r); - } - - /// Adds all elements in `r_from` to `r_to` (because e.g., `r_to: - /// r_from`). - pub(crate) fn add_region(&mut self, r_to: N, r_from: N) -> bool { - self.points.union_rows(r_from, r_to) - | self.free_regions.union_rows(r_from, r_to) - | self.placeholders.union_rows(r_from, r_to) - } - - /// Returns `true` if the region `r` contains the given element. - pub(crate) fn contains(&self, r: N, elem: impl ToElementIndex) -> bool { - elem.contained_in_row(self, r) - } - - /// Returns the lowest statement index in `start..=end` which is not contained by `r`. - pub(crate) fn first_non_contained_inclusive( - &self, - r: N, - block: BasicBlock, - start: usize, - end: usize, - ) -> Option { - let row = self.points.row(r)?; - let block = self.elements.entry_point(block); - let start = block.plus(start); - let end = block.plus(end); - let first_unset = row.first_unset_in(start..=end)?; - Some(first_unset.index() - block.index()) - } - - /// `self[to] |= values[from]`, essentially: that is, take all the - /// elements for the region `from` from `values` and add them to - /// the region `to` in `self`. - pub(crate) fn merge_liveness(&mut self, to: N, from: RegionVid, values: &LivenessValues) { - let Some(value_points) = &values.points else { - panic!("LivenessValues must track specific points for use in merge_liveness"); - }; - if let Some(set) = value_points.row(from) { - self.points.union_row(to, set); - } - } - - /// Returns `true` if `sup_region` contains all the CFG points that - /// `sub_region` contains. Ignores universal regions. - pub(crate) fn contains_points(&self, sup_region: N, sub_region: N) -> bool { - if let Some(sub_row) = self.points.row(sub_region) { - if let Some(sup_row) = self.points.row(sup_region) { - sup_row.superset(sub_row) - } else { - // sup row is empty, so sub row must be empty - sub_row.is_empty() - } - } else { - // sub row is empty, always true - true - } - } - - /// Returns the locations contained within a given region `r`. - pub(crate) fn locations_outlived_by<'a>(&'a self, r: N) -> impl Iterator + 'a { - self.points.row(r).into_iter().flat_map(move |set| { - set.iter() - .take_while(move |&p| self.elements.point_in_range(p)) - .map(move |p| self.elements.to_location(p)) - }) - } - - /// Returns just the universal regions that are contained in a given region's value. - pub(crate) fn universal_regions_outlived_by<'a>( - &'a self, - r: N, - ) -> impl Iterator + 'a { - self.free_regions.row(r).into_iter().flat_map(|set| set.iter()) - } - - /// Returns all the elements contained in a given region's value. - pub(crate) fn placeholders_contained_in<'a>( - &'a self, - r: N, - ) -> impl Iterator + 'a { - self.placeholders - .row(r) - .into_iter() - .flat_map(|set| set.iter()) - .map(move |p| self.placeholder_indices.lookup_placeholder(p)) - } - - /// Returns all the elements contained in a given region's value. - pub(crate) fn elements_contained_in<'a>( - &'a self, - r: N, - ) -> impl Iterator + 'a { - let points_iter = self.locations_outlived_by(r).map(RegionElement::Location); - - let free_regions_iter = - self.universal_regions_outlived_by(r).map(RegionElement::RootUniversalRegion); - - let placeholder_universes_iter = - self.placeholders_contained_in(r).map(RegionElement::PlaceholderRegion); - - points_iter.chain(free_regions_iter).chain(placeholder_universes_iter) - } - - /// Returns a "pretty" string value of the region. Meant for debugging. - pub(crate) fn region_value_str(&self, r: N) -> String { - pretty_print_region_elements(self.elements_contained_in(r)) - } -} - -pub(crate) trait ToElementIndex: Debug + Copy { - fn add_to_row(self, values: &mut RegionValues, row: N) -> bool; - - fn contained_in_row(self, values: &RegionValues, row: N) -> bool; -} - -impl ToElementIndex for Location { - fn add_to_row(self, values: &mut RegionValues, row: N) -> bool { - let index = values.elements.point_from_location(self); - values.points.insert(row, index) - } - - fn contained_in_row(self, values: &RegionValues, row: N) -> bool { - let index = values.elements.point_from_location(self); - values.points.contains(row, index) - } -} - -impl ToElementIndex for RegionVid { - fn add_to_row(self, values: &mut RegionValues, row: N) -> bool { - values.free_regions.insert(row, self) - } - - fn contained_in_row(self, values: &RegionValues, row: N) -> bool { - values.free_regions.contains(row, self) - } -} - -impl ToElementIndex for ty::PlaceholderRegion { - fn add_to_row(self, values: &mut RegionValues, row: N) -> bool { - let index = values.placeholder_indices.lookup_index(self); - values.placeholders.insert(row, index) - } - - fn contained_in_row(self, values: &RegionValues, row: N) -> bool { - let index = values.placeholder_indices.lookup_index(self); - values.placeholders.contains(row, index) - } -} - -/// For debugging purposes, returns a pretty-printed string of the given points. -pub(crate) fn pretty_print_points( - elements: &DenseLocationMap, - points: impl IntoIterator, -) -> String { - pretty_print_region_elements( - points - .into_iter() - .take_while(|&p| elements.point_in_range(p)) - .map(|p| elements.to_location(p)) - .map(RegionElement::Location), - ) -} - -/// For debugging purposes, returns a pretty-printed string of the given region elements. -fn pretty_print_region_elements(elements: impl IntoIterator) -> String { - let mut result = String::new(); - result.push('{'); - - // Set to Some(l1, l2) when we have observed all the locations - // from l1..=l2 (inclusive) but not yet printed them. This - // gets extended if we then see l3 where l3 is the successor - // to l2. - let mut open_location: Option<(Location, Location)> = None; - - let mut sep = ""; - let mut push_sep = |s: &mut String| { - s.push_str(sep); - sep = ", "; - }; - - for element in elements { - match element { - RegionElement::Location(l) => { - if let Some((location1, location2)) = open_location { - if location2.block == l.block - && location2.statement_index == l.statement_index - 1 - { - open_location = Some((location1, l)); - continue; - } - - push_sep(&mut result); - push_location_range(&mut result, location1, location2); - } - - open_location = Some((l, l)); - } - - RegionElement::RootUniversalRegion(fr) => { - if let Some((location1, location2)) = open_location { - push_sep(&mut result); - push_location_range(&mut result, location1, location2); - open_location = None; - } - - push_sep(&mut result); - result.push_str(&format!("{fr:?}")); - } - - RegionElement::PlaceholderRegion(placeholder) => { - if let Some((location1, location2)) = open_location { - push_sep(&mut result); - push_location_range(&mut result, location1, location2); - open_location = None; - } - - push_sep(&mut result); - result.push_str(&format!("{placeholder:?}")); - } - } - } - - if let Some((location1, location2)) = open_location { - push_sep(&mut result); - push_location_range(&mut result, location1, location2); - } - - result.push('}'); - - return result; - - fn push_location_range(str: &mut String, location1: Location, location2: Location) { - if location1 == location2 { - str.push_str(&format!("{location1:?}")); - } else { - assert_eq!(location1.block, location2.block); - str.push_str(&format!( - "{:?}[{}..={}]", - location1.block, location1.statement_index, location2.statement_index - )); - } - } -} +use rustc_data_structures::fx::FxHashSet;use rustc_data_structures::fx:://{();}; +FxIndexSet;use rustc_index::bit_set::SparseBitMatrix;use rustc_index::interval// +::IntervalSet;use rustc_index:: interval::SparseIntervalMatrix;use rustc_index:: +Idx;use rustc_middle::mir::{BasicBlock,Location};use rustc_middle::ty::{self,//; +RegionVid};use rustc_mir_dataflow::points::{DenseLocationMap,PointIndex};use//3; +std::fmt::Debug;use std::rc::Rc;use crate::BorrowIndex;rustc_index:://if true{}; +newtype_index!{#[debug_format="PlaceholderIndex({})"]pub struct//*&*&();((),()); +PlaceholderIndex{}}#[derive(Debug,Clone )]pub(crate)enum RegionElement{Location( +Location),RootUniversalRegion(RegionVid),PlaceholderRegion(ty:://*&*&();((),()); +PlaceholderRegion),}pub(crate)struct LivenessValues{elements:Rc,live_regions:Option>,points:Option>,pub( crate)loans:Option,} +pub(crate)struct LiveLoans{pub (crate)inflowing_loans:SparseBitMatrix,pub(crate)live_loans: SparseBitMatrix,}impl +LiveLoans{pub(crate)fn new(num_loans:usize)->Self{LiveLoans{live_loans://*&*&(); +SparseBitMatrix::new(num_loans),inflowing_loans :SparseBitMatrix::new(num_loans) +,}}}impl LivenessValues{pub(crate)fn with_specific_points(elements:Rc)->Self{LivenessValues{live_regions:None,points:Some(//((),()); +SparseIntervalMatrix::new(((elements.num_points())))),elements,loans:None,}}pub( +crate)fn without_specific_points(elements:Rc)->Self{//((),()); +LivenessValues{live_regions:Some(Default::default( )),points:None,elements,loans +:None,}}pub(crate)fn regions(&self)->impl Iterator+'_{self.//(); +points.as_ref().expect((((((((((("use with_specific_points"))))))))))).rows()}#[ +rustc_lint_query_instability]#[allow(rustc::potential_query_instability)]pub(//; +crate)fn live_regions_unordered(&self)->impl Iterator+'_{self.// +live_regions.as_ref().unwrap().iter().copied()}pub(crate)fn add_location(&mut//; +self,region:RegionVid,location:Location){*&*&();((),());let point=self.elements. +point_from_location(location);let _=||();let _=||();if true{};let _=||();debug!( +"LivenessValues::add_location(region={:?}, location={:?})",region,location);3;if +let Some(points)=&mut self.points{3;points.insert(region,point);3;}else{if self. +elements.point_in_range(point){{();};self.live_regions.as_mut().unwrap().insert( +region);3;}}if let Some(loans)=self.loans.as_mut(){if let Some(inflowing)=loans. +inflowing_loans.row(region){;loans.live_loans.union_row(point,inflowing);}}}pub( +crate)fn add_points(&mut self, region:RegionVid,points:&IntervalSet) +{;debug!("LivenessValues::add_points(region={:?}, points={:?})",region,points);; +if let Some(this)=&mut self.points{();this.union_row(region,points);();}else{if +points.iter().any(|point|self.elements.point_in_range(point)){;self.live_regions +.as_mut().unwrap().insert(region);();}}if let Some(loans)=self.loans.as_mut(){if +let Some(inflowing)=(loans.inflowing_loans.row(region)){if!inflowing.is_empty(){ +for point in points.iter(){;loans.live_loans.union_row(point,inflowing);}}}}}pub +(crate)fn add_all_points(&mut self,region:RegionVid){if let Some(points)=&mut//; +self.points{;points.insert_all_into_row(region);}else{self.live_regions.as_mut() +.unwrap().insert(region);{();};}}pub(crate)fn is_live_at(&self,region:RegionVid, +location:Location)->bool{;let point=self.elements.point_from_location(location); +if let Some(points)=(&self.points){points.row(region).is_some_and(|r|r.contains( +point))}else{unreachable!(//loop{break;};loop{break;};loop{break;};loop{break;}; +"Should be using LivenessValues::with_specific_points to ask whether live at a location" +)}}fn live_points(&self,region:RegionVid)->impl Iterator+'_{(); +let Some(points)=((((((((((((((((&self.points)))))))))))))))) else{unreachable!( +"Should be using LivenessValues::with_specific_points to ask whether live at a location" +)};;points.row(region).into_iter().flat_map(|set|set.iter()).take_while(|&p|self +.elements.point_in_range(p))} pub(crate)fn pretty_print_live_points(&self,region +:RegionVid)->String{pretty_print_region_elements( self.live_points(region).map(| +p|(RegionElement::Location(self.elements.to_location(p)))),)}#[inline]pub(crate) +fn point_from_location(&self,location:Location)->PointIndex{self.elements.//{;}; +point_from_location(location)}pub(crate)fn is_loan_live_at(&self,loan_idx://{;}; +BorrowIndex,point:PointIndex)->bool{(((((((( self.loans.as_ref())))))))).expect( +"Accessing live loans requires `-Zpolonius=next`").live_loans.contains(point,//; +loan_idx)}}#[derive(Debug,Default )]pub(crate)struct PlaceholderIndices{indices: +FxIndexSet,}impl PlaceholderIndices{pub(crate)fn insert( +&mut self,placeholder:ty::PlaceholderRegion)->PlaceholderIndex{{;};let(index,_)= +self.indices.insert_full(placeholder);3;index.into()}pub(crate)fn lookup_index(& +self,placeholder:ty::PlaceholderRegion)->PlaceholderIndex{self.indices.//*&*&(); +get_index_of(((&placeholder))).unwrap().into()}pub(crate)fn lookup_placeholder(& +self,placeholder:PlaceholderIndex,)->ty::PlaceholderRegion{self.indices[//{();}; +placeholder.index()]}pub(crate)fn len(&self)->usize{(((self.indices.len())))}}#[ +derive(Clone)]pub(crate)struct RegionValues{elements:Rc,placeholder_indices:Rc,points:SparseIntervalMatrix,free_regions:SparseBitMatrix,placeholders://let _=||(); +SparseBitMatrix,}implRegionValues{pub(crate)fn//3; +new(elements:&Rc,num_universal_regions:usize,//*&*&();((),()); +placeholder_indices:&Rc,)->Self{*&*&();let num_placeholders= +placeholder_indices.len();((),());((),());Self{elements:elements.clone(),points: +SparseIntervalMatrix::new((((((elements.num_points ())))))),placeholder_indices: +placeholder_indices.clone(),free_regions:SparseBitMatrix::new(//((),());((),()); +num_universal_regions),placeholders:(SparseBitMatrix:: new(num_placeholders)),}} +pub(crate)fn add_element(&mut self,r:N,elem:impl ToElementIndex)->bool{3;debug!( +"add(r={:?}, elem={:?})",r,elem);let _=||();elem.add_to_row(self,r)}pub(crate)fn +add_all_points(&mut self,r:N){;self.points.insert_all_into_row(r);;}pub(crate)fn +add_region(&mut self,r_to:N,r_from:N)-> bool{self.points.union_rows(r_from,r_to) +|self.free_regions.union_rows(r_from,r_to) |self.placeholders.union_rows(r_from, +r_to)}pub(crate)fn contains(&self,r:N,elem:impl ToElementIndex)->bool{elem.//(); +contained_in_row(self,r)}pub(crate)fn first_non_contained_inclusive(&self,r:N,// +block:BasicBlock,start:usize,end:usize,)->Option{;let row=self.points.row +(r)?;;let block=self.elements.entry_point(block);let start=block.plus(start);let +end=block.plus(end);3;3;let first_unset=row.first_unset_in(start..=end)?;3;Some( +first_unset.index()-(block.index()))}pub(crate)fn merge_liveness(&mut self,to:N, +from:RegionVid,values:&LivenessValues){{;};let Some(value_points)=&values.points +else{((),());let _=();((),());let _=();((),());let _=();((),());let _=();panic!( +"LivenessValues must track specific points for use in merge_liveness");;};if let +Some(set)=value_points.row(from){3;self.points.union_row(to,set);;}}pub(crate)fn +contains_points(&self,sup_region:N,sub_region:N)->bool{if let Some(sub_row)=//3; +self.points.row(sub_region){if let Some (sup_row)=(self.points.row(sup_region)){ +sup_row.superset(sub_row)}else{((sub_row.is_empty()))}}else{(true)}}pub(crate)fn +locations_outlived_by<'a>(&'a self,r:N)->impl Iterator+'a{self.// +points.row(r).into_iter().flat_map(move|set| {set.iter().take_while(move|&p|self +.elements.point_in_range(p)).map((move|p|(self.elements.to_location(p))))})}pub( +crate)fn universal_regions_outlived_by<'a>(&'a self,r:N,)->impl Iterator+'a{(self.free_regions.row(r).into_iter( ).flat_map(|set|set.iter()))} +pub(crate)fn placeholders_contained_in<'a>(&'a self,r:N,)->impl Iterator+'a{(self.placeholders.row (r).into_iter()).flat_map(|set| +set.iter()).map((move|p |(self.placeholder_indices.lookup_placeholder(p))))}pub( +crate)fn elements_contained_in<'a>(&'a self,r:N,)->impl Iterator+'a{loop{break};let points_iter=self.locations_outlived_by(r).map( +RegionElement::Location);if let _=(){};if let _=(){};let free_regions_iter=self. +universal_regions_outlived_by(r).map(RegionElement::RootUniversalRegion);3;3;let +placeholder_universes_iter=(self.placeholders_contained_in(r)).map(RegionElement +::PlaceholderRegion);((),());((),());points_iter.chain(free_regions_iter).chain( +placeholder_universes_iter)}pub(crate)fn region_value_str(&self,r:N)->String{//; +pretty_print_region_elements(((self.elements_contained_in(r))))}}pub(crate)trait +ToElementIndex:Debug+Copy{fn add_to_row(self,values:&mut RegionValues +,row:N)->bool;fn contained_in_row(self,values:&RegionValues,row:N)->// +bool;}impl ToElementIndex for Location{fn add_to_row(self,values:&mut//3; +RegionValues,row:N)->bool{;let index=values.elements.point_from_location(self +);{();};values.points.insert(row,index)}fn contained_in_row(self,values:& +RegionValues,row:N)->bool{;let index=values.elements.point_from_location(self +);*&*&();values.points.contains(row,index)}}impl ToElementIndex for RegionVid{fn +add_to_row(self,values:&mut RegionValues,row:N)->bool{values.//*&*&(); +free_regions.insert(row,self)}fn contained_in_row(self,values:&//((),()); +RegionValues,row:N)->bool{((( values.free_regions.contains(row,self))))}}impl +ToElementIndex for ty::PlaceholderRegion{fn add_to_row(self,values:&mut// +RegionValues,row:N)->bool{;let index=values.placeholder_indices.lookup_index( +self);{;};values.placeholders.insert(row,index)}fn contained_in_row(self, +values:&RegionValues,row:N)->bool{{();};let index=values.placeholder_indices. +lookup_index(self);((),());values.placeholders.contains(row,index)}}pub(crate)fn +pretty_print_points(elements:&DenseLocationMap,points:impl IntoIterator,)->String{pretty_print_region_elements((((((points.into_iter()))))). +take_while(|&p|elements.point_in_range(p)). map(|p|elements.to_location(p)).map( +RegionElement::Location),)}fn pretty_print_region_elements(elements:impl//{();}; +IntoIterator)->String{;let mut result=String::new();;result. +push('{');;let mut open_location:Option<(Location,Location)>=None;let mut sep="" +;;;let mut push_sep=|s:&mut String|{;s.push_str(sep);;;sep=", ";};for element in +elements{match element{RegionElement::Location(l)=>{if let Some((location1,//(); +location2))=open_location{if (((((((location2 .block==l.block)))))))&&location2. +statement_index==l.statement_index-1{;open_location=Some((location1,l));continue +;;};push_sep(&mut result);push_location_range(&mut result,location1,location2);} +open_location=Some((l,l));;}RegionElement::RootUniversalRegion(fr)=>{if let Some +((location1,location2))=open_location{;push_sep(&mut result);push_location_range +(&mut result,location1,location2);;;open_location=None;;};push_sep(&mut result); +result.push_str(&format!("{fr:?}"));if true{};}RegionElement::PlaceholderRegion( +placeholder)=>{if let Some((location1,location2))=open_location{();push_sep(&mut +result);;push_location_range(&mut result,location1,location2);open_location=None +;;};push_sep(&mut result);result.push_str(&format!("{placeholder:?}"));}}}if let +Some((location1,location2))=open_location{{();};push_sep(&mut result);({});({}); +push_location_range(&mut result,location1,location2);;};result.push('}');;return +result;();3;fn push_location_range(str:&mut String,location1:Location,location2: +Location){if location1==location2{;str.push_str(&format!("{location1:?}"));}else +{({});assert_eq!(location1.block,location2.block);{;};{;};str.push_str(&format!( +"{:?}[{}..={}]",location1.block,location1.statement_index,location2.//if true{}; +statement_index));*&*&();((),());*&*&();((),());}}if let _=(){};*&*&();((),());} diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs index dca8df3280028..e2d2ccb086f1b 100644 --- a/compiler/rustc_borrowck/src/renumber.rs +++ b/compiler/rustc_borrowck/src/renumber.rs @@ -1,123 +1,37 @@ -use crate::BorrowckInferCtxt; -use rustc_index::IndexSlice; -use rustc_infer::infer::NllRegionVariableOrigin; -use rustc_middle::mir::visit::{MutVisitor, TyContext}; -use rustc_middle::mir::{Body, ConstOperand, Location, Promoted}; -use rustc_middle::ty::GenericArgsRef; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc_span::Symbol; - -/// Replaces all free regions appearing in the MIR with fresh -/// inference variables, returning the number of variables created. -#[instrument(skip(infcx, body, promoted), level = "debug")] -pub fn renumber_mir<'tcx>( - infcx: &BorrowckInferCtxt<'_, 'tcx>, - body: &mut Body<'tcx>, - promoted: &mut IndexSlice>, -) { - debug!(?body.arg_count); - - let mut renumberer = RegionRenumberer { infcx }; - - for body in promoted.iter_mut() { - renumberer.visit_body(body); - } - - renumberer.visit_body(body); -} - -// FIXME(@lcnr): A lot of these variants overlap and it seems like -// this type is only used to decide which region should be used -// as representative. This should be cleaned up. -#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] -pub(crate) enum RegionCtxt { - Location(Location), - TyContext(TyContext), - Free(Symbol), - Bound(Symbol), - LateBound(Symbol), - Existential(Option), - Placeholder(Symbol), - Unknown, -} - -impl RegionCtxt { - /// Used to determine the representative of a component in the strongly connected - /// constraint graph - pub(crate) fn preference_value(self) -> usize { - match self { - RegionCtxt::Unknown => 1, - RegionCtxt::Existential(None) => 2, - RegionCtxt::Existential(Some(_)) | RegionCtxt::Free(_) => 2, - RegionCtxt::Location(_) => 3, - RegionCtxt::TyContext(_) => 4, - _ => 5, - } - } -} - -struct RegionRenumberer<'a, 'tcx> { - infcx: &'a BorrowckInferCtxt<'a, 'tcx>, -} - -impl<'a, 'tcx> RegionRenumberer<'a, 'tcx> { - /// Replaces all regions appearing in `value` with fresh inference - /// variables. - fn renumber_regions(&mut self, value: T, region_ctxt_fn: F) -> T - where - T: TypeFoldable>, - F: Fn() -> RegionCtxt, - { - let origin = NllRegionVariableOrigin::Existential { from_forall: false }; - self.infcx.tcx.fold_regions(value, |_region, _depth| { - self.infcx.next_nll_region_var(origin, || region_ctxt_fn()) - }) - } -} - -impl<'a, 'tcx> MutVisitor<'tcx> for RegionRenumberer<'a, 'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - #[instrument(skip(self), level = "debug")] - fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) { - if matches!(ty_context, TyContext::ReturnTy(_)) { - // We will renumber the return ty when called again with `TyContext::LocalDecl` - return; - } - *ty = self.renumber_regions(*ty, || RegionCtxt::TyContext(ty_context)); - - debug!(?ty); - } - - #[instrument(skip(self), level = "debug")] - fn visit_args(&mut self, args: &mut GenericArgsRef<'tcx>, location: Location) { - *args = self.renumber_regions(*args, || RegionCtxt::Location(location)); - - debug!(?args); - } - - #[instrument(skip(self), level = "debug")] - fn visit_region(&mut self, region: &mut ty::Region<'tcx>, location: Location) { - let old_region = *region; - *region = self.renumber_regions(old_region, || RegionCtxt::Location(location)); - - debug!(?region); - } - - #[instrument(skip(self), level = "debug")] - fn visit_ty_const(&mut self, ct: &mut ty::Const<'tcx>, location: Location) { - let old_ct = *ct; - *ct = self.renumber_regions(old_ct, || RegionCtxt::Location(location)); - - debug!(?ct); - } - - #[instrument(skip(self), level = "debug")] - fn visit_constant(&mut self, constant: &mut ConstOperand<'tcx>, location: Location) { - let const_ = constant.const_; - constant.const_ = self.renumber_regions(const_, || RegionCtxt::Location(location)); - debug!("constant: {:#?}", constant); - } -} +use crate::BorrowckInferCtxt;use rustc_index::IndexSlice;use rustc_infer::infer +::NllRegionVariableOrigin;use rustc_middle::mir ::visit::{MutVisitor,TyContext}; +use rustc_middle::mir::{Body,ConstOperand ,Location,Promoted};use rustc_middle:: +ty::GenericArgsRef;use rustc_middle::ty::{self,Ty,TyCtxt,TypeFoldable};use//{;}; +rustc_span::Symbol;#[instrument(skip(infcx, body,promoted),level="debug")]pub fn +renumber_mir<'tcx>(infcx:&BorrowckInferCtxt<'_,'tcx>,body:&mut Body<'tcx>,//{;}; +promoted:&mut IndexSlice>,){;debug!(?body.arg_count);let mut +renumberer=RegionRenumberer{infcx};;for body in promoted.iter_mut(){;renumberer. +visit_body(body);3;};renumberer.visit_body(body);;}#[derive(Copy,Clone,Debug,Eq, +PartialEq,Hash)]pub(crate)enum RegionCtxt{Location(Location),TyContext(//*&*&(); +TyContext),Free(Symbol),Bound(Symbol),LateBound(Symbol),Existential(Option),Placeholder(Symbol),Unknown,}impl RegionCtxt{pub(crate)fn//loop{break}; +preference_value(self)->usize{match self{RegionCtxt::Unknown=>((1)),RegionCtxt:: +Existential(None)=>(2),RegionCtxt::Existential(Some( _))|RegionCtxt::Free(_)=>2, +RegionCtxt::Location(_)=>((3)),RegionCtxt::TyContext(_ )=>((4)),_=>(5),}}}struct +RegionRenumberer<'a,'tcx>{infcx:&'a BorrowckInferCtxt<'a,'tcx>,}impl<'a,'tcx>//; +RegionRenumberer<'a,'tcx>{fn renumber_regions(&mut self,value:T,//let _=(); +region_ctxt_fn:F)->T where T:TypeFoldable>,F:Fn()->RegionCtxt,{;let +origin=NllRegionVariableOrigin::Existential{from_forall:false};3;self.infcx.tcx. +fold_regions(value,|_region,_depth|{self.infcx.next_nll_region_var(origin,||//3; +region_ctxt_fn())})}}impl< 'a,'tcx>MutVisitor<'tcx>for RegionRenumberer<'a,'tcx> +{fn tcx(&self)->TyCtxt<'tcx>{self.infcx.tcx}#[instrument(skip(self),level=//{;}; +"debug")]fn visit_ty(&mut self,ty:&mut Ty<'tcx>,ty_context:TyContext){if //({}); +matches!(ty_context,TyContext::ReturnTy(_)){;return;}*ty=self.renumber_regions(* +ty,||RegionCtxt::TyContext(ty_context));;;debug!(?ty);;}#[instrument(skip(self), +level="debug")]fn visit_args(&mut self ,args:&mut GenericArgsRef<'tcx>,location: +Location){;*args=self.renumber_regions(*args,||RegionCtxt::Location(location));; +debug!(?args);;}#[instrument(skip(self),level="debug")]fn visit_region(&mut self +,region:&mut ty::Region<'tcx>,location:Location){;let old_region=*region;*region +=self.renumber_regions(old_region,||RegionCtxt::Location(location));3;3;debug!(? +region);;}#[instrument(skip(self),level="debug")]fn visit_ty_const(&mut self,ct: +&mut ty::Const<'tcx>,location:Location){{();};let old_ct=*ct;({});({});*ct=self. +renumber_regions(old_ct,||RegionCtxt::Location(location));();3;debug!(?ct);3;}#[ +instrument(skip(self),level="debug")]fn visit_constant(&mut self,constant:&mut// +ConstOperand<'tcx>,location:Location){3;let const_=constant.const_;3;3;constant. +const_=self.renumber_regions(const_,||RegionCtxt::Location(location));3;;debug!( +"constant: {:#?}",constant);loop{break};loop{break;};loop{break};loop{break;};}} diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs index 40c2ef1c91e14..717d1dadf4474 100644 --- a/compiler/rustc_borrowck/src/session_diagnostics.rs +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -1,481 +1,125 @@ -use rustc_errors::{codes::*, MultiSpan}; -use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; -use rustc_middle::ty::{GenericArg, Ty}; -use rustc_span::Span; - -use crate::diagnostics::RegionName; - -#[derive(Diagnostic)] -#[diag(borrowck_move_unsized, code = E0161)] -pub(crate) struct MoveUnsized<'tcx> { - pub ty: Ty<'tcx>, - #[primary_span] - #[label] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(borrowck_higher_ranked_lifetime_error)] -pub(crate) struct HigherRankedLifetimeError { - #[subdiagnostic] - pub cause: Option, - #[primary_span] - pub span: Span, -} - -#[derive(Subdiagnostic)] -pub(crate) enum HigherRankedErrorCause { - #[note(borrowck_could_not_prove)] - CouldNotProve { predicate: String }, - #[note(borrowck_could_not_normalize)] - CouldNotNormalize { value: String }, -} - -#[derive(Diagnostic)] -#[diag(borrowck_higher_ranked_subtype_error)] -pub(crate) struct HigherRankedSubtypeError { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(borrowck_generic_does_not_live_long_enough)] -pub(crate) struct GenericDoesNotLiveLongEnough { - pub kind: String, - #[primary_span] - pub span: Span, -} - -#[derive(LintDiagnostic)] -#[diag(borrowck_var_does_not_need_mut)] -pub(crate) struct VarNeedNotMut { - #[suggestion(style = "short", applicability = "machine-applicable", code = "")] - pub span: Span, -} -#[derive(Diagnostic)] -#[diag(borrowck_var_cannot_escape_closure)] -#[note] -#[note(borrowck_cannot_escape)] -pub(crate) struct FnMutError { - #[primary_span] - pub span: Span, - #[subdiagnostic] - pub ty_err: FnMutReturnTypeErr, -} - -#[derive(Subdiagnostic)] -pub(crate) enum VarHereDenote { - #[label(borrowck_var_here_captured)] - Captured { - #[primary_span] - span: Span, - }, - #[label(borrowck_var_here_defined)] - Defined { - #[primary_span] - span: Span, - }, - #[label(borrowck_closure_inferred_mut)] - FnMutInferred { - #[primary_span] - span: Span, - }, -} - -#[derive(Subdiagnostic)] -pub(crate) enum FnMutReturnTypeErr { - #[label(borrowck_returned_closure_escaped)] - ReturnClosure { - #[primary_span] - span: Span, - }, - #[label(borrowck_returned_async_block_escaped)] - ReturnAsyncBlock { - #[primary_span] - span: Span, - }, - #[label(borrowck_returned_ref_escaped)] - ReturnRef { - #[primary_span] - span: Span, - }, -} - -#[derive(Diagnostic)] -#[diag(borrowck_lifetime_constraints_error)] -pub(crate) struct LifetimeOutliveErr { - #[primary_span] - pub span: Span, -} - -#[derive(Subdiagnostic)] -pub(crate) enum LifetimeReturnCategoryErr<'a> { - #[label(borrowck_returned_lifetime_wrong)] - WrongReturn { - #[primary_span] - span: Span, - mir_def_name: &'a str, - outlived_fr_name: RegionName, - fr_name: &'a RegionName, - }, - #[label(borrowck_returned_lifetime_short)] - ShortReturn { - #[primary_span] - span: Span, - category_desc: &'static str, - free_region_name: &'a RegionName, - outlived_fr_name: RegionName, - }, -} - -#[derive(Subdiagnostic)] -pub(crate) enum RequireStaticErr { - #[note(borrowck_used_impl_require_static)] - UsedImpl { - #[primary_span] - multi_span: MultiSpan, - }, -} - -#[derive(Subdiagnostic)] -pub(crate) enum CaptureVarPathUseCause { - #[label(borrowck_borrow_due_to_use_coroutine)] - BorrowInCoroutine { - #[primary_span] - path_span: Span, - }, - #[label(borrowck_use_due_to_use_coroutine)] - UseInCoroutine { - #[primary_span] - path_span: Span, - }, - #[label(borrowck_assign_due_to_use_coroutine)] - AssignInCoroutine { - #[primary_span] - path_span: Span, - }, - #[label(borrowck_assign_part_due_to_use_coroutine)] - AssignPartInCoroutine { - #[primary_span] - path_span: Span, - }, - #[label(borrowck_borrow_due_to_use_closure)] - BorrowInClosure { - #[primary_span] - path_span: Span, - }, - #[label(borrowck_use_due_to_use_closure)] - UseInClosure { - #[primary_span] - path_span: Span, - }, - #[label(borrowck_assign_due_to_use_closure)] - AssignInClosure { - #[primary_span] - path_span: Span, - }, - #[label(borrowck_assign_part_due_to_use_closure)] - AssignPartInClosure { - #[primary_span] - path_span: Span, - }, -} - -#[derive(Subdiagnostic)] -pub(crate) enum CaptureVarKind { - #[label(borrowck_capture_immute)] - Immut { - #[primary_span] - kind_span: Span, - }, - #[label(borrowck_capture_mut)] - Mut { - #[primary_span] - kind_span: Span, - }, - #[label(borrowck_capture_move)] - Move { - #[primary_span] - kind_span: Span, - }, -} - -#[derive(Subdiagnostic)] -pub(crate) enum CaptureVarCause { - #[label(borrowck_var_borrow_by_use_place_in_coroutine)] - BorrowUsePlaceCoroutine { - is_single_var: bool, - place: String, - #[primary_span] - var_span: Span, - }, - #[label(borrowck_var_borrow_by_use_place_in_closure)] - BorrowUsePlaceClosure { - is_single_var: bool, - place: String, - #[primary_span] - var_span: Span, - }, - #[label(borrowck_var_borrow_by_use_in_coroutine)] - BorrowUseInCoroutine { - #[primary_span] - var_span: Span, - }, - #[label(borrowck_var_borrow_by_use_in_closure)] - BorrowUseInClosure { - #[primary_span] - var_span: Span, - }, - #[label(borrowck_var_move_by_use_in_coroutine)] - MoveUseInCoroutine { - #[primary_span] - var_span: Span, - }, - #[label(borrowck_var_move_by_use_in_closure)] - MoveUseInClosure { - #[primary_span] - var_span: Span, - }, - #[label(borrowck_var_first_borrow_by_use_place_in_coroutine)] - FirstBorrowUsePlaceCoroutine { - place: String, - #[primary_span] - var_span: Span, - }, - #[label(borrowck_var_first_borrow_by_use_place_in_closure)] - FirstBorrowUsePlaceClosure { - place: String, - #[primary_span] - var_span: Span, - }, - #[label(borrowck_var_second_borrow_by_use_place_in_coroutine)] - SecondBorrowUsePlaceCoroutine { - place: String, - #[primary_span] - var_span: Span, - }, - #[label(borrowck_var_second_borrow_by_use_place_in_closure)] - SecondBorrowUsePlaceClosure { - place: String, - #[primary_span] - var_span: Span, - }, - #[label(borrowck_var_mutable_borrow_by_use_place_in_closure)] - MutableBorrowUsePlaceClosure { - place: String, - #[primary_span] - var_span: Span, - }, - #[label(borrowck_partial_var_move_by_use_in_coroutine)] - PartialMoveUseInCoroutine { - #[primary_span] - var_span: Span, - is_partial: bool, - }, - #[label(borrowck_partial_var_move_by_use_in_closure)] - PartialMoveUseInClosure { - #[primary_span] - var_span: Span, - is_partial: bool, - }, -} - -#[derive(Diagnostic)] -#[diag(borrowck_cannot_move_when_borrowed, code = E0505)] -pub(crate) struct MoveBorrow<'a> { - pub place: &'a str, - pub borrow_place: &'a str, - pub value_place: &'a str, - #[primary_span] - #[label(borrowck_move_label)] - pub span: Span, - #[label] - pub borrow_span: Span, -} - -#[derive(Diagnostic)] -#[diag(borrowck_opaque_type_non_generic_param, code = E0792)] -pub(crate) struct NonGenericOpaqueTypeParam<'a, 'tcx> { - pub ty: GenericArg<'tcx>, - pub kind: &'a str, - #[primary_span] - pub span: Span, - #[label] - pub param_span: Span, -} - -#[derive(Diagnostic)] -#[diag(borrowck_opaque_type_lifetime_mismatch)] -pub(crate) struct LifetimeMismatchOpaqueParam<'tcx> { - pub arg: GenericArg<'tcx>, - pub prev: GenericArg<'tcx>, - #[primary_span] - #[label] - #[note] - pub span: Span, - #[label(borrowck_prev_lifetime_label)] - pub prev_span: Span, -} - -#[derive(Subdiagnostic)] -pub(crate) enum CaptureReasonLabel<'a> { - #[label(borrowck_moved_due_to_call)] - Call { - #[primary_span] - fn_call_span: Span, - place_name: &'a str, - is_partial: bool, - is_loop_message: bool, - }, - #[label(borrowck_moved_due_to_usage_in_operator)] - OperatorUse { - #[primary_span] - fn_call_span: Span, - place_name: &'a str, - is_partial: bool, - is_loop_message: bool, - }, - #[label(borrowck_moved_due_to_implicit_into_iter_call)] - ImplicitCall { - #[primary_span] - fn_call_span: Span, - place_name: &'a str, - is_partial: bool, - is_loop_message: bool, - }, - #[label(borrowck_moved_due_to_method_call)] - MethodCall { - #[primary_span] - fn_call_span: Span, - place_name: &'a str, - is_partial: bool, - is_loop_message: bool, - }, - #[label(borrowck_moved_due_to_await)] - Await { - #[primary_span] - fn_call_span: Span, - place_name: &'a str, - is_partial: bool, - is_loop_message: bool, - }, - #[label(borrowck_value_moved_here)] - MovedHere { - #[primary_span] - move_span: Span, - is_partial: bool, - is_move_msg: bool, - is_loop_message: bool, - }, - #[label(borrowck_consider_borrow_type_contents)] - BorrowContent { - #[primary_span] - var_span: Span, - }, -} - -#[derive(Subdiagnostic)] -pub(crate) enum CaptureReasonNote { - #[note(borrowck_moved_a_fn_once_in_call)] - FnOnceMoveInCall { - #[primary_span] - var_span: Span, - }, - #[note(borrowck_calling_operator_moves)] - UnOpMoveByOperator { - #[primary_span] - span: Span, - }, - #[note(borrowck_calling_operator_moves_lhs)] - LhsMoveByOperator { - #[primary_span] - span: Span, - }, - #[note(borrowck_func_take_self_moved_place)] - FuncTakeSelf { - func: String, - place_name: String, - #[primary_span] - span: Span, - }, -} - -#[derive(Subdiagnostic)] -pub(crate) enum CaptureReasonSuggest<'tcx> { - #[suggestion( - borrowck_suggest_iterate_over_slice, - applicability = "maybe-incorrect", - code = "&", - style = "verbose" - )] - IterateSlice { - ty: Ty<'tcx>, - #[primary_span] - span: Span, - }, - #[suggestion( - borrowck_suggest_create_freash_reborrow, - applicability = "maybe-incorrect", - code = ".as_mut()", - style = "verbose" - )] - FreshReborrow { - #[primary_span] - span: Span, - }, -} - -#[derive(Subdiagnostic)] -pub(crate) enum CaptureArgLabel { - #[label(borrowck_value_capture_here)] - Capture { - is_within: bool, - #[primary_span] - args_span: Span, - }, - #[label(borrowck_move_out_place_here)] - MoveOutPlace { - place: String, - #[primary_span] - args_span: Span, - }, -} - -#[derive(Subdiagnostic)] -pub(crate) enum OnClosureNote<'a> { - #[note(borrowck_closure_invoked_twice)] - InvokedTwice { - place_name: &'a str, - #[primary_span] - span: Span, - }, - #[note(borrowck_closure_moved_twice)] - MovedTwice { - place_name: &'a str, - #[primary_span] - span: Span, - }, -} - -#[derive(Subdiagnostic)] -pub(crate) enum TypeNoCopy<'a, 'tcx> { - #[label(borrowck_ty_no_impl_copy)] - Label { - is_partial_move: bool, - ty: Ty<'tcx>, - place: &'a str, - #[primary_span] - span: Span, - }, - #[note(borrowck_ty_no_impl_copy)] - Note { is_partial_move: bool, ty: Ty<'tcx>, place: &'a str }, -} - -#[derive(Diagnostic)] -#[diag(borrowck_simd_intrinsic_arg_const)] -pub(crate) struct SimdIntrinsicArgConst { - #[primary_span] - pub span: Span, - pub arg: usize, - pub intrinsic: String, -} +use rustc_errors::{codes::*,MultiSpan};use rustc_macros::{Diagnostic,//let _=(); +LintDiagnostic,Subdiagnostic};use rustc_middle::ty::{GenericArg,Ty};use//*&*&(); +rustc_span::Span;use crate::diagnostics::RegionName ;#[derive(Diagnostic)]#[diag +(borrowck_move_unsized,code=E0161)]pub(crate) struct MoveUnsized<'tcx>{pub ty:Ty +<'tcx>,#[primary_span]#[label]pub span:Span,}#[derive(Diagnostic)]#[diag(//({}); +borrowck_higher_ranked_lifetime_error)]pub(crate)struct//let _=||();loop{break}; +HigherRankedLifetimeError{#[subdiagnostic]pub cause:Option,#[primary_span]pub span:Span,}#[derive(Subdiagnostic)]// +pub(crate)enum HigherRankedErrorCause{#[note(borrowck_could_not_prove)]//*&*&(); +CouldNotProve{predicate:String},#[note(borrowck_could_not_normalize)]//let _=(); +CouldNotNormalize{value:String},}#[derive(Diagnostic)]#[diag(//((),());let _=(); +borrowck_higher_ranked_subtype_error)]pub( crate)struct HigherRankedSubtypeError +{#[primary_span]pub span:Span,}#[derive(Diagnostic)]#[diag(//let _=();if true{}; +borrowck_generic_does_not_live_long_enough)]pub(crate)struct//let _=();let _=(); +GenericDoesNotLiveLongEnough{pub kind:String,#[primary_span]pub span:Span,}#[//; +derive(LintDiagnostic)]#[diag(borrowck_var_does_not_need_mut)]pub(crate)struct// +VarNeedNotMut{#[suggestion(style="short",applicability="machine-applicable",//3; +code="")]pub span:Span,}#[derive(Diagnostic)]#[diag(//loop{break;};loop{break;}; +borrowck_var_cannot_escape_closure)]#[note]#[note(borrowck_cannot_escape)]pub(// +crate)struct FnMutError{#[primary_span]pub span:Span,#[subdiagnostic]pub ty_err +:FnMutReturnTypeErr,}#[derive(Subdiagnostic)]pub(crate)enum VarHereDenote{#[//3; +label(borrowck_var_here_captured)]Captured{#[primary_span]span:Span,},#[label(// +borrowck_var_here_defined)]Defined{#[primary_span]span:Span,},#[label(//((),()); +borrowck_closure_inferred_mut)]FnMutInferred{#[primary_span]span:Span,},}#[//(); +derive(Subdiagnostic)]pub(crate)enum FnMutReturnTypeErr{#[label(//if let _=(){}; +borrowck_returned_closure_escaped)]ReturnClosure{#[primary_span]span:Span,},#[// +label(borrowck_returned_async_block_escaped)]ReturnAsyncBlock{#[primary_span]//; +span:Span,},#[label(borrowck_returned_ref_escaped)]ReturnRef{#[primary_span]//3; +span:Span,},}#[derive(Diagnostic)]#[diag(borrowck_lifetime_constraints_error)]// +pub(crate)struct LifetimeOutliveErr{#[primary_span]pub span:Span,}#[derive(//(); +Subdiagnostic)]pub(crate)enum LifetimeReturnCategoryErr<'a>{#[label(//if true{}; +borrowck_returned_lifetime_wrong)]WrongReturn{#[primary_span]span:Span,//*&*&(); +mir_def_name:&'a str,outlived_fr_name:RegionName,fr_name:&'a RegionName,},#[//3; +label(borrowck_returned_lifetime_short)]ShortReturn{#[primary_span]span:Span,//; +category_desc:&'static str,free_region_name:&'a RegionName,outlived_fr_name://3; +RegionName,},}#[derive(Subdiagnostic)]pub(crate)enum RequireStaticErr{#[note(//; +borrowck_used_impl_require_static)]UsedImpl{# [primary_span]multi_span:MultiSpan +,},}#[derive(Subdiagnostic)]pub(crate)enum CaptureVarPathUseCause{#[label(//{;}; +borrowck_borrow_due_to_use_coroutine)]BorrowInCoroutine{#[primary_span]//*&*&(); +path_span:Span,},#[label(borrowck_use_due_to_use_coroutine)]UseInCoroutine{#[//; +primary_span]path_span:Span,},#[label(borrowck_assign_due_to_use_coroutine)]//3; +AssignInCoroutine{#[primary_span]path_span:Span,},#[label(//if true{};if true{}; +borrowck_assign_part_due_to_use_coroutine)]AssignPartInCoroutine {#[primary_span +]path_span:Span,},# [label(borrowck_borrow_due_to_use_closure)]BorrowInClosure{# +[primary_span]path_span:Span,},#[label(borrowck_use_due_to_use_closure)]//{();}; +UseInClosure{#[primary_span]path_span:Span,},#[label(//loop{break};loop{break;}; +borrowck_assign_due_to_use_closure)]AssignInClosure{#[primary_span]path_span://; +Span,},#[label(borrowck_assign_part_due_to_use_closure)]AssignPartInClosure{#[// +primary_span]path_span:Span,},}#[derive(Subdiagnostic)]pub(crate)enum//let _=(); +CaptureVarKind{#[label(borrowck_capture_immute) ]Immut{#[primary_span]kind_span: +Span,},#[label(borrowck_capture_mut)]Mut{#[primary_span]kind_span:Span,},#[//(); +label(borrowck_capture_move)]Move{#[primary_span]kind_span:Span,},}#[derive(//3; +Subdiagnostic)]pub(crate)enum CaptureVarCause{#[label(//loop{break};loop{break}; +borrowck_var_borrow_by_use_place_in_coroutine)]BorrowUsePlaceCoroutine{//*&*&(); +is_single_var:bool,place:String,#[primary_span]var_span:Span,},#[label(//*&*&(); +borrowck_var_borrow_by_use_place_in_closure)]BorrowUsePlaceClosure{//let _=||(); +is_single_var:bool,place:String,#[primary_span]var_span:Span,},#[label(//*&*&(); +borrowck_var_borrow_by_use_in_coroutine)]BorrowUseInCoroutine{#[primary_span]//; +var_span:Span,},#[label(borrowck_var_borrow_by_use_in_closure)]//*&*&();((),()); +BorrowUseInClosure{#[primary_span]var_span:Span,},#[label(//if true{};if true{}; +borrowck_var_move_by_use_in_coroutine)]MoveUseInCoroutine{#[primary_span]//({}); +var_span:Span,},#[ label(borrowck_var_move_by_use_in_closure)]MoveUseInClosure{# +[primary_span]var_span:Span,},#[label(//if true{};if true{};if true{};if true{}; +borrowck_var_first_borrow_by_use_place_in_coroutine)]//loop{break};loop{break;}; +FirstBorrowUsePlaceCoroutine{place:String,#[primary_span]var_span:Span,},#[//(); +label(borrowck_var_first_borrow_by_use_place_in_closure)]//if true{};let _=||(); +FirstBorrowUsePlaceClosure{place:String,#[primary_span] var_span:Span,},#[label( +borrowck_var_second_borrow_by_use_place_in_coroutine)]//loop{break};loop{break}; +SecondBorrowUsePlaceCoroutine{place:String,#[primary_span]var_span:Span,},#[//3; +label(borrowck_var_second_borrow_by_use_place_in_closure)]//if true{};if true{}; +SecondBorrowUsePlaceClosure{place:String,#[primary_span ]var_span:Span,},#[label +(borrowck_var_mutable_borrow_by_use_place_in_closure)]//loop{break};loop{break}; +MutableBorrowUsePlaceClosure{place:String,#[primary_span]var_span:Span,},#[//(); +label(borrowck_partial_var_move_by_use_in_coroutine )]PartialMoveUseInCoroutine{ +#[primary_span]var_span:Span,is_partial:bool,},#[label(//let _=||();loop{break}; +borrowck_partial_var_move_by_use_in_closure)]PartialMoveUseInClosure{#[//*&*&(); +primary_span]var_span:Span,is_partial:bool,},}#[derive(Diagnostic)]#[diag(//{;}; +borrowck_cannot_move_when_borrowed,code=E0505)]pub( crate)struct MoveBorrow<'a>{ +pub place:&'a str,pub borrow_place:&'a str,pub value_place:&'a str,#[//let _=(); +primary_span]#[label(borrowck_move_label)]pub span:Span,#[label]pub borrow_span +:Span,}#[derive(Diagnostic )]#[diag(borrowck_opaque_type_non_generic_param,code= +E0792)]pub(crate)struct NonGenericOpaqueTypeParam<'a,'tcx>{pub ty:GenericArg,pub kind:&'a str,#[primary_span ]pub span:Span,#[label]pub param_span:Span +,}#[derive(Diagnostic)] #[diag(borrowck_opaque_type_lifetime_mismatch)]pub(crate +)struct LifetimeMismatchOpaqueParam<'tcx>{pub arg:GenericArg<'tcx>,pub prev://3; +GenericArg<'tcx>,#[primary_span]#[label]#[note]pub span:Span,#[label(//let _=(); +borrowck_prev_lifetime_label)]pub prev_span:Span,}#[derive(Subdiagnostic)]pub(// +crate)enum CaptureReasonLabel<'a>{#[label(borrowck_moved_due_to_call)]Call{#[//; +primary_span]fn_call_span:Span,place_name:&'a str,is_partial:bool,//loop{break}; +is_loop_message:bool,},#[label(borrowck_moved_due_to_usage_in_operator)]//{();}; +OperatorUse{#[primary_span]fn_call_span:Span, place_name:&'a str,is_partial:bool +,is_loop_message:bool,}, #[label(borrowck_moved_due_to_implicit_into_iter_call)] +ImplicitCall{#[primary_span]fn_call_span:Span,place_name:&'a str,is_partial://3; +bool,is_loop_message:bool,},#[label(borrowck_moved_due_to_method_call)]//*&*&(); +MethodCall{#[primary_span]fn_call_span:Span, place_name:&'a str,is_partial:bool, +is_loop_message:bool,},#[label(borrowck_moved_due_to_await)]Await{#[//if true{}; +primary_span]fn_call_span:Span,place_name:&'a str,is_partial:bool,//loop{break}; +is_loop_message:bool,},#[label(borrowck_value_moved_here)]MovedHere{#[//((),()); +primary_span]move_span:Span,is_partial:bool,is_move_msg:bool,is_loop_message://; +bool,},#[label(borrowck_consider_borrow_type_contents)]BorrowContent{#[//*&*&(); +primary_span]var_span:Span,},}#[derive(Subdiagnostic)]pub(crate)enum//if true{}; +CaptureReasonNote{#[note(borrowck_moved_a_fn_once_in_call)]FnOnceMoveInCall{#[// +primary_span]var_span:Span,},#[note(borrowck_calling_operator_moves)]//let _=(); +UnOpMoveByOperator{#[primary_span]span:Span,},#[note(//loop{break};loop{break;}; +borrowck_calling_operator_moves_lhs)]LhsMoveByOperator{# [primary_span]span:Span +,},#[note(borrowck_func_take_self_moved_place)]FuncTakeSelf{func:String,//{();}; +place_name:String,#[primary_span]span:Span, },}#[derive(Subdiagnostic)]pub(crate +)enum CaptureReasonSuggest<'tcx>{#[suggestion(//((),());((),());((),());((),()); +borrowck_suggest_iterate_over_slice,applicability="maybe-incorrect",code="&",//; +style="verbose")]IterateSlice{ty:Ty<'tcx>,#[primary_span]span:Span,},#[//*&*&(); +suggestion(borrowck_suggest_create_freash_reborrow,applicability=//loop{break;}; +"maybe-incorrect",code=".as_mut()",style="verbose")]FreshReborrow{#[//if true{}; +primary_span]span:Span,},}#[derive(Subdiagnostic)]pub(crate)enum//if let _=(){}; +CaptureArgLabel{#[label(borrowck_value_capture_here)]Capture{is_within:bool,#[// +primary_span]args_span:Span,},#[label(borrowck_move_out_place_here)]//if true{}; +MoveOutPlace{place:String,#[primary_span]args_span:Span,},}#[derive(//if true{}; +Subdiagnostic)]pub(crate)enum OnClosureNote<'a>{#[note(//let _=||();loop{break}; +borrowck_closure_invoked_twice)]InvokedTwice{place_name:& 'a str,#[primary_span] +span:Span,},#[note(borrowck_closure_moved_twice )]MovedTwice{place_name:&'a str, +#[primary_span]span:Span,},}#[derive(Subdiagnostic)]pub(crate)enum TypeNoCopy{#[label(borrowck_ty_no_impl_copy)]Label{is_partial_move:bool,ty:Ty,place:&'a str,#[primary_span ]span:Span,},#[note(borrowck_ty_no_impl_copy) +]Note{is_partial_move:bool,ty:Ty<'tcx>,place:&'a str},}#[derive(Diagnostic)]#[// +diag(borrowck_simd_intrinsic_arg_const)]pub (crate)struct SimdIntrinsicArgConst{ +#[primary_span]pub span:Span,pub arg:usize,pub intrinsic:String,}//loop{break;}; diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index f28b786e4f739..3db5d2fa140c5 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -1,213 +1,62 @@ -use std::fmt; - -use rustc_errors::ErrorGuaranteed; -use rustc_infer::infer::canonical::Canonical; -use rustc_middle::mir::ConstraintCategory; -use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable}; -use rustc_span::def_id::DefId; -use rustc_span::Span; -use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput}; -use rustc_trait_selection::traits::ObligationCause; - -use crate::diagnostics::ToUniverseInfo; - -use super::{Locations, NormalizeLocation, TypeChecker}; - -impl<'a, 'tcx> TypeChecker<'a, 'tcx> { - /// Given some operation `op` that manipulates types, proves - /// predicates, or otherwise uses the inference context, executes - /// `op` and then executes all the further obligations that `op` - /// returns. This will yield a set of outlives constraints amongst - /// regions which are extracted and stored as having occurred at - /// `locations`. - /// - /// **Any `rustc_infer::infer` operations that might generate region - /// constraints should occur within this method so that those - /// constraints can be properly localized!** - #[instrument(skip(self, op), level = "trace")] - pub(super) fn fully_perform_op( - &mut self, - locations: Locations, - category: ConstraintCategory<'tcx>, - op: Op, - ) -> Result - where - Op: type_op::TypeOp<'tcx, Output = R>, - Op::ErrorInfo: ToUniverseInfo<'tcx>, - { - let old_universe = self.infcx.universe(); - - let TypeOpOutput { output, constraints, error_info } = - op.fully_perform(self.infcx, locations.span(self.body))?; - - debug!(?output, ?constraints); - - if let Some(data) = constraints { - self.push_region_constraints(locations, category, data); - } - - // If the query has created new universes and errors are going to be emitted, register the - // cause of these new universes for improved diagnostics. - let universe = self.infcx.universe(); - if old_universe != universe - && let Some(error_info) = error_info - { - let universe_info = error_info.to_universe_info(old_universe); - for u in (old_universe + 1)..=universe { - self.borrowck_context.constraints.universe_causes.insert(u, universe_info.clone()); - } - } - - Ok(output) - } - - pub(super) fn instantiate_canonical( - &mut self, - span: Span, - canonical: &Canonical<'tcx, T>, - ) -> T - where - T: TypeFoldable>, - { - let (instantiated, _) = self.infcx.instantiate_canonical(span, canonical); - instantiated - } - - #[instrument(skip(self), level = "debug")] - pub(super) fn prove_trait_ref( - &mut self, - trait_ref: ty::TraitRef<'tcx>, - locations: Locations, - category: ConstraintCategory<'tcx>, - ) { - self.prove_predicate( - ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::Trait( - ty::TraitPredicate { trait_ref, polarity: ty::PredicatePolarity::Positive }, - ))), - locations, - category, - ); - } - - #[instrument(level = "debug", skip(self))] - pub(super) fn normalize_and_prove_instantiated_predicates( - &mut self, - // Keep this parameter for now, in case we start using - // it in `ConstraintCategory` at some point. - _def_id: DefId, - instantiated_predicates: ty::InstantiatedPredicates<'tcx>, - locations: Locations, - ) { - for (predicate, span) in instantiated_predicates { - debug!(?span, ?predicate); - let category = ConstraintCategory::Predicate(span); - let predicate = self.normalize_with_category(predicate, locations, category); - self.prove_predicate(predicate, locations, category); - } - } - - pub(super) fn prove_predicates( - &mut self, - predicates: impl IntoIterator + std::fmt::Debug>, - locations: Locations, - category: ConstraintCategory<'tcx>, - ) { - for predicate in predicates { - self.prove_predicate(predicate, locations, category); - } - } - - #[instrument(skip(self), level = "debug")] - pub(super) fn prove_predicate( - &mut self, - predicate: impl ToPredicate<'tcx> + std::fmt::Debug, - locations: Locations, - category: ConstraintCategory<'tcx>, - ) { - let param_env = self.param_env; - let predicate = predicate.to_predicate(self.tcx()); - let _: Result<_, ErrorGuaranteed> = self.fully_perform_op( - locations, - category, - param_env.and(type_op::prove_predicate::ProvePredicate::new(predicate)), - ); - } - - pub(super) fn normalize(&mut self, value: T, location: impl NormalizeLocation) -> T - where - T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx, - { - self.normalize_with_category(value, location, ConstraintCategory::Boring) - } - - #[instrument(skip(self), level = "debug")] - pub(super) fn normalize_with_category( - &mut self, - value: T, - location: impl NormalizeLocation, - category: ConstraintCategory<'tcx>, - ) -> T - where - T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx, - { - let param_env = self.param_env; - let result: Result<_, ErrorGuaranteed> = self.fully_perform_op( - location.to_locations(), - category, - param_env.and(type_op::normalize::Normalize::new(value)), - ); - result.unwrap_or(value) - } - - #[instrument(skip(self), level = "debug")] - pub(super) fn ascribe_user_type( - &mut self, - mir_ty: Ty<'tcx>, - user_ty: ty::UserType<'tcx>, - span: Span, - ) { - let _: Result<_, ErrorGuaranteed> = self.fully_perform_op( - Locations::All(span), - ConstraintCategory::Boring, - self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(mir_ty, user_ty)), - ); - } - - /// *Incorrectly* skips the WF checks we normally do in `ascribe_user_type`. - /// - /// FIXME(#104478, #104477): This is a hack for backward-compatibility. - #[instrument(skip(self), level = "debug")] - pub(super) fn ascribe_user_type_skip_wf( - &mut self, - mir_ty: Ty<'tcx>, - user_ty: ty::UserType<'tcx>, - span: Span, - ) { - let ty::UserType::Ty(user_ty) = user_ty else { bug!() }; - - // A fast path for a common case with closure input/output types. - if let ty::Infer(_) = user_ty.kind() { - self.eq_types(user_ty, mir_ty, Locations::All(span), ConstraintCategory::Boring) - .unwrap(); - return; - } - - // FIXME: Ideally MIR types are normalized, but this is not always true. - let mir_ty = self.normalize(mir_ty, Locations::All(span)); - - let cause = ObligationCause::dummy_with_span(span); - let param_env = self.param_env; - let _: Result<_, ErrorGuaranteed> = self.fully_perform_op( - Locations::All(span), - ConstraintCategory::Boring, - type_op::custom::CustomTypeOp::new( - |ocx| { - let user_ty = ocx.normalize(&cause, param_env, user_ty); - ocx.eq(&cause, param_env, user_ty, mir_ty)?; - Ok(()) - }, - "ascribe_user_type_skip_wf", - ), - ); - } -} +use std::fmt;use rustc_errors::ErrorGuaranteed;use rustc_infer::infer:://*&*&(); +canonical::Canonical;use rustc_middle ::mir::ConstraintCategory;use rustc_middle +::ty::{self,ToPredicate,Ty,TyCtxt,TypeFoldable};use rustc_span::def_id::DefId;// +use rustc_span::Span;use rustc_trait_selection::traits::query::type_op::{self,// +TypeOpOutput};use rustc_trait_selection::traits::ObligationCause;use crate:://3; +diagnostics::ToUniverseInfo;use super ::{Locations,NormalizeLocation,TypeChecker +};impl<'a,'tcx>TypeChecker<'a,'tcx>{#[instrument(skip(self,op),level="trace")]// +pub(super)fn fully_perform_op(&mut self,locations:Locations,//; +category:ConstraintCategory<'tcx>,op:Op,)->Resultwhere Op://; +type_op::TypeOp<'tcx,Output=R>,Op::ErrorInfo:ToUniverseInfo<'tcx>,{if true{};let +old_universe=self.infcx.universe();({});{;};let TypeOpOutput{output,constraints, +error_info}=op.fully_perform(self.infcx,locations.span(self.body))?;3;3;debug!(? +output,?constraints);;if let Some(data)=constraints{self.push_region_constraints +(locations,category,data);;}let universe=self.infcx.universe();if old_universe!= +universe&&let Some(error_info)=error_info{let _=();let universe_info=error_info. +to_universe_info(old_universe);{;};for u in(old_universe+1)..=universe{{;};self. +borrowck_context.constraints.universe_causes.insert(u,universe_info.clone());;}} +Ok(output)}pub(super)fn instantiate_canonical< T>(&mut self,span:Span,canonical: +&Canonical<'tcx,T>,)->T where T:TypeFoldable>,{;let(instantiated,_) +=self.infcx.instantiate_canonical(span,canonical);{;};instantiated}#[instrument( +skip(self),level="debug")]pub(super )fn prove_trait_ref(&mut self,trait_ref:ty:: +TraitRef<'tcx>,locations:Locations,category:ConstraintCategory<'tcx>,){{;};self. +prove_predicate(ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind:://3; +Trait(ty::TraitPredicate{trait_ref,polarity: ty::PredicatePolarity::Positive},)) +),locations,category,);({});}#[instrument(level="debug",skip(self))]pub(super)fn +normalize_and_prove_instantiated_predicates(&mut self,_def_id:DefId,//if true{}; +instantiated_predicates:ty::InstantiatedPredicates<'tcx >,locations:Locations,){ +for(predicate,span)in instantiated_predicates{3;debug!(?span,?predicate);3;3;let +category=ConstraintCategory::Predicate(span);((),());((),());let predicate=self. +normalize_with_category(predicate,locations,category);();3;self.prove_predicate( +predicate,locations,category);((),());}}pub(super)fn prove_predicates(&mut self, +predicates:impl IntoIterator+std::fmt::Debug>,locations: +Locations,category:ConstraintCategory<'tcx>,){for predicate in predicates{;self. +prove_predicate(predicate,locations,category);3;}}#[instrument(skip(self),level= +"debug")]pub(super)fn prove_predicate( &mut self,predicate:impl ToPredicate<'tcx +>+std::fmt::Debug,locations:Locations,category:ConstraintCategory<'tcx>,){();let +param_env=self.param_env;;let predicate=predicate.to_predicate(self.tcx());let _ +:Result<_,ErrorGuaranteed>=self.fully_perform_op(locations,category,param_env.// +and(type_op::prove_predicate::ProvePredicate::new(predicate)),);();}pub(super)fn +normalize(&mut self,value:T,location:impl NormalizeLocation)->T where T://(); +type_op::normalize::Normalizable<'tcx>+fmt::Display+Copy+'tcx,{self.//if true{}; +normalize_with_category(value,location,ConstraintCategory ::Boring)}#[instrument +(skip(self),level="debug")]pub(super)fn normalize_with_category(&mut self,//; +value:T,location:impl NormalizeLocation,category:ConstraintCategory<'tcx>,)->T// +where T:type_op::normalize::Normalizable<'tcx>+fmt::Display+Copy+'tcx,{{();};let +param_env=self.param_env;*&*&();{();};let result:Result<_,ErrorGuaranteed>=self. +fully_perform_op((((location.to_locations()))), category,param_env.and(type_op:: +normalize::Normalize::new(value)),);3;result.unwrap_or(value)}#[instrument(skip( +self),level="debug")]pub(super)fn ascribe_user_type(&mut self,mir_ty:Ty<'tcx>,// +user_ty:ty::UserType<'tcx>,span:Span,){{;};let _:Result<_,ErrorGuaranteed>=self. +fully_perform_op(Locations::All(span) ,ConstraintCategory::Boring,self.param_env +.and(type_op::ascribe_user_type::AscribeUserType::new(mir_ty,user_ty)),);{;};}#[ +instrument(skip(self),level="debug")]pub(super)fn ascribe_user_type_skip_wf(&//; +mut self,mir_ty:Ty<'tcx>,user_ty:ty::UserType<'tcx>,span:Span,){((),());let ty:: +UserType::Ty(user_ty)=user_ty else{bug!()};;if let ty::Infer(_)=user_ty.kind(){; +self.eq_types(user_ty,mir_ty,(Locations::All(span)),ConstraintCategory::Boring). +unwrap();;;return;;};let mir_ty=self.normalize(mir_ty,Locations::All(span));;let +cause=ObligationCause::dummy_with_span(span);;let param_env=self.param_env;let _ +:Result<_,ErrorGuaranteed>=self.fully_perform_op((((((Locations::All(span)))))), +ConstraintCategory::Boring,type_op::custom::CustomTypeOp::new(|ocx|{;let user_ty +=ocx.normalize(&cause,param_env,user_ty);;ocx.eq(&cause,param_env,user_ty,mir_ty +)?;let _=();let _=();Ok(())},"ascribe_user_type_skip_wf",),);((),());let _=();}} diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index de75a9857f8b5..d985787f4b72e 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -1,336 +1,107 @@ -use rustc_hir::def_id::DefId; -use rustc_infer::infer::canonical::QueryRegionConstraints; -use rustc_infer::infer::outlives::env::RegionBoundPairs; -use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate}; -use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound}; -use rustc_infer::infer::{self, InferCtxt, SubregionOrigin}; -use rustc_middle::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory}; -use rustc_middle::traits::query::NoSolution; -use rustc_middle::traits::ObligationCause; -use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; -use rustc_span::Span; -use rustc_trait_selection::solve::deeply_normalize; -use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp; -use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; - -use crate::{ - constraints::OutlivesConstraint, - region_infer::TypeTest, - type_check::{Locations, MirTypeckRegionConstraints}, - universal_regions::UniversalRegions, -}; - -pub(crate) struct ConstraintConversion<'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 - /// relationships like `T: 'a` that are added via implicit bounds - /// or the `param_env`. - /// - /// Each region here is guaranteed to be a key in the `indices` - /// map. We use the "original" regions (i.e., the keys from the - /// map, and not the values) because the code in - /// `process_registered_region_obligations` has some special-cased - /// logic expecting to see (e.g.) `ReStatic`, and if we supplied - /// our special inference variable there, we would mess that up. - region_bound_pairs: &'a RegionBoundPairs<'tcx>, - implicit_region_bound: ty::Region<'tcx>, - param_env: ty::ParamEnv<'tcx>, - known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>], - locations: Locations, - span: Span, - category: ConstraintCategory<'tcx>, - from_closure: bool, - constraints: &'a mut MirTypeckRegionConstraints<'tcx>, -} - -impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { - pub(crate) fn new( - infcx: &'a InferCtxt<'tcx>, - universal_regions: &'a UniversalRegions<'tcx>, - region_bound_pairs: &'a RegionBoundPairs<'tcx>, - implicit_region_bound: ty::Region<'tcx>, - param_env: ty::ParamEnv<'tcx>, - known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>], - locations: Locations, - span: Span, - category: ConstraintCategory<'tcx>, - constraints: &'a mut MirTypeckRegionConstraints<'tcx>, - ) -> Self { - Self { - infcx, - tcx: infcx.tcx, - universal_regions, - region_bound_pairs, - implicit_region_bound, - param_env, - known_type_outlives_obligations, - locations, - span, - category, - constraints, - from_closure: false, - } - } - - #[instrument(skip(self), level = "debug")] - pub(super) fn convert_all(&mut self, query_constraints: &QueryRegionConstraints<'tcx>) { - let QueryRegionConstraints { outlives, member_constraints } = query_constraints; - - // Annoying: to invoke `self.to_region_vid`, we need access to - // `self.constraints`, but we also want to be mutating - // `self.member_constraints`. For now, just swap out the value - // we want and replace at the end. - let mut tmp = std::mem::take(&mut self.constraints.member_constraints); - for member_constraint in member_constraints { - tmp.push_constraint(member_constraint, |r| self.to_region_vid(r)); - } - self.constraints.member_constraints = tmp; - - for &(predicate, constraint_category) in outlives { - self.convert(predicate, constraint_category); - } - } - - /// Given an instance of the closure type, this method instantiates the "extra" requirements - /// that we computed for the closure. This has the effect of adding new outlives obligations - /// to existing region variables in `closure_args`. - #[instrument(skip(self), level = "debug")] - pub fn apply_closure_requirements( - &mut self, - closure_requirements: &ClosureRegionRequirements<'tcx>, - closure_def_id: DefId, - closure_args: ty::GenericArgsRef<'tcx>, - ) { - // Extract the values of the free regions in `closure_args` - // into a vector. These are the regions that we will be - // relating to one another. - let closure_mapping = &UniversalRegions::closure_mapping( - self.tcx, - closure_args, - closure_requirements.num_external_vids, - closure_def_id.expect_local(), - ); - debug!(?closure_mapping); - - // Create the predicates. - let backup = (self.category, self.span, self.from_closure); - self.from_closure = true; - for outlives_requirement in &closure_requirements.outlives_requirements { - let outlived_region = closure_mapping[outlives_requirement.outlived_free_region]; - let subject = match outlives_requirement.subject { - ClosureOutlivesSubject::Region(re) => closure_mapping[re].into(), - ClosureOutlivesSubject::Ty(subject_ty) => { - subject_ty.instantiate(self.tcx, |vid| closure_mapping[vid]).into() - } - }; - - self.category = outlives_requirement.category; - self.span = outlives_requirement.blame_span; - self.convert(ty::OutlivesPredicate(subject, outlived_region), self.category); - } - (self.category, self.span, self.from_closure) = backup; - } - - fn convert( - &mut self, - predicate: ty::OutlivesPredicate, ty::Region<'tcx>>, - constraint_category: ConstraintCategory<'tcx>, - ) { - debug!("generate: constraints at: {:#?}", self.locations); - - // Extract out various useful fields we'll need below. - let ConstraintConversion { - tcx, - infcx, - region_bound_pairs, - implicit_region_bound, - known_type_outlives_obligations, - .. - } = *self; - - let mut outlives_predicates = vec![(predicate, constraint_category)]; - for iteration in 0.. { - if outlives_predicates.is_empty() { - break; - } - - if !self.tcx.recursion_limit().value_within_limit(iteration) { - bug!( - "FIXME(-Znext-solver): Overflowed when processing region obligations: {outlives_predicates:#?}" - ); - } - - let mut next_outlives_predicates = vec![]; - for (ty::OutlivesPredicate(k1, r2), constraint_category) in outlives_predicates { - match k1.unpack() { - GenericArgKind::Lifetime(r1) => { - let r1_vid = self.to_region_vid(r1); - let r2_vid = self.to_region_vid(r2); - self.add_outlives(r1_vid, r2_vid, constraint_category); - } - - GenericArgKind::Type(mut t1) => { - // Normalize the type we receive from a `TypeOutlives` obligation - // in the new trait solver. - if infcx.next_trait_solver() { - t1 = self.normalize_and_add_type_outlives_constraints( - t1, - &mut next_outlives_predicates, - ); - } - - // we don't actually use this for anything, but - // the `TypeOutlives` code needs an origin. - let origin = infer::RelateParamBound(self.span, t1, None); - - TypeOutlives::new( - &mut *self, - tcx, - region_bound_pairs, - Some(implicit_region_bound), - known_type_outlives_obligations, - ) - .type_must_outlive( - origin, - t1, - r2, - constraint_category, - ); - } - - GenericArgKind::Const(_) => unreachable!(), - } - } - - outlives_predicates = next_outlives_predicates; - } - } - - /// Placeholder regions need to be converted eagerly because it may - /// create new region variables, which we must not do when verifying - /// our region bounds. - /// - /// FIXME: This should get removed once higher ranked region obligations - /// are dealt with during trait solving. - fn replace_placeholders_with_nll>>(&mut self, value: T) -> T { - if value.has_placeholders() { - self.tcx.fold_regions(value, |r, _| match *r { - ty::RePlaceholder(placeholder) => { - self.constraints.placeholder_region(self.infcx, placeholder) - } - _ => r, - }) - } else { - value - } - } - - fn verify_to_type_test( - &mut self, - generic_kind: GenericKind<'tcx>, - region: ty::Region<'tcx>, - verify_bound: VerifyBound<'tcx>, - ) -> TypeTest<'tcx> { - let lower_bound = self.to_region_vid(region); - TypeTest { generic_kind, lower_bound, span: self.span, verify_bound } - } - - fn to_region_vid(&mut self, r: ty::Region<'tcx>) -> ty::RegionVid { - if let ty::RePlaceholder(placeholder) = *r { - self.constraints.placeholder_region(self.infcx, placeholder).as_var() - } else { - self.universal_regions.to_region_vid(r) - } - } - - fn add_outlives( - &mut self, - sup: ty::RegionVid, - sub: ty::RegionVid, - category: ConstraintCategory<'tcx>, - ) { - let category = match self.category { - ConstraintCategory::Boring | ConstraintCategory::BoringNoLocation => category, - _ => self.category, - }; - self.constraints.outlives_constraints.push(OutlivesConstraint { - locations: self.locations, - category, - span: self.span, - sub, - sup, - variance_info: ty::VarianceDiagInfo::default(), - from_closure: self.from_closure, - }); - } - - fn add_type_test(&mut self, type_test: TypeTest<'tcx>) { - debug!("add_type_test(type_test={:?})", type_test); - self.constraints.type_tests.push(type_test); - } - - fn normalize_and_add_type_outlives_constraints( - &self, - ty: Ty<'tcx>, - next_outlives_predicates: &mut Vec<( - ty::OutlivesPredicate, ty::Region<'tcx>>, - ConstraintCategory<'tcx>, - )>, - ) -> Ty<'tcx> { - let result = CustomTypeOp::new( - |ocx| { - deeply_normalize( - ocx.infcx.at(&ObligationCause::dummy_with_span(self.span), self.param_env), - ty, - ) - .map_err(|_| NoSolution) - }, - "normalize type outlives obligation", - ) - .fully_perform(self.infcx, self.span); - - match result { - Ok(TypeOpOutput { output: ty, constraints, .. }) => { - if let Some(constraints) = constraints { - assert!( - constraints.member_constraints.is_empty(), - "no member constraints expected from normalizing: {:#?}", - constraints.member_constraints - ); - next_outlives_predicates.extend(constraints.outlives.iter().copied()); - } - ty - } - Err(_) => ty, - } - } -} - -impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'b, 'tcx> { - fn push_sub_region_constraint( - &mut self, - _origin: SubregionOrigin<'tcx>, - a: ty::Region<'tcx>, - b: ty::Region<'tcx>, - constraint_category: ConstraintCategory<'tcx>, - ) { - let b = self.to_region_vid(b); - let a = self.to_region_vid(a); - self.add_outlives(b, a, constraint_category); - } - - fn push_verify( - &mut self, - _origin: SubregionOrigin<'tcx>, - kind: GenericKind<'tcx>, - a: ty::Region<'tcx>, - bound: VerifyBound<'tcx>, - ) { - let kind = self.replace_placeholders_with_nll(kind); - let bound = self.replace_placeholders_with_nll(bound); - let type_test = self.verify_to_type_test(kind, a, bound); - self.add_type_test(type_test); - } -} +use rustc_hir::def_id::DefId;use rustc_infer::infer::canonical:://if let _=(){}; +QueryRegionConstraints;use rustc_infer::infer ::outlives::env::RegionBoundPairs; +use rustc_infer::infer::outlives::obligations::{TypeOutlives,//((),());let _=(); +TypeOutlivesDelegate};use rustc_infer:: infer::region_constraints::{GenericKind, +VerifyBound};use rustc_infer::infer::{self,InferCtxt,SubregionOrigin};use//({}); +rustc_middle::mir::{ClosureOutlivesSubject,ClosureRegionRequirements,//let _=(); +ConstraintCategory};use rustc_middle::traits::query::NoSolution;use//let _=||(); +rustc_middle::traits::ObligationCause;use rustc_middle::ty::{self,//loop{break}; +GenericArgKind,Ty,TyCtxt,TypeFoldable,TypeVisitableExt};use rustc_span::Span;//; +use rustc_trait_selection::solve::deeply_normalize;use rustc_trait_selection::// +traits::query::type_op::custom::CustomTypeOp;use rustc_trait_selection::traits// +::query::type_op::{TypeOp,TypeOpOutput};use crate::{constraints:://loop{break;}; +OutlivesConstraint,region_infer::TypeTest,type_check::{Locations,//loop{break;}; +MirTypeckRegionConstraints},universal_regions::UniversalRegions,};pub(crate)//3; +struct ConstraintConversion<'a,'tcx>{infcx:& 'a InferCtxt<'tcx>,tcx:TyCtxt<'tcx> +,universal_regions:&'a UniversalRegions<'tcx>,region_bound_pairs:&'a//if true{}; +RegionBoundPairs<'tcx>,implicit_region_bound:ty::Region<'tcx>,param_env:ty:://3; +ParamEnv<'tcx>,known_type_outlives_obligations:&'tcx[ty:://if true{};let _=||(); +PolyTypeOutlivesPredicate<'tcx>],locations:Locations,span:Span,category://{();}; +ConstraintCategory<'tcx>,from_closure:bool,constraints:&'a mut//((),());((),()); +MirTypeckRegionConstraints<'tcx>,}impl<'a,'tcx>ConstraintConversion<'a,'tcx>{//; +pub(crate)fn new(infcx:&'a InferCtxt<'tcx>,universal_regions:&'a//if let _=(){}; +UniversalRegions<'tcx>,region_bound_pairs:&'a RegionBoundPairs<'tcx>,//let _=(); +implicit_region_bound:ty::Region<'tcx>,param_env:ty::ParamEnv<'tcx>,//if true{}; +known_type_outlives_obligations:&'tcx[ty::PolyTypeOutlivesPredicate<'tcx>],//(); +locations:Locations,span:Span,category :ConstraintCategory<'tcx>,constraints:&'a +mut MirTypeckRegionConstraints<'tcx>,)->Self{Self{infcx,tcx:infcx.tcx,//((),()); +universal_regions,region_bound_pairs,implicit_region_bound,param_env,//let _=(); +known_type_outlives_obligations,locations,span,category,constraints,//if true{}; +from_closure:((((false)))),}}#[instrument(skip(self),level="debug")]pub(super)fn +convert_all(&mut self,query_constraints:&QueryRegionConstraints<'tcx>){{();};let +QueryRegionConstraints{outlives,member_constraints}=query_constraints;3;;let mut +tmp=std::mem::take(&mut self.constraints.member_constraints);((),());((),());for +member_constraint in member_constraints{;tmp.push_constraint(member_constraint,| +r|self.to_region_vid(r));();}();self.constraints.member_constraints=tmp;();for&( +predicate,constraint_category)in outlives{*&*&();((),());self.convert(predicate, +constraint_category);loop{break};}}#[instrument(skip(self),level="debug")]pub fn +apply_closure_requirements(&mut self,closure_requirements:&//let _=();if true{}; +ClosureRegionRequirements<'tcx>,closure_def_id:DefId,closure_args:ty:://((),()); +GenericArgsRef<'tcx>,){3;let closure_mapping=&UniversalRegions::closure_mapping( +self.tcx,closure_args,closure_requirements.num_external_vids,closure_def_id.//3; +expect_local(),);;;debug!(?closure_mapping);let backup=(self.category,self.span, +self.from_closure);{;};();self.from_closure=true;();for outlives_requirement in& +closure_requirements.outlives_requirements{;let outlived_region=closure_mapping[ +outlives_requirement.outlived_free_region];if true{};if true{};let subject=match +outlives_requirement.subject{ClosureOutlivesSubject::Region(re)=>//loop{break;}; +closure_mapping[re].into(), ClosureOutlivesSubject::Ty(subject_ty)=>{subject_ty. +instantiate(self.tcx,|vid|closure_mapping[vid]).into()}};({});{;};self.category= +outlives_requirement.category;;;self.span=outlives_requirement.blame_span;;self. +convert(ty::OutlivesPredicate(subject,outlived_region),self.category);3;};(self. +category,self.span,self.from_closure)=backup;;}fn convert(&mut self,predicate:ty +::OutlivesPredicate ,ty::Region<'tcx>>,constraint_category: +ConstraintCategory<'tcx>,){*&*&();debug!("generate: constraints at: {:#?}",self. +locations);((),());*&*&();let ConstraintConversion{tcx,infcx,region_bound_pairs, +implicit_region_bound,known_type_outlives_obligations,..}=*self;({});{;};let mut +outlives_predicates=vec![(predicate,constraint_category)];;for iteration in 0..{ +if outlives_predicates.is_empty(){({});break;{;};}if!self.tcx.recursion_limit(). +value_within_limit(iteration){let _=||();let _=||();let _=||();loop{break};bug!( +"FIXME(-Znext-solver): Overflowed when processing region obligations: {outlives_predicates:#?}" +);3;};let mut next_outlives_predicates=vec![];;for(ty::OutlivesPredicate(k1,r2), +constraint_category)in outlives_predicates{match ( k1.unpack()){GenericArgKind:: +Lifetime(r1)=>{;let r1_vid=self.to_region_vid(r1);let r2_vid=self.to_region_vid( +r2);;self.add_outlives(r1_vid,r2_vid,constraint_category);}GenericArgKind::Type( +mut t1)=>{if infcx.next_trait_solver(){((),());((),());((),());let _=();t1=self. +normalize_and_add_type_outlives_constraints(t1,&mut next_outlives_predicates,);; +};let origin=infer::RelateParamBound(self.span,t1,None);;TypeOutlives::new(&mut* +self,tcx,region_bound_pairs,((((((((((((Some(implicit_region_bound))))))))))))), +known_type_outlives_obligations,).type_must_outlive(origin,t1,r2,//loop{break;}; +constraint_category,);*&*&();}GenericArgKind::Const(_)=>unreachable!(),}}*&*&(); +outlives_predicates=next_outlives_predicates;;}}fn replace_placeholders_with_nll +>>(&mut self ,value:T)->T{if value.has_placeholders( +){self.tcx.fold_regions(value,|r,_|match((*r)){ty::RePlaceholder(placeholder)=>{ +self.constraints.placeholder_region(self.infcx,placeholder) }_=>r,})}else{value} +}fn verify_to_type_test(&mut self,generic_kind:GenericKind<'tcx>,region:ty:://3; +Region<'tcx>,verify_bound:VerifyBound<'tcx>,)->TypeTest<'tcx>{3;let lower_bound= +self.to_region_vid(region);{;};TypeTest{generic_kind,lower_bound,span:self.span, +verify_bound}}fn to_region_vid(&mut self,r:ty::Region<'tcx>)->ty::RegionVid{if// +let ty::RePlaceholder(placeholder)=*r {self.constraints.placeholder_region(self. +infcx,placeholder).as_var()}else{((self.universal_regions.to_region_vid(r)))}}fn +add_outlives(&mut self,sup:ty::RegionVid,sub:ty::RegionVid,category://if true{}; +ConstraintCategory<'tcx>,){3;let category=match self.category{ConstraintCategory +::Boring|ConstraintCategory::BoringNoLocation=>category,_=>self.category,};;self +.constraints.outlives_constraints.push(OutlivesConstraint{locations:self.//({}); +locations,category,span:self.span,sub,sup,variance_info:ty::VarianceDiagInfo::// +default(),from_closure:self.from_closure,});((),());}fn add_type_test(&mut self, +type_test:TypeTest<'tcx>){3;debug!("add_type_test(type_test={:?})",type_test);;; +self.constraints.type_tests.push(type_test);((),());((),());((),());let _=();}fn +normalize_and_add_type_outlives_constraints(&self,ty:Ty<'tcx>,//((),());((),()); +next_outlives_predicates:&mut Vec<(ty::OutlivesPredicate,// +ty::Region<'tcx>>,ConstraintCategory<'tcx>,)>,)->Ty<'tcx>{let _=||();let result= +CustomTypeOp::new(|ocx|{deeply_normalize(ocx.infcx.at(&ObligationCause:://{();}; +dummy_with_span(self.span),self.param_env),ty,).map_err(((((|_|NoSolution)))))}, +"normalize type outlives obligation",).fully_perform(self.infcx,self.span);({}); +match result{Ok(TypeOpOutput{output:ty,constraints,..})=>{if let Some(//((),()); +constraints)=constraints{({});assert!(constraints.member_constraints.is_empty(), +"no member constraints expected from normalizing: {:#?}",constraints.//let _=(); +member_constraints);;next_outlives_predicates.extend(constraints.outlives.iter() +.copied());();}ty}Err(_)=>ty,}}}impl<'a,'b,'tcx>TypeOutlivesDelegate<'tcx>for&'a +mut ConstraintConversion<'b,'tcx>{fn push_sub_region_constraint(&mut self,//{;}; +_origin:SubregionOrigin<'tcx>,a:ty::Region<'tcx>,b:ty::Region<'tcx>,//if true{}; +constraint_category:ConstraintCategory<'tcx>,){;let b=self.to_region_vid(b);;let +a=self.to_region_vid(a);{;};();self.add_outlives(b,a,constraint_category);();}fn +push_verify(&mut self,_origin:SubregionOrigin<'tcx >,kind:GenericKind<'tcx>,a:ty +::Region<'tcx>,bound:VerifyBound<'tcx>,){loop{break};loop{break;};let kind=self. +replace_placeholders_with_nll(kind);*&*&();((),());if let _=(){};let bound=self. +replace_placeholders_with_nll(bound);3;3;let type_test=self.verify_to_type_test( +kind,a,bound);loop{break};let _=||();self.add_type_test(type_test);let _=||();}} 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 7553e3ee04fb4..ec1347bc5013b 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -1,420 +1,122 @@ -use rustc_data_structures::frozen::Frozen; -use rustc_data_structures::transitive_relation::{TransitiveRelation, TransitiveRelationBuilder}; -use rustc_hir::def::DefKind; -use rustc_infer::infer::canonical::QueryRegionConstraints; -use rustc_infer::infer::outlives; -use rustc_infer::infer::outlives::env::RegionBoundPairs; -use rustc_infer::infer::region_constraints::GenericKind; -use rustc_infer::infer::InferCtxt; -use rustc_middle::mir::ConstraintCategory; -use rustc_middle::traits::query::OutlivesBound; -use rustc_middle::traits::ObligationCause; -use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt}; -use rustc_span::{ErrorGuaranteed, Span}; -use rustc_trait_selection::solve::deeply_normalize; -use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; -use rustc_trait_selection::traits::query::type_op::{self, TypeOp}; -use std::rc::Rc; -use type_op::TypeOpOutput; - -use crate::{ - type_check::constraint_conversion, - type_check::{Locations, MirTypeckRegionConstraints}, - universal_regions::UniversalRegions, -}; - -#[derive(Debug)] -pub(crate) struct UniversalRegionRelations<'tcx> { - universal_regions: Rc>, - - /// Stores the outlives relations that are known to hold from the - /// implied bounds, in-scope where-clauses, and that sort of - /// thing. - outlives: TransitiveRelation, - - /// This is the `<=` relation; that is, if `a: b`, then `b <= a`, - /// and we store that here. This is useful when figuring out how - /// to express some local region in terms of external regions our - /// caller will understand. - inverse_outlives: TransitiveRelation, -} - -/// As part of computing the free region relations, we also have to -/// normalize the input-output types, which we then need later. So we -/// return those. This vector consists of first the input types and -/// then the output type as the last element. -type NormalizedInputsAndOutput<'tcx> = Vec>; - -pub(crate) struct CreateResult<'tcx> { - pub(crate) universal_region_relations: Frozen>, - pub(crate) region_bound_pairs: RegionBoundPairs<'tcx>, - pub(crate) known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>], - pub(crate) normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>, -} - -pub(crate) fn create<'tcx>( - infcx: &InferCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - implicit_region_bound: ty::Region<'tcx>, - universal_regions: &Rc>, - constraints: &mut MirTypeckRegionConstraints<'tcx>, -) -> CreateResult<'tcx> { - UniversalRegionRelationsBuilder { - infcx, - param_env, - implicit_region_bound, - constraints, - universal_regions: universal_regions.clone(), - region_bound_pairs: Default::default(), - outlives: Default::default(), - inverse_outlives: Default::default(), - } - .create() -} - -impl UniversalRegionRelations<'_> { - /// Given two universal regions, returns the postdominating - /// upper-bound (effectively the least upper bound). - /// - /// (See `TransitiveRelation::postdom_upper_bound` for details on - /// the postdominating upper bound in general.) - pub(crate) fn postdom_upper_bound(&self, fr1: RegionVid, fr2: RegionVid) -> RegionVid { - assert!(self.universal_regions.is_universal_region(fr1)); - assert!(self.universal_regions.is_universal_region(fr2)); - self.inverse_outlives - .postdom_upper_bound(fr1, fr2) - .unwrap_or(self.universal_regions.fr_static) - } - - /// Finds an "upper bound" for `fr` that is not local. In other - /// words, returns the smallest (*) known region `fr1` that (a) - /// outlives `fr` and (b) is not local. - /// - /// (*) If there are multiple competing choices, we return all of them. - pub(crate) fn non_local_upper_bounds(&self, fr: RegionVid) -> Vec { - debug!("non_local_upper_bound(fr={:?})", fr); - let res = self.non_local_bounds(&self.inverse_outlives, fr); - assert!(!res.is_empty(), "can't find an upper bound!?"); - res - } - - /// Finds a "lower bound" for `fr` that is not local. In other - /// words, returns the largest (*) known region `fr1` that (a) is - /// outlived by `fr` and (b) is not local. - /// - /// (*) If there are multiple competing choices, we pick the "postdominating" - /// one. See `TransitiveRelation::postdom_upper_bound` for details. - pub(crate) fn non_local_lower_bound(&self, fr: RegionVid) -> Option { - debug!("non_local_lower_bound(fr={:?})", fr); - let lower_bounds = self.non_local_bounds(&self.outlives, fr); - - // In case we find more than one, reduce to one for - // convenience. This is to prevent us from generating more - // complex constraints, but it will cause spurious errors. - let post_dom = self.outlives.mutual_immediate_postdominator(lower_bounds); - - debug!("non_local_bound: post_dom={:?}", post_dom); - - post_dom.and_then(|post_dom| { - // If the mutual immediate postdom is not local, then - // there is no non-local result we can return. - if !self.universal_regions.is_local_free_region(post_dom) { - Some(post_dom) - } else { - None - } - }) - } - - /// Helper for `non_local_upper_bounds` and `non_local_lower_bounds`. - /// Repeatedly invokes `postdom_parent` until we find something that is not - /// local. Returns `None` if we never do so. - fn non_local_bounds( - &self, - relation: &TransitiveRelation, - fr0: RegionVid, - ) -> Vec { - // This method assumes that `fr0` is one of the universally - // quantified region variables. - assert!(self.universal_regions.is_universal_region(fr0)); - - let mut external_parents = vec![]; - let mut queue = vec![fr0]; - - // Keep expanding `fr` into its parents until we reach - // non-local regions. - while let Some(fr) = queue.pop() { - if !self.universal_regions.is_local_free_region(fr) { - external_parents.push(fr); - continue; - } - - queue.extend(relation.parents(fr)); - } - - debug!("non_local_bound: external_parents={:?}", external_parents); - - external_parents - } - - /// Returns `true` if fr1 is known to outlive fr2. - /// - /// This will only ever be true for universally quantified regions. - pub(crate) fn outlives(&self, fr1: RegionVid, fr2: RegionVid) -> bool { - self.outlives.contains(fr1, fr2) - } - - /// Returns `true` if fr1 is known to equal fr2. - /// - /// This will only ever be true for universally quantified regions. - pub(crate) fn equal(&self, fr1: RegionVid, fr2: RegionVid) -> bool { - self.outlives.contains(fr1, fr2) && self.outlives.contains(fr2, fr1) - } - - /// Returns a vector of free regions `x` such that `fr1: x` is - /// known to hold. - pub(crate) fn regions_outlived_by(&self, fr1: RegionVid) -> Vec { - self.outlives.reachable_from(fr1) - } - - /// Returns the _non-transitive_ set of known `outlives` constraints between free regions. - pub(crate) fn known_outlives(&self) -> impl Iterator + '_ { - self.outlives.base_edges() - } -} - -struct UniversalRegionRelationsBuilder<'this, 'tcx> { - infcx: &'this InferCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - universal_regions: Rc>, - implicit_region_bound: ty::Region<'tcx>, - constraints: &'this mut MirTypeckRegionConstraints<'tcx>, - - // outputs: - outlives: TransitiveRelationBuilder, - inverse_outlives: TransitiveRelationBuilder, - region_bound_pairs: RegionBoundPairs<'tcx>, -} - -impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { - /// Records in the `outlives_relation` (and - /// `inverse_outlives_relation`) that `fr_a: fr_b`. - fn relate_universal_regions(&mut self, fr_a: RegionVid, fr_b: RegionVid) { - debug!("relate_universal_regions: fr_a={:?} outlives fr_b={:?}", fr_a, fr_b); - self.outlives.add(fr_a, fr_b); - self.inverse_outlives.add(fr_b, fr_a); - } - - #[instrument(level = "debug", skip(self))] - pub(crate) fn create(mut self) -> CreateResult<'tcx> { - let tcx = self.infcx.tcx; - let defining_ty_def_id = self.universal_regions.defining_ty.def_id().expect_local(); - let span = tcx.def_span(defining_ty_def_id); - - // Insert the `'a: 'b` we know from the predicates. - // This does not consider the type-outlives. - let param_env = self.param_env; - self.add_outlives_bounds(outlives::explicit_outlives_bounds(param_env)); - - // - outlives is reflexive, so `'r: 'r` for every region `'r` - // - `'static: 'r` for every region `'r` - // - `'r: 'fn_body` for every (other) universally quantified - // region `'r`, all of which are provided by our caller - let fr_static = self.universal_regions.fr_static; - let fr_fn_body = self.universal_regions.fr_fn_body; - for fr in self.universal_regions.universal_regions() { - debug!("build: relating free region {:?} to itself and to 'static", fr); - self.relate_universal_regions(fr, fr); - self.relate_universal_regions(fr_static, fr); - self.relate_universal_regions(fr, fr_fn_body); - } - - // Normalize the assumptions we use to borrowck the program. - let mut constraints = vec![]; - let mut known_type_outlives_obligations = vec![]; - for bound in param_env.caller_bounds() { - let Some(mut outlives) = bound.as_type_outlives_clause() else { continue }; - - // In the new solver, normalize the type-outlives obligation assumptions. - if self.infcx.next_trait_solver() { - match deeply_normalize( - self.infcx.at(&ObligationCause::misc(span, defining_ty_def_id), self.param_env), - outlives, - ) { - Ok(normalized_outlives) => { - outlives = normalized_outlives; - } - Err(e) => { - self.infcx.err_ctxt().report_fulfillment_errors(e); - } - } - } - - known_type_outlives_obligations.push(outlives); - } - let known_type_outlives_obligations = - self.infcx.tcx.arena.alloc_slice(&known_type_outlives_obligations); - - let unnormalized_input_output_tys = self - .universal_regions - .unnormalized_input_tys - .iter() - .cloned() - .chain(Some(self.universal_regions.unnormalized_output_ty)); - - // For each of the input/output types: - // - Normalize the type. This will create some region - // constraints, which we buffer up because we are - // not ready to process them yet. - // - Then compute the implied bounds. This will adjust - // the `region_bound_pairs` and so forth. - // - After this is done, we'll process the constraints, once - // the `relations` is built. - let mut normalized_inputs_and_output = - Vec::with_capacity(self.universal_regions.unnormalized_input_tys.len() + 1); - for ty in unnormalized_input_output_tys { - debug!("build: input_or_output={:?}", ty); - // We add implied bounds from both the unnormalized and normalized ty. - // See issue #87748 - let constraints_unnorm = self.add_implied_bounds(ty, span); - if let Some(c) = constraints_unnorm { - constraints.push(c) - } - let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } = self - .param_env - .and(type_op::normalize::Normalize::new(ty)) - .fully_perform(self.infcx, span) - .unwrap_or_else(|guar| TypeOpOutput { - output: Ty::new_error(self.infcx.tcx, guar), - constraints: None, - error_info: None, - }); - if let Some(c) = constraints_normalize { - constraints.push(c) - } - - // Note: we need this in examples like - // ``` - // trait Foo { - // type Bar; - // fn foo(&self) -> &Self::Bar; - // } - // impl Foo for () { - // type Bar = (); - // fn foo(&self) ->&() {} - // } - // ``` - // Both &Self::Bar and &() are WF - if ty != norm_ty { - let constraints_norm = self.add_implied_bounds(norm_ty, span); - if let Some(c) = constraints_norm { - constraints.push(c) - } - } - - normalized_inputs_and_output.push(norm_ty); - } - - // Add implied bounds from impl header. - if matches!(tcx.def_kind(defining_ty_def_id), DefKind::AssocFn | DefKind::AssocConst) { - for &(ty, _) in tcx.assumed_wf_types(tcx.local_parent(defining_ty_def_id)) { - let result: Result<_, ErrorGuaranteed> = self - .param_env - .and(type_op::normalize::Normalize::new(ty)) - .fully_perform(self.infcx, span); - let Ok(TypeOpOutput { output: norm_ty, constraints: c, .. }) = result else { - continue; - }; - - constraints.extend(c); - - // We currently add implied bounds from the normalized ty only. - // This is more conservative and matches wfcheck behavior. - let c = self.add_implied_bounds(norm_ty, span); - constraints.extend(c); - } - } - - for c in constraints { - constraint_conversion::ConstraintConversion::new( - self.infcx, - &self.universal_regions, - &self.region_bound_pairs, - self.implicit_region_bound, - param_env, - known_type_outlives_obligations, - Locations::All(span), - span, - ConstraintCategory::Internal, - self.constraints, - ) - .convert_all(c); - } - - CreateResult { - universal_region_relations: Frozen::freeze(UniversalRegionRelations { - universal_regions: self.universal_regions, - outlives: self.outlives.freeze(), - inverse_outlives: self.inverse_outlives.freeze(), - }), - known_type_outlives_obligations, - region_bound_pairs: self.region_bound_pairs, - normalized_inputs_and_output, - } - } - - /// Update the type of a single local, which should represent - /// either the return type of the MIR or one of its arguments. At - /// the same time, compute and add any implied bounds that come - /// from this local. - #[instrument(level = "debug", skip(self))] - fn add_implied_bounds( - &mut self, - ty: Ty<'tcx>, - span: Span, - ) -> Option<&'tcx QueryRegionConstraints<'tcx>> { - let TypeOpOutput { output: bounds, constraints, .. } = self - .param_env - .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty }) - .fully_perform(self.infcx, span) - .map_err(|_: ErrorGuaranteed| debug!("failed to compute implied bounds {:?}", ty)) - .ok()?; - debug!(?bounds, ?constraints); - // Because of #109628, we may have unexpected placeholders. Ignore them! - // FIXME(#109628): panic in this case once the issue is fixed. - let bounds = bounds.into_iter().filter(|bound| !bound.has_placeholders()); - self.add_outlives_bounds(bounds); - constraints - } - - /// Registers the `OutlivesBound` items from `outlives_bounds` in - /// the outlives relation as well as the region-bound pairs - /// listing. - fn add_outlives_bounds(&mut self, outlives_bounds: I) - where - I: IntoIterator>, - { - for outlives_bound in outlives_bounds { - debug!("add_outlives_bounds(bound={:?})", outlives_bound); - - match outlives_bound { - OutlivesBound::RegionSubRegion(r1, r2) => { - // The bound says that `r1 <= r2`; we store `r2: r1`. - let r1 = self.universal_regions.to_region_vid(r1); - let r2 = self.universal_regions.to_region_vid(r2); - self.relate_universal_regions(r2, r1); - } - - OutlivesBound::RegionSubParam(r_a, param_b) => { - self.region_bound_pairs - .insert(ty::OutlivesPredicate(GenericKind::Param(param_b), r_a)); - } - - OutlivesBound::RegionSubAlias(r_a, alias_b) => { - self.region_bound_pairs - .insert(ty::OutlivesPredicate(GenericKind::Alias(alias_b), r_a)); - } - } - } - } -} +use rustc_data_structures::frozen::Frozen;use rustc_data_structures:://let _=(); +transitive_relation::{TransitiveRelation,TransitiveRelationBuilder};use//*&*&(); +rustc_hir::def::DefKind;use rustc_infer::infer::canonical:://let _=();if true{}; +QueryRegionConstraints;use rustc_infer::infer::outlives;use rustc_infer::infer// +::outlives::env::RegionBoundPairs;use rustc_infer::infer::region_constraints::// +GenericKind;use rustc_infer::infer::InferCtxt;use rustc_middle::mir:://let _=(); +ConstraintCategory;use rustc_middle::traits::query::OutlivesBound;use//let _=(); +rustc_middle::traits::ObligationCause;use rustc_middle ::ty::{self,RegionVid,Ty, +TypeVisitableExt};use rustc_span::{ErrorGuaranteed,Span};use//let _=();let _=(); +rustc_trait_selection::solve::deeply_normalize;use rustc_trait_selection:://{;}; +traits::error_reporting::TypeErrCtxtExt;use rustc_trait_selection::traits:://(); +query::type_op::{self,TypeOp};use std::rc::Rc;use type_op::TypeOpOutput;use//(); +crate::{type_check::constraint_conversion,type_check::{Locations,//loop{break;}; +MirTypeckRegionConstraints},universal_regions::UniversalRegions,};#[derive(//(); +Debug)]pub(crate)struct UniversalRegionRelations<'tcx>{universal_regions:Rc>,outlives :TransitiveRelation,inverse_outlives +:TransitiveRelation,}type NormalizedInputsAndOutput<'tcx>=Vec>;pub(crate)struct CreateResult<'tcx>{pub(crate)universal_region_relations +:Frozen>,pub(crate)region_bound_pairs://let _=(); +RegionBoundPairs<'tcx>,pub(crate)known_type_outlives_obligations:&'tcx[ty:://(); +PolyTypeOutlivesPredicate<'tcx>],pub(crate)normalized_inputs_and_output://{();}; +NormalizedInputsAndOutput<'tcx>,}pub(crate)fn create<'tcx>(infcx:&InferCtxt,param_env:ty::ParamEnv<'tcx>,implicit_region_bound:ty::Region<'tcx>,//{;}; +universal_regions:&Rc>,constraints:&mut//((),());((),()); +MirTypeckRegionConstraints<'tcx>,)->CreateResult<'tcx>{//let _=||();loop{break}; +UniversalRegionRelationsBuilder{infcx,param_env,implicit_region_bound,//((),()); +constraints,universal_regions:((universal_regions. clone())),region_bound_pairs: +Default::default(),outlives:(((Default ::default()))),inverse_outlives:Default:: +default(),}.create()}impl UniversalRegionRelations<'_>{pub(crate)fn//let _=||(); +postdom_upper_bound(&self,fr1:RegionVid,fr2:RegionVid)->RegionVid{;assert!(self. +universal_regions.is_universal_region(fr1));();3;assert!(self.universal_regions. +is_universal_region(fr2));();self.inverse_outlives.postdom_upper_bound(fr1,fr2). +unwrap_or(self.universal_regions.fr_static) }pub(crate)fn non_local_upper_bounds +(&self,fr:RegionVid)->Vec{;debug!("non_local_upper_bound(fr={:?})",fr +);3;3;let res=self.non_local_bounds(&self.inverse_outlives,fr);3;3;assert!(!res. +is_empty(),"can't find an upper bound!?");let _=||();let _=||();res}pub(crate)fn +non_local_lower_bound(&self,fr:RegionVid)->Option{loop{break};debug!( +"non_local_lower_bound(fr={:?})",fr);3;;let lower_bounds=self.non_local_bounds(& +self.outlives,fr);3;3;let post_dom=self.outlives.mutual_immediate_postdominator( +lower_bounds);();3;debug!("non_local_bound: post_dom={:?}",post_dom);3;post_dom. +and_then(|post_dom|{if(! self.universal_regions.is_local_free_region(post_dom)){ +Some(post_dom)}else{None}})}fn non_local_bounds(&self,relation:&//if let _=(){}; +TransitiveRelation,fr0:RegionVid,)->Vec{({});assert!(self. +universal_regions.is_universal_region(fr0));;let mut external_parents=vec![];let +mut queue=vec![fr0];();while let Some(fr)=queue.pop(){if!self.universal_regions. +is_local_free_region(fr){3;external_parents.push(fr);;;continue;;};queue.extend( +relation.parents(fr));({});}{;};debug!("non_local_bound: external_parents={:?}", +external_parents);();external_parents}pub(crate)fn outlives(&self,fr1:RegionVid, +fr2:RegionVid)->bool{(self.outlives.contains(fr1,fr2))}pub(crate)fn equal(&self, +fr1:RegionVid,fr2:RegionVid)->bool{(((self .outlives.contains(fr1,fr2))))&&self. +outlives.contains(fr2,fr1)}pub (crate)fn regions_outlived_by(&self,fr1:RegionVid +)->Vec{self.outlives. reachable_from(fr1)}pub(crate)fn known_outlives +(&self)->impl Iterator+'_{self.outlives.base_edges( +)}}struct UniversalRegionRelationsBuilder<'this,'tcx>{infcx:&'this InferCtxt,param_env:ty::ParamEnv<'tcx >,universal_regions:Rc> +,implicit_region_bound:ty::Region<'tcx>,constraints:&'this mut//((),());((),()); +MirTypeckRegionConstraints<'tcx>,outlives :TransitiveRelationBuilder, +inverse_outlives:TransitiveRelationBuilder,region_bound_pairs://({}); +RegionBoundPairs<'tcx>,}impl<'tcx>UniversalRegionRelationsBuilder<'_,'tcx>{fn//; +relate_universal_regions(&mut self,fr_a:RegionVid,fr_b:RegionVid){*&*&();debug!( +"relate_universal_regions: fr_a={:?} outlives fr_b={:?}",fr_a,fr_b);{;};();self. +outlives.add(fr_a,fr_b);3;3;self.inverse_outlives.add(fr_b,fr_a);;}#[instrument( +level="debug",skip(self))]pub(crate)fn create(mut self)->CreateResult<'tcx>{;let +tcx=self.infcx.tcx;3;;let defining_ty_def_id=self.universal_regions.defining_ty. +def_id().expect_local();;let span=tcx.def_span(defining_ty_def_id);let param_env +=self.param_env;3;3;self.add_outlives_bounds(outlives::explicit_outlives_bounds( +param_env));;let fr_static=self.universal_regions.fr_static;let fr_fn_body=self. +universal_regions.fr_fn_body;;for fr in self.universal_regions.universal_regions +(){;debug!("build: relating free region {:?} to itself and to 'static",fr);self. +relate_universal_regions(fr,fr);;;self.relate_universal_regions(fr_static,fr);;; +self.relate_universal_regions(fr,fr_fn_body);;};let mut constraints=vec![];;;let +mut known_type_outlives_obligations=vec![];;for bound in param_env.caller_bounds +(){;let Some(mut outlives)=bound.as_type_outlives_clause()else{continue};if self +.infcx.next_trait_solver(){match deeply_normalize(self.infcx.at(&//loop{break;}; +ObligationCause::misc(span,defining_ty_def_id),self.param_env),outlives,){Ok(//; +normalized_outlives)=>{();outlives=normalized_outlives;3;}Err(e)=>{3;self.infcx. +err_ctxt().report_fulfillment_errors(e);;}}}known_type_outlives_obligations.push +(outlives);{();};}({});let known_type_outlives_obligations=self.infcx.tcx.arena. +alloc_slice(&known_type_outlives_obligations);;let unnormalized_input_output_tys +=self.universal_regions.unnormalized_input_tys.iter() .cloned().chain(Some(self. +universal_regions.unnormalized_output_ty));;let mut normalized_inputs_and_output +=Vec::with_capacity(self.universal_regions.unnormalized_input_tys.len()+1);3;for +ty in unnormalized_input_output_tys{;debug!("build: input_or_output={:?}",ty);;; +let constraints_unnorm=self.add_implied_bounds(ty,span);let _=();if let Some(c)= +constraints_unnorm{constraints.push(c)}let _=();let TypeOpOutput{output:norm_ty, +constraints:constraints_normalize,..}=self.param_env.and(type_op::normalize:://; +Normalize::new(ty)).fully_perform(self.infcx,span).unwrap_or_else(|guar|//{();}; +TypeOpOutput{output:((((Ty::new_error(self.infcx.tcx,guar))))),constraints:None, +error_info:None,});;if let Some(c)=constraints_normalize{constraints.push(c)}if +ty!=norm_ty{3;let constraints_norm=self.add_implied_bounds(norm_ty,span);;if let +Some(c)=constraints_norm{constraints.push(c)}};normalized_inputs_and_output.push +(norm_ty);*&*&();}if matches!(tcx.def_kind(defining_ty_def_id),DefKind::AssocFn| +DefKind::AssocConst){for&(ty,_)in tcx.assumed_wf_types(tcx.local_parent(//{();}; +defining_ty_def_id)){();let result:Result<_,ErrorGuaranteed>=self.param_env.and( +type_op::normalize::Normalize::new(ty)).fully_perform(self.infcx,span);;;let Ok( +TypeOpOutput{output:norm_ty,constraints:c,..})=result else{();continue;();};3;3; +constraints.extend(c);;;let c=self.add_implied_bounds(norm_ty,span);constraints. +extend(c);;}}for c in constraints{;constraint_conversion::ConstraintConversion:: +new(self.infcx,(((&self.universal_regions ))),((&self.region_bound_pairs)),self. +implicit_region_bound,param_env,known_type_outlives_obligations ,Locations::All( +span),span,ConstraintCategory::Internal,self.constraints,).convert_all(c);({});} +CreateResult{universal_region_relations: Frozen::freeze(UniversalRegionRelations +{universal_regions:self.universal_regions,outlives:(((self.outlives.freeze()))), +inverse_outlives:((((((((((((((self.inverse_outlives.freeze ())))))))))))))),}), +known_type_outlives_obligations,region_bound_pairs:self.region_bound_pairs,//(); +normalized_inputs_and_output,}}#[instrument(level="debug",skip(self))]fn//{();}; +add_implied_bounds(&mut self,ty:Ty<'tcx>,span:Span,)->Option<&'tcx//loop{break}; +QueryRegionConstraints<'tcx>>{();let TypeOpOutput{output:bounds,constraints,..}= +self.param_env.and(type_op:: implied_outlives_bounds::ImpliedOutlivesBounds{ty}) +.fully_perform(self.infcx,span).map_err(|_:ErrorGuaranteed|debug!(//loop{break}; +"failed to compute implied bounds {:?}",ty)).ok()?;;debug!(?bounds,?constraints) +;;;let bounds=bounds.into_iter().filter(|bound|!bound.has_placeholders());;self. +add_outlives_bounds(bounds);{;};constraints}fn add_outlives_bounds(&mut self, +outlives_bounds:I)where I:IntoIterator>,{for//let _=(); +outlives_bound in outlives_bounds{({});debug!("add_outlives_bounds(bound={:?})", +outlives_bound);3;match outlives_bound{OutlivesBound::RegionSubRegion(r1,r2)=>{; +let r1=self.universal_regions.to_region_vid(r1);;;let r2=self.universal_regions. +to_region_vid(r2);();();self.relate_universal_regions(r2,r1);();}OutlivesBound:: +RegionSubParam(r_a,param_b)=>{*&*&();((),());self.region_bound_pairs.insert(ty:: +OutlivesPredicate(GenericKind::Param(param_b),r_a));loop{break};}OutlivesBound:: +RegionSubAlias(r_a,alias_b)=>{*&*&();((),());self.region_bound_pairs.insert(ty:: +OutlivesPredicate(GenericKind::Alias(alias_b),r_a));let _=||();loop{break};}}}}} diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index a4c1066ee8e92..fa5daadfde1ea 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -1,223 +1,70 @@ -//! This module contains code to equate the input/output types appearing -//! in the MIR with the expected input/output types from the function -//! signature. This requires a bit of processing, as the expected types -//! are supplied to us before normalization and may contain opaque -//! `impl Trait` instances. In contrast, the input/output types found in -//! the MIR (specifically, in the special local variables for the -//! `RETURN_PLACE` the MIR arguments) are always fully normalized (and -//! contain revealed `impl Trait` values). - -use std::assert_matches::assert_matches; - -use itertools::Itertools; -use rustc_hir as hir; -use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_infer::infer::{BoundRegionConversionTime, RegionVariableOrigin}; -use rustc_middle::mir::*; -use rustc_middle::ty::{self, Ty}; -use rustc_span::Span; - -use crate::renumber::RegionCtxt; -use crate::universal_regions::{DefiningTy, UniversalRegions}; - -use super::{Locations, TypeChecker}; - -impl<'a, 'tcx> TypeChecker<'a, 'tcx> { - /// Check explicit closure signature annotation, - /// e.g., `|x: FxIndexMap<_, &'static u32>| ...`. - #[instrument(skip(self, body), level = "debug")] - pub(super) fn check_signature_annotation(&mut self, body: &Body<'tcx>) { - let mir_def_id = body.source.def_id().expect_local(); - - if !self.tcx().is_closure_like(mir_def_id.to_def_id()) { - return; - } - - let user_provided_poly_sig = self.tcx().closure_user_provided_sig(mir_def_id); - - // Instantiate the canonicalized variables from user-provided signature - // (e.g., the `_` in the code above) with fresh variables. - // Then replace the bound items in the fn sig with fresh variables, - // so that they represent the view from "inside" the closure. - let user_provided_sig = self.instantiate_canonical(body.span, &user_provided_poly_sig); - let mut user_provided_sig = self.infcx.instantiate_binder_with_fresh_vars( - body.span, - BoundRegionConversionTime::FnCall, - user_provided_sig, - ); - - // FIXME(async_closures): It's kind of wacky that we must apply this - // transformation here, since we do the same thing in HIR typeck. - // Maybe we could just fix up the canonicalized signature during HIR typeck? - if let DefiningTy::CoroutineClosure(_, args) = - self.borrowck_context.universal_regions.defining_ty - { - assert_matches!( - self.tcx().coroutine_kind(self.tcx().coroutine_for_closure(mir_def_id)), - Some(hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, - hir::CoroutineSource::Closure - )), - "this needs to be modified if we're lowering non-async closures" - ); - // Make sure to use the args from `DefiningTy` so the right NLL region vids are prepopulated - // into the type. - let args = args.as_coroutine_closure(); - let tupled_upvars_ty = ty::CoroutineClosureSignature::tupled_upvars_by_closure_kind( - self.tcx(), - args.kind(), - Ty::new_tup(self.tcx(), user_provided_sig.inputs()), - args.tupled_upvars_ty(), - args.coroutine_captures_by_ref_ty(), - self.infcx.next_region_var(RegionVariableOrigin::MiscVariable(body.span), || { - RegionCtxt::Unknown - }), - ); - - let next_ty_var = || { - self.infcx.next_ty_var(TypeVariableOrigin { - span: body.span, - kind: TypeVariableOriginKind::MiscVariable, - }) - }; - let output_ty = Ty::new_coroutine( - self.tcx(), - self.tcx().coroutine_for_closure(mir_def_id), - ty::CoroutineArgs::new( - self.tcx(), - ty::CoroutineArgsParts { - parent_args: args.parent_args(), - kind_ty: Ty::from_coroutine_closure_kind(self.tcx(), args.kind()), - return_ty: user_provided_sig.output(), - tupled_upvars_ty, - // For async closures, none of these can be annotated, so just fill - // them with fresh ty vars. - resume_ty: next_ty_var(), - yield_ty: next_ty_var(), - witness: next_ty_var(), - }, - ) - .args, - ); - - user_provided_sig = self.tcx().mk_fn_sig( - user_provided_sig.inputs().iter().copied(), - output_ty, - user_provided_sig.c_variadic, - user_provided_sig.unsafety, - user_provided_sig.abi, - ); - } - - let is_coroutine_with_implicit_resume_ty = self.tcx().is_coroutine(mir_def_id.to_def_id()) - && user_provided_sig.inputs().is_empty(); - - for (&user_ty, arg_decl) in user_provided_sig.inputs().iter().zip_eq( - // In MIR, closure args begin with an implicit `self`. - // Also, coroutines have a resume type which may be implicitly `()`. - body.args_iter() - .skip(1 + if is_coroutine_with_implicit_resume_ty { 1 } else { 0 }) - .map(|local| &body.local_decls[local]), - ) { - self.ascribe_user_type_skip_wf( - arg_decl.ty, - ty::UserType::Ty(user_ty), - arg_decl.source_info.span, - ); - } - - // If the user explicitly annotated the output type, enforce it. - let output_decl = &body.local_decls[RETURN_PLACE]; - self.ascribe_user_type_skip_wf( - output_decl.ty, - ty::UserType::Ty(user_provided_sig.output()), - output_decl.source_info.span, - ); - } - - #[instrument(skip(self, body, universal_regions), level = "debug")] - pub(super) fn equate_inputs_and_outputs( - &mut self, - body: &Body<'tcx>, - universal_regions: &UniversalRegions<'tcx>, - normalized_inputs_and_output: &[Ty<'tcx>], - ) { - let (&normalized_output_ty, normalized_input_tys) = - normalized_inputs_and_output.split_last().unwrap(); - - debug!(?normalized_output_ty); - debug!(?normalized_input_tys); - - // Equate expected input tys with those in the MIR. - for (argument_index, &normalized_input_ty) in normalized_input_tys.iter().enumerate() { - if argument_index + 1 >= body.local_decls.len() { - self.tcx() - .dcx() - .span_bug(body.span, "found more normalized_input_ty than local_decls"); - } - - // In MIR, argument N is stored in local N+1. - let local = Local::from_usize(argument_index + 1); - - let mir_input_ty = body.local_decls[local].ty; - - let mir_input_span = body.local_decls[local].source_info.span; - self.equate_normalized_input_or_output( - normalized_input_ty, - mir_input_ty, - mir_input_span, - ); - } - - if let Some(mir_yield_ty) = body.yield_ty() { - let yield_span = body.local_decls[RETURN_PLACE].source_info.span; - self.equate_normalized_input_or_output( - universal_regions.yield_ty.unwrap(), - mir_yield_ty, - yield_span, - ); - } - - if let Some(mir_resume_ty) = body.resume_ty() { - let yield_span = body.local_decls[RETURN_PLACE].source_info.span; - self.equate_normalized_input_or_output( - universal_regions.resume_ty.unwrap(), - mir_resume_ty, - yield_span, - ); - } - - // Return types are a bit more complex. They may contain opaque `impl Trait` types. - let mir_output_ty = body.local_decls[RETURN_PLACE].ty; - let output_span = body.local_decls[RETURN_PLACE].source_info.span; - self.equate_normalized_input_or_output(normalized_output_ty, mir_output_ty, output_span); - } - - #[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) - { - // FIXME(jackh726): This is a hack. It's somewhat like - // `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 = 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`. - if let Err(terr) = - self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation) - { - span_mirbug!( - self, - Location::START, - "equate_normalized_input_or_output: `{:?}=={:?}` failed with `{:?}`", - a, - b, - terr - ); - } - } - } -} +use std::assert_matches::assert_matches;use itertools::Itertools;use rustc_hir// +as hir;use rustc_infer::infer::type_variable::{TypeVariableOrigin,//loop{break}; +TypeVariableOriginKind};use rustc_infer::infer::{BoundRegionConversionTime,//(); +RegionVariableOrigin};use rustc_middle::mir::*; use rustc_middle::ty::{self,Ty}; +use rustc_span::Span;use crate::renumber::RegionCtxt;use crate:://if let _=(){}; +universal_regions::{DefiningTy,UniversalRegions};use super::{Locations,//*&*&(); +TypeChecker};impl<'a,'tcx>TypeChecker<'a,'tcx>{#[instrument(skip(self,body),//3; +level="debug")]pub(super)fn check_signature_annotation(&mut self,body:&Body){{;};let mir_def_id=body.source.def_id().expect_local();{;};if!self.tcx(). +is_closure_like(mir_def_id.to_def_id()){;return;}let user_provided_poly_sig=self +.tcx().closure_user_provided_sig(mir_def_id);{;};{;};let user_provided_sig=self. +instantiate_canonical(body.span,&user_provided_poly_sig);((),());((),());let mut +user_provided_sig=self.infcx.instantiate_binder_with_fresh_vars(body.span,//{;}; +BoundRegionConversionTime::FnCall,user_provided_sig,);*&*&();if let DefiningTy:: +CoroutineClosure(_,args)=self.borrowck_context.universal_regions.defining_ty{(); +assert_matches!(self.tcx().coroutine_kind(self.tcx().coroutine_for_closure(//(); +mir_def_id)),Some(hir:: CoroutineKind::Desugared(hir::CoroutineDesugaring::Async +,hir::CoroutineSource::Closure)),//let _=||();let _=||();let _=||();loop{break}; +"this needs to be modified if we're lowering non-async closures");;let args=args +.as_coroutine_closure();3;3;let tupled_upvars_ty=ty::CoroutineClosureSignature:: +tupled_upvars_by_closure_kind((self.tcx()),(args.kind()),Ty::new_tup(self.tcx(), +user_provided_sig.inputs()),((((((((((( args.tupled_upvars_ty()))))))))))),args. +coroutine_captures_by_ref_ty(),self.infcx.next_region_var(RegionVariableOrigin// +::MiscVariable(body.span),||{RegionCtxt::Unknown}),);3;;let next_ty_var=||{self. +infcx.next_ty_var(TypeVariableOrigin{span :body.span,kind:TypeVariableOriginKind +::MiscVariable,})};{;};();let output_ty=Ty::new_coroutine(self.tcx(),self.tcx(). +coroutine_for_closure(mir_def_id),ty::CoroutineArgs::new(((((self.tcx())))),ty:: +CoroutineArgsParts{parent_args:(((((((((args.parent_args()))))))))),kind_ty:Ty:: +from_coroutine_closure_kind(self.tcx(),args .kind()),return_ty:user_provided_sig +.output(),tupled_upvars_ty,resume_ty:((next_ty_var())),yield_ty:(next_ty_var()), +witness:next_ty_var(),},).args,);{;};{;};user_provided_sig=self.tcx().mk_fn_sig( +user_provided_sig.inputs().iter().copied(),output_ty,user_provided_sig.//*&*&(); +c_variadic,user_provided_sig.unsafety,user_provided_sig.abi,);*&*&();}*&*&();let +is_coroutine_with_implicit_resume_ty=((((self.tcx())))).is_coroutine(mir_def_id. +to_def_id())&&user_provided_sig.inputs().is_empty();();for(&user_ty,arg_decl)in +user_provided_sig.inputs().iter().zip_eq( (((body.args_iter()))).skip((((1)))+if +is_coroutine_with_implicit_resume_ty{(1)}else{0}) .map(|local|&body.local_decls[ +local]),){;self.ascribe_user_type_skip_wf(arg_decl.ty,ty::UserType::Ty(user_ty), +arg_decl.source_info.span,);;};let output_decl=&body.local_decls[RETURN_PLACE];; +self.ascribe_user_type_skip_wf(output_decl.ty,ty::UserType::Ty(//*&*&();((),()); +user_provided_sig.output()),output_decl.source_info.span,);3;}#[instrument(skip( +self,body,universal_regions),level="debug")]pub(super)fn//let _=||();let _=||(); +equate_inputs_and_outputs(&mut self,body:&Body<'tcx>,universal_regions:&//{();}; +UniversalRegions<'tcx>,normalized_inputs_and_output:&[Ty<'tcx>],){let _=();let(& +normalized_output_ty,normalized_input_tys)=normalized_inputs_and_output.//{();}; +split_last().unwrap();({});({});debug!(?normalized_output_ty);({});({});debug!(? +normalized_input_tys);*&*&();((),());for(argument_index,&normalized_input_ty)in +normalized_input_tys.iter().enumerate(){if (argument_index+1)>=body.local_decls. +len(){let _=();if true{};let _=();if true{};self.tcx().dcx().span_bug(body.span, +"found more normalized_input_ty than local_decls");;}let local=Local::from_usize +(argument_index+1);{;};{;};let mir_input_ty=body.local_decls[local].ty;();();let +mir_input_span=body.local_decls[local].source_info.span;if true{};let _=();self. +equate_normalized_input_or_output(normalized_input_ty,mir_input_ty,//let _=||(); +mir_input_span,);;}if let Some(mir_yield_ty)=body.yield_ty(){let yield_span=body +.local_decls[RETURN_PLACE].source_info.span;((),());((),());*&*&();((),());self. +equate_normalized_input_or_output((((((universal_regions.yield_ty.unwrap()))))), +mir_yield_ty,yield_span,);();}if let Some(mir_resume_ty)=body.resume_ty(){();let +yield_span=body.local_decls[RETURN_PLACE].source_info.span;((),());((),());self. +equate_normalized_input_or_output(((((universal_regions.resume_ty .unwrap())))), +mir_resume_ty,yield_span,);;}let mir_output_ty=body.local_decls[RETURN_PLACE].ty +;();();let output_span=body.local_decls[RETURN_PLACE].source_info.span;3;3;self. +equate_normalized_input_or_output(normalized_output_ty,mir_output_ty,//let _=(); +output_span);loop{break};loop{break;};}#[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){;let b=self.normalize(b,Locations::All(span));if let Err(terr) +=self.eq_types(a,b,Locations::All(span),ConstraintCategory::BoringNoLocation){3; +span_mirbug!(self,Location::START,//let _=||();let _=||();let _=||();let _=||(); +"equate_normalized_input_or_output: `{:?}=={:?}` failed with `{:?}`",a,b,terr);; +}}}}//let _=();let _=();let _=();if true{};let _=();let _=();let _=();if true{}; diff --git a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs index da5456692ab13..b63d276dc16f2 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs @@ -1,170 +1,44 @@ -use rustc_data_structures::vec_linked_list as vll; -use rustc_index::IndexVec; -use rustc_middle::mir::visit::{PlaceContext, Visitor}; -use rustc_middle::mir::{Body, Local, Location}; -use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex}; - -use crate::def_use::{self, DefUse}; - -/// A map that cross references each local with the locations where it -/// is defined (assigned), used, or dropped. Used during liveness -/// computation. -/// -/// We keep track only of `Local`s we'll do the liveness analysis later, -/// this means that our internal `IndexVec`s will only be sparsely populated. -/// In the time-memory trade-off between keeping compact vectors with new -/// indexes (and needing to continuously map the `Local` index to its compact -/// counterpart) and having `IndexVec`s that we only use a fraction of, time -/// (and code simplicity) was favored. The rationale is that we only keep -/// a small number of `IndexVec`s throughout the entire analysis while, in -/// contrast, we're accessing each `Local` *many* times. -pub(crate) struct LocalUseMap { - /// Head of a linked list of **definitions** of each variable -- - /// definition in this context means assignment, e.g., `x` is - /// defined in `x = y` but not `y`; that first def is the head of - /// a linked list that lets you enumerate all places the variable - /// is assigned. - first_def_at: IndexVec>, - - /// Head of a linked list of **uses** of each variable -- use in - /// this context means that the existing value of the variable is - /// read or modified. e.g., `y` is used in `x = y` but not `x`. - /// Note that `DROP(x)` terminators are excluded from this list. - first_use_at: IndexVec>, - - /// Head of a linked list of **drops** of each variable -- these - /// are a special category of uses corresponding to the drop that - /// we add for each local variable. - first_drop_at: IndexVec>, - - appearances: IndexVec, -} - -struct Appearance { - point_index: PointIndex, - next: Option, -} - -rustc_index::newtype_index! { - pub struct AppearanceIndex {} -} - -impl vll::LinkElem for Appearance { - type LinkIndex = AppearanceIndex; - - fn next(elem: &Self) -> Option { - elem.next - } -} - -impl LocalUseMap { - pub(crate) fn build( - live_locals: &[Local], - elements: &DenseLocationMap, - body: &Body<'_>, - ) -> Self { - let nones = IndexVec::from_elem(None, &body.local_decls); - let mut local_use_map = LocalUseMap { - first_def_at: nones.clone(), - first_use_at: nones.clone(), - first_drop_at: nones, - appearances: IndexVec::new(), - }; - - if live_locals.is_empty() { - return local_use_map; - } - - let mut locals_with_use_data: IndexVec = - IndexVec::from_elem(false, &body.local_decls); - live_locals.iter().for_each(|&local| locals_with_use_data[local] = true); - - LocalUseMapBuild { local_use_map: &mut local_use_map, elements, locals_with_use_data } - .visit_body(body); - - local_use_map - } - - pub(crate) fn defs(&self, local: Local) -> impl Iterator + '_ { - vll::iter(self.first_def_at[local], &self.appearances) - .map(move |aa| self.appearances[aa].point_index) - } - - pub(crate) fn uses(&self, local: Local) -> impl Iterator + '_ { - vll::iter(self.first_use_at[local], &self.appearances) - .map(move |aa| self.appearances[aa].point_index) - } - - pub(crate) fn drops(&self, local: Local) -> impl Iterator + '_ { - vll::iter(self.first_drop_at[local], &self.appearances) - .map(move |aa| self.appearances[aa].point_index) - } -} - -struct LocalUseMapBuild<'me> { - local_use_map: &'me mut LocalUseMap, - elements: &'me DenseLocationMap, - - // Vector used in `visit_local` to signal which `Local`s do we need - // def/use/drop information on, constructed from `live_locals` (that - // contains the variables we'll do the liveness analysis for). - // This vector serves optimization purposes only: we could have - // obtained the same information from `live_locals` but we want to - // avoid repeatedly calling `Vec::contains()` (see `LocalUseMap` for - // the rationale on the time-memory trade-off we're favoring here). - locals_with_use_data: IndexVec, -} - -impl LocalUseMapBuild<'_> { - fn insert_def(&mut self, local: Local, location: Location) { - Self::insert( - self.elements, - &mut self.local_use_map.first_def_at[local], - &mut self.local_use_map.appearances, - location, - ); - } - - fn insert_use(&mut self, local: Local, location: Location) { - Self::insert( - self.elements, - &mut self.local_use_map.first_use_at[local], - &mut self.local_use_map.appearances, - location, - ); - } - - fn insert_drop(&mut self, local: Local, location: Location) { - Self::insert( - self.elements, - &mut self.local_use_map.first_drop_at[local], - &mut self.local_use_map.appearances, - location, - ); - } - - fn insert( - elements: &DenseLocationMap, - first_appearance: &mut Option, - appearances: &mut IndexVec, - location: Location, - ) { - let point_index = elements.point_from_location(location); - let appearance_index = - appearances.push(Appearance { point_index, next: *first_appearance }); - *first_appearance = Some(appearance_index); - } -} - -impl Visitor<'_> for LocalUseMapBuild<'_> { - fn visit_local(&mut self, local: Local, context: PlaceContext, location: Location) { - if self.locals_with_use_data[local] { - match def_use::categorize(context) { - Some(DefUse::Def) => self.insert_def(local, location), - Some(DefUse::Use) => self.insert_use(local, location), - Some(DefUse::Drop) => self.insert_drop(local, location), - _ => (), - } - } - } -} +use rustc_data_structures::vec_linked_list as vll;use rustc_index::IndexVec;use +rustc_middle::mir::visit::{PlaceContext,Visitor};use rustc_middle::mir::{Body,// +Local,Location};use rustc_mir_dataflow::points::{DenseLocationMap,PointIndex};// +use crate::def_use::{self,DefUse};pub(crate)struct LocalUseMap{first_def_at://3; +IndexVec>,first_use_at:IndexVec>,first_drop_at:IndexVec>,//{();}; +appearances:IndexVec,}struct Appearance{point_index +:PointIndex,next:Option,}rustc_index::newtype_index!{pub//({}); +struct AppearanceIndex{}}impl vll::LinkElem for Appearance{type LinkIndex=//{;}; +AppearanceIndex;fn next(elem:&Self)->Option{elem.next}}impl//3; +LocalUseMap{pub(crate)fn build(live_locals :&[Local],elements:&DenseLocationMap, +body:&Body<'_>,)->Self{;let nones=IndexVec::from_elem(None,&body.local_decls);;; +let mut local_use_map=LocalUseMap{first_def_at: nones.clone(),first_use_at:nones +.clone(),first_drop_at:nones,appearances:IndexVec::new(),};{();};if live_locals. +is_empty(){;return local_use_map;;};let mut locals_with_use_data:IndexVec=IndexVec::from_elem(false,&body.local_decls);;live_locals.iter().for_each( +|&local|locals_with_use_data[local]=true);3;;LocalUseMapBuild{local_use_map:&mut +local_use_map,elements,locals_with_use_data}.visit_body(body);;local_use_map}pub +(crate)fn defs(&self,local:Local)->impl Iterator+'_{vll::iter( +self.first_def_at[local],(&self.appearances)) .map(move|aa|self.appearances[aa]. +point_index)}pub(crate)fn uses(&self,local:Local)->impl Iterator+'_{(vll::iter(self.first_use_at[local],&self.appearances)).map(move| +aa|((self.appearances[aa])).point_index)}pub(crate)fn drops(&self,local:Local)-> +impl Iterator+'_{vll::iter(((self.first_drop_at[local])),&self. +appearances).map(((((move|aa|(((self.appearances[aa]))).point_index)))))}}struct +LocalUseMapBuild<'me>{local_use_map:&'me mut LocalUseMap,elements:&'me//((),()); +DenseLocationMap,locals_with_use_data:IndexVec,}impl//if let _=(){}; +LocalUseMapBuild<'_>{fn insert_def(&mut self,local:Local,location:Location){{;}; +Self::insert(self.elements,(&mut ( self.local_use_map.first_def_at[local])),&mut +self.local_use_map.appearances,location,);;}fn insert_use(&mut self,local:Local, +location:Location){if true{};Self::insert(self.elements,&mut self.local_use_map. +first_use_at[local],&mut self.local_use_map.appearances,location,);if true{};}fn +insert_drop(&mut self,local:Local,location:Location){;Self::insert(self.elements +,(((&mut ((self.local_use_map.first_drop_at[local]))))),&mut self.local_use_map. +appearances,location,);;}fn insert(elements:&DenseLocationMap,first_appearance:& +mut Option,appearances:&mut IndexVec,location:Location,){();let point_index=elements.point_from_location( +location);3;;let appearance_index=appearances.push(Appearance{point_index,next:* +first_appearance});;;*first_appearance=Some(appearance_index);}}impl Visitor<'_> +for LocalUseMapBuild<'_>{fn visit_local(&mut self,local:Local,context://((),()); +PlaceContext,location:Location){if (((self.locals_with_use_data[local]))){match +def_use::categorize(context){Some(DefUse:: Def)=>self.insert_def(local,location) +,Some(DefUse::Use)=>(self.insert_use(local ,location)),Some(DefUse::Drop)=>self. +insert_drop(local,location),_=>(((((((((((((((((((((()))))))))))))))))))))),}}}} diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs index 51ae7d14e4386..dc37506b83e9d 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs @@ -1,214 +1,62 @@ -use itertools::{Either, Itertools}; -use rustc_data_structures::fx::FxHashSet; -use rustc_middle::mir::visit::{TyContext, Visitor}; -use rustc_middle::mir::{Body, Local, Location, SourceInfo}; -use rustc_middle::ty::visit::TypeVisitable; -use rustc_middle::ty::{GenericArgsRef, Region, RegionVid, Ty, TyCtxt}; -use rustc_mir_dataflow::impls::MaybeInitializedPlaces; -use rustc_mir_dataflow::move_paths::MoveData; -use rustc_mir_dataflow::points::DenseLocationMap; -use rustc_mir_dataflow::ResultsCursor; -use std::rc::Rc; - -use crate::{ - constraints::OutlivesConstraintSet, - facts::{AllFacts, AllFactsExt}, - location::LocationTable, - region_infer::values::LivenessValues, - universal_regions::UniversalRegions, -}; - -use super::TypeChecker; - -mod local_use_map; -mod polonius; -mod trace; - -/// Combines liveness analysis with initialization analysis to -/// determine which variables are live at which points, both due to -/// ordinary uses and drops. Returns a set of (ty, location) pairs -/// that indicate which types must be live at which point in the CFG. -/// This vector is consumed by `constraint_generation`. -/// -/// N.B., this computation requires normalization; therefore, it must be -/// performed before -pub(super) fn generate<'mir, 'tcx>( - typeck: &mut TypeChecker<'_, 'tcx>, - body: &Body<'tcx>, - elements: &Rc, - flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, - move_data: &MoveData<'tcx>, - location_table: &LocationTable, - use_polonius: bool, -) { - debug!("liveness::generate"); - - let free_regions = regions_that_outlive_free_regions( - typeck.infcx.num_region_vars(), - typeck.borrowck_context.universal_regions, - &typeck.borrowck_context.constraints.outlives_constraints, - ); - let (relevant_live_locals, boring_locals) = - compute_relevant_live_locals(typeck.tcx(), &free_regions, body); - let facts_enabled = use_polonius || AllFacts::enabled(typeck.tcx()); - - let polonius_drop_used = facts_enabled.then(|| { - let mut drop_used = Vec::new(); - polonius::populate_access_facts(typeck, body, location_table, move_data, &mut drop_used); - drop_used - }); - - trace::trace( - typeck, - body, - elements, - flow_inits, - move_data, - relevant_live_locals, - boring_locals, - polonius_drop_used, - ); - - // Mark regions that should be live where they appear within rvalues or within a call: like - // args, regions, and types. - record_regular_live_regions( - typeck.tcx(), - &mut typeck.borrowck_context.constraints.liveness_constraints, - body, - ); -} - -// The purpose of `compute_relevant_live_locals` is to define the subset of `Local` -// variables for which we need to do a liveness computation. We only need -// to compute whether a variable `X` is live if that variable contains -// some region `R` in its type where `R` is not known to outlive a free -// region (i.e., where `R` may be valid for just a subset of the fn body). -fn compute_relevant_live_locals<'tcx>( - tcx: TyCtxt<'tcx>, - free_regions: &FxHashSet, - body: &Body<'tcx>, -) -> (Vec, Vec) { - let (boring_locals, relevant_live_locals): (Vec<_>, Vec<_>) = - body.local_decls.iter_enumerated().partition_map(|(local, local_decl)| { - if tcx.all_free_regions_meet(&local_decl.ty, |r| free_regions.contains(&r.as_var())) { - Either::Left(local) - } else { - Either::Right(local) - } - }); - - debug!("{} total variables", body.local_decls.len()); - debug!("{} variables need liveness", relevant_live_locals.len()); - debug!("{} regions outlive free regions", free_regions.len()); - - (relevant_live_locals, boring_locals) -} - -/// Computes all regions that are (currently) known to outlive free -/// regions. For these regions, we do not need to compute -/// liveness, since the outlives constraints will ensure that they -/// are live over the whole fn body anyhow. -fn regions_that_outlive_free_regions<'tcx>( - num_region_vars: usize, - universal_regions: &UniversalRegions<'tcx>, - constraint_set: &OutlivesConstraintSet<'tcx>, -) -> FxHashSet { - // Build a graph of the outlives constraints thus far. This is - // a reverse graph, so for each constraint `R1: R2` we have an - // edge `R2 -> R1`. Therefore, if we find all regions - // reachable from each free region, we will have all the - // regions that are forced to outlive some free region. - let rev_constraint_graph = constraint_set.reverse_graph(num_region_vars); - let fr_static = universal_regions.fr_static; - let rev_region_graph = rev_constraint_graph.region_graph(constraint_set, fr_static); - - // Stack for the depth-first search. Start out with all the free regions. - let mut stack: Vec<_> = universal_regions.universal_regions().collect(); - - // Set of all free regions, plus anything that outlives them. Initially - // just contains the free regions. - let mut outlives_free_region: FxHashSet<_> = stack.iter().cloned().collect(); - - // Do the DFS -- for each thing in the stack, find all things - // that outlive it and add them to the set. If they are not, - // push them onto the stack for later. - while let Some(sub_region) = stack.pop() { - stack.extend( - rev_region_graph - .outgoing_regions(sub_region) - .filter(|&r| outlives_free_region.insert(r)), - ); - } - - // Return the final set of things we visited. - outlives_free_region -} - -/// Some variables are "regular live" at `location` -- i.e., they may be used later. This means that -/// all regions appearing in their type must be live at `location`. -fn record_regular_live_regions<'tcx>( - tcx: TyCtxt<'tcx>, - liveness_constraints: &mut LivenessValues, - body: &Body<'tcx>, -) { - let mut visitor = LiveVariablesVisitor { tcx, liveness_constraints }; - for (bb, data) in body.basic_blocks.iter_enumerated() { - visitor.visit_basic_block_data(bb, data); - } -} - -/// Visitor looking for regions that should be live within rvalues or calls. -struct LiveVariablesVisitor<'cx, 'tcx> { - tcx: TyCtxt<'tcx>, - liveness_constraints: &'cx mut LivenessValues, -} - -impl<'cx, 'tcx> Visitor<'tcx> for LiveVariablesVisitor<'cx, 'tcx> { - /// We sometimes have `args` within an rvalue, or within a - /// call. Make them live at the location where they appear. - fn visit_args(&mut self, args: &GenericArgsRef<'tcx>, location: Location) { - self.record_regions_live_at(*args, location); - self.super_args(args); - } - - /// We sometimes have `region`s within an rvalue, or within a - /// call. Make them live at the location where they appear. - fn visit_region(&mut self, region: Region<'tcx>, location: Location) { - self.record_regions_live_at(region, location); - self.super_region(region); - } - - /// We sometimes have `ty`s within an rvalue, or within a - /// call. Make them live at the location where they appear. - fn visit_ty(&mut self, ty: Ty<'tcx>, ty_context: TyContext) { - match ty_context { - TyContext::ReturnTy(SourceInfo { span, .. }) - | TyContext::YieldTy(SourceInfo { span, .. }) - | TyContext::ResumeTy(SourceInfo { span, .. }) - | TyContext::UserTy(span) - | TyContext::LocalDecl { source_info: SourceInfo { span, .. }, .. } => { - span_bug!(span, "should not be visiting outside of the CFG: {:?}", ty_context); - } - TyContext::Location(location) => { - self.record_regions_live_at(ty, location); - } - } - - self.super_ty(ty); - } -} - -impl<'cx, 'tcx> LiveVariablesVisitor<'cx, 'tcx> { - /// Some variable is "regular live" at `location` -- i.e., it may be used later. This means that - /// all regions appearing in the type of `value` must be live at `location`. - fn record_regions_live_at(&mut self, value: T, location: Location) - where - T: TypeVisitable>, - { - debug!("record_regions_live_at(value={:?}, location={:?})", value, location); - self.tcx.for_each_free_region(&value, |live_region| { - let live_region_vid = live_region.as_var(); - self.liveness_constraints.add_location(live_region_vid, location); - }); - } -} +use itertools::{Either,Itertools};use rustc_data_structures::fx::FxHashSet;use// +rustc_middle::mir::visit::{TyContext,Visitor};use rustc_middle::mir::{Body,//(); +Local,Location,SourceInfo};use rustc_middle::ty::visit::TypeVisitable;use//({}); +rustc_middle::ty::{GenericArgsRef,Region,RegionVid,Ty,TyCtxt};use//loop{break;}; +rustc_mir_dataflow::impls::MaybeInitializedPlaces;use rustc_mir_dataflow:://{;}; +move_paths::MoveData;use rustc_mir_dataflow::points::DenseLocationMap;use//({}); +rustc_mir_dataflow::ResultsCursor;use std::rc::Rc;use crate::{constraints:://(); +OutlivesConstraintSet,facts::{AllFacts,AllFactsExt},location::LocationTable,//3; +region_infer::values::LivenessValues,universal_regions::UniversalRegions,};use// +super::TypeChecker;mod local_use_map;mod polonius;mod trace;pub(super)fn//{();}; +generate<'mir,'tcx>(typeck:&mut TypeChecker< '_,'tcx>,body:&Body<'tcx>,elements: +&Rc,flow_inits:&mut ResultsCursor<'mir,'tcx,//((),());((),()); +MaybeInitializedPlaces<'mir,'tcx>>,move_data:&MoveData<'tcx>,location_table:&//; +LocationTable,use_polonius:bool,){;debug!("liveness::generate");let free_regions +=regions_that_outlive_free_regions((((typeck.infcx .num_region_vars()))),typeck. +borrowck_context.universal_regions,&typeck.borrowck_context.constraints.//{();}; +outlives_constraints,);let _=();((),());let(relevant_live_locals,boring_locals)= +compute_relevant_live_locals(typeck.tcx(),&free_regions,body);;let facts_enabled +=use_polonius||AllFacts::enabled(typeck.tcx());({});({});let polonius_drop_used= +facts_enabled.then(||{*&*&();let mut drop_used=Vec::new();{();};{();};polonius:: +populate_access_facts(typeck,body,location_table,move_data,&mut drop_used);({}); +drop_used});*&*&();{();};trace::trace(typeck,body,elements,flow_inits,move_data, +relevant_live_locals,boring_locals,polonius_drop_used,);loop{break};loop{break}; +record_regular_live_regions((((((typeck.tcx()))))),&mut typeck.borrowck_context. +constraints.liveness_constraints,body,);;}fn compute_relevant_live_locals<'tcx>( +tcx:TyCtxt<'tcx>,free_regions:&FxHashSet,body:&Body<'tcx>,)->(Vec,Vec){;let(boring_locals,relevant_live_locals):(Vec<_>,Vec<_>)=body +.local_decls.iter_enumerated().partition_map(|(local,local_decl)|{if tcx.//({}); +all_free_regions_meet((&local_decl.ty),(|r|free_regions.contains(&r.as_var()))){ +Either::Left(local)}else{Either::Right(local)}});3;;debug!("{} total variables", +body.local_decls.len());if true{};if true{};debug!("{} variables need liveness", +relevant_live_locals.len());{();};({});debug!("{} regions outlive free regions", +free_regions.len());if true{};let _=||();(relevant_live_locals,boring_locals)}fn +regions_that_outlive_free_regions<'tcx>( num_region_vars:usize,universal_regions +:&UniversalRegions<'tcx>,constraint_set:&OutlivesConstraintSet<'tcx>,)->//{();}; +FxHashSet{({});let rev_constraint_graph=constraint_set.reverse_graph( +num_region_vars);;let fr_static=universal_regions.fr_static;let rev_region_graph +=rev_constraint_graph.region_graph(constraint_set,fr_static);;let mut stack:Vec< +_>=universal_regions.universal_regions().collect();;let mut outlives_free_region +:FxHashSet<_>=stack.iter().cloned().collect();;while let Some(sub_region)=stack. +pop(){{;};stack.extend(rev_region_graph.outgoing_regions(sub_region).filter(|&r| +outlives_free_region.insert(r)),);let _=||();let _=||();}outlives_free_region}fn +record_regular_live_regions<'tcx>(tcx:TyCtxt<'tcx>,liveness_constraints:&mut//3; +LivenessValues,body:&Body<'tcx>,){({});let mut visitor=LiveVariablesVisitor{tcx, +liveness_constraints};{;};for(bb,data)in body.basic_blocks.iter_enumerated(){(); +visitor.visit_basic_block_data(bb,data);;}}struct LiveVariablesVisitor<'cx,'tcx> +{tcx:TyCtxt<'tcx>,liveness_constraints:&'cx mut LivenessValues,}impl<'cx,'tcx>// +Visitor<'tcx>for LiveVariablesVisitor<'cx,'tcx>{fn visit_args(&mut self,args:&// +GenericArgsRef<'tcx>,location:Location){{();};self.record_regions_live_at(*args, +location);;self.super_args(args);}fn visit_region(&mut self,region:Region<'tcx>, +location:Location){{;};self.record_regions_live_at(region,location);{;};();self. +super_region(region);3;}fn visit_ty(&mut self,ty:Ty<'tcx>,ty_context:TyContext){ +match ty_context{TyContext::ReturnTy(SourceInfo{span,..})|TyContext::YieldTy(//; +SourceInfo{span,..})|TyContext::ResumeTy (SourceInfo{span,..})|TyContext::UserTy +(span)|TyContext::LocalDecl{source_info:SourceInfo{span,..},..}=>{{;};span_bug!( +span,"should not be visiting outside of the CFG: {:?}",ty_context);;}TyContext:: +Location(location)=>{;self.record_regions_live_at(ty,location);;}}self.super_ty( +ty);;}}impl<'cx,'tcx>LiveVariablesVisitor<'cx,'tcx>{fn record_regions_live_at +(&mut self,value:T,location:Location)where T:TypeVisitable>,{;debug +!("record_regions_live_at(value={:?}, location={:?})",value,location);;self.tcx. +for_each_free_region(&value,|live_region|{{();};let live_region_vid=live_region. +as_var();;self.liveness_constraints.add_location(live_region_vid,location);});}} diff --git a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs index 7f5302270439c..0fe6780fd1c25 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs @@ -1,142 +1,58 @@ -use crate::def_use::{self, DefUse}; -use crate::location::{LocationIndex, LocationTable}; -use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::{Body, Local, Location, Place}; -use rustc_middle::ty::GenericArg; -use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex}; - -use super::TypeChecker; - -type VarPointRelation = Vec<(Local, LocationIndex)>; -type PathPointRelation = Vec<(MovePathIndex, LocationIndex)>; - -struct UseFactsExtractor<'me, 'tcx> { - var_defined_at: &'me mut VarPointRelation, - var_used_at: &'me mut VarPointRelation, - location_table: &'me LocationTable, - var_dropped_at: &'me mut VarPointRelation, - move_data: &'me MoveData<'tcx>, - path_accessed_at_base: &'me mut PathPointRelation, -} - -// A Visitor to walk through the MIR and extract point-wise facts -impl<'tcx> UseFactsExtractor<'_, 'tcx> { - fn location_to_index(&self, location: Location) -> LocationIndex { - self.location_table.mid_index(location) - } - - fn insert_def(&mut self, local: Local, location: Location) { - debug!("UseFactsExtractor::insert_def()"); - self.var_defined_at.push((local, self.location_to_index(location))); - } - - fn insert_use(&mut self, local: Local, location: Location) { - debug!("UseFactsExtractor::insert_use()"); - self.var_used_at.push((local, self.location_to_index(location))); - } - - fn insert_drop_use(&mut self, local: Local, location: Location) { - debug!("UseFactsExtractor::insert_drop_use()"); - self.var_dropped_at.push((local, self.location_to_index(location))); - } - - fn insert_path_access(&mut self, path: MovePathIndex, location: Location) { - debug!("UseFactsExtractor::insert_path_access({:?}, {:?})", path, location); - self.path_accessed_at_base.push((path, self.location_to_index(location))); - } - - fn place_to_mpi(&self, place: &Place<'tcx>) -> Option { - match self.move_data.rev_lookup.find(place.as_ref()) { - LookupResult::Exact(mpi) => Some(mpi), - LookupResult::Parent(mmpi) => mmpi, - } - } -} - -impl<'a, 'tcx> Visitor<'tcx> for UseFactsExtractor<'a, 'tcx> { - fn visit_local(&mut self, local: Local, context: PlaceContext, location: Location) { - match def_use::categorize(context) { - Some(DefUse::Def) => self.insert_def(local, location), - Some(DefUse::Use) => self.insert_use(local, location), - Some(DefUse::Drop) => self.insert_drop_use(local, location), - _ => (), - } - } - - fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { - self.super_place(place, context, location); - match context { - PlaceContext::NonMutatingUse(_) => { - if let Some(mpi) = self.place_to_mpi(place) { - self.insert_path_access(mpi, location); - } - } - - PlaceContext::MutatingUse(MutatingUseContext::Borrow) => { - if let Some(mpi) = self.place_to_mpi(place) { - self.insert_path_access(mpi, location); - } - } - _ => (), - } - } -} - -pub(super) fn populate_access_facts<'a, 'tcx>( - typeck: &mut TypeChecker<'a, 'tcx>, - body: &Body<'tcx>, - location_table: &LocationTable, - move_data: &MoveData<'tcx>, - //FIXME: this is not mutated, but expected to be modified as - // out param, bug? - dropped_at: &mut Vec<(Local, Location)>, -) { - debug!("populate_access_facts()"); - - if let Some(facts) = typeck.borrowck_context.all_facts.as_mut() { - let mut extractor = UseFactsExtractor { - var_defined_at: &mut facts.var_defined_at, - var_used_at: &mut facts.var_used_at, - var_dropped_at: &mut facts.var_dropped_at, - path_accessed_at_base: &mut facts.path_accessed_at_base, - location_table, - move_data, - }; - extractor.visit_body(body); - - facts.var_dropped_at.extend( - dropped_at.iter().map(|&(local, location)| (local, location_table.mid_index(location))), - ); - - for (local, local_decl) in body.local_decls.iter_enumerated() { - debug!( - "add use_of_var_derefs_origin facts - local={:?}, type={:?}", - local, local_decl.ty - ); - let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation"); - let universal_regions = &typeck.borrowck_context.universal_regions; - typeck.infcx.tcx.for_each_free_region(&local_decl.ty, |region| { - let region_vid = universal_regions.to_region_vid(region); - facts.use_of_var_derefs_origin.push((local, region_vid)); - }); - } - } -} - -/// For every potentially drop()-touched region `region` in `local`'s type -/// (`kind`), emit a Polonius `use_of_var_derefs_origin(local, origin)` fact. -pub(super) fn add_drop_of_var_derefs_origin<'tcx>( - typeck: &mut TypeChecker<'_, 'tcx>, - local: Local, - kind: &GenericArg<'tcx>, -) { - debug!("add_drop_of_var_derefs_origin(local={:?}, kind={:?}", local, kind); - if let Some(facts) = typeck.borrowck_context.all_facts.as_mut() { - let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation"); - let universal_regions = &typeck.borrowck_context.universal_regions; - typeck.infcx.tcx.for_each_free_region(kind, |drop_live_region| { - let region_vid = universal_regions.to_region_vid(drop_live_region); - facts.drop_of_var_derefs_origin.push((local, region_vid)); - }); - } -} +use crate::def_use::{self,DefUse};use crate::location::{LocationIndex,//((),()); +LocationTable};use rustc_middle::mir::visit::{MutatingUseContext,PlaceContext,// +Visitor};use rustc_middle::mir::{Body,Local,Location,Place};use rustc_middle::// +ty::GenericArg;use rustc_mir_dataflow::move_paths::{LookupResult,MoveData,//{;}; +MovePathIndex};use super::TypeChecker;type VarPointRelation=Vec<(Local,//*&*&(); +LocationIndex)>;type PathPointRelation=Vec<(MovePathIndex,LocationIndex)>;//{;}; +struct UseFactsExtractor<'me,'tcx>{var_defined_at:&'me mut VarPointRelation,//3; +var_used_at:&'me mut VarPointRelation,location_table:&'me LocationTable,//{();}; +var_dropped_at:&'me mut VarPointRelation,move_data:&'me MoveData<'tcx>,//*&*&(); +path_accessed_at_base:&'me mut PathPointRelation,}impl<'tcx>UseFactsExtractor{fn location_to_index(&self,location:Location)->LocationIndex{self.//(); +location_table.mid_index(location)}fn insert_def (&mut self,local:Local,location +:Location){;debug!("UseFactsExtractor::insert_def()");self.var_defined_at.push(( +local,self.location_to_index(location)));3;}fn insert_use(&mut self,local:Local, +location:Location){;debug!("UseFactsExtractor::insert_use()");;self.var_used_at. +push((local,self.location_to_index(location)));();}fn insert_drop_use(&mut self, +local:Local,location:Location){;debug!("UseFactsExtractor::insert_drop_use()");; +self.var_dropped_at.push((local,self.location_to_index(location)));if true{};}fn +insert_path_access(&mut self,path:MovePathIndex,location:Location){{();};debug!( +"UseFactsExtractor::insert_path_access({:?}, {:?})",path,location);{;};{;};self. +path_accessed_at_base.push((path,self.location_to_index(location)));let _=();}fn +place_to_mpi(&self,place:&Place<'tcx>)->Option{match self.//({}); +move_data.rev_lookup.find((place.as_ref())){LookupResult::Exact(mpi)=>Some(mpi), +LookupResult::Parent(mmpi)=>mmpi,}}}impl<'a,'tcx>Visitor<'tcx>for//loop{break;}; +UseFactsExtractor<'a,'tcx>{fn visit_local(&mut self,local:Local,context://{();}; +PlaceContext,location:Location){match (def_use::categorize(context)){Some(DefUse +::Def)=>((self.insert_def(local,location) )),Some(DefUse::Use)=>self.insert_use( +local,location),Some(DefUse::Drop)=>self .insert_drop_use(local,location),_=>(), +}}fn visit_place(&mut self,place:&Place<'tcx>,context:PlaceContext,location://3; +Location){;self.super_place(place,context,location);match context{PlaceContext:: +NonMutatingUse(_)=>{if let Some(mpi)=self.place_to_mpi(place){loop{break;};self. +insert_path_access(mpi,location);;}}PlaceContext::MutatingUse(MutatingUseContext +::Borrow)=>{if let Some(mpi)=self.place_to_mpi(place){3;self.insert_path_access( +mpi,location);();}}_=>(),}}}pub(super)fn populate_access_facts<'a,'tcx>(typeck:& +mut TypeChecker<'a,'tcx>,body:&Body<'tcx>,location_table:&LocationTable,//{();}; +move_data:&MoveData<'tcx>,dropped_at:&mut Vec<(Local,Location)>,){*&*&();debug!( +"populate_access_facts()");;if let Some(facts)=typeck.borrowck_context.all_facts +.as_mut(){((),());let mut extractor=UseFactsExtractor{var_defined_at:&mut facts. +var_defined_at,var_used_at:((&mut facts.var_used_at)),var_dropped_at:&mut facts. +var_dropped_at,path_accessed_at_base:(((((&mut facts.path_accessed_at_base))))), +location_table,move_data,};3;;extractor.visit_body(body);;;facts.var_dropped_at. +extend(dropped_at.iter().map(| &(local,location)|(local,location_table.mid_index +(location))),);;for(local,local_decl)in body.local_decls.iter_enumerated(){debug +!("add use_of_var_derefs_origin facts - local={:?}, type={:?}" ,local,local_decl +.ty);if true{};if true{};let _prof_timer=typeck.infcx.tcx.prof.generic_activity( +"polonius_fact_generation");();3;let universal_regions=&typeck.borrowck_context. +universal_regions;;typeck.infcx.tcx.for_each_free_region(&local_decl.ty,|region| +{{();};let region_vid=universal_regions.to_region_vid(region);{();};{();};facts. +use_of_var_derefs_origin.push((local,region_vid));{();};});{();};}}}pub(super)fn +add_drop_of_var_derefs_origin<'tcx>(typeck:&mut TypeChecker<'_,'tcx>,local://(); +Local,kind:&GenericArg<'tcx>,){if true{};let _=||();if true{};let _=||();debug!( +"add_drop_of_var_derefs_origin(local={:?}, kind={:?}",local,kind);3;if let Some( +facts)=typeck.borrowck_context.all_facts.as_mut(){;let _prof_timer=typeck.infcx. +tcx.prof.generic_activity("polonius_fact_generation");3;;let universal_regions=& +typeck.borrowck_context.universal_regions;;typeck.infcx.tcx.for_each_free_region +(kind,|drop_live_region|{((),());let region_vid=universal_regions.to_region_vid( +drop_live_region);;facts.drop_of_var_derefs_origin.push((local,region_vid));});} +}//let _=();if true{};let _=();if true{};let _=();if true{};if true{};if true{}; diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index 8bdefdfc0ac99..8d9bd683321bf 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -1,614 +1,163 @@ -use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; -use rustc_data_structures::graph::WithSuccessors; -use rustc_index::bit_set::BitSet; -use rustc_index::interval::IntervalSet; -use rustc_infer::infer::canonical::QueryRegionConstraints; -use rustc_infer::infer::outlives::for_liveness; -use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location}; -use rustc_middle::traits::query::DropckOutlivesResult; -use rustc_middle::ty::{Ty, TyCtxt, TypeVisitable, TypeVisitableExt}; -use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex}; -use rustc_span::DUMMY_SP; -use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives; -use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; -use std::rc::Rc; - -use rustc_mir_dataflow::impls::MaybeInitializedPlaces; -use rustc_mir_dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex}; -use rustc_mir_dataflow::ResultsCursor; - -use crate::{ - region_infer::values::{self, LiveLoans}, - type_check::liveness::local_use_map::LocalUseMap, - type_check::liveness::polonius, - type_check::NormalizeLocation, - type_check::TypeChecker, -}; - -/// This is the heart of the liveness computation. For each variable X -/// that requires a liveness computation, it walks over all the uses -/// of X and does a reverse depth-first search ("trace") through the -/// MIR. This search stops when we find a definition of that variable. -/// The points visited in this search is the USE-LIVE set for the variable; -/// of those points is added to all the regions that appear in the variable's -/// type. -/// -/// We then also walks through each *drop* of those variables and does -/// another search, stopping when we reach a use or definition. This -/// is the DROP-LIVE set of points. Each of the points in the -/// DROP-LIVE set are to the liveness sets for regions found in the -/// `dropck_outlives` result of the variable's type (in particular, -/// this respects `#[may_dangle]` annotations). -pub(super) fn trace<'mir, 'tcx>( - typeck: &mut TypeChecker<'_, 'tcx>, - body: &Body<'tcx>, - elements: &Rc, - flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, - move_data: &MoveData<'tcx>, - relevant_live_locals: Vec, - boring_locals: Vec, - polonius_drop_used: Option>, -) { - let local_use_map = &LocalUseMap::build(&relevant_live_locals, elements, body); - - // When using `-Zpolonius=next`, compute the set of loans that can reach a given region. - if typeck.tcx().sess.opts.unstable_opts.polonius.is_next_enabled() { - let borrowck_context = &mut typeck.borrowck_context; - let borrow_set = &borrowck_context.borrow_set; - let mut live_loans = LiveLoans::new(borrow_set.len()); - let outlives_constraints = &borrowck_context.constraints.outlives_constraints; - let graph = outlives_constraints.graph(typeck.infcx.num_region_vars()); - let region_graph = - graph.region_graph(outlives_constraints, borrowck_context.universal_regions.fr_static); - - // Traverse each issuing region's constraints, and record the loan as flowing into the - // outlived region. - for (loan, issuing_region_data) in borrow_set.iter_enumerated() { - for succ in region_graph.depth_first_search(issuing_region_data.region) { - // We don't need to mention that a loan flows into its issuing region. - if succ == issuing_region_data.region { - continue; - } - - live_loans.inflowing_loans.insert(succ, loan); - } - } - - // Store the inflowing loans in the liveness constraints: they will be used to compute live - // loans when liveness data is recorded there. - borrowck_context.constraints.liveness_constraints.loans = Some(live_loans); - }; - - let cx = LivenessContext { - typeck, - body, - flow_inits, - elements, - local_use_map, - move_data, - drop_data: FxIndexMap::default(), - }; - - let mut results = LivenessResults::new(cx); - - if let Some(drop_used) = polonius_drop_used { - results.add_extra_drop_facts(drop_used, relevant_live_locals.iter().copied().collect()) - } - - results.compute_for_all_locals(relevant_live_locals); - - results.dropck_boring_locals(boring_locals); -} - -/// Contextual state for the type-liveness coroutine. -struct LivenessContext<'me, 'typeck, 'flow, 'tcx> { - /// Current type-checker, giving us our inference context etc. - typeck: &'me mut TypeChecker<'typeck, 'tcx>, - - /// Defines the `PointIndex` mapping - elements: &'me DenseLocationMap, - - /// MIR we are analyzing. - body: &'me Body<'tcx>, - - /// Mapping to/from the various indices used for initialization tracking. - move_data: &'me MoveData<'tcx>, - - /// Cache for the results of `dropck_outlives` query. - drop_data: FxIndexMap, DropData<'tcx>>, - - /// Results of dataflow tracking which variables (and paths) have been - /// initialized. - flow_inits: &'me mut ResultsCursor<'flow, 'tcx, MaybeInitializedPlaces<'flow, 'tcx>>, - - /// Index indicating where each variable is assigned, used, or - /// dropped. - local_use_map: &'me LocalUseMap, -} - -struct DropData<'tcx> { - dropck_result: DropckOutlivesResult<'tcx>, - region_constraint_data: Option<&'tcx QueryRegionConstraints<'tcx>>, -} - -struct LivenessResults<'me, 'typeck, 'flow, 'tcx> { - cx: LivenessContext<'me, 'typeck, 'flow, 'tcx>, - - /// Set of points that define the current local. - defs: BitSet, - - /// Points where the current variable is "use live" -- meaning - /// that there is a future "full use" that may use its value. - use_live_at: IntervalSet, - - /// Points where the current variable is "drop live" -- meaning - /// that there is no future "full use" that may use its value, but - /// there is a future drop. - drop_live_at: IntervalSet, - - /// Locations where drops may occur. - drop_locations: Vec, - - /// Stack used when doing (reverse) DFS. - stack: Vec, -} - -impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> { - fn new(cx: LivenessContext<'me, 'typeck, 'flow, 'tcx>) -> Self { - let num_points = cx.elements.num_points(); - LivenessResults { - cx, - defs: BitSet::new_empty(num_points), - use_live_at: IntervalSet::new(num_points), - drop_live_at: IntervalSet::new(num_points), - drop_locations: vec![], - stack: vec![], - } - } - - fn compute_for_all_locals(&mut self, relevant_live_locals: Vec) { - for local in relevant_live_locals { - self.reset_local_state(); - self.add_defs_for(local); - self.compute_use_live_points_for(local); - self.compute_drop_live_points_for(local); - - let local_ty = self.cx.body.local_decls[local].ty; - - if !self.use_live_at.is_empty() { - self.cx.add_use_live_facts_for(local_ty, &self.use_live_at); - } - - if !self.drop_live_at.is_empty() { - self.cx.add_drop_live_facts_for( - local, - local_ty, - &self.drop_locations, - &self.drop_live_at, - ); - } - } - } - - /// Runs dropck for locals whose liveness isn't relevant. This is - /// necessary to eagerly detect unbound recursion during drop glue computation. - /// - /// These are all the locals which do not potentially reference a region local - /// to this body. Locals which only reference free regions are always drop-live - /// and can therefore safely be dropped. - fn dropck_boring_locals(&mut self, boring_locals: Vec) { - for local in boring_locals { - let local_ty = self.cx.body.local_decls[local].ty; - let drop_data = self.cx.drop_data.entry(local_ty).or_insert_with({ - let typeck = &self.cx.typeck; - move || LivenessContext::compute_drop_data(typeck, local_ty) - }); - - drop_data.dropck_result.report_overflows( - self.cx.typeck.infcx.tcx, - self.cx.body.local_decls[local].source_info.span, - local_ty, - ); - } - } - - /// Add extra drop facts needed for Polonius. - /// - /// Add facts for all locals with free regions, since regions may outlive - /// the function body only at certain nodes in the CFG. - fn add_extra_drop_facts( - &mut self, - drop_used: Vec<(Local, Location)>, - relevant_live_locals: FxIndexSet, - ) { - let locations = IntervalSet::new(self.cx.elements.num_points()); - - for (local, location) in drop_used { - if !relevant_live_locals.contains(&local) { - let local_ty = self.cx.body.local_decls[local].ty; - if local_ty.has_free_regions() { - self.cx.add_drop_live_facts_for(local, local_ty, &[location], &locations); - } - } - } - } - - /// Clear the value of fields that are "per local variable". - fn reset_local_state(&mut self) { - self.defs.clear(); - self.use_live_at.clear(); - self.drop_live_at.clear(); - self.drop_locations.clear(); - assert!(self.stack.is_empty()); - } - - /// Adds the definitions of `local` into `self.defs`. - fn add_defs_for(&mut self, local: Local) { - for def in self.cx.local_use_map.defs(local) { - debug!("- defined at {:?}", def); - self.defs.insert(def); - } - } - - /// Computes all points where local is "use live" -- meaning its - /// current value may be used later (except by a drop). This is - /// done by walking backwards from each use of `local` until we - /// find a `def` of local. - /// - /// Requires `add_defs_for(local)` to have been executed. - fn compute_use_live_points_for(&mut self, local: Local) { - debug!("compute_use_live_points_for(local={:?})", local); - - self.stack.extend(self.cx.local_use_map.uses(local)); - while let Some(p) = self.stack.pop() { - // We are live in this block from the closest to us of: - // - // * Inclusively, the block start - // * Exclusively, the previous definition (if it's in this block) - // * Exclusively, the previous live_at setting (an optimization) - let block_start = self.cx.elements.to_block_start(p); - let previous_defs = self.defs.last_set_in(block_start..=p); - let previous_live_at = self.use_live_at.last_set_in(block_start..=p); - - let exclusive_start = match (previous_defs, previous_live_at) { - (Some(a), Some(b)) => Some(std::cmp::max(a, b)), - (Some(a), None) | (None, Some(a)) => Some(a), - (None, None) => None, - }; - - if let Some(exclusive) = exclusive_start { - self.use_live_at.insert_range(exclusive + 1..=p); - - // If we have a bound after the start of the block, we should - // not add the predecessors for this block. - continue; - } else { - // Add all the elements of this block. - self.use_live_at.insert_range(block_start..=p); - - // Then add the predecessors for this block, which are the - // terminators of predecessor basic blocks. Push those onto the - // stack so that the next iteration(s) will process them. - - let block = self.cx.elements.to_location(block_start).block; - self.stack.extend( - self.cx.body.basic_blocks.predecessors()[block] - .iter() - .map(|&pred_bb| self.cx.body.terminator_loc(pred_bb)) - .map(|pred_loc| self.cx.elements.point_from_location(pred_loc)), - ); - } - } - } - - /// Computes all points where local is "drop live" -- meaning its - /// current value may be dropped later (but not used). This is - /// done by iterating over the drops of `local` where `local` (or - /// some subpart of `local`) is initialized. For each such drop, - /// we walk backwards until we find a point where `local` is - /// either defined or use-live. - /// - /// Requires `compute_use_live_points_for` and `add_defs_for` to - /// have been executed. - fn compute_drop_live_points_for(&mut self, local: Local) { - debug!("compute_drop_live_points_for(local={:?})", local); - - let Some(mpi) = self.cx.move_data.rev_lookup.find_local(local) else { return }; - debug!("compute_drop_live_points_for: mpi = {:?}", mpi); - - // Find the drops where `local` is initialized. - for drop_point in self.cx.local_use_map.drops(local) { - let location = self.cx.elements.to_location(drop_point); - debug_assert_eq!(self.cx.body.terminator_loc(location.block), location,); - - if self.cx.initialized_at_terminator(location.block, mpi) { - if self.drop_live_at.insert(drop_point) { - self.drop_locations.push(location); - self.stack.push(drop_point); - } - } - } - - debug!("compute_drop_live_points_for: drop_locations={:?}", self.drop_locations); - - // Reverse DFS. But for drops, we do it a bit differently. - // The stack only ever stores *terminators of blocks*. Within - // a block, we walk back the statements in an inner loop. - while let Some(term_point) = self.stack.pop() { - self.compute_drop_live_points_for_block(mpi, term_point); - } - } - - /// Executes one iteration of the drop-live analysis loop. - /// - /// The parameter `mpi` is the `MovePathIndex` of the local variable - /// we are currently analyzing. - /// - /// The point `term_point` represents some terminator in the MIR, - /// where the local `mpi` is drop-live on entry to that terminator. - /// - /// This method adds all drop-live points within the block and -- - /// where applicable -- pushes the terminators of preceding blocks - /// onto `self.stack`. - fn compute_drop_live_points_for_block(&mut self, mpi: MovePathIndex, term_point: PointIndex) { - debug!( - "compute_drop_live_points_for_block(mpi={:?}, term_point={:?})", - self.cx.move_data.move_paths[mpi].place, - self.cx.elements.to_location(term_point), - ); - - // We are only invoked with terminators where `mpi` is - // drop-live on entry. - debug_assert!(self.drop_live_at.contains(term_point)); - - // Otherwise, scan backwards through the statements in the - // block. One of them may be either a definition or use - // live point. - let term_location = self.cx.elements.to_location(term_point); - debug_assert_eq!(self.cx.body.terminator_loc(term_location.block), term_location,); - let block = term_location.block; - let entry_point = self.cx.elements.entry_point(term_location.block); - for p in (entry_point..term_point).rev() { - debug!("compute_drop_live_points_for_block: p = {:?}", self.cx.elements.to_location(p)); - - if self.defs.contains(p) { - debug!("compute_drop_live_points_for_block: def site"); - return; - } - - if self.use_live_at.contains(p) { - debug!("compute_drop_live_points_for_block: use-live at {:?}", p); - return; - } - - if !self.drop_live_at.insert(p) { - debug!("compute_drop_live_points_for_block: already drop-live"); - return; - } - } - - let body = self.cx.body; - for &pred_block in body.basic_blocks.predecessors()[block].iter() { - debug!("compute_drop_live_points_for_block: pred_block = {:?}", pred_block,); - - // Check whether the variable is (at least partially) - // initialized at the exit of this predecessor. If so, we - // want to enqueue it on our list. If not, go check the - // next block. - // - // Note that we only need to check whether `live_local` - // became de-initialized at basic block boundaries. If it - // were to become de-initialized within the block, that - // would have been a "use-live" transition in the earlier - // loop, and we'd have returned already. - // - // NB. It's possible that the pred-block ends in a call - // which stores to the variable; in that case, the - // variable may be uninitialized "at exit" because this - // call only considers the *unconditional effects* of the - // terminator. *But*, in that case, the terminator is also - // a *definition* of the variable, in which case we want - // to stop the search anyhow. (But see Note 1 below.) - if !self.cx.initialized_at_exit(pred_block, mpi) { - debug!("compute_drop_live_points_for_block: not initialized"); - continue; - } - - let pred_term_loc = self.cx.body.terminator_loc(pred_block); - let pred_term_point = self.cx.elements.point_from_location(pred_term_loc); - - // If the terminator of this predecessor either *assigns* - // our value or is a "normal use", then stop. - if self.defs.contains(pred_term_point) { - debug!("compute_drop_live_points_for_block: defined at {:?}", pred_term_loc); - continue; - } - - if self.use_live_at.contains(pred_term_point) { - debug!("compute_drop_live_points_for_block: use-live at {:?}", pred_term_loc); - continue; - } - - // Otherwise, we are drop-live on entry to the terminator, - // so walk it. - if self.drop_live_at.insert(pred_term_point) { - debug!("compute_drop_live_points_for_block: pushed to stack"); - self.stack.push(pred_term_point); - } - } - - // Note 1. There is a weird scenario that you might imagine - // being problematic here, but which actually cannot happen. - // The problem would be if we had a variable that *is* initialized - // (but dead) on entry to the terminator, and where the current value - // will be dropped in the case of unwind. In that case, we ought to - // consider `X` to be drop-live in between the last use and call. - // Here is the example: - // - // ``` - // BB0 { - // X = ... - // use(X); // last use - // ... // <-- X ought to be drop-live here - // X = call() goto BB1 unwind BB2 - // } - // - // BB1 { - // DROP(X) - // } - // - // BB2 { - // DROP(X) - // } - // ``` - // - // However, the current code would, when walking back from BB2, - // simply stop and never explore BB0. This seems bad! But it turns - // out this code is flawed anyway -- note that the existing value of - // `X` would leak in the case where unwinding did *not* occur. - // - // What we *actually* generate is a store to a temporary - // for the call (`TMP = call()...`) and then a - // `Drop(X)` followed by `X = TMP` to swap that with `X`. - } -} - -impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { - /// Returns `true` if the local variable (or some part of it) is initialized at the current - /// cursor position. Callers should call one of the `seek` methods immediately before to point - /// the cursor to the desired location. - fn initialized_at_curr_loc(&self, mpi: MovePathIndex) -> bool { - let state = self.flow_inits.get(); - if state.contains(mpi) { - return true; - } - - let move_paths = &self.flow_inits.analysis().move_data().move_paths; - move_paths[mpi].find_descendant(move_paths, |mpi| state.contains(mpi)).is_some() - } - - /// Returns `true` if the local variable (or some part of it) is initialized in - /// the terminator of `block`. We need to check this to determine if a - /// DROP of some local variable will have an effect -- note that - /// drops, as they may unwind, are always terminators. - fn initialized_at_terminator(&mut self, block: BasicBlock, mpi: MovePathIndex) -> bool { - self.flow_inits.seek_before_primary_effect(self.body.terminator_loc(block)); - self.initialized_at_curr_loc(mpi) - } - - /// Returns `true` if the path `mpi` (or some part of it) is initialized at - /// the exit of `block`. - /// - /// **Warning:** Does not account for the result of `Call` - /// instructions. - fn initialized_at_exit(&mut self, block: BasicBlock, mpi: MovePathIndex) -> bool { - self.flow_inits.seek_after_primary_effect(self.body.terminator_loc(block)); - self.initialized_at_curr_loc(mpi) - } - - /// Stores the result that all regions in `value` are live for the - /// points `live_at`. - fn add_use_live_facts_for( - &mut self, - value: impl TypeVisitable>, - live_at: &IntervalSet, - ) { - debug!("add_use_live_facts_for(value={:?})", value); - Self::make_all_regions_live(self.elements, self.typeck, value, live_at); - } - - /// Some variable with type `live_ty` is "drop live" at `location` - /// -- i.e., it may be dropped later. This means that *some* of - /// the regions in its type must be live at `location`. The - /// precise set will depend on the dropck constraints, and in - /// particular this takes `#[may_dangle]` into account. - fn add_drop_live_facts_for( - &mut self, - dropped_local: Local, - dropped_ty: Ty<'tcx>, - drop_locations: &[Location], - live_at: &IntervalSet, - ) { - debug!( - "add_drop_live_constraint(\ +use rustc_data_structures::fx::{FxIndexMap,FxIndexSet};use//if true{};if true{}; +rustc_data_structures::graph::WithSuccessors;use rustc_index::bit_set::BitSet;// +use rustc_index::interval::IntervalSet;use rustc_infer::infer::canonical:://{;}; +QueryRegionConstraints;use rustc_infer::infer::outlives::for_liveness;use//({}); +rustc_middle::mir::{BasicBlock,Body,ConstraintCategory,Local,Location};use//{;}; +rustc_middle::traits::query::DropckOutlivesResult;use rustc_middle::ty::{Ty,//3; +TyCtxt,TypeVisitable,TypeVisitableExt};use rustc_mir_dataflow::points::{//{();}; +DenseLocationMap,PointIndex};use rustc_span::DUMMY_SP;use rustc_trait_selection +::traits::query::type_op::outlives::DropckOutlives;use rustc_trait_selection::// +traits::query::type_op::{TypeOp,TypeOpOutput};use std::rc::Rc;use//loop{break;}; +rustc_mir_dataflow::impls::MaybeInitializedPlaces;use rustc_mir_dataflow:://{;}; +move_paths::{HasMoveData,MoveData,MovePathIndex};use rustc_mir_dataflow:://({}); +ResultsCursor;use crate::{region_infer::values::{self,LiveLoans},type_check:://; +liveness::local_use_map::LocalUseMap,type_check::liveness::polonius,type_check// +::NormalizeLocation,type_check::TypeChecker,};pub(super)fn trace<'mir,'tcx>(//3; +typeck:&mut TypeChecker<'_,'tcx>,body :&Body<'tcx>,elements:&Rc,flow_inits:&mut ResultsCursor<'mir,'tcx,MaybeInitializedPlaces<'mir,'tcx>>,//; +move_data:&MoveData<'tcx>,relevant_live_locals:Vec,boring_locals:Vec,polonius_drop_used:Option>,){();let local_use_map=& +LocalUseMap::build(&relevant_live_locals,elements,body);3;;if typeck.tcx().sess. +opts.unstable_opts.polonius.is_next_enabled(){;let borrowck_context=&mut typeck. +borrowck_context;;let borrow_set=&borrowck_context.borrow_set;let mut live_loans +=LiveLoans::new(borrow_set.len());3;;let outlives_constraints=&borrowck_context. +constraints.outlives_constraints;3;;let graph=outlives_constraints.graph(typeck. +infcx.num_region_vars());if true{};let _=();let region_graph=graph.region_graph( +outlives_constraints,borrowck_context.universal_regions.fr_static);{;};for(loan, +issuing_region_data)in (borrow_set.iter_enumerated() ){for succ in region_graph. +depth_first_search(issuing_region_data.region){if succ==issuing_region_data.//3; +region{{;};continue;();}();live_loans.inflowing_loans.insert(succ,loan);();}}(); +borrowck_context.constraints.liveness_constraints.loans=Some(live_loans);;};;let +cx=LivenessContext{typeck,body,flow_inits,elements,local_use_map,move_data,//(); +drop_data:FxIndexMap::default(),};;;let mut results=LivenessResults::new(cx);;if +let Some(drop_used)=polonius_drop_used{results.add_extra_drop_facts(drop_used,// +relevant_live_locals.iter().copied().collect())};results.compute_for_all_locals( +relevant_live_locals);();3;results.dropck_boring_locals(boring_locals);3;}struct +LivenessContext<'me,'typeck,'flow,'tcx>{typeck:&'me mut TypeChecker<'typeck,//3; +'tcx>,elements:&'me DenseLocationMap,body:&'me Body<'tcx>,move_data:&'me//{();}; +MoveData<'tcx>,drop_data:FxIndexMap,DropData<'tcx>>,flow_inits:&'me//3; +mut ResultsCursor<'flow,'tcx, MaybeInitializedPlaces<'flow,'tcx>>,local_use_map: +&'me LocalUseMap,}struct DropData <'tcx>{dropck_result:DropckOutlivesResult<'tcx +>,region_constraint_data:Option<&'tcx QueryRegionConstraints<'tcx>>,}struct//(); +LivenessResults<'me,'typeck,'flow,'tcx>{cx:LivenessContext<'me,'typeck,'flow,//; +'tcx>,defs:BitSet ,use_live_at:IntervalSet,drop_live_at: +IntervalSet,drop_locations:Vec,stack:Vec,}//3; +impl<'me,'typeck,'flow,'tcx>LivenessResults<'me,'typeck,'flow,'tcx>{fn new(cx:// +LivenessContext<'me,'typeck,'flow,'tcx>)->Self{{();};let num_points=cx.elements. +num_points();;LivenessResults{cx,defs:BitSet::new_empty(num_points),use_live_at: +IntervalSet::new(num_points),drop_live_at :((((IntervalSet::new(num_points))))), +drop_locations:((vec![])),stack:(vec![ ]),}}fn compute_for_all_locals(&mut self, +relevant_live_locals:Vec){for local in relevant_live_locals{((),());self. +reset_local_state();;;self.add_defs_for(local);self.compute_use_live_points_for( +local);3;3;self.compute_drop_live_points_for(local);;;let local_ty=self.cx.body. +local_decls[local].ty;if true{};if!self.use_live_at.is_empty(){let _=();self.cx. +add_use_live_facts_for(local_ty,&self.use_live_at);*&*&();}if!self.drop_live_at. +is_empty(){;self.cx.add_drop_live_facts_for(local,local_ty,&self.drop_locations, +&self.drop_live_at,);{;};}}}fn dropck_boring_locals(&mut self,boring_locals:Vec< +Local>){for local in boring_locals{;let local_ty=self.cx.body.local_decls[local] +.ty;;let drop_data=self.cx.drop_data.entry(local_ty).or_insert_with({let typeck= +&self.cx.typeck;3;move||LivenessContext::compute_drop_data(typeck,local_ty)});;; +drop_data.dropck_result.report_overflows(self.cx.typeck .infcx.tcx,self.cx.body. +local_decls[local].source_info.span,local_ty,);();}}fn add_extra_drop_facts(&mut +self,drop_used:Vec<(Local,Location)>,relevant_live_locals:FxIndexSet,){3; +let locations=IntervalSet::new(self.cx.elements.num_points());((),());for(local, +location)in drop_used{if!relevant_live_locals.contains(&local){{;};let local_ty= +self.cx.body.local_decls[local].ty;();if local_ty.has_free_regions(){();self.cx. +add_drop_live_facts_for(local,local_ty,&[location],&locations);let _=||();}}}}fn +reset_local_state(&mut self){;self.defs.clear();;;self.use_live_at.clear();self. +drop_live_at.clear();;self.drop_locations.clear();assert!(self.stack.is_empty()) +;;}fn add_defs_for(&mut self,local:Local){for def in self.cx.local_use_map.defs( +local){{;};debug!("- defined at {:?}",def);{;};{;};self.defs.insert(def);();}}fn +compute_use_live_points_for(&mut self,local:Local){let _=||();let _=||();debug!( +"compute_use_live_points_for(local={:?})",local);();3;self.stack.extend(self.cx. +local_use_map.uses(local));;while let Some(p)=self.stack.pop(){;let block_start= +self.cx.elements.to_block_start(p);();3;let previous_defs=self.defs.last_set_in( +block_start..=p);;;let previous_live_at=self.use_live_at.last_set_in(block_start +..=p);;let exclusive_start=match(previous_defs,previous_live_at){(Some(a),Some(b +))=>Some(std::cmp::max(a,b)),(Some(a ),None)|(None,Some(a))=>Some(a),(None,None) +=>None,};;if let Some(exclusive)=exclusive_start{;self.use_live_at.insert_range( +exclusive+1..=p);;continue;}else{self.use_live_at.insert_range(block_start..=p); +let block=self.cx.elements.to_location(block_start).block;3;3;self.stack.extend( +self.cx.body.basic_blocks.predecessors()[block].iter().map(|&pred_bb|self.cx.//; +body.terminator_loc(pred_bb)).map(|pred_loc|self.cx.elements.//((),());let _=(); +point_from_location(pred_loc)),);3;}}}fn compute_drop_live_points_for(&mut self, +local:Local){;debug!("compute_drop_live_points_for(local={:?})",local);let Some( +mpi)=self.cx.move_data.rev_lookup.find_local(local)else{return};({});{;};debug!( +"compute_drop_live_points_for: mpi = {:?}",mpi);{();};for drop_point in self.cx. +local_use_map.drops(local){;let location=self.cx.elements.to_location(drop_point +);;;debug_assert_eq!(self.cx.body.terminator_loc(location.block),location,);;if +self.cx.initialized_at_terminator(location.block,mpi){if self.drop_live_at.//(); +insert(drop_point){{;};self.drop_locations.push(location);();();self.stack.push( +drop_point);;}}}debug!("compute_drop_live_points_for: drop_locations={:?}",self. +drop_locations);((),());while let Some(term_point)=self.stack.pop(){*&*&();self. +compute_drop_live_points_for_block(mpi,term_point);loop{break};loop{break;};}}fn +compute_drop_live_points_for_block(&mut self,mpi:MovePathIndex,term_point://{;}; +PointIndex){*&*&();((),());*&*&();((),());*&*&();((),());((),());((),());debug!( +"compute_drop_live_points_for_block(mpi={:?}, term_point={:?})",self.cx.//{();}; +move_data.move_paths[mpi].place,self.cx.elements.to_location(term_point),);();3; +debug_assert!(self.drop_live_at.contains(term_point));;let term_location=self.cx +.elements.to_location(term_point);;debug_assert_eq!(self.cx.body.terminator_loc( +term_location.block),term_location,);();();let block=term_location.block;3;3;let +entry_point=self.cx.elements.entry_point(term_location.block);let _=();for p in( +entry_point..term_point).rev(){if true{};let _=||();if true{};let _=||();debug!( +"compute_drop_live_points_for_block: p = {:?}",self.cx. elements.to_location(p)) +;;if self.defs.contains(p){debug!("compute_drop_live_points_for_block: def site" +);((),());((),());return;((),());}if self.use_live_at.contains(p){*&*&();debug!( +"compute_drop_live_points_for_block: use-live at {:?}",p);3;3;return;3;}if!self. +drop_live_at.insert(p){loop{break};loop{break;};loop{break};loop{break;};debug!( +"compute_drop_live_points_for_block: already drop-live");;return;}}let body=self +.cx.body;;for&pred_block in body.basic_blocks.predecessors()[block].iter(){debug +!("compute_drop_live_points_for_block: pred_block = {:?}",pred_block,);;if!self. +cx.initialized_at_exit(pred_block,mpi){((),());let _=();((),());let _=();debug!( +"compute_drop_live_points_for_block: not initialized");();();continue;();}();let +pred_term_loc=self.cx.body.terminator_loc(pred_block);;let pred_term_point=self. +cx.elements.point_from_location(pred_term_loc);let _=||();if self.defs.contains( +pred_term_point){3;debug!("compute_drop_live_points_for_block: defined at {:?}", +pred_term_loc);;;continue;}if self.use_live_at.contains(pred_term_point){debug!( +"compute_drop_live_points_for_block: use-live at {:?}",pred_term_loc);;continue; +}if self.drop_live_at.insert(pred_term_point){loop{break;};if let _=(){};debug!( +"compute_drop_live_points_for_block: pushed to stack");({});{;};self.stack.push( +pred_term_point);((),());((),());}}}}impl<'tcx>LivenessContext<'_,'_,'_,'tcx>{fn +initialized_at_curr_loc(&self,mpi:MovePathIndex)->bool{if true{};let state=self. +flow_inits.get();3;if state.contains(mpi){3;return true;;};let move_paths=&self. +flow_inits.analysis().move_data().move_paths;();move_paths[mpi].find_descendant( +move_paths,(|mpi|state.contains(mpi) )).is_some()}fn initialized_at_terminator(& +mut self,block:BasicBlock,mpi:MovePathIndex)->bool{loop{break;};self.flow_inits. +seek_before_primary_effect(self.body.terminator_loc(block));*&*&();((),());self. +initialized_at_curr_loc(mpi)}fn initialized_at_exit (&mut self,block:BasicBlock, +mpi:MovePathIndex)->bool{();self.flow_inits.seek_after_primary_effect(self.body. +terminator_loc(block));if true{};let _=||();self.initialized_at_curr_loc(mpi)}fn +add_use_live_facts_for(&mut self,value: impl TypeVisitable>,live_at +:&IntervalSet,){;debug!("add_use_live_facts_for(value={:?})",value); +Self::make_all_regions_live(self.elements,self.typeck,value,live_at);((),());}fn +add_drop_live_facts_for(&mut self,dropped_local:Local,dropped_ty:Ty<'tcx>,//{;}; +drop_locations:&[Location],live_at:&IntervalSet,){let _=||();debug!( +"add_drop_live_constraint(\ dropped_local={:?}, \ dropped_ty={:?}, \ drop_locations={:?}, \ - live_at={:?})", - dropped_local, - dropped_ty, - drop_locations, - values::pretty_print_points(self.elements, live_at.iter()), - ); - - let drop_data = self.drop_data.entry(dropped_ty).or_insert_with({ - let typeck = &self.typeck; - move || Self::compute_drop_data(typeck, dropped_ty) - }); - - if let Some(data) = &drop_data.region_constraint_data { - for &drop_location in drop_locations { - self.typeck.push_region_constraints( - drop_location.to_locations(), - ConstraintCategory::Boring, - data, - ); - } - } - - drop_data.dropck_result.report_overflows( - self.typeck.infcx.tcx, - self.body.source_info(*drop_locations.first().unwrap()).span, - dropped_ty, - ); - - // All things in the `outlives` array may be touched by - // the destructor and must be live at this point. - for &kind in &drop_data.dropck_result.kinds { - Self::make_all_regions_live(self.elements, self.typeck, kind, live_at); - polonius::add_drop_of_var_derefs_origin(self.typeck, dropped_local, &kind); - } - } - - fn make_all_regions_live( - elements: &DenseLocationMap, - typeck: &mut TypeChecker<'_, 'tcx>, - value: impl TypeVisitable>, - live_at: &IntervalSet, - ) { - debug!("make_all_regions_live(value={:?})", value); - debug!( - "make_all_regions_live: live_at={}", - values::pretty_print_points(elements, live_at.iter()), - ); - - value.visit_with(&mut for_liveness::FreeRegionsVisitor { - tcx: typeck.tcx(), - param_env: typeck.param_env, - op: |r| { - let live_region_vid = typeck.borrowck_context.universal_regions.to_region_vid(r); - - typeck - .borrowck_context - .constraints - .liveness_constraints - .add_points(live_region_vid, live_at); - }, - }); - } - - fn compute_drop_data(typeck: &TypeChecker<'_, 'tcx>, dropped_ty: Ty<'tcx>) -> DropData<'tcx> { - debug!("compute_drop_data(dropped_ty={:?})", dropped_ty,); - - match typeck - .param_env - .and(DropckOutlives::new(dropped_ty)) - .fully_perform(typeck.infcx, DUMMY_SP) - { - Ok(TypeOpOutput { output, constraints, .. }) => { - DropData { dropck_result: output, region_constraint_data: constraints } - } - Err(_) => DropData { dropck_result: Default::default(), region_constraint_data: None }, - } - } -} + live_at={:?})" +,dropped_local,dropped_ty,drop_locations,values::pretty_print_points(self.//{;}; +elements,live_at.iter()),);();();let drop_data=self.drop_data.entry(dropped_ty). +or_insert_with({3;let typeck=&self.typeck;;move||Self::compute_drop_data(typeck, +dropped_ty)});if true{};if let Some(data)=&drop_data.region_constraint_data{for& +drop_location in drop_locations{loop{break};self.typeck.push_region_constraints( +drop_location.to_locations(),ConstraintCategory::Boring,data,);();}}3;drop_data. +dropck_result.report_overflows(self.typeck.infcx.tcx,self.body.source_info(*//3; +drop_locations.first().unwrap()).span,dropped_ty,);*&*&();for&kind in&drop_data. +dropck_result.kinds{;Self::make_all_regions_live(self.elements,self.typeck,kind, +live_at);3;3;polonius::add_drop_of_var_derefs_origin(self.typeck,dropped_local,& +kind);let _=();}}fn make_all_regions_live(elements:&DenseLocationMap,typeck:&mut +TypeChecker<'_,'tcx>,value:impl TypeVisitable>,live_at:&//let _=(); +IntervalSet,){3;debug!("make_all_regions_live(value={:?})",value);;; +debug!("make_all_regions_live: live_at={}", values::pretty_print_points(elements +,live_at.iter()),);;;value.visit_with(&mut for_liveness::FreeRegionsVisitor{tcx: +typeck.tcx(),param_env:typeck.param_env,op:|r|{{();};let live_region_vid=typeck. +borrowck_context.universal_regions.to_region_vid(r);3;3;typeck.borrowck_context. +constraints.liveness_constraints.add_points(live_region_vid,live_at);3;},});;}fn +compute_drop_data(typeck:&TypeChecker<'_,'tcx>,dropped_ty:Ty<'tcx>)->DropData{3;debug!("compute_drop_data(dropped_ty={:?})",dropped_ty,);3;match typeck. +param_env.and((((DropckOutlives::new(dropped_ty))))).fully_perform(typeck.infcx, +DUMMY_SP){Ok(TypeOpOutput{output,constraints,..})=>{DropData{dropck_result://(); +output,region_constraint_data:constraints}}Err(_)=>DropData{dropck_result://{;}; +Default::default(),region_constraint_data:None},}}}//loop{break;};if let _=(){}; diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index b0bdf4af0975f..0de0305e235a6 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1,2911 +1,778 @@ -//! This pass type-checks the MIR to ensure it is not broken. - -use std::rc::Rc; -use std::{fmt, iter, mem}; - -use either::Either; - -use rustc_data_structures::frozen::Frozen; -use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; -use rustc_errors::ErrorGuaranteed; -use rustc_hir as hir; -use rustc_hir::def::DefKind; -use rustc_hir::def_id::LocalDefId; -use rustc_hir::lang_items::LangItem; -use rustc_index::{IndexSlice, IndexVec}; -use rustc_infer::infer::canonical::QueryRegionConstraints; -use rustc_infer::infer::outlives::env::RegionBoundPairs; -use rustc_infer::infer::region_constraints::RegionConstraintData; -use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_infer::infer::{ - BoundRegion, BoundRegionConversionTime, InferCtxt, NllRegionVariableOrigin, -}; -use rustc_middle::mir::tcx::PlaceTy; -use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::*; -use rustc_middle::traits::query::NoSolution; -use rustc_middle::traits::ObligationCause; -use rustc_middle::ty::adjustment::PointerCoercion; -use rustc_middle::ty::cast::CastTy; -use rustc_middle::ty::visit::TypeVisitableExt; -use rustc_middle::ty::{ - self, Binder, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, Dynamic, - OpaqueHiddenType, OpaqueTypeKey, RegionVid, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, -}; -use rustc_middle::ty::{GenericArgsRef, UserArgs}; -use rustc_mir_dataflow::points::DenseLocationMap; -use rustc_span::def_id::CRATE_DEF_ID; -use rustc_span::source_map::Spanned; -use rustc_span::symbol::sym; -use rustc_span::Span; -use rustc_target::abi::{FieldIdx, FIRST_VARIANT}; -use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints; -use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp; -use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; - -use rustc_trait_selection::traits::PredicateObligation; - -use rustc_mir_dataflow::impls::MaybeInitializedPlaces; -use rustc_mir_dataflow::move_paths::MoveData; -use rustc_mir_dataflow::ResultsCursor; - -use crate::session_diagnostics::{MoveUnsized, SimdIntrinsicArgConst}; -use crate::{ - borrow_set::BorrowSet, - constraints::{OutlivesConstraint, OutlivesConstraintSet}, - diagnostics::UniverseInfo, - facts::AllFacts, - location::LocationTable, - member_constraints::MemberConstraintSet, - path_utils, - region_infer::values::{LivenessValues, PlaceholderIndex, PlaceholderIndices}, - region_infer::TypeTest, - type_check::free_region_relations::{CreateResult, UniversalRegionRelations}, - universal_regions::{DefiningTy, UniversalRegions}, - BorrowckInferCtxt, -}; - -macro_rules! span_mirbug { - ($context:expr, $elem:expr, $($message:tt)*) => ({ - $crate::type_check::mirbug( - $context.tcx(), - $context.last_span, - format!( - "broken MIR in {:?} ({:?}): {}", - $context.body().source.def_id(), - $elem, - format_args!($($message)*), - ), - ) - }) -} - -macro_rules! span_mirbug_and_err { - ($context:expr, $elem:expr, $($message:tt)*) => ({ - { - span_mirbug!($context, $elem, $($message)*); - $context.error() - } - }) -} - -mod canonical; -mod constraint_conversion; -pub mod free_region_relations; -mod input_output; -pub(crate) mod liveness; -mod relate_tys; - -/// Type checks the given `mir` in the context of the inference -/// context `infcx`. Returns any region constraints that have yet to -/// be proven. This result includes liveness constraints that -/// ensure that regions appearing in the types of all local variables -/// are live at all points where that local variable may later be -/// used. -/// -/// This phase of type-check ought to be infallible -- this is because -/// the original, HIR-based type-check succeeded. So if any errors -/// occur here, we will get a `bug!` reported. -/// -/// # Parameters -/// -/// - `infcx` -- inference context to use -/// - `param_env` -- parameter environment to use for trait solving -/// - `body` -- MIR body to type-check -/// - `promoted` -- map of promoted constants within `body` -/// - `universal_regions` -- the universal regions from `body`s function signature -/// - `location_table` -- MIR location map of `body` -/// - `borrow_set` -- information about borrows occurring in `body` -/// - `all_facts` -- when using Polonius, this is the generated set of Polonius facts -/// - `flow_inits` -- results of a maybe-init dataflow analysis -/// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis -/// - `elements` -- MIR region map -pub(crate) fn type_check<'mir, 'tcx>( - infcx: &BorrowckInferCtxt<'_, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - body: &Body<'tcx>, - promoted: &IndexSlice>, - universal_regions: &Rc>, - location_table: &LocationTable, - borrow_set: &BorrowSet<'tcx>, - all_facts: &mut Option, - flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, - move_data: &MoveData<'tcx>, - elements: &Rc, - upvars: &[&ty::CapturedPlace<'tcx>], - use_polonius: bool, -) -> MirTypeckResults<'tcx> { - let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body); - let mut constraints = MirTypeckRegionConstraints { - placeholder_indices: PlaceholderIndices::default(), - placeholder_index_to_region: IndexVec::default(), - liveness_constraints: LivenessValues::with_specific_points(elements.clone()), - outlives_constraints: OutlivesConstraintSet::default(), - member_constraints: MemberConstraintSet::default(), - type_tests: Vec::default(), - universe_causes: FxIndexMap::default(), - }; - - let CreateResult { - universal_region_relations, - region_bound_pairs, - normalized_inputs_and_output, - known_type_outlives_obligations, - } = free_region_relations::create( - infcx, - param_env, - implicit_region_bound, - universal_regions, - &mut constraints, - ); - - debug!(?normalized_inputs_and_output); - - let mut borrowck_context = BorrowCheckContext { - universal_regions, - location_table, - borrow_set, - all_facts, - constraints: &mut constraints, - upvars, - }; - - let mut checker = TypeChecker::new( - infcx, - body, - param_env, - ®ion_bound_pairs, - known_type_outlives_obligations, - implicit_region_bound, - &mut borrowck_context, - ); - - checker.check_user_type_annotations(); - - let mut verifier = TypeVerifier::new(&mut checker, promoted); - verifier.visit_body(body); - - checker.typeck_mir(body); - checker.equate_inputs_and_outputs(body, universal_regions, &normalized_inputs_and_output); - checker.check_signature_annotation(body); - - liveness::generate( - &mut checker, - body, - elements, - flow_inits, - move_data, - location_table, - use_polonius, - ); - - translate_outlives_facts(&mut checker); - let opaque_type_values = infcx.take_opaque_types(); - - let opaque_type_values = opaque_type_values - .into_iter() - .map(|(opaque_type_key, decl)| { - let _: Result<_, ErrorGuaranteed> = checker.fully_perform_op( - Locations::All(body.span), - ConstraintCategory::OpaqueType, - CustomTypeOp::new( - |ocx| { - ocx.infcx.register_member_constraints( - opaque_type_key, - decl.hidden_type.ty, - decl.hidden_type.span, - ); - Ok(()) - }, - "opaque_type_map", - ), - ); - let hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type); - trace!("finalized opaque type {:?} to {:#?}", opaque_type_key, hidden_type.ty.kind()); - if hidden_type.has_non_region_infer() { - infcx.dcx().span_bug( - decl.hidden_type.span, - format!("could not resolve {:#?}", hidden_type.ty.kind()), - ); - } - - // Convert all regions to nll vars. - let (opaque_type_key, hidden_type) = - infcx.tcx.fold_regions((opaque_type_key, hidden_type), |region, _| { - match region.kind() { - ty::ReVar(_) => region, - ty::RePlaceholder(placeholder) => checker - .borrowck_context - .constraints - .placeholder_region(infcx, placeholder), - _ => ty::Region::new_var( - infcx.tcx, - checker.borrowck_context.universal_regions.to_region_vid(region), - ), - } - }); - - (opaque_type_key, hidden_type) - }) - .collect(); - - MirTypeckResults { constraints, universal_region_relations, opaque_type_values } -} - -fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) { - let cx = &mut typeck.borrowck_context; - if let Some(facts) = cx.all_facts { - let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation"); - let location_table = cx.location_table; - facts.subset_base.extend(cx.constraints.outlives_constraints.outlives().iter().flat_map( - |constraint: &OutlivesConstraint<'_>| { - if let Some(from_location) = constraint.locations.from_location() { - Either::Left(iter::once(( - constraint.sup, - constraint.sub, - location_table.mid_index(from_location), - ))) - } else { - Either::Right( - location_table - .all_points() - .map(move |location| (constraint.sup, constraint.sub, location)), - ) - } - }, - )); - } -} - -#[track_caller] -fn mirbug(tcx: TyCtxt<'_>, span: Span, msg: String) { - // We sometimes see MIR failures (notably predicate failures) due to - // the fact that we check rvalue sized predicates here. So use `span_delayed_bug` - // to avoid reporting bugs in those cases. - tcx.dcx().span_delayed_bug(span, msg); -} - -enum FieldAccessError { - OutOfRange { field_count: usize }, -} - -/// Verifies that MIR types are sane to not crash further checks. -/// -/// The sanitize_XYZ methods here take an MIR object and compute its -/// type, calling `span_mirbug` and returning an error type if there -/// is a problem. -struct TypeVerifier<'a, 'b, 'tcx> { - cx: &'a mut TypeChecker<'b, 'tcx>, - promoted: &'b IndexSlice>, - last_span: Span, -} - -impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { - fn visit_span(&mut self, span: Span) { - if !span.is_dummy() { - self.last_span = span; - } - } - - fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { - self.sanitize_place(place, location, context); - } - - fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, location: Location) { - debug!(?constant, ?location, "visit_constant"); - - self.super_constant(constant, location); - let ty = self.sanitize_type(constant, constant.const_.ty()); - - self.cx.infcx.tcx.for_each_free_region(&ty, |live_region| { - let live_region_vid = - self.cx.borrowck_context.universal_regions.to_region_vid(live_region); - self.cx - .borrowck_context - .constraints - .liveness_constraints - .add_location(live_region_vid, location); - }); - - // HACK(compiler-errors): Constants that are gathered into Body.required_consts - // have their locations erased... - let locations = if location != Location::START { - location.to_locations() - } else { - Locations::All(constant.span) - }; - - if let Some(annotation_index) = constant.user_ty { - if let Err(terr) = self.cx.relate_type_and_user_type( - constant.const_.ty(), - ty::Variance::Invariant, - &UserTypeProjection { base: annotation_index, projs: vec![] }, - locations, - ConstraintCategory::Boring, - ) { - let annotation = &self.cx.user_type_annotations[annotation_index]; - span_mirbug!( - self, - constant, - "bad constant user type {:?} vs {:?}: {:?}", - annotation, - constant.const_.ty(), - terr, - ); - } - } else { - let tcx = self.tcx(); - let maybe_uneval = match constant.const_ { - Const::Ty(ct) => match ct.kind() { - ty::ConstKind::Unevaluated(_) => { - bug!("should not encounter unevaluated Const::Ty here, got {:?}", ct) - } - _ => None, - }, - Const::Unevaluated(uv, _) => Some(uv), - _ => None, - }; - - if let Some(uv) = maybe_uneval { - if let Some(promoted) = uv.promoted { - let check_err = |verifier: &mut TypeVerifier<'a, 'b, 'tcx>, - promoted: &Body<'tcx>, - ty, - san_ty| { - if let Err(terr) = - verifier.cx.eq_types(ty, san_ty, locations, ConstraintCategory::Boring) - { - span_mirbug!( - verifier, - promoted, - "bad promoted type ({:?}: {:?}): {:?}", - ty, - san_ty, - terr - ); - }; - }; - - let promoted_body = &self.promoted[promoted]; - self.sanitize_promoted(promoted_body, location); - - let promoted_ty = promoted_body.return_ty(); - check_err(self, promoted_body, ty, promoted_ty); - } else { - self.cx.ascribe_user_type( - constant.const_.ty(), - UserType::TypeOf(uv.def, UserArgs { args: uv.args, user_self_ty: None }), - locations.span(self.cx.body), - ); - } - } else if let Some(static_def_id) = constant.check_static_ptr(tcx) { - let unnormalized_ty = tcx.type_of(static_def_id).instantiate_identity(); - let normalized_ty = self.cx.normalize(unnormalized_ty, locations); - let literal_ty = constant.const_.ty().builtin_deref(true).unwrap().ty; - - if let Err(terr) = self.cx.eq_types( - literal_ty, - normalized_ty, - locations, - ConstraintCategory::Boring, - ) { - span_mirbug!(self, constant, "bad static type {:?} ({:?})", constant, terr); - } - } - - if let ty::FnDef(def_id, args) = *constant.const_.ty().kind() { - let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, args); - self.cx.normalize_and_prove_instantiated_predicates( - def_id, - instantiated_predicates, - locations, - ); - - assert!(!matches!( - tcx.impl_of_method(def_id).map(|imp| tcx.def_kind(imp)), - Some(DefKind::Impl { of_trait: true }) - )); - self.cx.prove_predicates( - args.types().map(|ty| ty::ClauseKind::WellFormed(ty.into())), - locations, - ConstraintCategory::Boring, - ); - } - } - } - - fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { - self.super_rvalue(rvalue, location); - let rval_ty = rvalue.ty(self.body(), self.tcx()); - self.sanitize_type(rvalue, rval_ty); - } - - fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) { - self.super_local_decl(local, local_decl); - self.sanitize_type(local_decl, local_decl.ty); - - if let Some(user_ty) = &local_decl.user_ty { - for (user_ty, span) in user_ty.projections_and_spans() { - let ty = if !local_decl.is_nonref_binding() { - // If we have a binding of the form `let ref x: T = ..` - // then remove the outermost reference so we can check the - // type annotation for the remaining type. - if let ty::Ref(_, rty, _) = local_decl.ty.kind() { - *rty - } else { - bug!("{:?} with ref binding has wrong type {}", local, local_decl.ty); - } - } else { - local_decl.ty - }; - - if let Err(terr) = self.cx.relate_type_and_user_type( - ty, - ty::Variance::Invariant, - user_ty, - Locations::All(*span), - ConstraintCategory::TypeAnnotation, - ) { - span_mirbug!( - self, - local, - "bad user type on variable {:?}: {:?} != {:?} ({:?})", - local, - local_decl.ty, - local_decl.user_ty, - terr, - ); - } - } - } - } - - fn visit_body(&mut self, body: &Body<'tcx>) { - self.sanitize_type(&"return type", body.return_ty()); - // The types of local_decls are checked above which is called in super_body. - self.super_body(body); - } -} - -impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { - fn new( - cx: &'a mut TypeChecker<'b, 'tcx>, - promoted: &'b IndexSlice>, - ) -> Self { - TypeVerifier { promoted, last_span: cx.body.span, cx } - } - - fn body(&self) -> &Body<'tcx> { - self.cx.body - } - - fn tcx(&self) -> TyCtxt<'tcx> { - self.cx.infcx.tcx - } - - fn sanitize_type(&mut self, parent: &dyn fmt::Debug, ty: Ty<'tcx>) -> Ty<'tcx> { - if ty.has_escaping_bound_vars() || ty.references_error() { - span_mirbug_and_err!(self, parent, "bad type {:?}", ty) - } else { - ty - } - } - - /// Checks that the types internal to the `place` match up with - /// what would be expected. - #[instrument(level = "debug", skip(self, location), ret)] - fn sanitize_place( - &mut self, - place: &Place<'tcx>, - location: Location, - context: PlaceContext, - ) -> PlaceTy<'tcx> { - let mut place_ty = PlaceTy::from_ty(self.body().local_decls[place.local].ty); - - for elem in place.projection.iter() { - if place_ty.variant_index.is_none() { - if let Err(guar) = place_ty.ty.error_reported() { - return PlaceTy::from_ty(Ty::new_error(self.tcx(), guar)); - } - } - place_ty = self.sanitize_projection(place_ty, elem, place, location, context); - } - - if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context { - let tcx = self.tcx(); - let trait_ref = - ty::TraitRef::from_lang_item(tcx, LangItem::Copy, self.last_span, [place_ty.ty]); - - // To have a `Copy` operand, the type `T` of the - // value must be `Copy`. Note that we prove that `T: Copy`, - // rather than using the `is_copy_modulo_regions` - // test. This is important because - // `is_copy_modulo_regions` ignores the resulting region - // obligations and assumes they pass. This can result in - // bounds from `Copy` impls being unsoundly ignored (e.g., - // #29149). Note that we decide to use `Copy` before knowing - // whether the bounds fully apply: in effect, the rule is - // that if a value of some type could implement `Copy`, then - // it must. - self.cx.prove_trait_ref( - trait_ref, - location.to_locations(), - ConstraintCategory::CopyBound, - ); - } - - place_ty - } - - fn sanitize_promoted(&mut self, promoted_body: &'b Body<'tcx>, location: Location) { - // Determine the constraints from the promoted MIR by running the type - // checker on the promoted MIR, then transfer the constraints back to - // the main MIR, changing the locations to the provided location. - - let parent_body = mem::replace(&mut self.cx.body, promoted_body); - - // Use new sets of constraints and closure bounds so that we can - // modify their locations. - let all_facts = &mut None; - let mut constraints = Default::default(); - let mut liveness_constraints = - LivenessValues::without_specific_points(Rc::new(DenseLocationMap::new(promoted_body))); - // Don't try to add borrow_region facts for the promoted MIR - - let mut swap_constraints = |this: &mut Self| { - mem::swap(this.cx.borrowck_context.all_facts, all_facts); - mem::swap( - &mut this.cx.borrowck_context.constraints.outlives_constraints, - &mut constraints, - ); - mem::swap( - &mut this.cx.borrowck_context.constraints.liveness_constraints, - &mut liveness_constraints, - ); - }; - - swap_constraints(self); - - self.visit_body(promoted_body); - - self.cx.typeck_mir(promoted_body); - - self.cx.body = parent_body; - // Merge the outlives constraints back in, at the given location. - swap_constraints(self); - - let locations = location.to_locations(); - for constraint in constraints.outlives().iter() { - let mut constraint = *constraint; - constraint.locations = locations; - if let ConstraintCategory::Return(_) - | ConstraintCategory::UseAsConst - | ConstraintCategory::UseAsStatic = constraint.category - { - // "Returning" from a promoted is an assignment to a - // temporary from the user's point of view. - constraint.category = ConstraintCategory::Boring; - } - self.cx.borrowck_context.constraints.outlives_constraints.push(constraint) - } - // If the region is live at least one location in the promoted MIR, - // then add a liveness constraint to the main MIR for this region - // at the location provided as an argument to this method - // - // add_location doesn't care about ordering so not a problem for the live regions to be - // unordered. - #[allow(rustc::potential_query_instability)] - for region in liveness_constraints.live_regions_unordered() { - self.cx - .borrowck_context - .constraints - .liveness_constraints - .add_location(region, location); - } - } - - #[instrument(skip(self, location), ret, level = "debug")] - fn sanitize_projection( - &mut self, - base: PlaceTy<'tcx>, - pi: PlaceElem<'tcx>, - place: &Place<'tcx>, - location: Location, - context: PlaceContext, - ) -> PlaceTy<'tcx> { - let tcx = self.tcx(); - let base_ty = base.ty; - match pi { - ProjectionElem::Deref => { - let deref_ty = base_ty.builtin_deref(true); - PlaceTy::from_ty(deref_ty.map(|t| t.ty).unwrap_or_else(|| { - span_mirbug_and_err!(self, place, "deref of non-pointer {:?}", base_ty) - })) - } - ProjectionElem::Index(i) => { - let index_ty = Place::from(i).ty(self.body(), tcx).ty; - if index_ty != tcx.types.usize { - PlaceTy::from_ty(span_mirbug_and_err!(self, i, "index by non-usize {:?}", i)) - } else { - PlaceTy::from_ty(base_ty.builtin_index().unwrap_or_else(|| { - span_mirbug_and_err!(self, place, "index of non-array {:?}", base_ty) - })) - } - } - ProjectionElem::ConstantIndex { .. } => { - // consider verifying in-bounds - PlaceTy::from_ty(base_ty.builtin_index().unwrap_or_else(|| { - span_mirbug_and_err!(self, place, "index of non-array {:?}", base_ty) - })) - } - ProjectionElem::Subslice { from, to, from_end } => { - PlaceTy::from_ty(match base_ty.kind() { - ty::Array(inner, _) => { - assert!(!from_end, "array subslices should not use from_end"); - Ty::new_array(tcx, *inner, to - from) - } - ty::Slice(..) => { - assert!(from_end, "slice subslices should use from_end"); - base_ty - } - _ => span_mirbug_and_err!(self, place, "slice of non-array {:?}", base_ty), - }) - } - ProjectionElem::Downcast(maybe_name, index) => match base_ty.kind() { - ty::Adt(adt_def, _args) if adt_def.is_enum() => { - if index.as_usize() >= adt_def.variants().len() { - PlaceTy::from_ty(span_mirbug_and_err!( - self, - place, - "cast to variant #{:?} but enum only has {:?}", - index, - adt_def.variants().len() - )) - } else { - PlaceTy { ty: base_ty, variant_index: Some(index) } - } - } - // We do not need to handle coroutines here, because this runs - // before the coroutine transform stage. - _ => { - let ty = if let Some(name) = maybe_name { - span_mirbug_and_err!( - self, - place, - "can't downcast {:?} as {:?}", - base_ty, - name - ) - } else { - span_mirbug_and_err!(self, place, "can't downcast {:?}", base_ty) - }; - PlaceTy::from_ty(ty) - } - }, - ProjectionElem::Field(field, fty) => { - let fty = self.sanitize_type(place, fty); - let fty = self.cx.normalize(fty, location); - match self.field_ty(place, base, field, location) { - Ok(ty) => { - let ty = self.cx.normalize(ty, location); - debug!(?fty, ?ty); - - if let Err(terr) = self.cx.relate_types( - ty, - self.get_ambient_variance(context), - fty, - location.to_locations(), - ConstraintCategory::Boring, - ) { - span_mirbug!( - self, - place, - "bad field access ({:?}: {:?}): {:?}", - ty, - fty, - terr - ); - } - } - Err(FieldAccessError::OutOfRange { field_count }) => span_mirbug!( - self, - place, - "accessed field #{} but variant only has {}", - field.index(), - field_count - ), - } - PlaceTy::from_ty(fty) - } - ProjectionElem::Subtype(_) => { - bug!("ProjectionElem::Subtype shouldn't exist in borrowck") - } - ProjectionElem::OpaqueCast(ty) => { - let ty = self.sanitize_type(place, ty); - let ty = self.cx.normalize(ty, location); - self.cx - .relate_types( - ty, - self.get_ambient_variance(context), - base.ty, - location.to_locations(), - ConstraintCategory::TypeAnnotation, - ) - .unwrap(); - PlaceTy::from_ty(ty) - } - } - } - - fn error(&mut self) -> Ty<'tcx> { - Ty::new_misc_error(self.tcx()) - } - - fn get_ambient_variance(&self, context: PlaceContext) -> ty::Variance { - use rustc_middle::mir::visit::NonMutatingUseContext::*; - use rustc_middle::mir::visit::NonUseContext::*; - - match context { - PlaceContext::MutatingUse(_) => ty::Invariant, - PlaceContext::NonUse(StorageDead | StorageLive | VarDebugInfo) => ty::Invariant, - PlaceContext::NonMutatingUse( - Inspect | Copy | Move | PlaceMention | SharedBorrow | FakeBorrow | AddressOf - | Projection, - ) => ty::Covariant, - PlaceContext::NonUse(AscribeUserTy(variance)) => variance, - } - } - - fn field_ty( - &mut self, - parent: &dyn fmt::Debug, - base_ty: PlaceTy<'tcx>, - field: FieldIdx, - location: Location, - ) -> Result, FieldAccessError> { - let tcx = self.tcx(); - - let (variant, args) = match base_ty { - PlaceTy { ty, variant_index: Some(variant_index) } => match *ty.kind() { - ty::Adt(adt_def, args) => (adt_def.variant(variant_index), args), - ty::Coroutine(def_id, args) => { - let mut variants = args.as_coroutine().state_tys(def_id, tcx); - let Some(mut variant) = variants.nth(variant_index.into()) else { - bug!( - "variant_index of coroutine out of range: {:?}/{:?}", - variant_index, - args.as_coroutine().state_tys(def_id, tcx).count() - ); - }; - return match variant.nth(field.index()) { - Some(ty) => Ok(ty), - None => Err(FieldAccessError::OutOfRange { field_count: variant.count() }), - }; - } - _ => bug!("can't have downcast of non-adt non-coroutine type"), - }, - PlaceTy { ty, variant_index: None } => match *ty.kind() { - ty::Adt(adt_def, args) if !adt_def.is_enum() => { - (adt_def.variant(FIRST_VARIANT), args) - } - ty::Closure(_, args) => { - return match args.as_closure().upvar_tys().get(field.index()) { - Some(&ty) => Ok(ty), - None => Err(FieldAccessError::OutOfRange { - field_count: args.as_closure().upvar_tys().len(), - }), - }; - } - ty::CoroutineClosure(_, args) => { - return match args.as_coroutine_closure().upvar_tys().get(field.index()) { - Some(&ty) => Ok(ty), - None => Err(FieldAccessError::OutOfRange { - field_count: args.as_coroutine_closure().upvar_tys().len(), - }), - }; - } - ty::Coroutine(_, args) => { - // Only prefix fields (upvars and current state) are - // accessible without a variant index. - return match args.as_coroutine().prefix_tys().get(field.index()) { - Some(ty) => Ok(*ty), - None => Err(FieldAccessError::OutOfRange { - field_count: args.as_coroutine().prefix_tys().len(), - }), - }; - } - ty::Tuple(tys) => { - return match tys.get(field.index()) { - Some(&ty) => Ok(ty), - None => Err(FieldAccessError::OutOfRange { field_count: tys.len() }), - }; - } - _ => { - return Ok(span_mirbug_and_err!( - self, - parent, - "can't project out of {:?}", - base_ty - )); - } - }, - }; - - if let Some(field) = variant.fields.get(field) { - Ok(self.cx.normalize(field.ty(tcx, args), location)) - } else { - Err(FieldAccessError::OutOfRange { field_count: variant.fields.len() }) - } - } -} - -/// The MIR type checker. Visits the MIR and enforces all the -/// constraints needed for it to be valid and well-typed. Along the -/// way, it accrues region constraints -- these can later be used by -/// NLL region checking. -struct TypeChecker<'a, 'tcx> { - infcx: &'a BorrowckInferCtxt<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - last_span: Span, - body: &'a Body<'tcx>, - /// User type annotations are shared between the main MIR and the MIR of - /// all of the promoted items. - user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>, - region_bound_pairs: &'a RegionBoundPairs<'tcx>, - known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>], - implicit_region_bound: ty::Region<'tcx>, - reported_errors: FxIndexSet<(Ty<'tcx>, Span)>, - borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, -} - -struct BorrowCheckContext<'a, 'tcx> { - pub(crate) universal_regions: &'a UniversalRegions<'tcx>, - location_table: &'a LocationTable, - all_facts: &'a mut Option, - borrow_set: &'a BorrowSet<'tcx>, - pub(crate) constraints: &'a mut MirTypeckRegionConstraints<'tcx>, - upvars: &'a [&'a ty::CapturedPlace<'tcx>], -} - -/// Holder struct for passing results from MIR typeck to the rest of the non-lexical regions -/// inference computation. -pub(crate) struct MirTypeckResults<'tcx> { - pub(crate) constraints: MirTypeckRegionConstraints<'tcx>, - pub(crate) universal_region_relations: Frozen>, - pub(crate) opaque_type_values: FxIndexMap, OpaqueHiddenType<'tcx>>, -} - -/// A collection of region constraints that must be satisfied for the -/// program to be considered well-typed. -pub(crate) struct MirTypeckRegionConstraints<'tcx> { - /// Maps from a `ty::Placeholder` to the corresponding - /// `PlaceholderIndex` bit that we will use for it. - /// - /// To keep everything in sync, do not insert this set - /// directly. Instead, use the `placeholder_region` helper. - pub(crate) placeholder_indices: PlaceholderIndices, - - /// Each time we add a placeholder to `placeholder_indices`, we - /// also create a corresponding "representative" region vid for - /// that wraps it. This vector tracks those. This way, when we - /// convert the same `ty::RePlaceholder(p)` twice, we can map to - /// the same underlying `RegionVid`. - pub(crate) placeholder_index_to_region: IndexVec>, - - /// In general, the type-checker is not responsible for enforcing - /// liveness constraints; this job falls to the region inferencer, - /// which performs a liveness analysis. However, in some limited - /// cases, the MIR type-checker creates temporary regions that do - /// not otherwise appear in the MIR -- in particular, the - /// late-bound regions that it instantiates at call-sites -- and - /// hence it must report on their liveness constraints. - pub(crate) liveness_constraints: LivenessValues, - - pub(crate) outlives_constraints: OutlivesConstraintSet<'tcx>, - - pub(crate) member_constraints: MemberConstraintSet<'tcx, RegionVid>, - - pub(crate) universe_causes: FxIndexMap>, - - pub(crate) type_tests: Vec>, -} - -impl<'tcx> MirTypeckRegionConstraints<'tcx> { - /// Creates a `Region` for a given `PlaceholderRegion`, or returns the - /// region that corresponds to a previously created one. - fn placeholder_region( - &mut self, - infcx: &InferCtxt<'tcx>, - placeholder: ty::PlaceholderRegion, - ) -> ty::Region<'tcx> { - let placeholder_index = self.placeholder_indices.insert(placeholder); - match self.placeholder_index_to_region.get(placeholder_index) { - Some(&v) => v, - None => { - let origin = NllRegionVariableOrigin::Placeholder(placeholder); - let region = infcx.next_nll_region_var_in_universe(origin, placeholder.universe); - self.placeholder_index_to_region.push(region); - region - } - } - } -} - -/// The `Locations` type summarizes *where* region constraints are -/// required to hold. Normally, this is at a particular point which -/// created the obligation, but for constraints that the user gave, we -/// want the constraint to hold at all points. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -pub enum Locations { - /// Indicates that a type constraint should always be true. This - /// is particularly important in the new borrowck analysis for - /// things like the type of the return slot. Consider this - /// example: - /// - /// ```compile_fail,E0515 - /// fn foo<'a>(x: &'a u32) -> &'a u32 { - /// let y = 22; - /// return &y; // error - /// } - /// ``` - /// - /// Here, we wind up with the signature from the return type being - /// something like `&'1 u32` where `'1` is a universal region. But - /// the type of the return slot `_0` is something like `&'2 u32` - /// where `'2` is an existential region variable. The type checker - /// requires that `&'2 u32 = &'1 u32` -- but at what point? In the - /// older NLL analysis, we required this only at the entry point - /// to the function. By the nature of the constraints, this wound - /// up propagating to all points reachable from start (because - /// `'1` -- as a universal region -- is live everywhere). In the - /// newer analysis, though, this doesn't work: `_0` is considered - /// dead at the start (it has no usable value) and hence this type - /// equality is basically a no-op. Then, later on, when we do `_0 - /// = &'3 y`, that region `'3` never winds up related to the - /// universal region `'1` and hence no error occurs. Therefore, we - /// use Locations::All instead, which ensures that the `'1` and - /// `'2` are equal everything. We also use this for other - /// user-given type annotations; e.g., if the user wrote `let mut - /// x: &'static u32 = ...`, we would ensure that all values - /// assigned to `x` are of `'static` lifetime. - /// - /// The span points to the place the constraint arose. For example, - /// it points to the type in a user-given type annotation. If - /// there's no sensible span then it's DUMMY_SP. - All(Span), - - /// An outlives constraint that only has to hold at a single location, - /// usually it represents a point where references flow from one spot to - /// another (e.g., `x = y`) - Single(Location), -} - -impl Locations { - pub fn from_location(&self) -> Option { - match self { - Locations::All(_) => None, - Locations::Single(from_location) => Some(*from_location), - } - } - - /// Gets a span representing the location. - pub fn span(&self, body: &Body<'_>) -> Span { - match self { - Locations::All(span) => *span, - Locations::Single(l) => body.source_info(*l).span, - } - } -} - -impl<'a, 'tcx> TypeChecker<'a, 'tcx> { - fn new( - infcx: &'a BorrowckInferCtxt<'a, 'tcx>, - body: &'a Body<'tcx>, - param_env: ty::ParamEnv<'tcx>, - region_bound_pairs: &'a RegionBoundPairs<'tcx>, - known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>], - implicit_region_bound: ty::Region<'tcx>, - borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, - ) -> Self { - let mut checker = Self { - infcx, - last_span: body.span, - body, - user_type_annotations: &body.user_type_annotations, - param_env, - region_bound_pairs, - known_type_outlives_obligations, - implicit_region_bound, - borrowck_context, - reported_errors: Default::default(), - }; - - // FIXME(-Znext-solver): A bit dubious that we're only registering - // predefined opaques in the typeck root. - if infcx.next_trait_solver() && !infcx.tcx.is_typeck_child(body.source.def_id()) { - checker.register_predefined_opaques_for_next_solver(); - } - - checker - } - - pub(super) fn register_predefined_opaques_for_next_solver(&mut self) { - // OK to use the identity arguments for each opaque type key, since - // we remap opaques from HIR typeck back to their definition params. - let opaques: Vec<_> = self - .infcx - .tcx - .typeck(self.body.source.def_id().expect_local()) - .concrete_opaque_types - .iter() - .map(|(k, v)| (*k, *v)) - .collect(); - - let renumbered_opaques = self.infcx.tcx.fold_regions(opaques, |_, _| { - self.infcx.next_nll_region_var_in_universe( - NllRegionVariableOrigin::Existential { from_forall: false }, - ty::UniverseIndex::ROOT, - ) - }); - - let param_env = self.param_env; - let result = self.fully_perform_op( - Locations::All(self.body.span), - ConstraintCategory::OpaqueType, - CustomTypeOp::new( - |ocx| { - let mut obligations = Vec::new(); - for (opaque_type_key, hidden_ty) in renumbered_opaques { - let cause = ObligationCause::dummy(); - ocx.infcx.insert_hidden_type( - opaque_type_key, - &cause, - param_env, - hidden_ty.ty, - &mut obligations, - )?; - - ocx.infcx.add_item_bounds_for_hidden_type( - opaque_type_key.def_id.to_def_id(), - opaque_type_key.args, - cause, - param_env, - hidden_ty.ty, - &mut obligations, - ); - } - - ocx.register_obligations(obligations); - Ok(()) - }, - "register pre-defined opaques", - ), - ); - - if result.is_err() { - self.infcx - .dcx() - .span_bug(self.body.span, "failed re-defining predefined opaques in mir typeck"); - } - } - - fn body(&self) -> &Body<'tcx> { - self.body - } - - fn unsized_feature_enabled(&self) -> bool { - let features = self.tcx().features(); - features.unsized_locals || features.unsized_fn_params - } - - /// Equate the inferred type and the annotated type for user type annotations - #[instrument(skip(self), level = "debug")] - fn check_user_type_annotations(&mut self) { - debug!(?self.user_type_annotations); - let tcx = self.tcx(); - for user_annotation in self.user_type_annotations { - let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation; - let annotation = self.instantiate_canonical(span, user_ty); - if let ty::UserType::TypeOf(def, args) = annotation - && let DefKind::InlineConst = tcx.def_kind(def) - { - self.check_inline_const(inferred_ty, def.expect_local(), args, span); - } else { - self.ascribe_user_type(inferred_ty, annotation, span); - } - } - } - - #[instrument(skip(self, data), level = "debug")] - fn push_region_constraints( - &mut self, - locations: Locations, - category: ConstraintCategory<'tcx>, - data: &QueryRegionConstraints<'tcx>, - ) { - debug!("constraints generated: {:#?}", data); - - constraint_conversion::ConstraintConversion::new( - self.infcx, - self.borrowck_context.universal_regions, - self.region_bound_pairs, - self.implicit_region_bound, - self.param_env, - self.known_type_outlives_obligations, - locations, - locations.span(self.body), - category, - self.borrowck_context.constraints, - ) - .convert_all(data); - } - - /// Try to relate `sub <: sup` - fn sub_types( - &mut self, - sub: Ty<'tcx>, - sup: Ty<'tcx>, - locations: Locations, - category: ConstraintCategory<'tcx>, - ) -> Result<(), NoSolution> { - // Use this order of parameters because the sup type is usually the - // "expected" type in diagnostics. - self.relate_types(sup, ty::Variance::Contravariant, sub, locations, category) - } - - #[instrument(skip(self, category), level = "debug")] - fn eq_types( - &mut self, - expected: Ty<'tcx>, - found: Ty<'tcx>, - locations: Locations, - category: ConstraintCategory<'tcx>, - ) -> Result<(), NoSolution> { - self.relate_types(expected, ty::Variance::Invariant, found, locations, category) - } - - #[instrument(skip(self), level = "debug")] - fn relate_type_and_user_type( - &mut self, - a: Ty<'tcx>, - v: ty::Variance, - user_ty: &UserTypeProjection, - locations: Locations, - category: ConstraintCategory<'tcx>, - ) -> Result<(), NoSolution> { - let annotated_type = self.user_type_annotations[user_ty.base].inferred_ty; - trace!(?annotated_type); - let mut curr_projected_ty = PlaceTy::from_ty(annotated_type); - - let tcx = self.infcx.tcx; - - for proj in &user_ty.projs { - if let ty::Alias(ty::Opaque, ..) = curr_projected_ty.ty.kind() { - // There is nothing that we can compare here if we go through an opaque type. - // We're always in its defining scope as we can otherwise not project through - // it, so we're constraining it anyways. - return Ok(()); - } - let projected_ty = curr_projected_ty.projection_ty_core( - tcx, - self.param_env, - proj, - |this, field, ()| { - let ty = this.field_ty(tcx, field); - self.normalize(ty, locations) - }, - |_, _| unreachable!(), - ); - curr_projected_ty = projected_ty; - } - trace!(?curr_projected_ty); - - let ty = curr_projected_ty.ty; - self.relate_types(ty, v.xform(ty::Variance::Contravariant), a, locations, category)?; - - Ok(()) - } - - fn check_inline_const( - &mut self, - inferred_ty: Ty<'tcx>, - def_id: LocalDefId, - args: UserArgs<'tcx>, - span: Span, - ) { - assert!(args.user_self_ty.is_none()); - let tcx = self.tcx(); - let const_ty = tcx.type_of(def_id).instantiate(tcx, args.args); - if let Err(terr) = - self.eq_types(const_ty, inferred_ty, Locations::All(span), ConstraintCategory::Boring) - { - span_bug!( - span, - "bad inline const pattern: ({:?} = {:?}) {:?}", - const_ty, - inferred_ty, - terr - ); - } - let args = self.infcx.resolve_vars_if_possible(args.args); - let predicates = self.prove_closure_bounds(tcx, def_id, args, Locations::All(span)); - self.normalize_and_prove_instantiated_predicates( - def_id.to_def_id(), - predicates, - Locations::All(span), - ); - } - - fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - #[instrument(skip(self, body), level = "debug")] - fn check_stmt(&mut self, body: &Body<'tcx>, stmt: &Statement<'tcx>, location: Location) { - let tcx = self.tcx(); - debug!("stmt kind: {:?}", stmt.kind); - match &stmt.kind { - StatementKind::Assign(box (place, rv)) => { - // Assignments to temporaries are not "interesting"; - // they are not caused by the user, but rather artifacts - // of lowering. Assignments to other sorts of places *are* interesting - // though. - let category = match place.as_local() { - Some(RETURN_PLACE) => { - let defining_ty = &self.borrowck_context.universal_regions.defining_ty; - if defining_ty.is_const() { - if tcx.is_static(defining_ty.def_id()) { - ConstraintCategory::UseAsStatic - } else { - ConstraintCategory::UseAsConst - } - } else { - ConstraintCategory::Return(ReturnConstraint::Normal) - } - } - Some(l) - if matches!(body.local_decls[l].local_info(), LocalInfo::AggregateTemp) => - { - ConstraintCategory::Usage - } - Some(l) if !body.local_decls[l].is_user_variable() => { - ConstraintCategory::Boring - } - _ => ConstraintCategory::Assignment, - }; - debug!( - "assignment category: {:?} {:?}", - category, - place.as_local().map(|l| &body.local_decls[l]) - ); - - let place_ty = place.ty(body, tcx).ty; - debug!(?place_ty); - let place_ty = self.normalize(place_ty, location); - debug!("place_ty normalized: {:?}", place_ty); - let rv_ty = rv.ty(body, tcx); - debug!(?rv_ty); - let rv_ty = self.normalize(rv_ty, location); - debug!("normalized rv_ty: {:?}", rv_ty); - if let Err(terr) = - self.sub_types(rv_ty, place_ty, location.to_locations(), category) - { - span_mirbug!( - self, - stmt, - "bad assignment ({:?} = {:?}): {:?}", - place_ty, - rv_ty, - terr - ); - } - - if let Some(annotation_index) = self.rvalue_user_ty(rv) { - if let Err(terr) = self.relate_type_and_user_type( - rv_ty, - ty::Variance::Invariant, - &UserTypeProjection { base: annotation_index, projs: vec![] }, - location.to_locations(), - ConstraintCategory::Boring, - ) { - let annotation = &self.user_type_annotations[annotation_index]; - span_mirbug!( - self, - stmt, - "bad user type on rvalue ({:?} = {:?}): {:?}", - annotation, - rv_ty, - terr - ); - } - } - - self.check_rvalue(body, rv, location); - if !self.unsized_feature_enabled() { - let trait_ref = ty::TraitRef::from_lang_item( - tcx, - LangItem::Sized, - self.last_span, - [place_ty], - ); - self.prove_trait_ref( - trait_ref, - location.to_locations(), - ConstraintCategory::SizedBound, - ); - } - } - StatementKind::AscribeUserType(box (place, projection), variance) => { - let place_ty = place.ty(body, tcx).ty; - if let Err(terr) = self.relate_type_and_user_type( - place_ty, - *variance, - projection, - Locations::All(stmt.source_info.span), - ConstraintCategory::TypeAnnotation, - ) { - let annotation = &self.user_type_annotations[projection.base]; - span_mirbug!( - self, - stmt, - "bad type assert ({:?} <: {:?} with projections {:?}): {:?}", - place_ty, - annotation, - projection.projs, - terr - ); - } - } - StatementKind::Intrinsic(box kind) => match kind { - NonDivergingIntrinsic::Assume(op) => self.check_operand(op, location), - NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!( - stmt.source_info.span, - "Unexpected NonDivergingIntrinsic::CopyNonOverlapping, should only appear after lowering_intrinsics", - ), - }, - StatementKind::FakeRead(..) - | StatementKind::StorageLive(..) - | StatementKind::StorageDead(..) - | StatementKind::Retag { .. } - | StatementKind::Coverage(..) - | StatementKind::ConstEvalCounter - | StatementKind::PlaceMention(..) - | StatementKind::Nop => {} - StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => { - bug!("Statement not allowed in this MIR phase") - } - } - } - - #[instrument(skip(self, body, term_location), level = "debug")] - fn check_terminator( - &mut self, - body: &Body<'tcx>, - term: &Terminator<'tcx>, - term_location: Location, - ) { - let tcx = self.tcx(); - debug!("terminator kind: {:?}", term.kind); - match &term.kind { - TerminatorKind::Goto { .. } - | TerminatorKind::UnwindResume - | TerminatorKind::UnwindTerminate(_) - | TerminatorKind::Return - | TerminatorKind::CoroutineDrop - | TerminatorKind::Unreachable - | TerminatorKind::Drop { .. } - | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::InlineAsm { .. } => { - // no checks needed for these - } - - TerminatorKind::SwitchInt { discr, .. } => { - self.check_operand(discr, term_location); - - let switch_ty = discr.ty(body, tcx); - if !switch_ty.is_integral() && !switch_ty.is_char() && !switch_ty.is_bool() { - span_mirbug!(self, term, "bad SwitchInt discr ty {:?}", switch_ty); - } - // FIXME: check the values - } - TerminatorKind::Call { func, args, destination, call_source, target, .. } => { - self.check_operand(func, term_location); - for arg in args { - self.check_operand(&arg.node, term_location); - } - - let func_ty = func.ty(body, tcx); - debug!("func_ty.kind: {:?}", func_ty.kind()); - - let sig = match func_ty.kind() { - ty::FnDef(..) | ty::FnPtr(_) => func_ty.fn_sig(tcx), - _ => { - span_mirbug!(self, term, "call to non-function {:?}", func_ty); - return; - } - }; - let (unnormalized_sig, map) = tcx.instantiate_bound_regions(sig, |br| { - use crate::renumber::RegionCtxt; - - let region_ctxt_fn = || { - let reg_info = match br.kind { - ty::BoundRegionKind::BrAnon => sym::anon, - ty::BoundRegionKind::BrNamed(_, name) => name, - ty::BoundRegionKind::BrEnv => sym::env, - }; - - RegionCtxt::LateBound(reg_info) - }; - - self.infcx.next_region_var( - BoundRegion( - term.source_info.span, - br.kind, - BoundRegionConversionTime::FnCall, - ), - region_ctxt_fn, - ) - }); - debug!(?unnormalized_sig); - // IMPORTANT: We have to prove well formed for the function signature before - // we normalize it, as otherwise types like `<&'a &'b () as Trait>::Assoc` - // get normalized away, causing us to ignore the `'b: 'a` bound used by the function. - // - // Normalization results in a well formed type if the input is well formed, so we - // don't have to check it twice. - // - // See #91068 for an example. - self.prove_predicates( - unnormalized_sig.inputs_and_output.iter().map(|ty| { - ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed( - ty.into(), - ))) - }), - term_location.to_locations(), - ConstraintCategory::Boring, - ); - - let sig = self.normalize(unnormalized_sig, term_location); - // HACK(#114936): `WF(sig)` does not imply `WF(normalized(sig))` - // with built-in `Fn` implementations, since the impl may not be - // well-formed itself. - if sig != unnormalized_sig { - self.prove_predicates( - sig.inputs_and_output.iter().map(|ty| { - ty::Binder::dummy(ty::PredicateKind::Clause( - ty::ClauseKind::WellFormed(ty.into()), - )) - }), - term_location.to_locations(), - ConstraintCategory::Boring, - ); - } - - self.check_call_dest(body, term, &sig, *destination, *target, term_location); - - // The ordinary liveness rules will ensure that all - // regions in the type of the callee are live here. We - // then further constrain the late-bound regions that - // were instantiated at the call site to be live as - // well. The resulting is that all the input (and - // output) types in the signature must be live, since - // all the inputs that fed into it were live. - for &late_bound_region in map.values() { - let region_vid = - self.borrowck_context.universal_regions.to_region_vid(late_bound_region); - self.borrowck_context - .constraints - .liveness_constraints - .add_location(region_vid, term_location); - } - - self.check_call_inputs(body, term, func, &sig, args, term_location, *call_source); - } - TerminatorKind::Assert { cond, msg, .. } => { - self.check_operand(cond, term_location); - - let cond_ty = cond.ty(body, tcx); - if cond_ty != tcx.types.bool { - span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty); - } - - if let AssertKind::BoundsCheck { len, index } = &**msg { - if len.ty(body, tcx) != tcx.types.usize { - span_mirbug!(self, len, "bounds-check length non-usize {:?}", len) - } - if index.ty(body, tcx) != tcx.types.usize { - span_mirbug!(self, index, "bounds-check index non-usize {:?}", index) - } - } - } - TerminatorKind::Yield { value, resume_arg, .. } => { - self.check_operand(value, term_location); - - match body.yield_ty() { - None => span_mirbug!(self, term, "yield in non-coroutine"), - Some(ty) => { - let value_ty = value.ty(body, tcx); - if let Err(terr) = self.sub_types( - value_ty, - ty, - term_location.to_locations(), - ConstraintCategory::Yield, - ) { - span_mirbug!( - self, - term, - "type of yield value is {:?}, but the yield type is {:?}: {:?}", - value_ty, - ty, - terr - ); - } - } - } - - match body.resume_ty() { - None => span_mirbug!(self, term, "yield in non-coroutine"), - Some(ty) => { - let resume_ty = resume_arg.ty(body, tcx); - if let Err(terr) = self.sub_types( - ty, - resume_ty.ty, - term_location.to_locations(), - ConstraintCategory::Yield, - ) { - span_mirbug!( - self, - term, - "type of resume place is {:?}, but the resume type is {:?}: {:?}", - resume_ty, - ty, - terr - ); - } - } - } - } - } - } - - fn check_call_dest( - &mut self, - body: &Body<'tcx>, - term: &Terminator<'tcx>, - sig: &ty::FnSig<'tcx>, - destination: Place<'tcx>, - target: Option, - term_location: Location, - ) { - let tcx = self.tcx(); - match target { - Some(_) => { - let dest_ty = destination.ty(body, tcx).ty; - let dest_ty = self.normalize(dest_ty, term_location); - let category = match destination.as_local() { - Some(RETURN_PLACE) => { - if let BorrowCheckContext { - universal_regions: - UniversalRegions { - defining_ty: - DefiningTy::Const(def_id, _) - | DefiningTy::InlineConst(def_id, _), - .. - }, - .. - } = self.borrowck_context - { - if tcx.is_static(*def_id) { - ConstraintCategory::UseAsStatic - } else { - ConstraintCategory::UseAsConst - } - } else { - ConstraintCategory::Return(ReturnConstraint::Normal) - } - } - Some(l) if !body.local_decls[l].is_user_variable() => { - ConstraintCategory::Boring - } - _ => ConstraintCategory::Assignment, - }; - - let locations = term_location.to_locations(); - - if let Err(terr) = self.sub_types(sig.output(), dest_ty, locations, category) { - span_mirbug!( - self, - term, - "call dest mismatch ({:?} <- {:?}): {:?}", - dest_ty, - sig.output(), - terr - ); - } - - // When `unsized_fn_params` and `unsized_locals` are both not enabled, - // this check is done at `check_local`. - if self.unsized_feature_enabled() { - let span = term.source_info.span; - self.ensure_place_sized(dest_ty, span); - } - } - None => { - // The signature in this call can reference region variables, - // so erase them before calling a query. - let output_ty = self.tcx().erase_regions(sig.output()); - if !output_ty.is_privately_uninhabited(self.tcx(), self.param_env) { - span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig); - } - } - } - } - - #[instrument(level = "debug", skip(self, body, term, func, term_location, call_source))] - fn check_call_inputs( - &mut self, - body: &Body<'tcx>, - term: &Terminator<'tcx>, - func: &Operand<'tcx>, - sig: &ty::FnSig<'tcx>, - args: &[Spanned>], - term_location: Location, - call_source: CallSource, - ) { - if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.c_variadic) { - span_mirbug!(self, term, "call to {:?} with wrong # of args", sig); - } - - let func_ty = func.ty(body, self.infcx.tcx); - if let ty::FnDef(def_id, _) = *func_ty.kind() { - // Some of the SIMD intrinsics are special: they need a particular argument to be a constant. - // (Eventually this should use const-generics, but those are not up for the task yet: - // https://github.com/rust-lang/rust/issues/85229.) - if let Some(name @ (sym::simd_shuffle | sym::simd_insert | sym::simd_extract)) = - self.tcx().intrinsic(def_id).map(|i| i.name) - { - let idx = match name { - sym::simd_shuffle => 2, - _ => 1, - }; - if !matches!(args[idx], Spanned { node: Operand::Constant(_), .. }) { - self.tcx().dcx().emit_err(SimdIntrinsicArgConst { - span: term.source_info.span, - arg: idx + 1, - intrinsic: name.to_string(), - }); - } - } - } - debug!(?func_ty); - - for (n, (fn_arg, op_arg)) in iter::zip(sig.inputs(), args).enumerate() { - let op_arg_ty = op_arg.node.ty(body, self.tcx()); - - let op_arg_ty = self.normalize(op_arg_ty, term_location); - let category = if call_source.from_hir_call() { - ConstraintCategory::CallArgument(Some(self.infcx.tcx.erase_regions(func_ty))) - } else { - ConstraintCategory::Boring - }; - if let Err(terr) = - self.sub_types(op_arg_ty, *fn_arg, term_location.to_locations(), category) - { - span_mirbug!( - self, - term, - "bad arg #{:?} ({:?} <- {:?}): {:?}", - n, - fn_arg, - op_arg_ty, - terr - ); - } - } - } - - fn check_iscleanup(&mut self, body: &Body<'tcx>, block_data: &BasicBlockData<'tcx>) { - let is_cleanup = block_data.is_cleanup; - self.last_span = block_data.terminator().source_info.span; - match block_data.terminator().kind { - TerminatorKind::Goto { target } => { - self.assert_iscleanup(body, block_data, target, is_cleanup) - } - TerminatorKind::SwitchInt { ref targets, .. } => { - for target in targets.all_targets() { - self.assert_iscleanup(body, block_data, *target, is_cleanup); - } - } - TerminatorKind::UnwindResume => { - if !is_cleanup { - span_mirbug!(self, block_data, "resume on non-cleanup block!") - } - } - TerminatorKind::UnwindTerminate(_) => { - if !is_cleanup { - span_mirbug!(self, block_data, "terminate on non-cleanup block!") - } - } - TerminatorKind::Return => { - if is_cleanup { - span_mirbug!(self, block_data, "return on cleanup block") - } - } - TerminatorKind::CoroutineDrop { .. } => { - if is_cleanup { - span_mirbug!(self, block_data, "coroutine_drop in cleanup block") - } - } - TerminatorKind::Yield { resume, drop, .. } => { - if is_cleanup { - span_mirbug!(self, block_data, "yield in cleanup block") - } - self.assert_iscleanup(body, block_data, resume, is_cleanup); - if let Some(drop) = drop { - self.assert_iscleanup(body, block_data, drop, is_cleanup); - } - } - TerminatorKind::Unreachable => {} - TerminatorKind::Drop { target, unwind, .. } - | TerminatorKind::Assert { target, unwind, .. } => { - self.assert_iscleanup(body, block_data, target, is_cleanup); - self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup); - } - TerminatorKind::Call { ref target, unwind, .. } => { - if let &Some(target) = target { - self.assert_iscleanup(body, block_data, target, is_cleanup); - } - self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup); - } - TerminatorKind::FalseEdge { real_target, imaginary_target } => { - self.assert_iscleanup(body, block_data, real_target, is_cleanup); - self.assert_iscleanup(body, block_data, imaginary_target, is_cleanup); - } - TerminatorKind::FalseUnwind { real_target, unwind } => { - self.assert_iscleanup(body, block_data, real_target, is_cleanup); - self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup); - } - TerminatorKind::InlineAsm { ref targets, unwind, .. } => { - for &target in targets { - self.assert_iscleanup(body, block_data, target, is_cleanup); - } - self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup); - } - } - } - - fn assert_iscleanup( - &mut self, - body: &Body<'tcx>, - ctxt: &dyn fmt::Debug, - bb: BasicBlock, - iscleanuppad: bool, - ) { - if body[bb].is_cleanup != iscleanuppad { - span_mirbug!(self, ctxt, "cleanuppad mismatch: {:?} should be {:?}", bb, iscleanuppad); - } - } - - fn assert_iscleanup_unwind( - &mut self, - body: &Body<'tcx>, - ctxt: &dyn fmt::Debug, - unwind: UnwindAction, - is_cleanup: bool, - ) { - match unwind { - UnwindAction::Cleanup(unwind) => { - if is_cleanup { - span_mirbug!(self, ctxt, "unwind on cleanup block") - } - self.assert_iscleanup(body, ctxt, unwind, true); - } - UnwindAction::Continue => { - if is_cleanup { - span_mirbug!(self, ctxt, "unwind on cleanup block") - } - } - UnwindAction::Unreachable | UnwindAction::Terminate(_) => (), - } - } - - fn check_local(&mut self, body: &Body<'tcx>, local: Local, local_decl: &LocalDecl<'tcx>) { - match body.local_kind(local) { - LocalKind::ReturnPointer | LocalKind::Arg => { - // return values of normal functions are required to be - // sized by typeck, but return values of ADT constructors are - // not because we don't include a `Self: Sized` bounds on them. - // - // Unbound parts of arguments were never required to be Sized - // - maybe we should make that a warning. - return; - } - LocalKind::Temp => {} - } - - // When `unsized_fn_params` or `unsized_locals` is enabled, only function calls - // and nullary ops are checked in `check_call_dest`. - if !self.unsized_feature_enabled() { - let span = local_decl.source_info.span; - let ty = local_decl.ty; - self.ensure_place_sized(ty, span); - } - } - - fn ensure_place_sized(&mut self, ty: Ty<'tcx>, span: Span) { - let tcx = self.tcx(); - - // Erase the regions from `ty` to get a global type. The - // `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, 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 - // to check all temps, return slots and locals. - if self.reported_errors.replace((ty, span)).is_none() { - // While this is located in `nll::typeck` this error is not - // an NLL error, it's a required check to prevent creation - // of unsized rvalues in a call expression. - self.tcx().dcx().emit_err(MoveUnsized { ty, span }); - } - } - } - - fn aggregate_field_ty( - &mut self, - ak: &AggregateKind<'tcx>, - field_index: FieldIdx, - location: Location, - ) -> Result, FieldAccessError> { - let tcx = self.tcx(); - - match *ak { - AggregateKind::Adt(adt_did, variant_index, args, _, active_field_index) => { - let def = tcx.adt_def(adt_did); - let variant = &def.variant(variant_index); - let adj_field_index = active_field_index.unwrap_or(field_index); - if let Some(field) = variant.fields.get(adj_field_index) { - Ok(self.normalize(field.ty(tcx, args), location)) - } else { - Err(FieldAccessError::OutOfRange { field_count: variant.fields.len() }) - } - } - AggregateKind::Closure(_, args) => { - match args.as_closure().upvar_tys().get(field_index.as_usize()) { - Some(ty) => Ok(*ty), - None => Err(FieldAccessError::OutOfRange { - field_count: args.as_closure().upvar_tys().len(), - }), - } - } - AggregateKind::Coroutine(_, args) => { - // It doesn't make sense to look at a field beyond the prefix; - // these require a variant index, and are not initialized in - // aggregate rvalues. - match args.as_coroutine().prefix_tys().get(field_index.as_usize()) { - Some(ty) => Ok(*ty), - None => Err(FieldAccessError::OutOfRange { - field_count: args.as_coroutine().prefix_tys().len(), - }), - } - } - AggregateKind::CoroutineClosure(_, args) => { - match args.as_coroutine_closure().upvar_tys().get(field_index.as_usize()) { - Some(ty) => Ok(*ty), - None => Err(FieldAccessError::OutOfRange { - field_count: args.as_coroutine_closure().upvar_tys().len(), - }), - } - } - AggregateKind::Array(ty) => Ok(ty), - AggregateKind::Tuple => { - unreachable!("This should have been covered in check_rvalues"); - } - } - } - - fn check_operand(&mut self, op: &Operand<'tcx>, location: Location) { - debug!(?op, ?location, "check_operand"); - - if let Operand::Constant(constant) = op { - let maybe_uneval = match constant.const_ { - Const::Val(..) | Const::Ty(_) => None, - Const::Unevaluated(uv, _) => Some(uv), - }; - - if let Some(uv) = maybe_uneval { - if uv.promoted.is_none() { - let tcx = self.tcx(); - let def_id = uv.def; - if tcx.def_kind(def_id) == DefKind::InlineConst { - let def_id = def_id.expect_local(); - let predicates = self.prove_closure_bounds( - tcx, - def_id, - uv.args, - location.to_locations(), - ); - self.normalize_and_prove_instantiated_predicates( - def_id.to_def_id(), - predicates, - location.to_locations(), - ); - } - } - } - } - } - - #[instrument(skip(self, body), level = "debug")] - fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) { - let tcx = self.tcx(); - let span = body.source_info(location).span; - - match rvalue { - Rvalue::Aggregate(ak, ops) => { - for op in ops { - self.check_operand(op, location); - } - self.check_aggregate_rvalue(body, rvalue, ak, ops, location) - } - - Rvalue::Repeat(operand, len) => { - self.check_operand(operand, location); - - let array_ty = rvalue.ty(body.local_decls(), tcx); - self.prove_predicate( - ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(array_ty.into())), - Locations::Single(location), - ConstraintCategory::Boring, - ); - - // If the length cannot be evaluated we must assume that the length can be larger - // than 1. - // If the length is larger than 1, the repeat expression will need to copy the - // element, so we require the `Copy` trait. - if len.try_eval_target_usize(tcx, self.param_env).map_or(true, |len| len > 1) { - match operand { - Operand::Copy(..) | Operand::Constant(..) => { - // These are always okay: direct use of a const, or a value that can evidently be copied. - } - Operand::Move(place) => { - // Make sure that repeated elements implement `Copy`. - let ty = place.ty(body, tcx).ty; - let trait_ref = - ty::TraitRef::from_lang_item(tcx, LangItem::Copy, span, [ty]); - - self.prove_trait_ref( - trait_ref, - Locations::Single(location), - ConstraintCategory::CopyBound, - ); - } - } - } - } - - &Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, ty) => { - let trait_ref = ty::TraitRef::from_lang_item(tcx, LangItem::Sized, span, [ty]); - - self.prove_trait_ref( - trait_ref, - location.to_locations(), - ConstraintCategory::SizedBound, - ); - } - &Rvalue::NullaryOp(NullOp::UbChecks, _) => {} - - Rvalue::ShallowInitBox(operand, ty) => { - self.check_operand(operand, location); - - let trait_ref = ty::TraitRef::from_lang_item(tcx, LangItem::Sized, span, [*ty]); - - self.prove_trait_ref( - trait_ref, - location.to_locations(), - ConstraintCategory::SizedBound, - ); - } - - Rvalue::Cast(cast_kind, op, ty) => { - self.check_operand(op, location); - - match cast_kind { - CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer) => { - let fn_sig = op.ty(body, tcx).fn_sig(tcx); - - // The type that we see in the fcx is like - // `foo::<'a, 'b>`, where `foo` is the path to a - // function definition. When we extract the - // signature, it comes from the `fn_sig` query, - // and hence may contain unnormalized results. - let fn_sig = self.normalize(fn_sig, location); - - let ty_fn_ptr_from = Ty::new_fn_ptr(tcx, fn_sig); - - if let Err(terr) = self.eq_types( - *ty, - ty_fn_ptr_from, - location.to_locations(), - ConstraintCategory::Cast { unsize_to: None }, - ) { - span_mirbug!( - self, - rvalue, - "equating {:?} with {:?} yields {:?}", - ty_fn_ptr_from, - ty, - terr - ); - } - } - - CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(unsafety)) => { - let sig = match op.ty(body, tcx).kind() { - ty::Closure(_, args) => args.as_closure().sig(), - _ => bug!(), - }; - let ty_fn_ptr_from = - Ty::new_fn_ptr(tcx, tcx.signature_unclosure(sig, *unsafety)); - - if let Err(terr) = self.eq_types( - *ty, - ty_fn_ptr_from, - location.to_locations(), - ConstraintCategory::Cast { unsize_to: None }, - ) { - span_mirbug!( - self, - rvalue, - "equating {:?} with {:?} yields {:?}", - ty_fn_ptr_from, - ty, - terr - ); - } - } - - CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer) => { - let fn_sig = op.ty(body, tcx).fn_sig(tcx); - - // The type that we see in the fcx is like - // `foo::<'a, 'b>`, where `foo` is the path to a - // function definition. When we extract the - // signature, it comes from the `fn_sig` query, - // and hence may contain unnormalized results. - let fn_sig = self.normalize(fn_sig, location); - - let ty_fn_ptr_from = tcx.safe_to_unsafe_fn_ty(fn_sig); - - if let Err(terr) = self.eq_types( - *ty, - ty_fn_ptr_from, - location.to_locations(), - ConstraintCategory::Cast { unsize_to: None }, - ) { - span_mirbug!( - self, - rvalue, - "equating {:?} with {:?} yields {:?}", - ty_fn_ptr_from, - ty, - terr - ); - } - } - - CastKind::PointerCoercion(PointerCoercion::Unsize) => { - let &ty = ty; - let trait_ref = ty::TraitRef::from_lang_item( - tcx, - LangItem::CoerceUnsized, - span, - [op.ty(body, tcx), ty], - ); - - self.prove_trait_ref( - trait_ref, - location.to_locations(), - ConstraintCategory::Cast { - unsize_to: Some(tcx.fold_regions(ty, |r, _| { - if let ty::ReVar(_) = r.kind() { - tcx.lifetimes.re_erased - } else { - r - } - })), - }, - ); - } - - CastKind::DynStar => { - // get the constraints from the target type (`dyn* Clone`) - // - // apply them to prove that the source type `Foo` implements `Clone` etc - let (existential_predicates, region) = match ty.kind() { - Dynamic(predicates, region, ty::DynStar) => (predicates, region), - _ => panic!("Invalid dyn* cast_ty"), - }; - - let self_ty = op.ty(body, tcx); - - self.prove_predicates( - existential_predicates - .iter() - .map(|predicate| predicate.with_self_ty(tcx, self_ty)), - location.to_locations(), - ConstraintCategory::Cast { unsize_to: None }, - ); - - let outlives_predicate = tcx.mk_predicate(Binder::dummy( - ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives( - ty::OutlivesPredicate(self_ty, *region), - )), - )); - self.prove_predicate( - outlives_predicate, - location.to_locations(), - ConstraintCategory::Cast { unsize_to: None }, - ); - } - - CastKind::PointerCoercion(PointerCoercion::MutToConstPointer) => { - let ty::RawPtr(ty_from, hir::Mutability::Mut) = op.ty(body, tcx).kind() - else { - span_mirbug!(self, rvalue, "unexpected base type for cast {:?}", ty,); - return; - }; - let ty::RawPtr(ty_to, hir::Mutability::Not) = ty.kind() else { - span_mirbug!(self, rvalue, "unexpected target type for cast {:?}", ty,); - return; - }; - if let Err(terr) = self.sub_types( - *ty_from, - *ty_to, - location.to_locations(), - ConstraintCategory::Cast { unsize_to: None }, - ) { - span_mirbug!( - self, - rvalue, - "relating {:?} with {:?} yields {:?}", - ty_from, - ty_to, - terr - ); - } - } - - CastKind::PointerCoercion(PointerCoercion::ArrayToPointer) => { - let ty_from = op.ty(body, tcx); - - let opt_ty_elem_mut = match ty_from.kind() { - ty::RawPtr(array_ty, array_mut) => match array_ty.kind() { - ty::Array(ty_elem, _) => Some((ty_elem, *array_mut)), - _ => None, - }, - _ => None, - }; - - let Some((ty_elem, ty_mut)) = opt_ty_elem_mut else { - span_mirbug!( - self, - rvalue, - "ArrayToPointer cast from unexpected type {:?}", - ty_from, - ); - return; - }; - - let (ty_to, ty_to_mut) = match ty.kind() { - ty::RawPtr(ty_to, ty_to_mut) => (ty_to, *ty_to_mut), - _ => { - span_mirbug!( - self, - rvalue, - "ArrayToPointer cast to unexpected type {:?}", - ty, - ); - return; - } - }; - - if ty_to_mut.is_mut() && ty_mut.is_not() { - span_mirbug!( - self, - rvalue, - "ArrayToPointer cast from const {:?} to mut {:?}", - ty, - ty_to - ); - return; - } - - if let Err(terr) = self.sub_types( - *ty_elem, - *ty_to, - location.to_locations(), - ConstraintCategory::Cast { unsize_to: None }, - ) { - span_mirbug!( - self, - rvalue, - "relating {:?} with {:?} yields {:?}", - ty_elem, - ty_to, - terr - ) - } - } - - CastKind::PointerExposeAddress => { - 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(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => (), - _ => { - span_mirbug!( - self, - rvalue, - "Invalid PointerExposeAddress cast {:?} -> {:?}", - ty_from, - ty - ) - } - } - } - - CastKind::PointerFromExposedAddress => { - 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::Ptr(_))) => (), - _ => { - span_mirbug!( - self, - rvalue, - "Invalid PointerFromExposedAddress cast {:?} -> {:?}", - ty_from, - ty - ) - } - } - } - 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); - match (cast_ty_from, cast_ty_to) { - (Some(CastTy::Int(_)), Some(CastTy::Int(_))) => (), - _ => { - span_mirbug!( - self, - rvalue, - "Invalid IntToInt cast {:?} -> {:?}", - ty_from, - 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 - ) - } - } - } - CastKind::Transmute => { - span_mirbug!( - self, - rvalue, - "Unexpected CastKind::Transmute, which is not permitted in Analysis MIR", - ); - } - } - } - - Rvalue::Ref(region, _borrow_kind, borrowed_place) => { - self.add_reborrow_constraint(body, location, *region, borrowed_place); - } - - Rvalue::BinaryOp( - BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge, - box (left, right), - ) => { - self.check_operand(left, location); - self.check_operand(right, location); - - let ty_left = left.ty(body, tcx); - match ty_left.kind() { - // Types with regions are comparable if they have a common super-type. - ty::RawPtr(_, _) | ty::FnPtr(_) => { - let ty_right = right.ty(body, tcx); - let common_ty = self.infcx.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::MiscVariable, - span: body.source_info(location).span, - }); - self.sub_types( - ty_left, - common_ty, - location.to_locations(), - ConstraintCategory::Boring, - ) - .unwrap_or_else(|err| { - bug!("Could not equate type variable with {:?}: {:?}", ty_left, err) - }); - if let Err(terr) = self.sub_types( - ty_right, - common_ty, - location.to_locations(), - ConstraintCategory::Boring, - ) { - span_mirbug!( - self, - rvalue, - "unexpected comparison types {:?} and {:?} yields {:?}", - ty_left, - ty_right, - terr - ) - } - } - // For types with no regions we can just check that the - // both operands have the same type. - ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_) - if ty_left == right.ty(body, tcx) => {} - // Other types are compared by trait methods, not by - // `Rvalue::BinaryOp`. - _ => span_mirbug!( - self, - rvalue, - "unexpected comparison types {:?} and {:?}", - ty_left, - right.ty(body, tcx) - ), - } - } - - Rvalue::Use(operand) | Rvalue::UnaryOp(_, operand) => { - self.check_operand(operand, location); - } - Rvalue::CopyForDeref(place) => { - let op = &Operand::Copy(*place); - self.check_operand(op, location); - } - - Rvalue::BinaryOp(_, box (left, right)) - | Rvalue::CheckedBinaryOp(_, box (left, right)) => { - self.check_operand(left, location); - self.check_operand(right, location); - } - - Rvalue::AddressOf(..) - | Rvalue::ThreadLocalRef(..) - | Rvalue::Len(..) - | Rvalue::Discriminant(..) - | Rvalue::NullaryOp(NullOp::OffsetOf(..), _) => {} - } - } - - /// If this rvalue supports a user-given type annotation, then - /// extract and return it. This represents the final type of the - /// rvalue and will be unified with the inferred type. - fn rvalue_user_ty(&self, rvalue: &Rvalue<'tcx>) -> Option { - match rvalue { - Rvalue::Use(_) - | Rvalue::ThreadLocalRef(_) - | Rvalue::Repeat(..) - | Rvalue::Ref(..) - | Rvalue::AddressOf(..) - | Rvalue::Len(..) - | Rvalue::Cast(..) - | Rvalue::ShallowInitBox(..) - | Rvalue::BinaryOp(..) - | Rvalue::CheckedBinaryOp(..) - | Rvalue::NullaryOp(..) - | Rvalue::CopyForDeref(..) - | Rvalue::UnaryOp(..) - | Rvalue::Discriminant(..) => None, - - Rvalue::Aggregate(aggregate, _) => match **aggregate { - AggregateKind::Adt(_, _, _, user_ty, _) => user_ty, - AggregateKind::Array(_) => None, - AggregateKind::Tuple => None, - AggregateKind::Closure(_, _) => None, - AggregateKind::Coroutine(_, _) => None, - AggregateKind::CoroutineClosure(_, _) => None, - }, - } - } - - fn check_aggregate_rvalue( - &mut self, - body: &Body<'tcx>, - rvalue: &Rvalue<'tcx>, - aggregate_kind: &AggregateKind<'tcx>, - operands: &IndexSlice>, - location: Location, - ) { - let tcx = self.tcx(); - - self.prove_aggregate_predicates(aggregate_kind, location); - - if *aggregate_kind == AggregateKind::Tuple { - // tuple rvalue field type is always the type of the op. Nothing to check here. - return; - } - - for (i, operand) in operands.iter_enumerated() { - let field_ty = match self.aggregate_field_ty(aggregate_kind, i, location) { - Ok(field_ty) => field_ty, - Err(FieldAccessError::OutOfRange { field_count }) => { - span_mirbug!( - self, - rvalue, - "accessed field #{} but variant only has {}", - i.as_u32(), - field_count, - ); - continue; - } - }; - let operand_ty = operand.ty(body, tcx); - let operand_ty = self.normalize(operand_ty, location); - - if let Err(terr) = self.sub_types( - operand_ty, - field_ty, - location.to_locations(), - ConstraintCategory::Boring, - ) { - span_mirbug!( - self, - rvalue, - "{:?} is not a subtype of {:?}: {:?}", - operand_ty, - field_ty, - terr - ); - } - } - } - - /// Adds the constraints that arise from a borrow expression `&'a P` at the location `L`. - /// - /// # Parameters - /// - /// - `location`: the location `L` where the borrow expression occurs - /// - `borrow_region`: the region `'a` associated with the borrow - /// - `borrowed_place`: the place `P` being borrowed - fn add_reborrow_constraint( - &mut self, - body: &Body<'tcx>, - location: Location, - borrow_region: ty::Region<'tcx>, - borrowed_place: &Place<'tcx>, - ) { - // These constraints are only meaningful during borrowck: - let BorrowCheckContext { borrow_set, location_table, all_facts, constraints, .. } = - self.borrowck_context; - - // In Polonius mode, we also push a `loan_issued_at` fact - // linking the loan to the region (in some cases, though, - // there is no loan associated with this borrow expression -- - // that occurs when we are borrowing an unsafe place, for - // example). - if let Some(all_facts) = all_facts { - let _prof_timer = self.infcx.tcx.prof.generic_activity("polonius_fact_generation"); - if let Some(borrow_index) = borrow_set.get_index_of(&location) { - let region_vid = borrow_region.as_var(); - all_facts.loan_issued_at.push(( - region_vid, - borrow_index, - location_table.mid_index(location), - )); - } - } - - // If we are reborrowing the referent of another reference, we - // need to add outlives relationships. In a case like `&mut - // *p`, where the `p` has type `&'b mut Foo`, for example, we - // need to ensure that `'b: 'a`. - - debug!( - "add_reborrow_constraint({:?}, {:?}, {:?})", - location, borrow_region, borrowed_place - ); - - let tcx = self.infcx.tcx; - let field = path_utils::is_upvar_field_projection( - tcx, - self.borrowck_context.upvars, - borrowed_place.as_ref(), - body, - ); - let category = if let Some(field) = field { - ConstraintCategory::ClosureUpvar(field) - } else { - ConstraintCategory::Boring - }; - - for (base, elem) in borrowed_place.as_ref().iter_projections().rev() { - debug!("add_reborrow_constraint - iteration {:?}", elem); - - match elem { - ProjectionElem::Deref => { - let base_ty = base.ty(body, tcx).ty; - - debug!("add_reborrow_constraint - base_ty = {:?}", base_ty); - match base_ty.kind() { - ty::Ref(ref_region, _, mutbl) => { - constraints.outlives_constraints.push(OutlivesConstraint { - sup: ref_region.as_var(), - sub: borrow_region.as_var(), - locations: location.to_locations(), - span: location.to_locations().span(body), - category, - variance_info: ty::VarianceDiagInfo::default(), - from_closure: false, - }); - - match mutbl { - hir::Mutability::Not => { - // Immutable reference. We don't need the base - // to be valid for the entire lifetime of - // the borrow. - break; - } - hir::Mutability::Mut => { - // Mutable reference. We *do* need the base - // to be valid, because after the base becomes - // invalid, someone else can use our mutable deref. - - // This is in order to make the following function - // illegal: - // ``` - // fn unsafe_deref<'a, 'b>(x: &'a &'b mut T) -> &'b mut T { - // &mut *x - // } - // ``` - // - // As otherwise you could clone `&mut T` using the - // following function: - // ``` - // fn bad(x: &mut T) -> (&mut T, &mut T) { - // let my_clone = unsafe_deref(&'a x); - // ENDREGION 'a; - // (my_clone, x) - // } - // ``` - } - } - } - ty::RawPtr(..) => { - // deref of raw pointer, guaranteed to be valid - break; - } - ty::Adt(def, _) if def.is_box() => { - // deref of `Box`, need the base to be valid - propagate - } - _ => bug!("unexpected deref ty {:?} in {:?}", base_ty, borrowed_place), - } - } - ProjectionElem::Field(..) - | ProjectionElem::Downcast(..) - | ProjectionElem::OpaqueCast(..) - | ProjectionElem::Index(..) - | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. } => { - // other field access - } - ProjectionElem::Subtype(_) => { - bug!("ProjectionElem::Subtype shouldn't exist in borrowck") - } - } - } - } - - fn prove_aggregate_predicates( - &mut self, - aggregate_kind: &AggregateKind<'tcx>, - location: Location, - ) { - let tcx = self.tcx(); - - debug!( - "prove_aggregate_predicates(aggregate_kind={:?}, location={:?})", - aggregate_kind, location - ); - - let (def_id, instantiated_predicates) = match *aggregate_kind { - AggregateKind::Adt(adt_did, _, args, _, _) => { - (adt_did, tcx.predicates_of(adt_did).instantiate(tcx, args)) - } - - // For closures, we have some **extra requirements** we - // have to check. In particular, in their upvars and - // signatures, closures often reference various regions - // from the surrounding function -- we call those the - // closure's free regions. When we borrow-check (and hence - // region-check) closures, we may find that the closure - // requires certain relationships between those free - // regions. However, because those free regions refer to - // portions of the CFG of their caller, the closure is not - // in a position to verify those relationships. In that - // case, the requirements get "propagated" to us, and so - // we have to solve them here where we instantiate the - // closure. - // - // Despite the opacity of the previous paragraph, this is - // actually relatively easy to understand in terms of the - // desugaring. A closure gets desugared to a struct, and - // these extra requirements are basically like where - // clauses on the struct. - AggregateKind::Closure(def_id, args) - | AggregateKind::CoroutineClosure(def_id, args) - | AggregateKind::Coroutine(def_id, args) => ( - def_id, - self.prove_closure_bounds( - tcx, - def_id.expect_local(), - args, - location.to_locations(), - ), - ), - - AggregateKind::Array(_) | AggregateKind::Tuple => { - (CRATE_DEF_ID.to_def_id(), ty::InstantiatedPredicates::empty()) - } - }; - - self.normalize_and_prove_instantiated_predicates( - def_id, - instantiated_predicates, - location.to_locations(), - ); - } - - fn prove_closure_bounds( - &mut self, - tcx: TyCtxt<'tcx>, - def_id: LocalDefId, - args: GenericArgsRef<'tcx>, - locations: Locations, - ) -> ty::InstantiatedPredicates<'tcx> { - if let Some(closure_requirements) = &tcx.mir_borrowck(def_id).closure_requirements { - constraint_conversion::ConstraintConversion::new( - self.infcx, - self.borrowck_context.universal_regions, - self.region_bound_pairs, - self.implicit_region_bound, - self.param_env, - self.known_type_outlives_obligations, - locations, - self.body.span, // irrelevant; will be overridden. - ConstraintCategory::Boring, // same as above. - self.borrowck_context.constraints, - ) - .apply_closure_requirements(closure_requirements, def_id.to_def_id(), args); - } - - // Now equate closure args to regions inherited from `typeck_root_def_id`. Fixes #98589. - let typeck_root_def_id = tcx.typeck_root_def_id(self.body.source.def_id()); - let typeck_root_args = ty::GenericArgs::identity_for_item(tcx, typeck_root_def_id); - - let parent_args = match tcx.def_kind(def_id) { - // We don't want to dispatch on 3 different kind of closures here, so take - // advantage of the fact that the `parent_args` is the same length as the - // `typeck_root_args`. - DefKind::Closure => { - // FIXME(async_closures): It may be useful to add a debug assert here - // to actually call `type_of` and check the `parent_args` are the same - // length as the `typeck_root_args`. - &args[..typeck_root_args.len()] - } - DefKind::InlineConst => args.as_inline_const().parent_args(), - other => bug!("unexpected item {:?}", other), - }; - let parent_args = tcx.mk_args(parent_args); - - assert_eq!(typeck_root_args.len(), parent_args.len()); - if let Err(_) = self.eq_args( - typeck_root_args, - parent_args, - locations, - ConstraintCategory::BoringNoLocation, - ) { - span_mirbug!( - self, - def_id, - "could not relate closure to parent {:?} != {:?}", - typeck_root_args, - parent_args - ); - } - - tcx.predicates_of(def_id).instantiate(tcx, args) - } - - #[instrument(skip(self, body), level = "debug")] - fn typeck_mir(&mut self, body: &Body<'tcx>) { - self.last_span = body.span; - debug!(?body.span); - - for (local, local_decl) in body.local_decls.iter_enumerated() { - self.check_local(body, local, local_decl); - } - - for (block, block_data) in body.basic_blocks.iter_enumerated() { - let mut location = Location { block, statement_index: 0 }; - for stmt in &block_data.statements { - if !stmt.source_info.span.is_dummy() { - self.last_span = stmt.source_info.span; - } - self.check_stmt(body, stmt, location); - location.statement_index += 1; - } - - self.check_terminator(body, block_data.terminator(), location); - self.check_iscleanup(body, block_data); - } - } -} - -trait NormalizeLocation: fmt::Debug + Copy { - fn to_locations(self) -> Locations; -} - -impl NormalizeLocation for Locations { - fn to_locations(self) -> Locations { - self - } -} - -impl NormalizeLocation for Location { - fn to_locations(self) -> Locations { - Locations::Single(self) - } -} - -/// Runs `infcx.instantiate_opaque_types`. Unlike other `TypeOp`s, -/// this is not canonicalized - it directly affects the main `InferCtxt` -/// that we use during MIR borrowchecking. -#[derive(Debug)] -pub(super) struct InstantiateOpaqueType<'tcx> { - pub base_universe: Option, - pub region_constraints: Option>, - pub obligations: Vec>, -} - -impl<'tcx> TypeOp<'tcx> for InstantiateOpaqueType<'tcx> { - type Output = (); - /// We use this type itself to store the information used - /// when reporting errors. Since this is not a query, we don't - /// re-run anything during error reporting - we just use the information - /// we saved to help extract an error from the already-existing region - /// constraints in our `InferCtxt` - type ErrorInfo = InstantiateOpaqueType<'tcx>; - - fn fully_perform( - mut self, - infcx: &InferCtxt<'tcx>, - span: Span, - ) -> Result, ErrorGuaranteed> { - let (mut output, region_constraints) = scrape_region_constraints( - infcx, - |ocx| { - ocx.register_obligations(self.obligations.clone()); - Ok(()) - }, - "InstantiateOpaqueType", - span, - )?; - self.region_constraints = Some(region_constraints); - output.error_info = Some(self); - Ok(output) - } -} +use std::rc::Rc;use std::{fmt,iter,mem};use either::Either;use//((),());((),()); +rustc_data_structures::frozen::Frozen;use rustc_data_structures::fx::{//((),()); +FxIndexMap,FxIndexSet};use rustc_errors::ErrorGuaranteed;use rustc_hir as hir;// +use rustc_hir::def::DefKind;use rustc_hir::def_id::LocalDefId;use rustc_hir:://; +lang_items::LangItem;use rustc_index::{IndexSlice,IndexVec};use rustc_infer:://; +infer::canonical::QueryRegionConstraints;use rustc_infer::infer::outlives::env// +::RegionBoundPairs;use rustc_infer::infer::region_constraints:://*&*&();((),()); +RegionConstraintData;use rustc_infer:: infer::type_variable::{TypeVariableOrigin +,TypeVariableOriginKind};use rustc_infer::infer::{BoundRegion,//((),());((),()); +BoundRegionConversionTime,InferCtxt,NllRegionVariableOrigin,};use rustc_middle// +::mir::tcx::PlaceTy;use rustc_middle::mir::visit::{NonMutatingUseContext,//({}); +PlaceContext,Visitor};use rustc_middle::mir::*;use rustc_middle::traits::query// +::NoSolution;use rustc_middle::traits::ObligationCause;use rustc_middle::ty:://; +adjustment::PointerCoercion;use rustc_middle:: ty::cast::CastTy;use rustc_middle +::ty::visit::TypeVisitableExt;use rustc_middle::ty::{self,Binder,//loop{break;}; +CanonicalUserTypeAnnotation,CanonicalUserTypeAnnotations,Dynamic,//loop{break;}; +OpaqueHiddenType,OpaqueTypeKey,RegionVid,Ty,TyCtxt,UserType,//let _=();let _=(); +UserTypeAnnotationIndex,};use rustc_middle::ty::{GenericArgsRef,UserArgs};use//; +rustc_mir_dataflow::points::DenseLocationMap;use rustc_span::def_id:://let _=(); +CRATE_DEF_ID;use rustc_span::source_map::Spanned;use rustc_span::symbol::sym;//; +use rustc_span::Span;use rustc_target::abi::{FieldIdx,FIRST_VARIANT};use//{();}; +rustc_trait_selection::traits::query::type_op::custom:://let _=||();loop{break}; +scrape_region_constraints;use rustc_trait_selection::traits::query::type_op:://; +custom::CustomTypeOp;use rustc_trait_selection:: traits::query::type_op::{TypeOp +,TypeOpOutput};use rustc_trait_selection::traits::PredicateObligation;use//({}); +rustc_mir_dataflow::impls::MaybeInitializedPlaces;use rustc_mir_dataflow:://{;}; +move_paths::MoveData;use rustc_mir_dataflow::ResultsCursor;use crate:://((),()); +session_diagnostics::{MoveUnsized,SimdIntrinsicArgConst} ;use crate::{borrow_set +::BorrowSet,constraints::{ OutlivesConstraint,OutlivesConstraintSet},diagnostics +::UniverseInfo,facts::AllFacts,location::LocationTable,member_constraints:://(); +MemberConstraintSet,path_utils,region_infer::values::{LivenessValues,//let _=(); +PlaceholderIndex,PlaceholderIndices},region_infer::TypeTest,type_check:://{();}; +free_region_relations::{CreateResult,UniversalRegionRelations},//*&*&();((),()); +universal_regions::{DefiningTy,UniversalRegions},BorrowckInferCtxt,};//let _=(); +macro_rules!span_mirbug{($context:expr,$elem:expr,$($message:tt)*)=>({$crate::// +type_check::mirbug($context.tcx(),$context.last_span,format!(//((),());let _=(); +"broken MIR in {:?} ({:?}): {}",$context.body().source.def_id(),$elem,//((),()); +format_args!($($message)*),), )})}macro_rules!span_mirbug_and_err{($context:expr +,$elem:expr,$($message:tt)*)=>({{span_mirbug!($context,$elem,$($message)*);$//3; +context.error()}})}mod canonical;mod constraint_conversion;pub mod//loop{break}; +free_region_relations;mod input_output;pub(crate)mod liveness;mod relate_tys;//; +pub(crate)fn type_check<'mir,'tcx> (infcx:&BorrowckInferCtxt<'_,'tcx>,param_env: +ty::ParamEnv<'tcx>,body:&Body<'tcx>,promoted:&IndexSlice>,// +universal_regions:&Rc>,location_table:&LocationTable,//3; +borrow_set:&BorrowSet<'tcx>,all_facts:&mut Option,flow_inits:&mut//(); +ResultsCursor<'mir,'tcx,MaybeInitializedPlaces<'mir ,'tcx>>,move_data:&MoveData< +'tcx>,elements:&Rc,upvars:&[&ty::CapturedPlace<'tcx>],//{();}; +use_polonius:bool,)->MirTypeckResults<'tcx>{{();};let implicit_region_bound=ty:: +Region::new_var(infcx.tcx,universal_regions.fr_fn_body);3;3;let mut constraints= +MirTypeckRegionConstraints{placeholder_indices:(PlaceholderIndices ::default()), +placeholder_index_to_region:(((((IndexVec::default ()))))),liveness_constraints: +LivenessValues::with_specific_points(((elements.clone()))),outlives_constraints: +OutlivesConstraintSet::default(),member_constraints:MemberConstraintSet:://({}); +default(),type_tests:Vec::default(),universe_causes:FxIndexMap::default(),};;let +CreateResult{universal_region_relations,region_bound_pairs,//let _=();if true{}; +normalized_inputs_and_output,known_type_outlives_obligations,}=//*&*&();((),()); +free_region_relations::create(infcx,param_env,implicit_region_bound,//if true{}; +universal_regions,&mut constraints,);;;debug!(?normalized_inputs_and_output);let +mut borrowck_context=BorrowCheckContext{universal_regions,location_table,//({}); +borrow_set,all_facts,constraints:&mut constraints,upvars,};();3;let mut checker= +TypeChecker::new(infcx,body,param_env,(((((((((((®ion_bound_pairs))))))))))), +known_type_outlives_obligations,implicit_region_bound,&mut borrowck_context,);;; +checker.check_user_type_annotations();3;;let mut verifier=TypeVerifier::new(&mut +checker,promoted);;;verifier.visit_body(body);;checker.typeck_mir(body);checker. +equate_inputs_and_outputs(body,universal_regions, &normalized_inputs_and_output) +;;checker.check_signature_annotation(body);liveness::generate(&mut checker,body, +elements,flow_inits,move_data,location_table,use_polonius,);if true{};if true{}; +translate_outlives_facts(&mut checker);{();};{();};let opaque_type_values=infcx. +take_opaque_types();;let opaque_type_values=opaque_type_values.into_iter().map(| +(opaque_type_key,decl)|{((),());((),());let _:Result<_,ErrorGuaranteed>=checker. +fully_perform_op((((Locations::All(body.span)))),ConstraintCategory::OpaqueType, +CustomTypeOp::new(|ocx|{3;ocx.infcx.register_member_constraints(opaque_type_key, +decl.hidden_type.ty,decl.hidden_type.span,);;Ok(())},"opaque_type_map",),);;;let +hidden_type=infcx.resolve_vars_if_possible(decl.hidden_type);{();};{();};trace!( +"finalized opaque type {:?} to {:#?}",opaque_type_key,hidden_type.ty.kind());;if +hidden_type.has_non_region_infer(){3;infcx.dcx().span_bug(decl.hidden_type.span, +format!("could not resolve {:#?}",hidden_type.ty.kind()),);;}let(opaque_type_key +,hidden_type)=infcx.tcx.fold_regions(((opaque_type_key,hidden_type)),|region,_|{ +match (((region.kind()))){ty::ReVar (_)=>region,ty::RePlaceholder(placeholder)=> +checker.borrowck_context.constraints.placeholder_region(infcx,placeholder),_=>// +ty::Region::new_var(infcx.tcx,checker.borrowck_context.universal_regions.//({}); +to_region_vid(region),),}});({});(opaque_type_key,hidden_type)}).collect();({}); +MirTypeckResults{constraints,universal_region_relations,opaque_type_values}}fn// +translate_outlives_facts(typeck:&mut TypeChecker<'_,'_>){{;};let cx=&mut typeck. +borrowck_context;;if let Some(facts)=cx.all_facts{;let _prof_timer=typeck.infcx. +tcx.prof.generic_activity("polonius_fact_generation");3;3;let location_table=cx. +location_table;3;3;facts.subset_base.extend(cx.constraints.outlives_constraints. +outlives().iter().flat_map(|constraint:&OutlivesConstraint<'_>|{if let Some(//3; +from_location)=(constraint.locations.from_location()) {Either::Left(iter::once(( +constraint.sup,constraint.sub,location_table.mid_index( from_location),)))}else{ +Either::Right(((location_table.all_points())).map(move|location|(constraint.sup, +constraint.sub,location)),)}},));;}}#[track_caller]fn mirbug(tcx:TyCtxt<'_>,span +:Span,msg:String){;tcx.dcx().span_delayed_bug(span,msg);;}enum FieldAccessError{ +OutOfRange{field_count:usize},}struct TypeVerifier<'a,'b,'tcx>{cx:&'a mut//({}); +TypeChecker<'b,'tcx>,promoted:&'b IndexSlice>,last_span://3; +Span,}impl<'a,'b,'tcx>Visitor<'tcx> for TypeVerifier<'a,'b,'tcx>{fn visit_span(& +mut self,span:Span){if!span.is_dummy(){3;self.last_span=span;;}}fn visit_place(& +mut self,place:&Place<'tcx>,context:PlaceContext,location:Location){*&*&();self. +sanitize_place(place,location,context);3;}fn visit_constant(&mut self,constant:& +ConstOperand<'tcx>,location:Location){*&*&();((),());debug!(?constant,?location, +"visit_constant");();();self.super_constant(constant,location);();3;let ty=self. +sanitize_type(constant,constant.const_.ty());let _=();((),());self.cx.infcx.tcx. +for_each_free_region(&ty,|live_region|{loop{break;};let live_region_vid=self.cx. +borrowck_context.universal_regions.to_region_vid(live_region);({});({});self.cx. +borrowck_context.constraints.liveness_constraints .add_location(live_region_vid, +location);;});let locations=if location!=Location::START{location.to_locations() +}else{Locations::All(constant.span)};{;};if let Some(annotation_index)=constant. +user_ty{if let Err(terr)=self .cx.relate_type_and_user_type(constant.const_.ty() +,ty::Variance::Invariant,&UserTypeProjection{ base:annotation_index,projs:vec![] +},locations,ConstraintCategory::Boring,){*&*&();((),());let annotation=&self.cx. +user_type_annotations[annotation_index];*&*&();{();};span_mirbug!(self,constant, +"bad constant user type {:?} vs {:?}: {:?}",annotation,constant.const_.ty(),//3; +terr,);;}}else{let tcx=self.tcx();let maybe_uneval=match constant.const_{Const:: +Ty(ct)=>match (((((((((ct.kind()))))))))) {ty::ConstKind::Unevaluated(_)=>{bug!( +"should not encounter unevaluated Const::Ty here, got {:?}",ct)} _=>None,},Const +::Unevaluated(uv,_)=>Some(uv),_=>None,};({});if let Some(uv)=maybe_uneval{if let +Some(promoted)=uv.promoted{;let check_err=|verifier:&mut TypeVerifier<'a,'b,'tcx +>,promoted:&Body<'tcx>,ty,san_ty|{({});if let Err(terr)=verifier.cx.eq_types(ty, +san_ty,locations,ConstraintCategory::Boring){{;};span_mirbug!(verifier,promoted, +"bad promoted type ({:?}: {:?}): {:?}",ty,san_ty,terr);;};;};let promoted_body=& +self.promoted[promoted];3;3;self.sanitize_promoted(promoted_body,location);;;let +promoted_ty=promoted_body.return_ty();({});({});check_err(self,promoted_body,ty, +promoted_ty);3;}else{3;self.cx.ascribe_user_type(constant.const_.ty(),UserType:: +TypeOf(uv.def,UserArgs{args:uv.args,user_self_ty :None}),locations.span(self.cx. +body),);3;}}else if let Some(static_def_id)=constant.check_static_ptr(tcx){3;let +unnormalized_ty=tcx.type_of(static_def_id).instantiate_identity();{();};({});let +normalized_ty=self.cx.normalize(unnormalized_ty,locations);();();let literal_ty= +constant.const_.ty().builtin_deref(true).unwrap().ty;3;if let Err(terr)=self.cx. +eq_types(literal_ty,normalized_ty,locations,ConstraintCategory::Boring,){*&*&(); +span_mirbug!(self,constant,"bad static type {:?} ({:?})",constant,terr);{;};}}if +let ty::FnDef(def_id,args)=*constant.const_.ty().kind(){if true{};let _=||();let +instantiated_predicates=tcx.predicates_of(def_id).instantiate(tcx,args);;self.cx +.normalize_and_prove_instantiated_predicates(def_id,instantiated_predicates,//3; +locations,);;assert!(!matches!(tcx.impl_of_method(def_id).map(|imp|tcx.def_kind( +imp)),Some(DefKind::Impl{of_trait:true})));;self.cx.prove_predicates(args.types( +).map(|ty|ty::ClauseKind::WellFormed( ty.into())),locations,ConstraintCategory:: +Boring,);;}}}fn visit_rvalue(&mut self,rvalue:&Rvalue<'tcx>,location:Location){; +self.super_rvalue(rvalue,location);;let rval_ty=rvalue.ty(self.body(),self.tcx() +);;self.sanitize_type(rvalue,rval_ty);}fn visit_local_decl(&mut self,local:Local +,local_decl:&LocalDecl<'tcx>){3;self.super_local_decl(local,local_decl);3;;self. +sanitize_type(local_decl,local_decl.ty);*&*&();if let Some(user_ty)=&local_decl. +user_ty{for(user_ty,span)in user_ty.projections_and_spans(){if true{};let ty=if! +local_decl.is_nonref_binding(){if let ty::Ref(_ ,rty,_)=(local_decl.ty.kind()){* +rty}else{;bug!("{:?} with ref binding has wrong type {}",local,local_decl.ty);}} +else{local_decl.ty};3;if let Err(terr)=self.cx.relate_type_and_user_type(ty,ty:: +Variance::Invariant,user_ty,(((Locations::All(((*span)))))),ConstraintCategory:: +TypeAnnotation,){let _=();if true{};if true{};if true{};span_mirbug!(self,local, +"bad user type on variable {:?}: {:?} != {:?} ({:?})",local,local_decl.ty,//{;}; +local_decl.user_ty,terr,);3;}}}}fn visit_body(&mut self,body:&Body<'tcx>){;self. +sanitize_type(&"return type",body.return_ty());;self.super_body(body);}}impl<'a, +'b,'tcx>TypeVerifier<'a,'b,'tcx>{fn new(cx:&'a mut TypeChecker<'b,'tcx>,//{();}; +promoted:&'b IndexSlice>,)->Self{TypeVerifier{promoted,//(); +last_span:cx.body.span,cx}}fn body(&self)->&Body<'tcx>{self.cx.body}fn tcx(&//3; +self)->TyCtxt<'tcx>{self.cx.infcx.tcx}fn sanitize_type(&mut self,parent:&dyn//3; +fmt::Debug,ty:Ty<'tcx>)->Ty<'tcx>{if (((((ty.has_escaping_bound_vars())))))||ty. +references_error(){span_mirbug_and_err!(self ,parent,"bad type {:?}",ty)}else{ty +}}#[instrument(level="debug",skip(self,location),ret)]fn sanitize_place(&mut//3; +self,place:&Place<'tcx>,location: Location,context:PlaceContext,)->PlaceTy<'tcx> +{;let mut place_ty=PlaceTy::from_ty(self.body().local_decls[place.local].ty);for +elem in (place.projection.iter()){if place_ty.variant_index.is_none(){if let Err +(guar)=place_ty.ty.error_reported(){;return PlaceTy::from_ty(Ty::new_error(self. +tcx(),guar));;}};place_ty=self.sanitize_projection(place_ty,elem,place,location, +context);({});}if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy)= +context{3;let tcx=self.tcx();3;3;let trait_ref=ty::TraitRef::from_lang_item(tcx, +LangItem::Copy,self.last_span,[place_ty.ty]);;self.cx.prove_trait_ref(trait_ref, +location.to_locations(),ConstraintCategory::CopyBound,);loop{break};}place_ty}fn +sanitize_promoted(&mut self,promoted_body:&'b Body<'tcx>,location:Location){;let +parent_body=mem::replace(&mut self.cx.body,promoted_body);3;3;let all_facts=&mut +None;3;3;let mut constraints=Default::default();3;;let mut liveness_constraints= +LivenessValues::without_specific_points(Rc::new(DenseLocationMap::new(//((),()); +promoted_body)));;;let mut swap_constraints=|this:&mut Self|{;mem::swap(this.cx. +borrowck_context.all_facts,all_facts);;;mem::swap(&mut this.cx.borrowck_context. +constraints.outlives_constraints,&mut constraints,);();3;mem::swap(&mut this.cx. +borrowck_context.constraints.liveness_constraints,&mut liveness_constraints,);;} +;;;swap_constraints(self);;;self.visit_body(promoted_body);;;self.cx.typeck_mir( +promoted_body);;;self.cx.body=parent_body;;swap_constraints(self);let locations= +location.to_locations();;for constraint in constraints.outlives().iter(){let mut +constraint=*constraint;*&*&();*&*&();constraint.locations=locations;{();};if let +ConstraintCategory::Return(_) |ConstraintCategory::UseAsConst|ConstraintCategory +::UseAsStatic=constraint.category{{();};constraint.category=ConstraintCategory:: +Boring;let _=();}self.cx.borrowck_context.constraints.outlives_constraints.push( +constraint)}#[allow(rustc::potential_query_instability)]for region in //((),()); +liveness_constraints.live_regions_unordered(){let _=();self.cx.borrowck_context. +constraints.liveness_constraints.add_location(region,location);3;}}#[instrument( +skip(self,location),ret,level="debug")]fn sanitize_projection(&mut self,base://; +PlaceTy<'tcx>,pi:PlaceElem<'tcx>,place:&Place<'tcx>,location:Location,context:// +PlaceContext,)->PlaceTy<'tcx>{;let tcx=self.tcx();;let base_ty=base.ty;match pi{ +ProjectionElem::Deref=>{();let deref_ty=base_ty.builtin_deref(true);();PlaceTy:: +from_ty(deref_ty.map(|t|t.ty ).unwrap_or_else(||{span_mirbug_and_err!(self,place +,"deref of non-pointer {:?}",base_ty)}))}ProjectionElem::Index(i)=>{let _=();let +index_ty=Place::from(i).ty(self.body(),tcx).ty;{;};if index_ty!=tcx.types.usize{ +PlaceTy::from_ty(span_mirbug_and_err!(self, i,"index by non-usize {:?}",i))}else +{PlaceTy::from_ty(base_ty.builtin_index ().unwrap_or_else(||{span_mirbug_and_err +!(self,place,"index of non-array {:?}",base_ty)}))}}ProjectionElem:://if true{}; +ConstantIndex{..}=>{PlaceTy::from_ty( base_ty.builtin_index().unwrap_or_else(||{ +span_mirbug_and_err!(self,place,"index of non-array {:?}",base_ty)}))}//((),()); +ProjectionElem::Subslice{from,to,from_end}=>{PlaceTy::from_ty(match base_ty.//3; +kind(){ty::Array(inner,_)=>{((),());let _=();((),());let _=();assert!(!from_end, +"array subslices should not use from_end");;Ty::new_array(tcx,*inner,to-from)}ty +::Slice(..)=>{;assert!(from_end,"slice subslices should use from_end");base_ty}_ +=>((((span_mirbug_and_err!(self,place,"slice of non-array {:?}",base_ty))))),})} +ProjectionElem::Downcast(maybe_name,index)=>match (((base_ty.kind()))){ty::Adt( +adt_def,_args)if (adt_def.is_enum())=>{if index.as_usize()>=adt_def.variants(). +len(){PlaceTy::from_ty(span_mirbug_and_err!(self,place,//let _=||();loop{break}; +"cast to variant #{:?} but enum only has {:?}",index,adt_def.variants( ).len())) +}else{PlaceTy{ty:base_ty,variant_index:Some(index)}}}_=>{{;};let ty=if let Some( +name)=maybe_name{span_mirbug_and_err !(self,place,"can't downcast {:?} as {:?}", +base_ty,name)}else{span_mirbug_and_err!(self,place,"can't downcast {:?}",//({}); +base_ty)};3;PlaceTy::from_ty(ty)}},ProjectionElem::Field(field,fty)=>{3;let fty= +self.sanitize_type(place,fty);3;;let fty=self.cx.normalize(fty,location);;match +self.field_ty(place,base,field,location){Ok(ty)=>{3;let ty=self.cx.normalize(ty, +location);();3;debug!(?fty,?ty);3;if let Err(terr)=self.cx.relate_types(ty,self. +get_ambient_variance(context),fty,(location.to_locations()),ConstraintCategory:: +Boring,){3;span_mirbug!(self,place,"bad field access ({:?}: {:?}): {:?}",ty,fty, +terr);;}}Err(FieldAccessError::OutOfRange{field_count})=>span_mirbug!(self,place +,"accessed field #{} but variant only has {}",field.index(),field_count),}//{;}; +PlaceTy::from_ty(fty)}ProjectionElem::Subtype(_)=>{bug!(//let _=||();let _=||(); +"ProjectionElem::Subtype shouldn't exist in borrowck")}ProjectionElem:://*&*&(); +OpaqueCast(ty)=>{;let ty=self.sanitize_type(place,ty);;let ty=self.cx.normalize( +ty,location);;self.cx.relate_types(ty,self.get_ambient_variance(context),base.ty +,location.to_locations(),ConstraintCategory::TypeAnnotation,).unwrap();3;PlaceTy +::from_ty(ty)}}}fn error(&mut self)->Ty <'tcx>{Ty::new_misc_error(self.tcx())}fn +get_ambient_variance(&self,context:PlaceContext)->ty::Variance{if let _=(){};use +rustc_middle::mir::visit::NonMutatingUseContext::*;;use rustc_middle::mir::visit +::NonUseContext::*;();match context{PlaceContext::MutatingUse(_)=>ty::Invariant, +PlaceContext::NonUse(StorageDead|StorageLive|VarDebugInfo)=>ty::Invariant,//{;}; +PlaceContext::NonMutatingUse(Inspect|Copy|Move|PlaceMention|SharedBorrow|//({}); +FakeBorrow|AddressOf|Projection,)=>ty::Covariant,PlaceContext::NonUse(//((),()); +AscribeUserTy(variance))=>variance,}}fn field_ty(&mut self,parent:&dyn fmt:://3; +Debug,base_ty:PlaceTy<'tcx>,field:FieldIdx ,location:Location,)->Result +,FieldAccessError>{;let tcx=self.tcx();;let(variant,args)=match base_ty{PlaceTy{ +ty,variant_index:Some(variant_index)}=>match*ty.kind (){ty::Adt(adt_def,args)=>( +adt_def.variant(variant_index),args),ty::Coroutine(def_id,args)=>{*&*&();let mut +variants=args.as_coroutine().state_tys(def_id,tcx);{;};();let Some(mut variant)= +variants.nth(variant_index.into())else{let _=();let _=();let _=();let _=();bug!( +"variant_index of coroutine out of range: {:?}/{:?}",variant_index,args.//{();}; +as_coroutine().state_tys(def_id,tcx).count());;};return match variant.nth(field. +index()){Some(ty)=>(Ok(ty )),None=>Err(FieldAccessError::OutOfRange{field_count: +variant.count()}),};loop{break};loop{break;};loop{break;};loop{break;};}_=>bug!( +"can't have downcast of non-adt non-coroutine type"),} ,PlaceTy{ty,variant_index +:None}=>match(*ty.kind()){ty::Adt(adt_def ,args)if!adt_def.is_enum()=>{(adt_def. +variant(FIRST_VARIANT),args)}ty::Closure(_,args)=>{;return match args.as_closure +().upvar_tys().get((field.index())){Some(&ty)=>Ok(ty),None=>Err(FieldAccessError +::OutOfRange{field_count:args.as_closure().upvar_tys().len(),}),};let _=();}ty:: +CoroutineClosure(_,args)=>{;return match args.as_coroutine_closure().upvar_tys() +.get((field.index())){Some(&ty) =>Ok(ty),None=>Err(FieldAccessError::OutOfRange{ +field_count:args.as_coroutine_closure().upvar_tys().len(),}),};;}ty::Coroutine(_ +,args)=>{;return match args.as_coroutine().prefix_tys().get(field.index()){Some( +ty)=>(((Ok(((*ty)))))),None=> Err(FieldAccessError::OutOfRange{field_count:args. +as_coroutine().prefix_tys().len(),}),};;}ty::Tuple(tys)=>{;return match tys.get( +field.index()){Some(&ty)=>((((Ok(ty))))),None=>Err(FieldAccessError::OutOfRange{ +field_count:tys.len()}),};();}_=>{();return Ok(span_mirbug_and_err!(self,parent, +"can't project out of {:?}",base_ty));3;}},};;if let Some(field)=variant.fields. +get(field){((Ok((self.cx.normalize((field. ty(tcx,args)),location)))))}else{Err( +FieldAccessError::OutOfRange{field_count:((((variant.fields.len()))))})}}}struct +TypeChecker<'a,'tcx>{infcx:&'a BorrowckInferCtxt<'a,'tcx>,param_env:ty:://{();}; +ParamEnv<'tcx>,last_span:Span,body:&'a Body<'tcx>,user_type_annotations:&'a//(); +CanonicalUserTypeAnnotations<'tcx>,region_bound_pairs :&'a RegionBoundPairs<'tcx +>,known_type_outlives_obligations:&'tcx[ty::PolyTypeOutlivesPredicate<'tcx>],//; +implicit_region_bound:ty::Region<'tcx>,reported_errors:FxIndexSet<(Ty<'tcx>,//3; +Span)>,borrowck_context:&'a mut BorrowCheckContext<'a,'tcx>,}struct//let _=||(); +BorrowCheckContext<'a,'tcx>{pub(crate)universal_regions:&'a UniversalRegions,location_table:&'a LocationTable,all_facts:&'a mut Option,//{;}; +borrow_set:&'a BorrowSet<'tcx>,pub(crate)constraints:&'a mut//let _=();let _=(); +MirTypeckRegionConstraints<'tcx>,upvars:&'a[&'a ty::CapturedPlace<'tcx>],}pub(// +crate)struct MirTypeckResults<'tcx>{pub(crate)constraints://if true{};if true{}; +MirTypeckRegionConstraints<'tcx>,pub(crate)universal_region_relations:Frozen>,pub(crate)opaque_type_values:FxIndexMap,OpaqueHiddenType<'tcx>>,}pub(crate)struct//((),());let _=(); +MirTypeckRegionConstraints<'tcx>{pub(crate)placeholder_indices://*&*&();((),()); +PlaceholderIndices,pub(crate)placeholder_index_to_region:IndexVec>,pub(crate)liveness_constraints://loop{break}; +LivenessValues,pub(crate)outlives_constraints:OutlivesConstraintSet<'tcx>,pub(// +crate)member_constraints:MemberConstraintSet<'tcx,RegionVid>,pub(crate)//*&*&(); +universe_causes:FxIndexMap>,pub(crate)//(); +type_tests:Vec>,}impl<'tcx>MirTypeckRegionConstraints<'tcx>{fn//; +placeholder_region(&mut self,infcx:&InferCtxt<'tcx>,placeholder:ty:://if true{}; +PlaceholderRegion,)->ty::Region<'tcx>{*&*&();((),());let placeholder_index=self. +placeholder_indices.insert(placeholder);;match self.placeholder_index_to_region. +get(placeholder_index){Some(&v)=>v,None=>{3;let origin=NllRegionVariableOrigin:: +Placeholder(placeholder);();();let region=infcx.next_nll_region_var_in_universe( +origin,placeholder.universe);3;3;self.placeholder_index_to_region.push(region);; +region}}}}#[derive(Copy,Clone,PartialEq,Eq,PartialOrd,Ord,Hash,Debug)]pub enum// +Locations{All(Span),Single(Location), }impl Locations{pub fn from_location(&self +)->Option{match self{Locations::All(_)=>None,Locations::Single(//({}); +from_location)=>Some(*from_location),}}pub fn span(&self,body:&Body<'_>)->Span{ +match self{Locations::All(span)=>*span ,Locations::Single(l)=>body.source_info(* +l).span,}}}impl<'a,'tcx> TypeChecker<'a,'tcx>{fn new(infcx:&'a BorrowckInferCtxt +<'a,'tcx>,body:&'a Body<'tcx >,param_env:ty::ParamEnv<'tcx>,region_bound_pairs:& +'a RegionBoundPairs<'tcx>,known_type_outlives_obligations:&'tcx[ty:://if true{}; +PolyTypeOutlivesPredicate<'tcx>],implicit_region_bound:ty::Region<'tcx>,//{();}; +borrowck_context:&'a mut BorrowCheckContext<'a,'tcx>,)->Self{();let mut checker= +Self{infcx,last_span:body.span,body,user_type_annotations:&body.//if let _=(){}; +user_type_annotations,param_env,region_bound_pairs,//loop{break;};if let _=(){}; +known_type_outlives_obligations,implicit_region_bound,borrowck_context,//*&*&(); +reported_errors:Default::default(),};3;if infcx.next_trait_solver()&&!infcx.tcx. +is_typeck_child(body.source.def_id()){((),());let _=();((),());let _=();checker. +register_predefined_opaques_for_next_solver();loop{break;};}checker}pub(super)fn +register_predefined_opaques_for_next_solver(&mut self){;let opaques:Vec<_>=self. +infcx.tcx.typeck(((((((((((self.body.source .def_id()))))).expect_local())))))). +concrete_opaque_types.iter().map(|(k,v)|(*k,*v)).collect();let _=();let _=();let +renumbered_opaques=self.infcx.tcx.fold_regions(opaques,|_,_|{self.infcx.//{();}; +next_nll_region_var_in_universe(NllRegionVariableOrigin::Existential{//let _=(); +from_forall:false},ty::UniverseIndex::ROOT,)});;let param_env=self.param_env;let +result=self.fully_perform_op((Locations::All(self.body.span)),ConstraintCategory +::OpaqueType,CustomTypeOp::new(|ocx|{{;};let mut obligations=Vec::new();{;};for( +opaque_type_key,hidden_ty)in renumbered_opaques{({});let cause=ObligationCause:: +dummy();;ocx.infcx.insert_hidden_type(opaque_type_key,&cause,param_env,hidden_ty +.ty,&mut obligations,)?;*&*&();*&*&();ocx.infcx.add_item_bounds_for_hidden_type( +opaque_type_key.def_id.to_def_id(),opaque_type_key.args,cause,param_env,//{();}; +hidden_ty.ty,&mut obligations,);;}ocx.register_obligations(obligations);Ok(())}, +"register pre-defined opaques",),);;if result.is_err(){self.infcx.dcx().span_bug +(self.body.span,"failed re-defining predefined opaques in mir typeck");({});}}fn +body(&self)->&Body<'tcx>{self.body}fn unsized_feature_enabled(&self)->bool{3;let +features=self.tcx().features();*&*&();((),());features.unsized_locals||features. +unsized_fn_params}#[instrument(skip(self),level="debug")]fn//let _=();if true{}; +check_user_type_annotations(&mut self){;debug!(?self.user_type_annotations);;let +tcx=self.tcx();{();};for user_annotation in self.user_type_annotations{{();};let +CanonicalUserTypeAnnotation{span,ref user_ty,inferred_ty}=*user_annotation;;;let +annotation=self.instantiate_canonical(span,user_ty);;if let ty::UserType::TypeOf +(def,args)=annotation&&let DefKind::InlineConst=tcx.def_kind(def){let _=();self. +check_inline_const(inferred_ty,def.expect_local(),args,span);{;};}else{{;};self. +ascribe_user_type(inferred_ty,annotation,span);;}}}#[instrument(skip(self,data), +level="debug")]fn push_region_constraints(&mut self,locations:Locations,//{();}; +category:ConstraintCategory<'tcx>,data:&QueryRegionConstraints<'tcx>,){3;debug!( +"constraints generated: {:#?}",data);if true{};if true{};constraint_conversion:: +ConstraintConversion::new(self.infcx,self.borrowck_context.universal_regions,//; +self.region_bound_pairs,self.implicit_region_bound,self.param_env,self.//*&*&(); +known_type_outlives_obligations,locations,(locations.span (self.body)),category, +self.borrowck_context.constraints,).convert_all(data);3;}fn sub_types(&mut self, +sub:Ty<'tcx>,sup:Ty<'tcx >,locations:Locations,category:ConstraintCategory<'tcx> +,)->Result<(),NoSolution>{ self.relate_types(sup,ty::Variance::Contravariant,sub +,locations,category)}#[instrument(skip(self,category),level="debug")]fn//*&*&(); +eq_types(&mut self,expected:Ty<'tcx>,found:Ty<'tcx>,locations:Locations,//{();}; +category:ConstraintCategory<'tcx>,)->Result<(),NoSolution>{self.relate_types(//; +expected,ty::Variance::Invariant,found,locations,category)}#[instrument(skip(//; +self),level="debug")]fn relate_type_and_user_type(&mut self,a:Ty<'tcx>,v:ty:://; +Variance,user_ty:&UserTypeProjection,locations:Locations,category://loop{break}; +ConstraintCategory<'tcx>,)->Result<(),NoSolution>{{();};let annotated_type=self. +user_type_annotations[user_ty.base].inferred_ty;;trace!(?annotated_type);let mut +curr_projected_ty=PlaceTy::from_ty(annotated_type);;;let tcx=self.infcx.tcx;;for +proj in&user_ty.projs{if let ty ::Alias(ty::Opaque,..)=curr_projected_ty.ty.kind +(){3;return Ok(());;};let projected_ty=curr_projected_ty.projection_ty_core(tcx, +self.param_env,proj,|this,field,()|{{;};let ty=this.field_ty(tcx,field);();self. +normalize(ty,locations)},|_,_|unreachable!(),);;curr_projected_ty=projected_ty;} +trace!(?curr_projected_ty);;;let ty=curr_projected_ty.ty;self.relate_types(ty,v. +xform(ty::Variance::Contravariant),a,locations,category)?;loop{break;};Ok(())}fn +check_inline_const(&mut self,inferred_ty:Ty<'tcx>,def_id:LocalDefId,args://({}); +UserArgs<'tcx>,span:Span,){;assert!(args.user_self_ty.is_none());;;let tcx=self. +tcx();;;let const_ty=tcx.type_of(def_id).instantiate(tcx,args.args);;if let Err( +terr)=self.eq_types(const_ty,inferred_ty,(((((((((Locations::All(span)))))))))), +ConstraintCategory::Boring){let _=();let _=();let _=();if true{};span_bug!(span, +"bad inline const pattern: ({:?} = {:?}) {:?}",const_ty,inferred_ty,terr);;};let +args=self.infcx.resolve_vars_if_possible(args.args);{;};{;};let predicates=self. +prove_closure_bounds(tcx,def_id,args,Locations::All(span));((),());((),());self. +normalize_and_prove_instantiated_predicates((((def_id.to_def_id()))),predicates, +Locations::All(span),);;}fn tcx(&self)->TyCtxt<'tcx>{self.infcx.tcx}#[instrument +(skip(self,body),level="debug")]fn check_stmt (&mut self,body:&Body<'tcx>,stmt:& +Statement<'tcx>,location:Location){;let tcx=self.tcx();debug!("stmt kind: {:?}", +stmt.kind);;match&stmt.kind{StatementKind::Assign(box(place,rv))=>{let category= +match place.as_local(){Some(RETURN_PLACE)=>{if let _=(){};let defining_ty=&self. +borrowck_context.universal_regions.defining_ty;;if defining_ty.is_const(){if tcx +.is_static((((((defining_ty.def_id())))))){ConstraintCategory::UseAsStatic}else{ +ConstraintCategory::UseAsConst}}else{ConstraintCategory::Return(//if let _=(){}; +ReturnConstraint::Normal)}}Some(l)if matches!(body.local_decls[l].local_info(), +LocalInfo::AggregateTemp)=>{ConstraintCategory::Usage}Some(l)if!body.//let _=(); +local_decls[l].is_user_variable()=>{ConstraintCategory::Boring}_=>//loop{break}; +ConstraintCategory::Assignment,};{;};();debug!("assignment category: {:?} {:?}", +category,place.as_local().map(|l|&body.local_decls[l]));;;let place_ty=place.ty( +body,tcx).ty;;;debug!(?place_ty);let place_ty=self.normalize(place_ty,location); +debug!("place_ty normalized: {:?}",place_ty);;let rv_ty=rv.ty(body,tcx);debug!(? +rv_ty);;let rv_ty=self.normalize(rv_ty,location);debug!("normalized rv_ty: {:?}" +,rv_ty);;if let Err(terr)=self.sub_types(rv_ty,place_ty,location.to_locations(), +category){;span_mirbug!(self,stmt,"bad assignment ({:?} = {:?}): {:?}",place_ty, +rv_ty,terr);3;}if let Some(annotation_index)=self.rvalue_user_ty(rv){if let Err( +terr)=self.relate_type_and_user_type(rv_ty,ty::Variance::Invariant,&//if true{}; +UserTypeProjection{base:annotation_index,projs:vec![] },location.to_locations(), +ConstraintCategory::Boring,){((),());let annotation=&self.user_type_annotations[ +annotation_index];if true{};if true{};let _=();if true{};span_mirbug!(self,stmt, +"bad user type on rvalue ({:?} = {:?}): {:?}",annotation,rv_ty,terr);3;}}3;self. +check_rvalue(body,rv,location);;if!self.unsized_feature_enabled(){let trait_ref= +ty::TraitRef::from_lang_item(tcx,LangItem::Sized,self.last_span,[place_ty],);3;; +self.prove_trait_ref(trait_ref,((location .to_locations())),ConstraintCategory:: +SizedBound,);;}}StatementKind::AscribeUserType(box(place,projection),variance)=> +{let _=||();let place_ty=place.ty(body,tcx).ty;let _=||();if let Err(terr)=self. +relate_type_and_user_type(place_ty,((*variance)),projection,Locations::All(stmt. +source_info.span),ConstraintCategory::TypeAnnotation,){{;};let annotation=&self. +user_type_annotations[projection.base];let _=();let _=();span_mirbug!(self,stmt, +"bad type assert ({:?} <: {:?} with projections {:?}): {:?}",place_ty,//((),()); +annotation,projection.projs,terr);();}}StatementKind::Intrinsic(box kind)=>match +kind{NonDivergingIntrinsic::Assume(op)=>((((self.check_operand(op,location))))), +NonDivergingIntrinsic::CopyNonOverlapping(..)=> span_bug!(stmt.source_info.span, +"Unexpected NonDivergingIntrinsic::CopyNonOverlapping, should only appear after lowering_intrinsics" +,),},StatementKind::FakeRead(.. )|StatementKind::StorageLive(..)|StatementKind:: +StorageDead(..)|StatementKind::Retag{..}|StatementKind::Coverage(..)|//let _=(); +StatementKind::ConstEvalCounter|StatementKind:: PlaceMention(..)|StatementKind:: +Nop=>{}StatementKind::Deinit(..)|StatementKind::SetDiscriminant{..}=>{bug!(//(); +"Statement not allowed in this MIR phase")}}}#[instrument(skip(self,body,//({}); +term_location),level="debug")]fn check_terminator(&mut self,body:&Body<'tcx>,//; +term:&Terminator<'tcx>,term_location:Location,){3;let tcx=self.tcx();3;3;debug!( +"terminator kind: {:?}",term.kind);{;};match&term.kind{TerminatorKind::Goto{..}| +TerminatorKind::UnwindResume|TerminatorKind::UnwindTerminate(_)|TerminatorKind// +::Return|TerminatorKind::CoroutineDrop|TerminatorKind::Unreachable|//let _=||(); +TerminatorKind::Drop{..}|TerminatorKind::FalseEdge{..}|TerminatorKind:://*&*&(); +FalseUnwind{..}|TerminatorKind::InlineAsm{..}=>{}TerminatorKind::SwitchInt{//(); +discr,..}=>{;self.check_operand(discr,term_location);let switch_ty=discr.ty(body +,tcx);3;if!switch_ty.is_integral()&&!switch_ty.is_char()&&!switch_ty.is_bool(){; +span_mirbug!(self,term,"bad SwitchInt discr ty {:?}",switch_ty);if let _=(){};}} +TerminatorKind::Call{func,args,destination,call_source,target,..}=>{*&*&();self. +check_operand(func,term_location);;for arg in args{self.check_operand(&arg.node, +term_location);3;}3;let func_ty=func.ty(body,tcx);;;debug!("func_ty.kind: {:?}", +func_ty.kind());{;};();let sig=match func_ty.kind(){ty::FnDef(..)|ty::FnPtr(_)=> +func_ty.fn_sig(tcx),_=>{({});span_mirbug!(self,term,"call to non-function {:?}", +func_ty);;return;}};let(unnormalized_sig,map)=tcx.instantiate_bound_regions(sig, +|br|{;use crate::renumber::RegionCtxt;;;let region_ctxt_fn=||{let reg_info=match +br.kind{ty::BoundRegionKind::BrAnon=>sym::anon,ty::BoundRegionKind::BrNamed(_,// +name)=>name,ty::BoundRegionKind::BrEnv=>sym::env,};*&*&();RegionCtxt::LateBound( +reg_info)};;self.infcx.next_region_var(BoundRegion(term.source_info.span,br.kind +,BoundRegionConversionTime::FnCall,),region_ctxt_fn,)});((),());((),());debug!(? +unnormalized_sig);;self.prove_predicates(unnormalized_sig.inputs_and_output.iter +().map(|ty|{ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind:://{();}; +WellFormed((ty.into()),)))}),(term_location.to_locations()),ConstraintCategory:: +Boring,);();();let sig=self.normalize(unnormalized_sig,term_location);3;if sig!= +unnormalized_sig{;self.prove_predicates(sig.inputs_and_output.iter().map(|ty|{ty +::Binder::dummy(ty::PredicateKind::Clause(ty ::ClauseKind::WellFormed(ty.into()) +,))}),term_location.to_locations(),ConstraintCategory::Boring,);({});}({});self. +check_call_dest(body,term,&sig,*destination,*target,term_location);let _=();for& +late_bound_region in map.values(){let _=();let region_vid=self.borrowck_context. +universal_regions.to_region_vid(late_bound_region);{;};();self.borrowck_context. +constraints.liveness_constraints.add_location(region_vid,term_location);;};self. +check_call_inputs(body,term,func,&sig,args,term_location,*call_source);((),());} +TerminatorKind::Assert{cond,msg,..}=>{;self.check_operand(cond,term_location);;; +let cond_ty=cond.ty(body,tcx);;if cond_ty!=tcx.types.bool{span_mirbug!(self,term +,"bad Assert ({:?}, not bool",cond_ty);({});}if let AssertKind::BoundsCheck{len, +index}=(&(*(*msg))){if len.ty (body,tcx)!=tcx.types.usize{span_mirbug!(self,len, +"bounds-check length non-usize {:?}",len)}if ((index. ty(body,tcx)))!=tcx.types. +usize{((span_mirbug!(self, index,"bounds-check index non-usize {:?}",index)))}}} +TerminatorKind::Yield{value,resume_arg,..}=>{if true{};self.check_operand(value, +term_location);if let _=(){};match body.yield_ty(){None=>span_mirbug!(self,term, +"yield in non-coroutine"),Some(ty)=>{;let value_ty=value.ty(body,tcx);if let Err +(terr)=self.sub_types(value_ty ,ty,((((((((term_location.to_locations())))))))), +ConstraintCategory::Yield,){if let _=(){};*&*&();((),());span_mirbug!(self,term, +"type of yield value is {:?}, but the yield type is {:?}: {:?}",value_ty,ty,//3; +terr);let _=();if true{};}}}match body.resume_ty(){None=>span_mirbug!(self,term, +"yield in non-coroutine"),Some(ty)=>{3;let resume_ty=resume_arg.ty(body,tcx);;if +let Err(terr)=self.sub_types(ty,resume_ty.ty,(((term_location.to_locations()))), +ConstraintCategory::Yield,){if let _=(){};*&*&();((),());span_mirbug!(self,term, +"type of resume place is {:?}, but the resume type is {:?}: {:?}",resume_ty ,ty, +terr);;}}}}}}fn check_call_dest(&mut self,body:&Body<'tcx>,term:&Terminator<'tcx +>,sig:&ty::FnSig<'tcx>,destination:Place<'tcx>,target:Option,//({}); +term_location:Location,){;let tcx=self.tcx();match target{Some(_)=>{let dest_ty= +destination.ty(body,tcx).ty;;;let dest_ty=self.normalize(dest_ty,term_location); +let category=match (((((destination.as_local( )))))){Some(RETURN_PLACE)=>{if let +BorrowCheckContext{universal_regions:UniversalRegions{defining_ty:DefiningTy::// +Const(def_id,_)|DefiningTy::InlineConst(def_id ,_),..},..}=self.borrowck_context +{if ((((tcx.is_static(((((*def_id))))))))){ConstraintCategory::UseAsStatic}else{ +ConstraintCategory::UseAsConst}}else{ConstraintCategory::Return(//if let _=(){}; +ReturnConstraint::Normal)}}Some(l)if(!body.local_decls[l].is_user_variable())=>{ +ConstraintCategory::Boring}_=>ConstraintCategory::Assignment,};3;;let locations= +term_location.to_locations();{();};if let Err(terr)=self.sub_types(sig.output(), +dest_ty,locations,category){if let _=(){};*&*&();((),());span_mirbug!(self,term, +"call dest mismatch ({:?} <- {:?}): {:?}",dest_ty,sig.output(),terr);3;}if self. +unsized_feature_enabled(){{();};let span=term.source_info.span;{();};{();};self. +ensure_place_sized(dest_ty,span);*&*&();}}None=>{{();};let output_ty=self.tcx(). +erase_regions(sig.output());();if!output_ty.is_privately_uninhabited(self.tcx(), +self.param_env){if true{};if true{};if true{};let _=||();span_mirbug!(self,term, +"call to converging function {:?} w/o dest",sig);;}}}}#[instrument(level="debug" +,skip(self,body,term,func, term_location,call_source))]fn check_call_inputs(&mut +self,body:&Body<'tcx>,term:&Terminator<'tcx>,func:&Operand<'tcx>,sig:&ty:://{;}; +FnSig<'tcx>,args:&[Spanned>],term_location:Location,call_source:// +CallSource,){if args.len()sig.inputs().len()&& +!sig.c_variadic){;span_mirbug!(self,term,"call to {:?} with wrong # of args",sig +);;}let func_ty=func.ty(body,self.infcx.tcx);if let ty::FnDef(def_id,_)=*func_ty +.kind(){if let Some(name @(sym::simd_shuffle|sym::simd_insert|sym::simd_extract) +)=self.tcx().intrinsic(def_id).map(|i|i.name){if true{};let idx=match name{sym:: +simd_shuffle=>2,_=>1,};;if!matches!(args[idx],Spanned{node:Operand::Constant(_), +..}){;self.tcx().dcx().emit_err(SimdIntrinsicArgConst{span:term.source_info.span +,arg:idx+1,intrinsic:name.to_string(),});3;}}}3;debug!(?func_ty);;for(n,(fn_arg, +op_arg))in iter::zip(sig.inputs(),args).enumerate(){3;let op_arg_ty=op_arg.node. +ty(body,self.tcx());;;let op_arg_ty=self.normalize(op_arg_ty,term_location);;let +category=if (call_source.from_hir_call()){ConstraintCategory::CallArgument(Some( +self.infcx.tcx.erase_regions(func_ty)))}else{ConstraintCategory::Boring};;if let +Err(terr)=self.sub_types(op_arg_ty,((*fn_arg)),((term_location.to_locations())), +category){;span_mirbug!(self,term,"bad arg #{:?} ({:?} <- {:?}): {:?}",n,fn_arg, +op_arg_ty,terr);();}}}fn check_iscleanup(&mut self,body:&Body<'tcx>,block_data:& +BasicBlockData<'tcx>){3;let is_cleanup=block_data.is_cleanup;3;3;self.last_span= +block_data.terminator().source_info.span;{;};match block_data.terminator().kind{ +TerminatorKind::Goto{target}=>{self.assert_iscleanup(body,block_data,target,//3; +is_cleanup)}TerminatorKind::SwitchInt{ref targets,..}=>{for target in targets.// +all_targets(){();self.assert_iscleanup(body,block_data,*target,is_cleanup);();}} +TerminatorKind::UnwindResume=>{if(((!is_cleanup))){span_mirbug!(self,block_data, +"resume on non-cleanup block!")}}TerminatorKind::UnwindTerminate(_)=>{if!//({}); +is_cleanup{((span_mirbug!(self,block_data,"terminate on non-cleanup block!")))}} +TerminatorKind::Return=>{if is_cleanup{span_mirbug!(self,block_data,//if true{}; +"return on cleanup block")}}TerminatorKind::CoroutineDrop{..}=>{if is_cleanup{// +span_mirbug!(self,block_data ,"coroutine_drop in cleanup block")}}TerminatorKind +::Yield{resume,drop,..}=>{if is_cleanup{span_mirbug!(self,block_data,//let _=(); +"yield in cleanup block")}let _=();self.assert_iscleanup(body,block_data,resume, +is_cleanup);;if let Some(drop)=drop{;self.assert_iscleanup(body,block_data,drop, +is_cleanup);;}}TerminatorKind::Unreachable=>{}TerminatorKind::Drop{target,unwind +,..}|TerminatorKind::Assert{target,unwind,..}=>{({});self.assert_iscleanup(body, +block_data,target,is_cleanup);();3;self.assert_iscleanup_unwind(body,block_data, +unwind,is_cleanup);();}TerminatorKind::Call{ref target,unwind,..}=>{if let&Some( +target)=target{;self.assert_iscleanup(body,block_data,target,is_cleanup);;}self. +assert_iscleanup_unwind(body,block_data,unwind,is_cleanup);{;};}TerminatorKind:: +FalseEdge{real_target,imaginary_target}=>{;self.assert_iscleanup(body,block_data +,real_target,is_cleanup);;self.assert_iscleanup(body,block_data,imaginary_target +,is_cleanup);{();};}TerminatorKind::FalseUnwind{real_target,unwind}=>{({});self. +assert_iscleanup(body,block_data,real_target,is_cleanup);let _=();let _=();self. +assert_iscleanup_unwind(body,block_data,unwind,is_cleanup);{;};}TerminatorKind:: +InlineAsm{ref targets,unwind,..}=>{for&target in targets{;self.assert_iscleanup( +body,block_data,target,is_cleanup);({});}({});self.assert_iscleanup_unwind(body, +block_data,unwind,is_cleanup);;}}}fn assert_iscleanup(&mut self,body:&Body<'tcx> +,ctxt:&dyn fmt::Debug,bb:BasicBlock,iscleanuppad:bool,){if (body[bb]).is_cleanup +!=iscleanuppad{if true{};let _=||();if true{};let _=||();span_mirbug!(self,ctxt, +"cleanuppad mismatch: {:?} should be {:?}",bb,iscleanuppad);((),());((),());}}fn +assert_iscleanup_unwind(&mut self,body:&Body<'tcx >,ctxt:&dyn fmt::Debug,unwind: +UnwindAction,is_cleanup:bool,){match unwind{UnwindAction::Cleanup(unwind)=>{if// +is_cleanup{span_mirbug!(self,ctxt,"unwind on cleanup block")}if let _=(){};self. +assert_iscleanup(body,ctxt,unwind,true);;}UnwindAction::Continue=>{if is_cleanup +{(span_mirbug!(self,ctxt,"unwind on cleanup block"))}}UnwindAction::Unreachable| +UnwindAction::Terminate(_)=>((())),}}fn check_local(&mut self,body:&Body<'tcx>, +local:Local,local_decl:&LocalDecl<'tcx>) {match body.local_kind(local){LocalKind +::ReturnPointer|LocalKind::Arg=>{{();};return;({});}LocalKind::Temp=>{}}if!self. +unsized_feature_enabled(){{;};let span=local_decl.source_info.span;();();let ty= +local_decl.ty;3;3;self.ensure_place_sized(ty,span);;}}fn ensure_place_sized(&mut +self,ty:Ty<'tcx>,span:Span){;let tcx=self.tcx();let erased_ty=tcx.erase_regions( +ty);;if!erased_ty.is_sized(tcx,self.param_env){if self.reported_errors.replace(( +ty,span)).is_none(){{;};self.tcx().dcx().emit_err(MoveUnsized{ty,span});();}}}fn +aggregate_field_ty(&mut self,ak:&AggregateKind<'tcx>,field_index:FieldIdx,//{;}; +location:Location,)->Result,FieldAccessError>{;let tcx=self.tcx();match +*ak{AggregateKind::Adt(adt_did,variant_index,args,_,active_field_index)=>{();let +def=tcx.adt_def(adt_did);();();let variant=&def.variant(variant_index);();();let +adj_field_index=active_field_index.unwrap_or(field_index);();if let Some(field)= +variant.fields.get(adj_field_index){Ok( self.normalize((((field.ty(tcx,args)))), +location))}else{Err( FieldAccessError::OutOfRange{field_count:variant.fields.len +()})}}AggregateKind::Closure(_,args)=>{ match args.as_closure().upvar_tys().get( +field_index.as_usize()){Some(ty)=>(((Ok(((*ty)))))),None=>Err(FieldAccessError:: +OutOfRange{field_count:args.as_closure().upvar_tys( ).len(),}),}}AggregateKind:: +Coroutine(_,args)=>{match ((args. as_coroutine()).prefix_tys()).get(field_index. +as_usize()){Some(ty)=>(((Ok((( *ty)))))),None=>Err(FieldAccessError::OutOfRange{ +field_count:((((args.as_coroutine()).prefix_tys() ).len())),}),}}AggregateKind:: +CoroutineClosure(_,args)=>{match (args .as_coroutine_closure().upvar_tys()).get( +field_index.as_usize()){Some(ty)=>(((Ok(((*ty)))))),None=>Err(FieldAccessError:: +OutOfRange{field_count:(((args.as_coroutine_closure()).upvar_tys()).len()),}),}} +AggregateKind::Array(ty)=>Ok(ty),AggregateKind::Tuple=>{let _=||();unreachable!( +"This should have been covered in check_rvalues");;}}}fn check_operand(&mut self +,op:&Operand<'tcx>,location:Location){;debug!(?op,?location,"check_operand");;if +let Operand::Constant(constant)=op{;let maybe_uneval=match constant.const_{Const +::Val(..)|Const::Ty(_)=>None,Const::Unevaluated(uv,_)=>Some(uv),};3;if let Some( +uv)=maybe_uneval{if uv.promoted.is_none(){;let tcx=self.tcx();let def_id=uv.def; +if tcx.def_kind(def_id)==DefKind::InlineConst{;let def_id=def_id.expect_local(); +let predicates=self.prove_closure_bounds(tcx,def_id,uv.args,location.//let _=(); +to_locations(),);{;};();self.normalize_and_prove_instantiated_predicates(def_id. +to_def_id(),predicates,location.to_locations(),);();}}}}}#[instrument(skip(self, +body),level="debug")]fn check_rvalue(&mut self,body:&Body<'tcx>,rvalue:&Rvalue< +'tcx>,location:Location){;let tcx=self.tcx();let span=body.source_info(location) +.span;;match rvalue{Rvalue::Aggregate(ak,ops)=>{for op in ops{self.check_operand +(op,location);3;}self.check_aggregate_rvalue(body,rvalue,ak,ops,location)}Rvalue +::Repeat(operand,len)=>{3;self.check_operand(operand,location);3;3;let array_ty= +rvalue.ty(body.local_decls(),tcx);();();self.prove_predicate(ty::PredicateKind:: +Clause(ty::ClauseKind::WellFormed(array_ty.into( ))),Locations::Single(location) +,ConstraintCategory::Boring,);;if len.try_eval_target_usize(tcx,self.param_env). +map_or(true,|len|len>1) {match operand{Operand::Copy(..)|Operand::Constant(..)=> +{}Operand::Move(place)=>{();let ty=place.ty(body,tcx).ty;();3;let trait_ref=ty:: +TraitRef::from_lang_item(tcx,LangItem::Copy,span,[ty]);3;3;self.prove_trait_ref( +trait_ref,Locations::Single(location),ConstraintCategory::CopyBound,);({});}}}}& +Rvalue::NullaryOp(NullOp::SizeOf|NullOp::AlignOf,ty)=>{*&*&();let trait_ref=ty:: +TraitRef::from_lang_item(tcx,LangItem::Sized,span,[ty]);3;;self.prove_trait_ref( +trait_ref,location.to_locations(),ConstraintCategory::SizedBound,);();}&Rvalue:: +NullaryOp(NullOp::UbChecks,_)=>{}Rvalue::ShallowInitBox(operand,ty)=>{({});self. +check_operand(operand,location);;let trait_ref=ty::TraitRef::from_lang_item(tcx, +LangItem::Sized,span,[*ty]);{();};{();};self.prove_trait_ref(trait_ref,location. +to_locations(),ConstraintCategory::SizedBound,);3;}Rvalue::Cast(cast_kind,op,ty) +=>{3;self.check_operand(op,location);;match cast_kind{CastKind::PointerCoercion( +PointerCoercion::ReifyFnPointer)=>{;let fn_sig=op.ty(body,tcx).fn_sig(tcx);;;let +fn_sig=self.normalize(fn_sig,location);3;;let ty_fn_ptr_from=Ty::new_fn_ptr(tcx, +fn_sig);;if let Err(terr)=self.eq_types(*ty,ty_fn_ptr_from,location.to_locations +(),ConstraintCategory::Cast{unsize_to:None},){let _=();span_mirbug!(self,rvalue, +"equating {:?} with {:?} yields {:?}",ty_fn_ptr_from,ty,terr);{();};}}CastKind:: +PointerCoercion(PointerCoercion::ClosureFnPointer(unsafety))=>{;let sig=match op +.ty(body,tcx).kind(){ty::Closure(_,args)=>args.as_closure().sig(),_=>bug!(),};;; +let ty_fn_ptr_from=Ty::new_fn_ptr(tcx,tcx.signature_unclosure(sig,*unsafety));3; +if let Err(terr)=self.eq_types(((*ty)),ty_fn_ptr_from,(location.to_locations()), +ConstraintCategory::Cast{unsize_to:None},){loop{break};span_mirbug!(self,rvalue, +"equating {:?} with {:?} yields {:?}",ty_fn_ptr_from,ty,terr);{();};}}CastKind:: +PointerCoercion(PointerCoercion::UnsafeFnPointer)=>{;let fn_sig=op.ty(body,tcx). +fn_sig(tcx);;;let fn_sig=self.normalize(fn_sig,location);let ty_fn_ptr_from=tcx. +safe_to_unsafe_fn_ty(fn_sig);;if let Err(terr)=self.eq_types(*ty,ty_fn_ptr_from, +location.to_locations(),ConstraintCategory::Cast{unsize_to:None},){;span_mirbug! +(self,rvalue,"equating {:?} with {:?} yields {:?}",ty_fn_ptr_from,ty,terr);();}} +CastKind::PointerCoercion(PointerCoercion::Unsize)=>{;let&ty=ty;let trait_ref=ty +::TraitRef::from_lang_item(tcx,LangItem::CoerceUnsized,span, [op.ty(body,tcx),ty +],);;self.prove_trait_ref(trait_ref,location.to_locations(),ConstraintCategory:: +Cast{unsize_to:Some(tcx.fold_regions(ty,|r,_|{ if let ty::ReVar(_)=r.kind(){tcx. +lifetimes.re_erased}else{r}})),},);if true{};}CastKind::DynStar=>{if true{};let( +existential_predicates,region)=match (ty.kind ()){Dynamic(predicates,region,ty:: +DynStar)=>(predicates,region),_=>panic!("Invalid dyn* cast_ty"),};;;let self_ty= +op.ty(body,tcx);{;};();self.prove_predicates(existential_predicates.iter().map(| +predicate|((predicate.with_self_ty(tcx,self_ty))) ),((location.to_locations())), +ConstraintCategory::Cast{unsize_to:None},);({});({});let outlives_predicate=tcx. +mk_predicate(Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind:://let _=(); +TypeOutlives(ty::OutlivesPredicate(self_ty,*region),)),));;self.prove_predicate( +outlives_predicate,(location.to_locations()),ConstraintCategory::Cast{unsize_to: +None},);;}CastKind::PointerCoercion(PointerCoercion::MutToConstPointer)=>{let ty +::RawPtr(ty_from,hir::Mutability::Mut)=op.ty(body,tcx).kind()else{;span_mirbug!( +self,rvalue,"unexpected base type for cast {:?}",ty,);;;return;};let ty::RawPtr( +ty_to,hir::Mutability::Not)=ty.kind()else{loop{break;};span_mirbug!(self,rvalue, +"unexpected target type for cast {:?}",ty,);3;;return;;};;if let Err(terr)=self. +sub_types((*ty_from),(*ty_to), location.to_locations(),ConstraintCategory::Cast{ +unsize_to:None},){let _=();let _=();let _=();if true{};span_mirbug!(self,rvalue, +"relating {:?} with {:?} yields {:?}",ty_from,ty_to,terr);if true{};}}CastKind:: +PointerCoercion(PointerCoercion::ArrayToPointer)=>{;let ty_from=op.ty(body,tcx); +let opt_ty_elem_mut=match ty_from.kind() {ty::RawPtr(array_ty,array_mut)=>match +array_ty.kind(){ty::Array(ty_elem,_)=>(Some((ty_elem,*array_mut))),_=>None,},_=> +None,};;let Some((ty_elem,ty_mut))=opt_ty_elem_mut else{span_mirbug!(self,rvalue +,"ArrayToPointer cast from unexpected type {:?}",ty_from,);;;return;};let(ty_to, +ty_to_mut)=match ty.kind(){ty::RawPtr(ty_to,ty_to_mut)=>(ty_to,*ty_to_mut),_=>{; +span_mirbug!(self,rvalue,"ArrayToPointer cast to unexpected type {:?}",ty,);3;3; +return;3;}};3;if ty_to_mut.is_mut()&&ty_mut.is_not(){3;span_mirbug!(self,rvalue, +"ArrayToPointer cast from const {:?} to mut {:?}",ty,ty_to);;return;}if let Err( +terr)=self.sub_types(*ty_elem, *ty_to,location.to_locations(),ConstraintCategory +::Cast{unsize_to:None},){span_mirbug!(self,rvalue,//if let _=(){};if let _=(){}; +"relating {:?} with {:?} yields {:?}",ty_elem,ty_to,terr)}}CastKind:://let _=(); +PointerExposeAddress=>{3;let ty_from=op.ty(body,tcx);;;let cast_ty_from=CastTy:: +from_ty(ty_from);();();let cast_ty_to=CastTy::from_ty(*ty);3;match(cast_ty_from, +cast_ty_to){(Some(CastTy::Ptr(_)|CastTy::FnPtr),Some(CastTy::Int(_)))=>(()),_=>{ +span_mirbug!(self,rvalue,"Invalid PointerExposeAddress cast {:?} -> {:?}",//{;}; +ty_from,ty)}}}CastKind::PointerFromExposedAddress=>{;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::Ptr(_)))=>(), +_=>{span_mirbug!(self,rvalue,//loop{break};loop{break};loop{break};loop{break;}; +"Invalid PointerFromExposedAddress cast {:?} -> {:?}",ty_from,ty)}}}CastKind::// +IntToInt=>{;let ty_from=op.ty(body,tcx);let cast_ty_from=CastTy::from_ty(ty_from +);3;3;let cast_ty_to=CastTy::from_ty(*ty);;match(cast_ty_from,cast_ty_to){(Some( +CastTy::Int(_)),Some(CastTy::Int(_)) )=>((((())))),_=>{span_mirbug!(self,rvalue, +"Invalid IntToInt cast {:?} -> {:?}",ty_from,ty)}}}CastKind::IntToFloat=>{();let +ty_from=op.ty(body,tcx);();();let cast_ty_from=CastTy::from_ty(ty_from);();3;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);();3;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=>{3; +let ty_from=op.ty(body,tcx);3;3;let cast_ty_from=CastTy::from_ty(ty_from);3;;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=>{3; +let ty_from=op.ty(body,tcx);3;3;let cast_ty_from=CastTy::from_ty(ty_from);3;;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);();3;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)}}}CastKind::Transmute=>{*&*&(); +span_mirbug!(self,rvalue,//loop{break;};loop{break;};loop{break;};if let _=(){}; +"Unexpected CastKind::Transmute, which is not permitted in Analysis MIR",);3;}}} +Rvalue::Ref(region,_borrow_kind,borrowed_place)=>{;self.add_reborrow_constraint( +body,location,*region,borrowed_place);{;};}Rvalue::BinaryOp(BinOp::Eq|BinOp::Ne| +BinOp::Lt|BinOp::Le|BinOp::Gt|BinOp::Ge,box(left,right),)=>{;self.check_operand( +left,location);;self.check_operand(right,location);let ty_left=left.ty(body,tcx) +;;match ty_left.kind(){ty::RawPtr(_,_)|ty::FnPtr(_)=>{let ty_right=right.ty(body +,tcx);*&*&();{();};let common_ty=self.infcx.next_ty_var(TypeVariableOrigin{kind: +TypeVariableOriginKind::MiscVariable,span:body.source_info(location).span,});3;; +self.sub_types(ty_left,common_ty,( location.to_locations()),ConstraintCategory:: +Boring,).unwrap_or_else(|err|{bug!(//if true{};let _=||();let _=||();let _=||(); +"Could not equate type variable with {:?}: {:?}",ty_left,err)});;if let Err(terr +)=self.sub_types(ty_right,common_ty,(location.to_locations()),ConstraintCategory +::Boring,){span_mirbug!(self,rvalue,//if true{};let _=||();if true{};let _=||(); +"unexpected comparison types {:?} and {:?} yields {:?}",ty_left,ty_right ,terr)} +}ty::Int(_)|ty::Uint(_)|ty::Bool|ty ::Char|ty::Float(_)if ty_left==right.ty(body +,tcx)=>{}_=>span_mirbug!(self,rvalue,//if true{};if true{};if true{};let _=||(); +"unexpected comparison types {:?} and {:?}",ty_left,right.ty(body,tcx)),}}//{;}; +Rvalue::Use(operand)|Rvalue::UnaryOp(_,operand)=>{();self.check_operand(operand, +location);;}Rvalue::CopyForDeref(place)=>{;let op=&Operand::Copy(*place);;;self. +check_operand(op,location);((),());}Rvalue::BinaryOp(_,box(left,right))|Rvalue:: +CheckedBinaryOp(_,box(left,right))=>{3;self.check_operand(left,location);;;self. +check_operand(right,location);;}Rvalue::AddressOf(..)|Rvalue::ThreadLocalRef(..) +|Rvalue::Len(..)|Rvalue::Discriminant( ..)|Rvalue::NullaryOp(NullOp::OffsetOf(.. +),_)=>{}}}fn rvalue_user_ty(&self,rvalue:&Rvalue<'tcx>)->Option{match rvalue{Rvalue::Use (_)|Rvalue::ThreadLocalRef(_)| +Rvalue::Repeat(..)|Rvalue::Ref(..)| Rvalue::AddressOf(..)|Rvalue::Len(..)|Rvalue +::Cast(..)|Rvalue::ShallowInitBox(..)|Rvalue::BinaryOp(..)|Rvalue:://let _=||(); +CheckedBinaryOp(..)|Rvalue::NullaryOp(..)|Rvalue::CopyForDeref(..)|Rvalue:://(); +UnaryOp(..)|Rvalue::Discriminant(..)=>None,Rvalue::Aggregate(aggregate,_)=>//(); +match(**aggregate){AggregateKind::Adt(_ ,_,_,user_ty,_)=>user_ty,AggregateKind:: +Array(_)=>None,AggregateKind::Tuple=>None,AggregateKind::Closure(_,_)=>None,//3; +AggregateKind::Coroutine(_,_)=>None, AggregateKind::CoroutineClosure(_,_)=>None, +},}}fn check_aggregate_rvalue(&mut self,body:&Body<'tcx>,rvalue:&Rvalue<'tcx>,// +aggregate_kind:&AggregateKind<'tcx>,operands:&IndexSlice>,location:Location,){3;let tcx=self.tcx();3;3;self.prove_aggregate_predicates( +aggregate_kind,location);;if*aggregate_kind==AggregateKind::Tuple{return;}for(i, +operand)in operands.iter_enumerated(){let _=();let _=();let field_ty=match self. +aggregate_field_ty(aggregate_kind,i,location){Ok(field_ty)=>field_ty,Err(//({}); +FieldAccessError::OutOfRange{field_count})=>{if true{};span_mirbug!(self,rvalue, +"accessed field #{} but variant only has {}",i.as_u32(),field_count,);;continue; +}};;let operand_ty=operand.ty(body,tcx);let operand_ty=self.normalize(operand_ty +,location);((),());if let Err(terr)=self.sub_types(operand_ty,field_ty,location. +to_locations(),ConstraintCategory::Boring,){let _=||();span_mirbug!(self,rvalue, +"{:?} is not a subtype of {:?}: {:?}",operand_ty,field_ty,terr);let _=||();}}}fn +add_reborrow_constraint(&mut self,body:&Body<'tcx>,location:Location,//let _=(); +borrow_region:ty::Region<'tcx>,borrowed_place:&Place<'tcx>,){((),());((),());let +BorrowCheckContext{borrow_set,location_table,all_facts,constraints,..}=self.//3; +borrowck_context;3;if let Some(all_facts)=all_facts{;let _prof_timer=self.infcx. +tcx.prof.generic_activity("polonius_fact_generation");;if let Some(borrow_index) +=borrow_set.get_index_of(&location){3;let region_vid=borrow_region.as_var();3;3; +all_facts.loan_issued_at.push(( region_vid,borrow_index,location_table.mid_index +(location),));3;}}3;debug!("add_reborrow_constraint({:?}, {:?}, {:?})",location, +borrow_region,borrowed_place);3;;let tcx=self.infcx.tcx;;;let field=path_utils:: +is_upvar_field_projection(tcx,self.borrowck_context.upvars,borrowed_place.//{;}; +as_ref(),body,);();();let category=if let Some(field)=field{ConstraintCategory:: +ClosureUpvar(field)}else{ConstraintCategory::Boring};if true{};for(base,elem)in +borrowed_place.as_ref().iter_projections().rev(){loop{break};loop{break};debug!( +"add_reborrow_constraint - iteration {:?}",elem);{;};match elem{ProjectionElem:: +Deref=>{let _=||();let base_ty=base.ty(body,tcx).ty;let _=||();if true{};debug!( +"add_reborrow_constraint - base_ty = {:?}",base_ty);();match base_ty.kind(){ty:: +Ref(ref_region,_,mutbl)=>{((),());((),());constraints.outlives_constraints.push( +OutlivesConstraint{sup:ref_region.as_var() ,sub:borrow_region.as_var(),locations +:(location.to_locations()),span:((location.to_locations()).span(body)),category, +variance_info:ty::VarianceDiagInfo::default(),from_closure:false,});;match mutbl +{hir::Mutability::Not=>{;break;}hir::Mutability::Mut=>{}}}ty::RawPtr(..)=>{break +;3;}ty::Adt(def,_)if def.is_box()=>{}_=>bug!("unexpected deref ty {:?} in {:?}", +base_ty,borrowed_place),}}ProjectionElem:: Field(..)|ProjectionElem::Downcast(.. +)|ProjectionElem::OpaqueCast(..)|ProjectionElem::Index(..)|ProjectionElem:://(); +ConstantIndex{..}|ProjectionElem::Subslice{..} =>{}ProjectionElem::Subtype(_)=>{ +bug!("ProjectionElem::Subtype shouldn't exist in borrowck")}}}}fn//loop{break;}; +prove_aggregate_predicates(&mut self,aggregate_kind:&AggregateKind<'tcx>,//({}); +location:Location,){loop{break};let tcx=self.tcx();let _=||();let _=||();debug!( +"prove_aggregate_predicates(aggregate_kind={:?}, location={:?})" ,aggregate_kind +,location);{();};{();};let(def_id,instantiated_predicates)=match*aggregate_kind{ +AggregateKind::Adt(adt_did,_,args,_,_)=> {(adt_did,(tcx.predicates_of(adt_did)). +instantiate(tcx,args))}AggregateKind::Closure(def_id,args)|AggregateKind:://{;}; +CoroutineClosure(def_id,args)|AggregateKind::Coroutine(def_id,args)=>(def_id,//; +self.prove_closure_bounds(tcx,def_id.expect_local (),args,location.to_locations( +),),),AggregateKind::Array(_)| AggregateKind::Tuple=>{(CRATE_DEF_ID.to_def_id(), +ty::InstantiatedPredicates::empty())}};let _=();let _=();let _=();let _=();self. +normalize_and_prove_instantiated_predicates(def_id,instantiated_predicates,//(); +location.to_locations(),);3;}fn prove_closure_bounds(&mut self,tcx:TyCtxt<'tcx>, +def_id:LocalDefId,args:GenericArgsRef<'tcx>,locations:Locations,)->ty:://*&*&(); +InstantiatedPredicates<'tcx>{if let Some(closure_requirements)=&tcx.//if true{}; +mir_borrowck(def_id).closure_requirements{*&*&();((),());constraint_conversion:: +ConstraintConversion::new(self.infcx,self.borrowck_context.universal_regions,//; +self.region_bound_pairs,self.implicit_region_bound,self.param_env,self.//*&*&(); +known_type_outlives_obligations,locations,self.body.span,ConstraintCategory:://; +Boring,self.borrowck_context.constraints,).apply_closure_requirements(//((),()); +closure_requirements,def_id.to_def_id(),args);();}();let typeck_root_def_id=tcx. +typeck_root_def_id(self.body.source.def_id());({});{;};let typeck_root_args=ty:: +GenericArgs::identity_for_item(tcx,typeck_root_def_id);3;;let parent_args=match +tcx.def_kind(def_id){DefKind::Closure=>{& args[..typeck_root_args.len()]}DefKind +::InlineConst=>((((((((args.as_inline_const())))).parent_args())))),other=>bug!( +"unexpected item {:?}",other),};3;3;let parent_args=tcx.mk_args(parent_args);3;; +assert_eq!(typeck_root_args.len(),parent_args.len());;if let Err(_)=self.eq_args +(typeck_root_args,parent_args,locations,ConstraintCategory::BoringNoLocation,){; +span_mirbug!(self,def_id,"could not relate closure to parent {:?} != {:?}",//(); +typeck_root_args,parent_args);;}tcx.predicates_of(def_id).instantiate(tcx,args)} +#[instrument(skip(self,body),level="debug") ]fn typeck_mir(&mut self,body:&Body< +'tcx>){;self.last_span=body.span;debug!(?body.span);for(local,local_decl)in body +.local_decls.iter_enumerated(){3;self.check_local(body,local,local_decl);3;}for( +block,block_data)in body.basic_blocks.iter_enumerated(){*&*&();let mut location= +Location{block,statement_index:0};{;};for stmt in&block_data.statements{if!stmt. +source_info.span.is_dummy(){();self.last_span=stmt.source_info.span;();}();self. +check_stmt(body,stmt,location);{;};{;};location.statement_index+=1;{;};}();self. +check_terminator(body,block_data.terminator(),location);3;;self.check_iscleanup( +body,block_data);{;};}}}trait NormalizeLocation:fmt::Debug+Copy{fn to_locations( +self)->Locations;}impl NormalizeLocation for Locations{fn to_locations(self)->// +Locations{self}}impl NormalizeLocation for Location{fn to_locations(self)->//(); +Locations{((((((Locations::Single(self)))))))}} #[derive(Debug)]pub(super)struct +InstantiateOpaqueType<'tcx>{pub base_universe:Option,pub//(); +region_constraints:Option>,pub obligations:Vec>,}impl<'tcx>TypeOp<'tcx>for InstantiateOpaqueType{type Output=();type ErrorInfo=InstantiateOpaqueType<'tcx>;fn//loop{break}; +fully_perform(mut self,infcx:&InferCtxt<'tcx >,span:Span,)->Result,ErrorGuaranteed>{((),());let _=();let(mut output,region_constraints)= +scrape_region_constraints(infcx,|ocx|{;ocx.register_obligations(self.obligations +.clone());;Ok(())},"InstantiateOpaqueType",span,)?;self.region_constraints=Some( +region_constraints);*&*&();{();};output.error_info=Some(self);{();};Ok(output)}} diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index 78609a482ed22..da4df29673142 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -1,602 +1,162 @@ -use rustc_data_structures::fx::FxHashMap; -use rustc_errors::ErrorGuaranteed; -use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_infer::infer::NllRegionVariableOrigin; -use rustc_infer::infer::{ObligationEmittingRelation, StructurallyRelateAliases}; -use rustc_infer::traits::{Obligation, PredicateObligations}; -use rustc_middle::mir::ConstraintCategory; -use rustc_middle::traits::query::NoSolution; -use rustc_middle::traits::ObligationCause; -use rustc_middle::ty::fold::FnMutDelegate; -use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; -use rustc_span::symbol::sym; -use rustc_span::{Span, Symbol}; - -use crate::constraints::OutlivesConstraint; -use crate::diagnostics::UniverseInfo; -use crate::renumber::RegionCtxt; -use crate::type_check::{InstantiateOpaqueType, Locations, TypeChecker}; - -impl<'a, 'tcx> TypeChecker<'a, 'tcx> { - /// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`: - /// - /// - "Covariant" `a <: b` - /// - "Invariant" `a == b` - /// - "Contravariant" `a :> b` - /// - /// N.B., the type `a` is permitted to have unresolved inference - /// variables, but not the type `b`. - #[instrument(skip(self), level = "debug")] - pub(super) fn relate_types( - &mut self, - a: Ty<'tcx>, - v: ty::Variance, - b: Ty<'tcx>, - locations: Locations, - category: ConstraintCategory<'tcx>, - ) -> Result<(), NoSolution> { - NllTypeRelating::new(self, locations, category, UniverseInfo::relate(a, b), v) - .relate(a, b)?; - Ok(()) - } - - /// Add sufficient constraints to ensure `a == b`. See also [Self::relate_types]. - pub(super) fn eq_args( - &mut self, - a: ty::GenericArgsRef<'tcx>, - b: ty::GenericArgsRef<'tcx>, - locations: Locations, - category: ConstraintCategory<'tcx>, - ) -> Result<(), NoSolution> { - NllTypeRelating::new( - self, - locations, - category, - UniverseInfo::other(), - ty::Variance::Invariant, - ) - .relate(a, b)?; - Ok(()) - } -} - -pub struct NllTypeRelating<'me, 'bccx, 'tcx> { - type_checker: &'me mut TypeChecker<'bccx, 'tcx>, - - /// Where (and why) is this relation taking place? - locations: Locations, - - /// What category do we assign the resulting `'a: 'b` relationships? - category: ConstraintCategory<'tcx>, - - /// Information so that error reporting knows what types we are relating - /// when reporting a bound region error. - universe_info: UniverseInfo<'tcx>, - - /// How are we relating `a` and `b`? - /// - /// - Covariant means `a <: b`. - /// - Contravariant means `b <: a`. - /// - Invariant means `a == b`. - /// - Bivariant means that it doesn't matter. - ambient_variance: ty::Variance, - - ambient_variance_info: ty::VarianceDiagInfo<'tcx>, -} - -impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> { - pub fn new( - type_checker: &'me mut TypeChecker<'bccx, 'tcx>, - locations: Locations, - category: ConstraintCategory<'tcx>, - universe_info: UniverseInfo<'tcx>, - ambient_variance: ty::Variance, - ) -> Self { - Self { - type_checker, - locations, - category, - universe_info, - ambient_variance, - ambient_variance_info: ty::VarianceDiagInfo::default(), - } - } - - fn ambient_covariance(&self) -> bool { - match self.ambient_variance { - ty::Variance::Covariant | ty::Variance::Invariant => true, - ty::Variance::Contravariant | ty::Variance::Bivariant => false, - } - } - - fn ambient_contravariance(&self) -> bool { - match self.ambient_variance { - ty::Variance::Contravariant | ty::Variance::Invariant => true, - ty::Variance::Covariant | ty::Variance::Bivariant => false, - } - } - - fn relate_opaques(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { - let infcx = self.type_checker.infcx; - debug_assert!(!infcx.next_trait_solver()); - // `handle_opaque_type` cannot handle subtyping, so to support subtyping - // we instead eagerly generalize here. This is a bit of a mess but will go - // away once we're using the new solver. - // - // Given `opaque rel B`, we create a new infer var `ty_vid` constrain it - // by using `ty_vid rel B` and then finally and end by equating `ty_vid` to - // the opaque. - let mut enable_subtyping = |ty, opaque_is_expected| { - let ty_vid = infcx.next_ty_var_id_in_universe( - TypeVariableOrigin { - kind: TypeVariableOriginKind::MiscVariable, - span: self.span(), - }, - ty::UniverseIndex::ROOT, - ); - - let variance = if opaque_is_expected { - self.ambient_variance - } else { - self.ambient_variance.xform(ty::Contravariant) - }; - - self.type_checker.infcx.instantiate_ty_var( - self, - opaque_is_expected, - ty_vid, - variance, - ty, - )?; - Ok(infcx.resolve_vars_if_possible(Ty::new_infer(infcx.tcx, ty::TyVar(ty_vid)))) - }; - - let (a, b) = match (a.kind(), b.kind()) { - (&ty::Alias(ty::Opaque, ..), _) => (a, enable_subtyping(b, true)?), - (_, &ty::Alias(ty::Opaque, ..)) => (enable_subtyping(a, false)?, b), - _ => unreachable!( - "expected at least one opaque type in `relate_opaques`, got {a} and {b}." - ), - }; - let cause = ObligationCause::dummy_with_span(self.span()); - let obligations = infcx.handle_opaque_type(a, b, &cause, self.param_env())?.obligations; - self.register_obligations(obligations); - Ok(()) - } - - fn enter_forall( - &mut self, - binder: ty::Binder<'tcx, T>, - f: impl FnOnce(&mut Self, T) -> U, - ) -> U - where - T: ty::TypeFoldable> + Copy, - { - let value = if let Some(inner) = binder.no_bound_vars() { - inner - } else { - let infcx = self.type_checker.infcx; - let mut lazy_universe = None; - let delegate = FnMutDelegate { - regions: &mut |br: ty::BoundRegion| { - // The first time this closure is called, create a - // new universe for the placeholders we will make - // from here out. - let universe = lazy_universe.unwrap_or_else(|| { - let universe = self.create_next_universe(); - lazy_universe = Some(universe); - universe - }); - - let placeholder = ty::PlaceholderRegion { universe, bound: br }; - debug!(?placeholder); - let placeholder_reg = self.next_placeholder_region(placeholder); - debug!(?placeholder_reg); - - placeholder_reg - }, - types: &mut |_bound_ty: ty::BoundTy| { - unreachable!("we only replace regions in nll_relate, not types") - }, - consts: &mut |_bound_var: ty::BoundVar, _ty| { - unreachable!("we only replace regions in nll_relate, not consts") - }, - }; - - infcx.tcx.replace_bound_vars_uncached(binder, delegate) - }; - - debug!(?value); - f(self, value) - } - - #[instrument(skip(self), level = "debug")] - fn instantiate_binder_with_existentials(&mut self, binder: ty::Binder<'tcx, T>) -> T - where - T: ty::TypeFoldable> + Copy, - { - if let Some(inner) = binder.no_bound_vars() { - return inner; - } - - let infcx = self.type_checker.infcx; - let mut reg_map = FxHashMap::default(); - let delegate = FnMutDelegate { - regions: &mut |br: ty::BoundRegion| { - if let Some(ex_reg_var) = reg_map.get(&br) { - return *ex_reg_var; - } else { - let ex_reg_var = self.next_existential_region_var(true, br.kind.get_name()); - debug!(?ex_reg_var); - reg_map.insert(br, ex_reg_var); - - ex_reg_var - } - }, - types: &mut |_bound_ty: ty::BoundTy| { - unreachable!("we only replace regions in nll_relate, not types") - }, - consts: &mut |_bound_var: ty::BoundVar, _ty| { - unreachable!("we only replace regions in nll_relate, not consts") - }, - }; - - let replaced = infcx.tcx.replace_bound_vars_uncached(binder, delegate); - debug!(?replaced); - - replaced - } - - fn create_next_universe(&mut self) -> ty::UniverseIndex { - let universe = self.type_checker.infcx.create_next_universe(); - self.type_checker - .borrowck_context - .constraints - .universe_causes - .insert(universe, self.universe_info.clone()); - universe - } - - #[instrument(skip(self), level = "debug")] - fn next_existential_region_var( - &mut self, - from_forall: bool, - name: Option, - ) -> ty::Region<'tcx> { - let origin = NllRegionVariableOrigin::Existential { from_forall }; - - let reg_var = - self.type_checker.infcx.next_nll_region_var(origin, || RegionCtxt::Existential(name)); - - reg_var - } - - #[instrument(skip(self), level = "debug")] - fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx> { - let reg = self - .type_checker - .borrowck_context - .constraints - .placeholder_region(self.type_checker.infcx, placeholder); - - let reg_info = match placeholder.bound.kind { - ty::BoundRegionKind::BrAnon => sym::anon, - ty::BoundRegionKind::BrNamed(_, name) => name, - ty::BoundRegionKind::BrEnv => sym::env, - }; - - if cfg!(debug_assertions) { - let mut var_to_origin = self.type_checker.infcx.reg_var_to_origin.borrow_mut(); - let new = RegionCtxt::Placeholder(reg_info); - let prev = var_to_origin.insert(reg.as_var(), new); - if let Some(prev) = prev { - assert_eq!(new, prev); - } - } - - reg - } - - fn push_outlives( - &mut self, - sup: ty::Region<'tcx>, - sub: ty::Region<'tcx>, - info: ty::VarianceDiagInfo<'tcx>, - ) { - let sub = self.type_checker.borrowck_context.universal_regions.to_region_vid(sub); - let sup = self.type_checker.borrowck_context.universal_regions.to_region_vid(sup); - self.type_checker.borrowck_context.constraints.outlives_constraints.push( - OutlivesConstraint { - sup, - sub, - locations: self.locations, - span: self.locations.span(self.type_checker.body), - category: self.category, - variance_info: info, - from_closure: false, - }, - ); - } -} - -impl<'bccx, 'tcx> TypeRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.type_checker.infcx.tcx - } - - fn tag(&self) -> &'static str { - "nll::subtype" - } - - #[instrument(skip(self, info), level = "trace", ret)] - fn relate_with_variance>( - &mut self, - variance: ty::Variance, - info: ty::VarianceDiagInfo<'tcx>, - a: T, - b: T, - ) -> RelateResult<'tcx, T> { - let old_ambient_variance = self.ambient_variance; - self.ambient_variance = self.ambient_variance.xform(variance); - self.ambient_variance_info = self.ambient_variance_info.xform(info); - - debug!(?self.ambient_variance); - // In a bivariant context this always succeeds. - let r = if self.ambient_variance == ty::Variance::Bivariant { - Ok(a) - } else { - self.relate(a, b) - }; - - self.ambient_variance = old_ambient_variance; - - r - } - - #[instrument(skip(self), level = "debug")] - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - let infcx = self.type_checker.infcx; - - let a = self.type_checker.infcx.shallow_resolve(a); - assert!(!b.has_non_region_infer(), "unexpected inference var {:?}", b); - - if a == b { - return Ok(a); - } - - match (a.kind(), b.kind()) { - (_, &ty::Infer(ty::TyVar(_))) => { - span_bug!( - self.span(), - "should not be relating type variables on the right in MIR typeck" - ); - } - - (&ty::Infer(ty::TyVar(a_vid)), _) => { - infcx.instantiate_ty_var(self, true, a_vid, self.ambient_variance, b)? - } - - ( - &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }), - &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }), - ) if a_def_id == b_def_id || infcx.next_trait_solver() => { - infcx.super_combine_tys(self, a, b).map(|_| ()).or_else(|err| { - // This behavior is only there for the old solver, the new solver - // shouldn't ever fail. Instead, it unconditionally emits an - // alias-relate goal. - assert!(!self.type_checker.infcx.next_trait_solver()); - self.tcx().dcx().span_delayed_bug( - self.span(), - "failure to relate an opaque to itself should result in an error later on", - ); - if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) } - })?; - } - (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _) - | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) - if def_id.is_local() && !self.type_checker.infcx.next_trait_solver() => - { - self.relate_opaques(a, b)?; - } - - _ => { - debug!(?a, ?b, ?self.ambient_variance); - - // Will also handle unification of `IntVar` and `FloatVar`. - self.type_checker.infcx.super_combine_tys(self, a, b)?; - } - } - - Ok(a) - } - - #[instrument(skip(self), level = "trace")] - fn regions( - &mut self, - a: ty::Region<'tcx>, - b: ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>> { - debug!(?self.ambient_variance); - - if self.ambient_covariance() { - // Covariant: &'a u8 <: &'b u8. Hence, `'a: 'b`. - self.push_outlives(a, b, self.ambient_variance_info); - } - - if self.ambient_contravariance() { - // Contravariant: &'b u8 <: &'a u8. Hence, `'b: 'a`. - self.push_outlives(b, a, self.ambient_variance_info); - } - - Ok(a) - } - - fn consts( - &mut self, - a: ty::Const<'tcx>, - b: ty::Const<'tcx>, - ) -> RelateResult<'tcx, ty::Const<'tcx>> { - let a = self.type_checker.infcx.shallow_resolve(a); - assert!(!a.has_non_region_infer(), "unexpected inference var {:?}", a); - assert!(!b.has_non_region_infer(), "unexpected inference var {:?}", b); - - self.type_checker.infcx.super_combine_consts(self, a, b) - } - - #[instrument(skip(self), level = "trace")] - fn binders( - &mut self, - a: ty::Binder<'tcx, T>, - b: ty::Binder<'tcx, T>, - ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> - where - T: Relate<'tcx>, - { - // We want that - // - // ``` - // for<'a> fn(&'a u32) -> &'a u32 <: - // fn(&'b u32) -> &'b u32 - // ``` - // - // but not - // - // ``` - // fn(&'a u32) -> &'a u32 <: - // for<'b> fn(&'b u32) -> &'b u32 - // ``` - // - // We therefore proceed as follows: - // - // - Instantiate binders on `b` universally, yielding a universe U1. - // - Instantiate binders on `a` existentially in U1. - - debug!(?self.ambient_variance); - - if let (Some(a), Some(b)) = (a.no_bound_vars(), b.no_bound_vars()) { - // Fast path for the common case. - self.relate(a, b)?; - return Ok(ty::Binder::dummy(a)); - } - - match self.ambient_variance { - ty::Variance::Covariant => { - // Covariance, so we want `for<..> A <: for<..> B` -- - // therefore we compare any instantiation of A (i.e., A - // instantiated with existentials) against every - // instantiation of B (i.e., B instantiated with - // universals). - - // Note: the order here is important. Create the placeholders first, otherwise - // we assign the wrong universe to the existential! - self.enter_forall(b, |this, b| { - let a = this.instantiate_binder_with_existentials(a); - this.relate(a, b) - })?; - } - - ty::Variance::Contravariant => { - // Contravariance, so we want `for<..> A :> for<..> B` -- - // therefore we compare every instantiation of A (i.e., A - // instantiated with universals) against any - // instantiation of B (i.e., B instantiated with - // existentials). Opposite of above. - - // Note: the order here is important. Create the placeholders first, otherwise - // we assign the wrong universe to the existential! - self.enter_forall(a, |this, a| { - let b = this.instantiate_binder_with_existentials(b); - this.relate(a, b) - })?; - } - - ty::Variance::Invariant => { - // Invariant, so we want `for<..> A == for<..> B` -- - // therefore we want `exists<..> A == for<..> B` and - // `exists<..> B == for<..> A`. - // - // See the comment in `fn Equate::binders` for more details. - - // Note: the order here is important. Create the placeholders first, otherwise - // we assign the wrong universe to the existential! - self.enter_forall(b, |this, b| { - let a = this.instantiate_binder_with_existentials(a); - this.relate(a, b) - })?; - // Note: the order here is important. Create the placeholders first, otherwise - // we assign the wrong universe to the existential! - self.enter_forall(a, |this, a| { - let b = this.instantiate_binder_with_existentials(b); - this.relate(a, b) - })?; - } - - ty::Variance::Bivariant => {} - } - - Ok(a) - } -} - -impl<'bccx, 'tcx> ObligationEmittingRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> { - fn span(&self) -> Span { - self.locations.span(self.type_checker.body) - } - - fn structurally_relate_aliases(&self) -> StructurallyRelateAliases { - StructurallyRelateAliases::No - } - - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.type_checker.param_env - } - - fn register_predicates(&mut self, obligations: impl IntoIterator>) { - self.register_obligations( - obligations - .into_iter() - .map(|to_pred| { - Obligation::new(self.tcx(), ObligationCause::dummy(), self.param_env(), to_pred) - }) - .collect(), - ); - } - - fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) { - let _: Result<_, ErrorGuaranteed> = self.type_checker.fully_perform_op( - self.locations, - self.category, - InstantiateOpaqueType { - obligations, - // These fields are filled in during execution of the operation - base_universe: None, - region_constraints: None, - }, - ); - } - - fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) { - self.register_predicates([ty::Binder::dummy(match self.ambient_variance { - ty::Variance::Covariant => ty::PredicateKind::AliasRelate( - a.into(), - b.into(), - ty::AliasRelationDirection::Subtype, - ), - // a :> b is b <: a - ty::Variance::Contravariant => ty::PredicateKind::AliasRelate( - b.into(), - a.into(), - ty::AliasRelationDirection::Subtype, - ), - ty::Variance::Invariant => ty::PredicateKind::AliasRelate( - a.into(), - b.into(), - ty::AliasRelationDirection::Equate, - ), - ty::Variance::Bivariant => { - unreachable!("cannot defer an alias-relate goal with Bivariant variance (yet?)") - } - })]); - } -} +use rustc_data_structures::fx::FxHashMap;use rustc_errors::ErrorGuaranteed;use// +rustc_infer::infer::type_variable:: {TypeVariableOrigin,TypeVariableOriginKind}; +use rustc_infer::infer::NllRegionVariableOrigin;use rustc_infer::infer::{//({}); +ObligationEmittingRelation,StructurallyRelateAliases}; use rustc_infer::traits:: +{Obligation,PredicateObligations};use rustc_middle::mir::ConstraintCategory;use +rustc_middle::traits::query::NoSolution;use rustc_middle::traits:://loop{break}; +ObligationCause;use rustc_middle::ty::fold::FnMutDelegate;use rustc_middle::ty// +::relate::{Relate,RelateResult,TypeRelation};use rustc_middle::ty::{self,Ty,//3; +TyCtxt,TypeVisitableExt};use rustc_span::symbol::sym;use rustc_span::{Span,//(); +Symbol};use crate::constraints::OutlivesConstraint;use crate::diagnostics:://(); +UniverseInfo;use crate::renumber::RegionCtxt;use crate::type_check::{//let _=(); +InstantiateOpaqueType,Locations,TypeChecker};impl<'a ,'tcx>TypeChecker<'a,'tcx>{ +#[instrument(skip(self),level="debug")]pub (super)fn relate_types(&mut self,a:Ty +<'tcx>,v:ty::Variance,b:Ty<'tcx>,locations:Locations,category://((),());((),()); +ConstraintCategory<'tcx>,)->Result<(),NoSolution>{{;};NllTypeRelating::new(self, +locations,category,UniverseInfo::relate(a,b),v).relate(a,b)?;3;Ok(())}pub(super) +fn eq_args(&mut self,a:ty::GenericArgsRef<'tcx>,b:ty::GenericArgsRef<'tcx>,//(); +locations:Locations,category:ConstraintCategory<'tcx>,)->Result<(),NoSolution>{; +NllTypeRelating::new(self,locations,category, UniverseInfo::other(),ty::Variance +::Invariant,).relate(a,b)?;3;Ok(())}}pub struct NllTypeRelating<'me,'bccx,'tcx>{ +type_checker:&'me mut TypeChecker<'bccx,'tcx>,locations:Locations,category://(); +ConstraintCategory<'tcx>,universe_info:UniverseInfo <'tcx>,ambient_variance:ty:: +Variance,ambient_variance_info:ty::VarianceDiagInfo<'tcx> ,}impl<'me,'bccx,'tcx> +NllTypeRelating<'me,'bccx,'tcx>{pub fn new(type_checker:&'me mut TypeChecker,locations:Locations ,category:ConstraintCategory<'tcx>,universe_info +:UniverseInfo<'tcx>,ambient_variance:ty::Variance,)->Self{Self{type_checker,//3; +locations,category,universe_info,ambient_variance,ambient_variance_info:ty:://3; +VarianceDiagInfo::default(),}}fn ambient_covariance(&self)->bool{match self.//3; +ambient_variance{ty::Variance::Covariant|ty:: Variance::Invariant=>((true)),ty:: +Variance::Contravariant|ty::Variance:: Bivariant=>((((((((((false)))))))))),}}fn +ambient_contravariance(&self)->bool{match self.ambient_variance{ty::Variance::// +Contravariant|ty::Variance::Invariant=>((((true)))),ty::Variance::Covariant|ty:: +Variance::Bivariant=>false,}}fn relate_opaques(&mut self,a:Ty<'tcx>,b:Ty<'tcx>) +->RelateResult<'tcx,()>{;let infcx=self.type_checker.infcx;debug_assert!(!infcx. +next_trait_solver());();3;let mut enable_subtyping=|ty,opaque_is_expected|{3;let +ty_vid=infcx.next_ty_var_id_in_universe(TypeVariableOrigin{kind://if let _=(){}; +TypeVariableOriginKind::MiscVariable,span:self.span( ),},ty::UniverseIndex::ROOT +,);({});({});let variance=if opaque_is_expected{self.ambient_variance}else{self. +ambient_variance.xform(ty::Contravariant)};*&*&();{();};self.type_checker.infcx. +instantiate_ty_var(self,opaque_is_expected,ty_vid,variance,ty,)?;{();};Ok(infcx. +resolve_vars_if_possible(Ty::new_infer(infcx.tcx,ty::TyVar(ty_vid))))};;let(a,b) +=match(a.kind(),b.kind()){(& ty::Alias(ty::Opaque,..),_)=>(a,enable_subtyping(b, +true)?),(_,&ty::Alias(ty::Opaque,..)) =>((((enable_subtyping(a,false))?),b)),_=> +unreachable!(//((),());((),());((),());((),());((),());((),());((),());let _=(); +"expected at least one opaque type in `relate_opaques`, got {a} and {b}."),};3;; +let cause=ObligationCause::dummy_with_span(self.span());;;let obligations=infcx. +handle_opaque_type(a,b,&cause,self.param_env())?.obligations;*&*&();*&*&();self. +register_obligations(obligations);;Ok(())}fn enter_forall(&mut self,binder: +ty::Binder<'tcx,T>,f:impl FnOnce(&mut Self,T)->U,)->U where T:ty::TypeFoldable< +TyCtxt<'tcx>>+Copy,{3;let value=if let Some(inner)=binder.no_bound_vars(){inner} +else{;let infcx=self.type_checker.infcx;let mut lazy_universe=None;let delegate= +FnMutDelegate{regions:&mut|br:ty::BoundRegion|{{();};let universe=lazy_universe. +unwrap_or_else(||{;let universe=self.create_next_universe();;lazy_universe=Some( +universe);;universe});;let placeholder=ty::PlaceholderRegion{universe,bound:br}; +debug!(?placeholder);({});({});let placeholder_reg=self.next_placeholder_region( +placeholder);;;debug!(?placeholder_reg);placeholder_reg},types:&mut|_bound_ty:ty +::BoundTy|{(unreachable! ("we only replace regions in nll_relate, not types"))}, +consts:&mut|_bound_var:ty::BoundVar,_ty|{unreachable!(//loop{break};loop{break}; +"we only replace regions in nll_relate, not consts")},};if let _=(){};infcx.tcx. +replace_bound_vars_uncached(binder,delegate)};;;debug!(?value);;f(self,value)}#[ +instrument(skip(self),level= "debug")]fn instantiate_binder_with_existentials +(&mut self,binder:ty::Binder<'tcx,T> )->T where T:ty::TypeFoldable> ++Copy,{if let Some(inner)=binder.no_bound_vars(){;return inner;;}let infcx=self. +type_checker.infcx;();();let mut reg_map=FxHashMap::default();();3;let delegate= +FnMutDelegate{regions:&mut|br:ty::BoundRegion |{if let Some(ex_reg_var)=reg_map. +get(&br){let _=();return*ex_reg_var;let _=();}else{let _=();let ex_reg_var=self. +next_existential_region_var(true,br.kind.get_name());3;3;debug!(?ex_reg_var);3;; +reg_map.insert(br,ex_reg_var);();ex_reg_var}},types:&mut|_bound_ty:ty::BoundTy|{ +unreachable!("we only replace regions in nll_relate, not types")},consts:&mut|// +_bound_var:ty::BoundVar,_ty|{unreachable!(//let _=();let _=();let _=();let _=(); +"we only replace regions in nll_relate, not consts")},};;let replaced=infcx.tcx. +replace_bound_vars_uncached(binder,delegate);3;3;debug!(?replaced);3;replaced}fn +create_next_universe(&mut self)->ty::UniverseIndex{let _=||();let universe=self. +type_checker.infcx.create_next_universe();3;;self.type_checker.borrowck_context. +constraints.universe_causes.insert(universe,self.universe_info.clone());((),()); +universe}#[instrument(skip(self) ,level="debug")]fn next_existential_region_var( +&mut self,from_forall:bool,name:Option,)->ty::Region<'tcx>{3;let origin= +NllRegionVariableOrigin::Existential{from_forall};;let reg_var=self.type_checker +.infcx.next_nll_region_var(origin,||RegionCtxt::Existential(name));();reg_var}#[ +instrument(skip(self),level="debug")]fn next_placeholder_region(&mut self,//{;}; +placeholder:ty::PlaceholderRegion)->ty::Region<'tcx>{;let reg=self.type_checker. +borrowck_context.constraints.placeholder_region(self.type_checker.infcx,//{();}; +placeholder);3;3;let reg_info=match placeholder.bound.kind{ty::BoundRegionKind:: +BrAnon=>sym::anon,ty::BoundRegionKind::BrNamed(_,name)=>name,ty:://loop{break;}; +BoundRegionKind::BrEnv=>sym::env,};{();};if cfg!(debug_assertions){{();};let mut +var_to_origin=self.type_checker.infcx.reg_var_to_origin.borrow_mut();3;;let new= +RegionCtxt::Placeholder(reg_info);3;;let prev=var_to_origin.insert(reg.as_var(), +new);3;if let Some(prev)=prev{;assert_eq!(new,prev);;}}reg}fn push_outlives(&mut +self,sup:ty::Region<'tcx>,sub:ty ::Region<'tcx>,info:ty::VarianceDiagInfo<'tcx>, +){();let sub=self.type_checker.borrowck_context.universal_regions.to_region_vid( +sub);;let sup=self.type_checker.borrowck_context.universal_regions.to_region_vid +(sup);;self.type_checker.borrowck_context.constraints.outlives_constraints.push( +OutlivesConstraint{sup,sub,locations:self.locations,span:self.locations.span(//; +self.type_checker.body),category: self.category,variance_info:info,from_closure: +false,},);;}}impl<'bccx,'tcx>TypeRelation<'tcx>for NllTypeRelating<'_,'bccx,'tcx +>{fn tcx(&self)->TyCtxt<'tcx>{self.type_checker.infcx.tcx}fn tag(&self)->&//{;}; +'static str{("nll::subtype")}#[instrument(skip (self,info),level="trace",ret)]fn +relate_with_variance>(&mut self,variance:ty::Variance,info:ty::// +VarianceDiagInfo<'tcx>,a:T,b:T,)->RelateResult<'tcx,T>{;let old_ambient_variance +=self.ambient_variance;{;};();self.ambient_variance=self.ambient_variance.xform( +variance);;;self.ambient_variance_info=self.ambient_variance_info.xform(info);;; +debug!(?self.ambient_variance);3;;let r=if self.ambient_variance==ty::Variance:: +Bivariant{Ok(a)}else{self.relate(a,b)};if true{};let _=();self.ambient_variance= +old_ambient_variance;;r}#[instrument(skip(self),level="debug")]fn tys(&mut self, +a:Ty<'tcx>,b:Ty<'tcx>)->RelateResult<'tcx,Ty<'tcx>>{;let infcx=self.type_checker +.infcx;{;};();let a=self.type_checker.infcx.shallow_resolve(a);();();assert!(!b. +has_non_region_infer(),"unexpected inference var {:?}",b);;if a==b{return Ok(a); +}match(a.kind(),b.kind()){(_,&ty::Infer(ty::TyVar(_)))=>{;span_bug!(self.span(), +"should not be relating type variables on the right in MIR typeck");({});}(&ty:: +Infer(ty::TyVar(a_vid)),_)=>{ infcx.instantiate_ty_var(self,((true)),a_vid,self. +ambient_variance,b)?}(&ty::Alias(ty::Opaque,ty::AliasTy{def_id:a_def_id,..}),&// +ty::Alias(ty::Opaque,ty::AliasTy{def_id:b_def_id,..}),)if (a_def_id==b_def_id)|| +infcx.next_trait_solver()=>{*&*&();infcx.super_combine_tys(self,a,b).map(|_|()). +or_else(|err|{;assert!(!self.type_checker.infcx.next_trait_solver());self.tcx(). +dcx().span_delayed_bug((((((((((((((((((((((( self.span())))))))))))))))))))))), +"failure to relate an opaque to itself should result in an error later on",);;if +a_def_id.is_local(){self.relate_opaques(a,b)}else{Err(err)}})?;3;}(&ty::Alias(ty +::Opaque,ty::AliasTy{def_id,..}),_)| (_,&ty::Alias(ty::Opaque,ty::AliasTy{def_id +,..}))if def_id.is_local()&&!self.type_checker.infcx.next_trait_solver()=>{;self +.relate_opaques(a,b)?;();}_=>{();debug!(?a,?b,?self.ambient_variance);();3;self. +type_checker.infcx.super_combine_tys(self,a,b)?;;}}Ok(a)}#[instrument(skip(self) +,level="trace")]fn regions(&mut self,a:ty::Region<'tcx>,b:ty::Region<'tcx>,)->// +RelateResult<'tcx,ty::Region<'tcx>>{();debug!(?self.ambient_variance);3;if self. +ambient_covariance(){3;self.push_outlives(a,b,self.ambient_variance_info);3;}if +self.ambient_contravariance(){;self.push_outlives(b,a,self.ambient_variance_info +);loop{break};}Ok(a)}fn consts(&mut self,a:ty::Const<'tcx>,b:ty::Const<'tcx>,)-> +RelateResult<'tcx,ty::Const<'tcx>>{*&*&();((),());let a=self.type_checker.infcx. +shallow_resolve(a);if let _=(){};loop{break;};assert!(!a.has_non_region_infer(), +"unexpected inference var {:?}",a);{();};({});assert!(!b.has_non_region_infer(), +"unexpected inference var {:?}",b);;self.type_checker.infcx.super_combine_consts +(self,a,b)}#[instrument(skip(self),level="trace")]fn binders(&mut self,a:ty// +::Binder<'tcx,T>,b:ty::Binder<'tcx,T>,)->RelateResult<'tcx,ty::Binder<'tcx,T>>// +where T:Relate<'tcx>,{;debug!(?self.ambient_variance);if let(Some(a),Some(b))=(a +.no_bound_vars(),b.no_bound_vars()){3;self.relate(a,b)?;;;return Ok(ty::Binder:: +dummy(a));({});}match self.ambient_variance{ty::Variance::Covariant=>{({});self. +enter_forall(b,|this,b|{;let a=this.instantiate_binder_with_existentials(a);this +.relate(a,b)})?;;}ty::Variance::Contravariant=>{self.enter_forall(a,|this,a|{let +b=this.instantiate_binder_with_existentials(b);{;};this.relate(a,b)})?;{;};}ty:: +Variance::Invariant=>{let _=();self.enter_forall(b,|this,b|{let _=();let a=this. +instantiate_binder_with_existentials(a);;this.relate(a,b)})?;self.enter_forall(a +,|this,a|{;let b=this.instantiate_binder_with_existentials(b);this.relate(a,b)}) +?;loop{break;};loop{break;};}ty::Variance::Bivariant=>{}}Ok(a)}}impl<'bccx,'tcx> +ObligationEmittingRelation<'tcx>for NllTypeRelating<'_,'bccx,'tcx>{fn span(&//3; +self)->Span{(((((((((((self.locations.span(self.type_checker.body))))))))))))}fn +structurally_relate_aliases(&self)->StructurallyRelateAliases{//((),());((),()); +StructurallyRelateAliases::No}fn param_env(&self)->ty::ParamEnv<'tcx>{self.//(); +type_checker.param_env}fn register_predicates(&mut self,obligations:impl//{();}; +IntoIterator>){;self.register_obligations(obligations +.into_iter().map(|to_pred|{Obligation::new (self.tcx(),ObligationCause::dummy(), +self.param_env(),to_pred)}).collect(),);({});}fn register_obligations(&mut self, +obligations:PredicateObligations<'tcx>){();let _:Result<_,ErrorGuaranteed>=self. +type_checker.fully_perform_op(self.locations,self.category,//let _=();if true{}; +InstantiateOpaqueType{obligations,base_universe:None ,region_constraints:None,}, +);3;}fn register_type_relate_obligation(&mut self,a:Ty<'tcx>,b:Ty<'tcx>){3;self. +register_predicates([ty::Binder::dummy (match self.ambient_variance{ty::Variance +::Covariant=>ty::PredicateKind::AliasRelate(((((a.into())))),(((b.into()))),ty:: +AliasRelationDirection::Subtype,),ty::Variance::Contravariant=>ty:://let _=||(); +PredicateKind::AliasRelate(((b.into())), (a.into()),ty::AliasRelationDirection:: +Subtype,),ty::Variance::Invariant=>ty:: PredicateKind::AliasRelate((a.into()),b. +into(),ty::AliasRelationDirection::Equate,),ty::Variance::Bivariant=>{//((),()); +unreachable! ("cannot defer an alias-relate goal with Bivariant variance (yet?)" +)}})]);((),());let _=();let _=();let _=();let _=();let _=();let _=();let _=();}} diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 9c65f64b03fec..fc593ddd8d4e3 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -1,935 +1,232 @@ -//! Code to extract the universally quantified regions declared on a -//! function and the relationships between them. For example: -//! -//! ``` -//! fn foo<'a, 'b, 'c: 'b>() { } -//! ``` -//! -//! here we would return a map assigning each of `{'a, 'b, 'c}` -//! to an index, as well as the `FreeRegionMap` which can compute -//! relationships between them. -//! -//! The code in this file doesn't *do anything* with those results; it -//! just returns them for other code to use. - -#![allow(rustc::diagnostic_outside_of_impl)] -#![allow(rustc::untranslatable_diagnostic)] - -use rustc_data_structures::fx::FxIndexMap; -use rustc_errors::Diag; -use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::lang_items::LangItem; -use rustc_hir::BodyOwnerKind; -use rustc_index::IndexVec; -use rustc_infer::infer::NllRegionVariableOrigin; -use rustc_macros::extension; -use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, InlineConstArgs, InlineConstArgsParts, RegionVid, Ty, TyCtxt}; -use rustc_middle::ty::{GenericArgs, GenericArgsRef}; -use rustc_span::symbol::{kw, sym}; -use rustc_span::Symbol; -use std::iter; - -use crate::renumber::RegionCtxt; -use crate::BorrowckInferCtxt; - -#[derive(Debug)] -pub struct UniversalRegions<'tcx> { - indices: UniversalRegionIndices<'tcx>, - - /// The vid assigned to `'static` - pub fr_static: RegionVid, - - /// A special region vid created to represent the current MIR fn - /// body. It will outlive the entire CFG but it will not outlive - /// any other universal regions. - pub fr_fn_body: RegionVid, - - /// We create region variables such that they are ordered by their - /// `RegionClassification`. The first block are globals, then - /// externals, then locals. So, things from: - /// - `FIRST_GLOBAL_INDEX..first_extern_index` are global, - /// - `first_extern_index..first_local_index` are external, - /// - `first_local_index..num_universals` are local. - first_extern_index: usize, - - /// See `first_extern_index`. - first_local_index: usize, - - /// The total number of universal region variables instantiated. - num_universals: usize, - - /// The "defining" type for this function, with all universal - /// regions instantiated. For a closure or coroutine, this is the - /// closure type, but for a top-level function it's the `FnDef`. - pub defining_ty: DefiningTy<'tcx>, - - /// The return type of this function, with all regions replaced by - /// their universal `RegionVid` equivalents. - /// - /// N.B., associated types in this type have not been normalized, - /// as the name suggests. =) - pub unnormalized_output_ty: Ty<'tcx>, - - /// The fully liberated input types of this function, with all - /// regions replaced by their universal `RegionVid` equivalents. - /// - /// N.B., associated types in these types have not been normalized, - /// as the name suggests. =) - pub unnormalized_input_tys: &'tcx [Ty<'tcx>], - - pub yield_ty: Option>, - - pub resume_ty: Option>, -} - -/// The "defining type" for this MIR. The key feature of the "defining -/// type" is that it contains the information needed to derive all the -/// universal regions that are in scope as well as the types of the -/// inputs/output from the MIR. In general, early-bound universal -/// regions appear free in the defining type and late-bound regions -/// appear bound in the signature. -#[derive(Copy, Clone, Debug)] -pub enum DefiningTy<'tcx> { - /// The MIR is a closure. The signature is found via - /// `ClosureArgs::closure_sig_ty`. - Closure(DefId, GenericArgsRef<'tcx>), - - /// The MIR is a coroutine. The signature is that coroutines take - /// no parameters and return the result of - /// `ClosureArgs::coroutine_return_ty`. - Coroutine(DefId, GenericArgsRef<'tcx>), - - /// The MIR is a special kind of closure that returns coroutines. - /// - /// See the documentation on `CoroutineClosureSignature` for details - /// on how to construct the callable signature of the coroutine from - /// its args. - CoroutineClosure(DefId, GenericArgsRef<'tcx>), - - /// The MIR is a fn item with the given `DefId` and args. The signature - /// of the function can be bound then with the `fn_sig` query. - FnDef(DefId, GenericArgsRef<'tcx>), - - /// The MIR represents some form of constant. The signature then - /// is that it has no inputs and a single return value, which is - /// the value of the constant. - Const(DefId, GenericArgsRef<'tcx>), - - /// The MIR represents an inline const. The signature has no inputs and a - /// single return value found via `InlineConstArgs::ty`. - InlineConst(DefId, GenericArgsRef<'tcx>), -} - -impl<'tcx> DefiningTy<'tcx> { - /// Returns a list of all the upvar types for this MIR. If this is - /// not a closure or coroutine, there are no upvars, and hence it - /// will be an empty list. The order of types in this list will - /// match up with the upvar order in the HIR, typesystem, and MIR. - pub fn upvar_tys(self) -> &'tcx ty::List> { - match self { - DefiningTy::Closure(_, args) => args.as_closure().upvar_tys(), - DefiningTy::CoroutineClosure(_, args) => args.as_coroutine_closure().upvar_tys(), - DefiningTy::Coroutine(_, args) => args.as_coroutine().upvar_tys(), - DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => { - ty::List::empty() - } - } - } - - /// Number of implicit inputs -- notably the "environment" - /// parameter for closures -- that appear in MIR but not in the - /// user's code. - pub fn implicit_inputs(self) -> usize { - match self { - DefiningTy::Closure(..) - | DefiningTy::CoroutineClosure(..) - | DefiningTy::Coroutine(..) => 1, - DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => 0, - } - } - - pub fn is_fn_def(&self) -> bool { - matches!(*self, DefiningTy::FnDef(..)) - } - - pub fn is_const(&self) -> bool { - matches!(*self, DefiningTy::Const(..) | DefiningTy::InlineConst(..)) - } - - pub fn def_id(&self) -> DefId { - match *self { - DefiningTy::Closure(def_id, ..) - | DefiningTy::CoroutineClosure(def_id, ..) - | DefiningTy::Coroutine(def_id, ..) - | DefiningTy::FnDef(def_id, ..) - | DefiningTy::Const(def_id, ..) - | DefiningTy::InlineConst(def_id, ..) => def_id, - } - } -} - -#[derive(Debug)] -struct UniversalRegionIndices<'tcx> { - /// For those regions that may appear in the parameter environment - /// ('static and early-bound regions), we maintain a map from the - /// `ty::Region` to the internal `RegionVid` we are using. This is - /// used because trait matching and type-checking will feed us - /// region constraints that reference those regions and we need to - /// be able to map them to our internal `RegionVid`. This is - /// basically equivalent to an `GenericArgs`, except that it also - /// contains an entry for `ReStatic` -- it might be nice to just - /// use an args, and then handle `ReStatic` another way. - indices: FxIndexMap, RegionVid>, - - /// The vid assigned to `'static`. Used only for diagnostics. - pub fr_static: RegionVid, -} - -#[derive(Debug, PartialEq)] -pub enum RegionClassification { - /// A **global** region is one that can be named from - /// anywhere. There is only one, `'static`. - Global, - - /// An **external** region is only relevant for - /// closures, coroutines, and inline consts. In that - /// case, it refers to regions that are free in the type - /// -- basically, something bound in the surrounding context. - /// - /// Consider this example: - /// - /// ```ignore (pseudo-rust) - /// fn foo<'a, 'b>(a: &'a u32, b: &'b u32, c: &'static u32) { - /// let closure = for<'x> |x: &'x u32| { .. }; - /// // ^^^^^^^ pretend this were legal syntax - /// // for declaring a late-bound region in - /// // a closure signature - /// } - /// ``` - /// - /// Here, the lifetimes `'a` and `'b` would be **external** to the - /// closure. - /// - /// If we are not analyzing a closure/coroutine/inline-const, - /// there are no external lifetimes. - External, - - /// A **local** lifetime is one about which we know the full set - /// of relevant constraints (that is, relationships to other named - /// regions). For a closure, this includes any region bound in - /// the closure's signature. For a fn item, this includes all - /// regions other than global ones. - /// - /// Continuing with the example from `External`, if we were - /// analyzing the closure, then `'x` would be local (and `'a` and - /// `'b` are external). If we are analyzing the function item - /// `foo`, then `'a` and `'b` are local (and `'x` is not in - /// scope). - Local, -} - -const FIRST_GLOBAL_INDEX: usize = 0; - -impl<'tcx> UniversalRegions<'tcx> { - /// Creates a new and fully initialized `UniversalRegions` that - /// contains indices for all the free regions found in the given - /// MIR -- that is, all the regions that appear in the function's - /// signature. This will also compute the relationships that are - /// known between those regions. - pub fn new( - infcx: &BorrowckInferCtxt<'_, 'tcx>, - mir_def: LocalDefId, - param_env: ty::ParamEnv<'tcx>, - ) -> Self { - UniversalRegionsBuilder { infcx, mir_def, param_env }.build() - } - - /// Given a reference to a closure type, extracts all the values - /// from its free regions and returns a vector with them. This is - /// used when the closure's creator checks that the - /// `ClosureRegionRequirements` are met. The requirements from - /// `ClosureRegionRequirements` are expressed in terms of - /// `RegionVid` entries that map into the returned vector `V`: so - /// if the `ClosureRegionRequirements` contains something like - /// `'1: '2`, then the caller would impose the constraint that - /// `V[1]: V[2]`. - pub fn closure_mapping( - tcx: TyCtxt<'tcx>, - closure_args: GenericArgsRef<'tcx>, - expected_num_vars: usize, - closure_def_id: LocalDefId, - ) -> IndexVec> { - let mut region_mapping = IndexVec::with_capacity(expected_num_vars); - region_mapping.push(tcx.lifetimes.re_static); - tcx.for_each_free_region(&closure_args, |fr| { - region_mapping.push(fr); - }); - - for_each_late_bound_region_in_recursive_scope(tcx, tcx.local_parent(closure_def_id), |r| { - region_mapping.push(r); - }); - - assert_eq!( - region_mapping.len(), - expected_num_vars, - "index vec had unexpected number of variables" - ); - - region_mapping - } - - /// Returns `true` if `r` is a member of this set of universal regions. - pub fn is_universal_region(&self, r: RegionVid) -> bool { - (FIRST_GLOBAL_INDEX..self.num_universals).contains(&r.index()) - } - - /// Classifies `r` as a universal region, returning `None` if this - /// is not a member of this set of universal regions. - pub fn region_classification(&self, r: RegionVid) -> Option { - let index = r.index(); - if (FIRST_GLOBAL_INDEX..self.first_extern_index).contains(&index) { - Some(RegionClassification::Global) - } else if (self.first_extern_index..self.first_local_index).contains(&index) { - Some(RegionClassification::External) - } else if (self.first_local_index..self.num_universals).contains(&index) { - Some(RegionClassification::Local) - } else { - None - } - } - - /// Returns an iterator over all the RegionVids corresponding to - /// universally quantified free regions. - pub fn universal_regions(&self) -> impl Iterator { - (FIRST_GLOBAL_INDEX..self.num_universals).map(RegionVid::from_usize) - } - - /// Returns `true` if `r` is classified as a local region. - pub fn is_local_free_region(&self, r: RegionVid) -> bool { - self.region_classification(r) == Some(RegionClassification::Local) - } - - /// Returns the number of universal regions created in any category. - pub fn len(&self) -> usize { - self.num_universals - } - - /// Returns the number of global plus external universal regions. - /// For closures, these are the regions that appear free in the - /// closure type (versus those bound in the closure - /// signature). They are therefore the regions between which the - /// closure may impose constraints that its creator must verify. - pub fn num_global_and_external_regions(&self) -> usize { - self.first_local_index - } - - /// Gets an iterator over all the early-bound regions that have names. - pub fn named_universal_regions<'s>( - &'s self, - ) -> impl Iterator, ty::RegionVid)> + 's { - self.indices.indices.iter().map(|(&r, &v)| (r, v)) - } - - /// See `UniversalRegionIndices::to_region_vid`. - pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid { - self.indices.to_region_vid(r) - } - - /// As part of the NLL unit tests, you can annotate a function with - /// `#[rustc_regions]`, and we will emit information about the region - /// inference context and -- in particular -- the external constraints - /// that this region imposes on others. The methods in this file - /// handle the part about dumping the inference context internal - /// state. - pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diag<'_, ()>) { - match self.defining_ty { - DefiningTy::Closure(def_id, args) => { - let v = with_no_trimmed_paths!( - args[tcx.generics_of(def_id).parent_count..] - .iter() - .map(|arg| arg.to_string()) - .collect::>() - ); - err.note(format!( - "defining type: {} with closure args [\n {},\n]", - tcx.def_path_str_with_args(def_id, args), - v.join(",\n "), - )); - - // FIXME: It'd be nice to print the late-bound regions - // here, but unfortunately these wind up stored into - // tests, and the resulting print-outs include def-ids - // and other things that are not stable across tests! - // So we just include the region-vid. Annoying. - for_each_late_bound_region_in_recursive_scope(tcx, def_id.expect_local(), |r| { - err.note(format!("late-bound region is {:?}", self.to_region_vid(r))); - }); - } - DefiningTy::CoroutineClosure(..) => { - todo!() - } - DefiningTy::Coroutine(def_id, args) => { - let v = with_no_trimmed_paths!( - args[tcx.generics_of(def_id).parent_count..] - .iter() - .map(|arg| arg.to_string()) - .collect::>() - ); - err.note(format!( - "defining type: {} with coroutine args [\n {},\n]", - tcx.def_path_str_with_args(def_id, args), - v.join(",\n "), - )); - - // FIXME: As above, we'd like to print out the region - // `r` but doing so is not stable across architectures - // and so forth. - for_each_late_bound_region_in_recursive_scope(tcx, def_id.expect_local(), |r| { - err.note(format!("late-bound region is {:?}", self.to_region_vid(r))); - }); - } - DefiningTy::FnDef(def_id, args) => { - err.note(format!("defining type: {}", tcx.def_path_str_with_args(def_id, args),)); - } - DefiningTy::Const(def_id, args) => { - err.note(format!( - "defining constant type: {}", - tcx.def_path_str_with_args(def_id, args), - )); - } - DefiningTy::InlineConst(def_id, args) => { - err.note(format!( - "defining inline constant type: {}", - tcx.def_path_str_with_args(def_id, args), - )); - } - } - } -} - -struct UniversalRegionsBuilder<'cx, 'tcx> { - infcx: &'cx BorrowckInferCtxt<'cx, 'tcx>, - mir_def: LocalDefId, - param_env: ty::ParamEnv<'tcx>, -} - -const FR: NllRegionVariableOrigin = NllRegionVariableOrigin::FreeRegion; - -impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { - fn build(self) -> UniversalRegions<'tcx> { - debug!("build(mir_def={:?})", self.mir_def); - - let param_env = self.param_env; - debug!("build: param_env={:?}", param_env); - - assert_eq!(FIRST_GLOBAL_INDEX, self.infcx.num_region_vars()); - - // Create the "global" region that is always free in all contexts: 'static. - let fr_static = - self.infcx.next_nll_region_var(FR, || RegionCtxt::Free(kw::Static)).as_var(); - - // We've now added all the global regions. The next ones we - // add will be external. - let first_extern_index = self.infcx.num_region_vars(); - - let defining_ty = self.defining_ty(); - debug!("build: defining_ty={:?}", defining_ty); - - let mut indices = self.compute_indices(fr_static, defining_ty); - debug!("build: indices={:?}", indices); - - let typeck_root_def_id = self.infcx.tcx.typeck_root_def_id(self.mir_def.to_def_id()); - - // If this is a 'root' body (not a closure/coroutine/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.to_def_id() == typeck_root_def_id { - first_extern_index - } else { - // If this is a closure, coroutine, or inline-const, then the late-bound regions from the enclosing - // function/closures are actually external regions to us. For example, here, 'a is not local - // to the closure c (although it is local to the fn foo): - // fn foo<'a>() { - // let c = || { let x: &'a u32 = ...; } - // } - for_each_late_bound_region_in_recursive_scope( - self.infcx.tcx, - self.infcx.tcx.local_parent(self.mir_def), - |r| { - debug!(?r); - if !indices.indices.contains_key(&r) { - let region_vid = { - let name = r.get_name_or_anon(); - self.infcx.next_nll_region_var(FR, || RegionCtxt::LateBound(name)) - }; - - debug!(?region_vid); - indices.insert_late_bound_region(r, region_vid.as_var()); - } - }, - ); - - // Any regions created during the execution of `defining_ty` or during the above - // late-bound region replacement are all considered 'extern' regions - self.infcx.num_region_vars() - }; - - // "Liberate" the late-bound regions. These correspond to - // "local" free regions. - let bound_inputs_and_output = self.compute_inputs_and_output(&indices, defining_ty); - - let inputs_and_output = self.infcx.replace_bound_regions_with_nll_infer_vars( - FR, - self.mir_def, - bound_inputs_and_output, - &mut indices, - ); - // Converse of above, if this is a function/closure then the late-bound regions declared on its - // signature are local. - for_each_late_bound_region_in_item(self.infcx.tcx, self.mir_def, |r| { - debug!(?r); - if !indices.indices.contains_key(&r) { - let region_vid = { - let name = r.get_name_or_anon(); - self.infcx.next_nll_region_var(FR, || RegionCtxt::LateBound(name)) - }; - - debug!(?region_vid); - indices.insert_late_bound_region(r, region_vid.as_var()); - } - }); - - let (unnormalized_output_ty, mut unnormalized_input_tys) = - inputs_and_output.split_last().unwrap(); - - // C-variadic fns also have a `VaList` input that's not listed in the signature - // (as it's created inside the body itself, not passed in from outside). - if let DefiningTy::FnDef(def_id, _) = defining_ty { - if self.infcx.tcx.fn_sig(def_id).skip_binder().c_variadic() { - let va_list_did = self.infcx.tcx.require_lang_item( - LangItem::VaList, - Some(self.infcx.tcx.def_span(self.mir_def)), - ); - - let reg_vid = self - .infcx - .next_nll_region_var(FR, || RegionCtxt::Free(Symbol::intern("c-variadic"))) - .as_var(); - - let region = ty::Region::new_var(self.infcx.tcx, reg_vid); - let va_list_ty = self - .infcx - .tcx - .type_of(va_list_did) - .instantiate(self.infcx.tcx, &[region.into()]); - - unnormalized_input_tys = self.infcx.tcx.mk_type_list_from_iter( - unnormalized_input_tys.iter().copied().chain(iter::once(va_list_ty)), - ); - } - } - - let fr_fn_body = self - .infcx - .next_nll_region_var(FR, || RegionCtxt::Free(Symbol::intern("fn_body"))) - .as_var(); - - let num_universals = self.infcx.num_region_vars(); - - debug!("build: global regions = {}..{}", FIRST_GLOBAL_INDEX, first_extern_index); - debug!("build: extern regions = {}..{}", first_extern_index, first_local_index); - debug!("build: local regions = {}..{}", first_local_index, num_universals); - - let (resume_ty, yield_ty) = match defining_ty { - DefiningTy::Coroutine(_, args) => { - let tys = args.as_coroutine(); - (Some(tys.resume_ty()), Some(tys.yield_ty())) - } - _ => (None, None), - }; - - UniversalRegions { - indices, - fr_static, - fr_fn_body, - first_extern_index, - first_local_index, - num_universals, - defining_ty, - unnormalized_output_ty: *unnormalized_output_ty, - unnormalized_input_tys, - yield_ty, - resume_ty, - } - } - - /// Returns the "defining type" of the current MIR; - /// see `DefiningTy` for details. - fn defining_ty(&self) -> DefiningTy<'tcx> { - let tcx = self.infcx.tcx; - let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.to_def_id()); - - match tcx.hir().body_owner_kind(self.mir_def) { - BodyOwnerKind::Closure | BodyOwnerKind::Fn => { - let defining_ty = tcx.type_of(self.mir_def).instantiate_identity(); - - debug!("defining_ty (pre-replacement): {:?}", defining_ty); - - let defining_ty = - self.infcx.replace_free_regions_with_nll_infer_vars(FR, defining_ty); - - match *defining_ty.kind() { - ty::Closure(def_id, args) => DefiningTy::Closure(def_id, args), - ty::Coroutine(def_id, args) => DefiningTy::Coroutine(def_id, args), - ty::CoroutineClosure(def_id, args) => { - DefiningTy::CoroutineClosure(def_id, args) - } - ty::FnDef(def_id, args) => DefiningTy::FnDef(def_id, args), - _ => span_bug!( - tcx.def_span(self.mir_def), - "expected defining type for `{:?}`: `{:?}`", - self.mir_def, - defining_ty - ), - } - } - - BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(..) => { - let identity_args = GenericArgs::identity_for_item(tcx, typeck_root_def_id); - if self.mir_def.to_def_id() == typeck_root_def_id { - let args = - self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_args); - DefiningTy::Const(self.mir_def.to_def_id(), args) - } else { - // FIXME this line creates a dependency between borrowck and typeck. - // - // This is required for `AscribeUserType` canonical query, which will call - // `type_of(inline_const_def_id)`. That `type_of` would inject erased lifetimes - // into borrowck, which is ICE #78174. - // - // As a workaround, inline consts have an additional generic param (`ty` - // below), so that `type_of(inline_const_def_id).args(args)` uses the - // proper type with NLL infer vars. - let ty = tcx - .typeck(self.mir_def) - .node_type(tcx.local_def_id_to_hir_id(self.mir_def)); - let args = InlineConstArgs::new( - tcx, - InlineConstArgsParts { parent_args: identity_args, ty }, - ) - .args; - let args = self.infcx.replace_free_regions_with_nll_infer_vars(FR, args); - DefiningTy::InlineConst(self.mir_def.to_def_id(), args) - } - } - } - } - - /// Builds a hashmap that maps from the universal regions that are - /// in scope (as a `ty::Region<'tcx>`) to their indices (as a - /// `RegionVid`). The map returned by this function contains only - /// the early-bound regions. - fn compute_indices( - &self, - fr_static: RegionVid, - defining_ty: DefiningTy<'tcx>, - ) -> UniversalRegionIndices<'tcx> { - let tcx = self.infcx.tcx; - let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.to_def_id()); - let identity_args = GenericArgs::identity_for_item(tcx, typeck_root_def_id); - let fr_args = match defining_ty { - DefiningTy::Closure(_, args) - | DefiningTy::CoroutineClosure(_, args) - | DefiningTy::Coroutine(_, args) - | DefiningTy::InlineConst(_, args) => { - // In the case of closures, we rely on the fact that - // the first N elements in the ClosureArgs are - // inherited from the `typeck_root_def_id`. - // Therefore, when we zip together (below) with - // `identity_args`, we will get only those regions - // that correspond to early-bound regions declared on - // the `typeck_root_def_id`. - assert!(args.len() >= identity_args.len()); - assert_eq!(args.regions().count(), identity_args.regions().count()); - args - } - - DefiningTy::FnDef(_, args) | DefiningTy::Const(_, args) => args, - }; - - let global_mapping = iter::once((tcx.lifetimes.re_static, fr_static)); - let arg_mapping = iter::zip(identity_args.regions(), fr_args.regions().map(|r| r.as_var())); - - UniversalRegionIndices { indices: global_mapping.chain(arg_mapping).collect(), fr_static } - } - - fn compute_inputs_and_output( - &self, - indices: &UniversalRegionIndices<'tcx>, - defining_ty: DefiningTy<'tcx>, - ) -> ty::Binder<'tcx, &'tcx ty::List>> { - let tcx = self.infcx.tcx; - match defining_ty { - DefiningTy::Closure(def_id, args) => { - assert_eq!(self.mir_def.to_def_id(), def_id); - let closure_sig = args.as_closure().sig(); - let inputs_and_output = closure_sig.inputs_and_output(); - let bound_vars = tcx.mk_bound_variable_kinds_from_iter( - inputs_and_output - .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::BrEnv, - }; - let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, br); - let closure_ty = tcx.closure_env_ty( - Ty::new_closure(tcx, def_id, args), - args.as_closure().kind(), - env_region, - ); - - // The "inputs" of the closure in the - // signature appear as a tuple. The MIR side - // flattens this tuple. - let (&output, tuplized_inputs) = - inputs_and_output.skip_binder().split_last().unwrap(); - assert_eq!(tuplized_inputs.len(), 1, "multiple closure inputs"); - let &ty::Tuple(inputs) = tuplized_inputs[0].kind() else { - bug!("closure inputs not a tuple: {:?}", tuplized_inputs[0]); - }; - - ty::Binder::bind_with_vars( - tcx.mk_type_list_from_iter( - iter::once(closure_ty).chain(inputs).chain(iter::once(output)), - ), - bound_vars, - ) - } - - DefiningTy::Coroutine(def_id, args) => { - assert_eq!(self.mir_def.to_def_id(), def_id); - let resume_ty = args.as_coroutine().resume_ty(); - let output = args.as_coroutine().return_ty(); - let coroutine_ty = Ty::new_coroutine(tcx, def_id, args); - let inputs_and_output = - self.infcx.tcx.mk_type_list(&[coroutine_ty, resume_ty, output]); - ty::Binder::dummy(inputs_and_output) - } - - // Construct the signature of the CoroutineClosure for the purposes of borrowck. - // This is pretty straightforward -- we: - // 1. first grab the `coroutine_closure_sig`, - // 2. compute the self type (`&`/`&mut`/no borrow), - // 3. flatten the tupled_input_tys, - // 4. construct the correct generator type to return with - // `CoroutineClosureSignature::to_coroutine_given_kind_and_upvars`. - // Then we wrap it all up into a list of inputs and output. - DefiningTy::CoroutineClosure(def_id, args) => { - assert_eq!(self.mir_def.to_def_id(), def_id); - let closure_sig = args.as_coroutine_closure().coroutine_closure_sig(); - let bound_vars = tcx.mk_bound_variable_kinds_from_iter( - closure_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::BrEnv, - }; - let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, br); - let closure_kind = args.as_coroutine_closure().kind(); - - let closure_ty = tcx.closure_env_ty( - Ty::new_coroutine_closure(tcx, def_id, args), - closure_kind, - env_region, - ); - - let inputs = closure_sig.skip_binder().tupled_inputs_ty.tuple_fields(); - let output = closure_sig.skip_binder().to_coroutine_given_kind_and_upvars( - tcx, - args.as_coroutine_closure().parent_args(), - tcx.coroutine_for_closure(def_id), - closure_kind, - env_region, - args.as_coroutine_closure().tupled_upvars_ty(), - args.as_coroutine_closure().coroutine_captures_by_ref_ty(), - ); - - ty::Binder::bind_with_vars( - tcx.mk_type_list_from_iter( - iter::once(closure_ty).chain(inputs).chain(iter::once(output)), - ), - bound_vars, - ) - } - - DefiningTy::FnDef(def_id, _) => { - let sig = tcx.fn_sig(def_id).instantiate_identity(); - let sig = indices.fold_to_region_vids(tcx, sig); - sig.inputs_and_output() - } - - DefiningTy::Const(def_id, _) => { - // For a constant body, there are no inputs, and one - // "output" (the type of the constant). - assert_eq!(self.mir_def.to_def_id(), def_id); - let ty = tcx.type_of(self.mir_def).instantiate_identity(); - let ty = indices.fold_to_region_vids(tcx, ty); - ty::Binder::dummy(tcx.mk_type_list(&[ty])) - } - - DefiningTy::InlineConst(def_id, args) => { - assert_eq!(self.mir_def.to_def_id(), def_id); - let ty = args.as_inline_const().ty(); - ty::Binder::dummy(tcx.mk_type_list(&[ty])) - } - } - } -} - -#[extension(trait InferCtxtExt<'tcx>)] -impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> { - #[instrument(skip(self), level = "debug")] - fn replace_free_regions_with_nll_infer_vars( - &self, - origin: NllRegionVariableOrigin, - value: T, - ) -> T - where - T: TypeFoldable>, - { - self.infcx.tcx.fold_regions(value, |region, _depth| { - let name = region.get_name_or_anon(); - debug!(?region, ?name); - - self.next_nll_region_var(origin, || RegionCtxt::Free(name)) - }) - } - - #[instrument(level = "debug", skip(self, indices))] - fn replace_bound_regions_with_nll_infer_vars( - &self, - origin: NllRegionVariableOrigin, - all_outlive_scope: LocalDefId, - value: ty::Binder<'tcx, T>, - indices: &mut UniversalRegionIndices<'tcx>, - ) -> T - where - T: TypeFoldable>, - { - let (value, _map) = self.tcx.instantiate_bound_regions(value, |br| { - debug!(?br); - let liberated_region = - ty::Region::new_late_param(self.tcx, all_outlive_scope.to_def_id(), br.kind); - let region_vid = { - let name = match br.kind.get_name() { - Some(name) => name, - _ => sym::anon, - }; - - self.next_nll_region_var(origin, || RegionCtxt::Bound(name)) - }; - - indices.insert_late_bound_region(liberated_region, region_vid.as_var()); - debug!(?liberated_region, ?region_vid); - region_vid - }); - value - } -} - -impl<'tcx> UniversalRegionIndices<'tcx> { - /// Initially, the `UniversalRegionIndices` map contains only the - /// early-bound regions in scope. Once that is all setup, we come - /// in later and instantiate the late-bound regions, and then we - /// insert the `ReLateParam` version of those into the map as - /// well. These are used for error reporting. - fn insert_late_bound_region(&mut self, r: ty::Region<'tcx>, vid: ty::RegionVid) { - debug!("insert_late_bound_region({:?}, {:?})", r, vid); - self.indices.insert(r, vid); - } - - /// Converts `r` into a local inference variable: `r` can either - /// be a `ReVar` (i.e., already a reference to an inference - /// variable) or it can be `'static` or some early-bound - /// region. This is useful when taking the results from - /// type-checking and trait-matching, which may sometimes - /// reference those regions from the `ParamEnv`. It is also used - /// during initialization. Relies on the `indices` map having been - /// fully initialized. - pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid { - if let ty::ReVar(..) = *r { - r.as_var() - } else if r.is_error() { - // We use the `'static` `RegionVid` because `ReError` doesn't actually exist in the - // `UniversalRegionIndices`. This is fine because 1) it is a fallback only used if - // errors are being emitted and 2) it leaves the happy path unaffected. - self.fr_static - } else { - *self - .indices - .get(&r) - .unwrap_or_else(|| bug!("cannot convert `{:?}` to a region vid", r)) - } - } - - /// Replaces all free regions in `value` with region vids, as - /// returned by `to_region_vid`. - pub fn fold_to_region_vids(&self, tcx: TyCtxt<'tcx>, value: T) -> T - where - T: TypeFoldable>, - { - tcx.fold_regions(value, |region, _| ty::Region::new_var(tcx, self.to_region_vid(region))) - } -} - -/// Iterates over the late-bound regions defined on `mir_def_id` and all of its -/// parents, up to the typeck root, and invokes `f` with the liberated form -/// of each one. -fn for_each_late_bound_region_in_recursive_scope<'tcx>( - tcx: TyCtxt<'tcx>, - mut mir_def_id: LocalDefId, - mut f: impl FnMut(ty::Region<'tcx>), -) { - let typeck_root_def_id = tcx.typeck_root_def_id(mir_def_id.to_def_id()); - - // Walk up the tree, collecting late-bound regions until we hit the typeck root - loop { - for_each_late_bound_region_in_item(tcx, mir_def_id, &mut f); - - if mir_def_id.to_def_id() == typeck_root_def_id { - break; - } else { - mir_def_id = tcx.local_parent(mir_def_id); - } - } -} - -/// Iterates over the late-bound regions defined on `mir_def_id` and all of its -/// parents, up to the typeck root, and invokes `f` with the liberated form -/// of each one. -fn for_each_late_bound_region_in_item<'tcx>( - tcx: TyCtxt<'tcx>, - mir_def_id: LocalDefId, - mut f: impl FnMut(ty::Region<'tcx>), -) { - if !tcx.def_kind(mir_def_id).is_fn_like() { - return; - } - - for bound_var in tcx.late_bound_vars(tcx.local_def_id_to_hir_id(mir_def_id)) { - let ty::BoundVariableKind::Region(bound_region) = bound_var else { - continue; - }; - let liberated_region = - ty::Region::new_late_param(tcx, mir_def_id.to_def_id(), bound_region); - f(liberated_region); - } -} +#![allow(rustc::diagnostic_outside_of_impl)]#![allow(rustc:://let _=();let _=(); +untranslatable_diagnostic)]use rustc_data_structures::fx::FxIndexMap;use//{();}; +rustc_errors::Diag;use rustc_hir::def_id::{DefId,LocalDefId};use rustc_hir:://3; +lang_items::LangItem;use rustc_hir:: BodyOwnerKind;use rustc_index::IndexVec;use +rustc_infer::infer::NllRegionVariableOrigin;use rustc_macros::extension;use//(); +rustc_middle::ty::fold::TypeFoldable;use rustc_middle::ty::print:://loop{break}; +with_no_trimmed_paths;use rustc_middle::ty::{self,InlineConstArgs,//loop{break}; +InlineConstArgsParts,RegionVid,Ty,TyCtxt};use rustc_middle::ty::{GenericArgs,//; +GenericArgsRef};use rustc_span::symbol::{kw, sym};use rustc_span::Symbol;use std +::iter;use crate::renumber::RegionCtxt;use crate::BorrowckInferCtxt;#[derive(//; +Debug)]pub struct UniversalRegions<'tcx>{indices:UniversalRegionIndices<'tcx>,// +pub fr_static:RegionVid,pub fr_fn_body:RegionVid,first_extern_index:usize,//{;}; +first_local_index:usize,num_universals:usize,pub defining_ty:DefiningTy<'tcx>,// +pub unnormalized_output_ty:Ty<'tcx>,pub unnormalized_input_tys:&'tcx[Ty<'tcx>], +pub yield_ty:Option>,pub resume_ty:Option>,}#[derive(Copy,//3; +Clone,Debug)]pub enum DefiningTy<'tcx>{Closure(DefId,GenericArgsRef<'tcx>),//(); +Coroutine(DefId,GenericArgsRef<'tcx>),CoroutineClosure(DefId,GenericArgsRef),FnDef(DefId,GenericArgsRef<'tcx>),Const(DefId,GenericArgsRef<'tcx>),//(); +InlineConst(DefId,GenericArgsRef<'tcx>),}impl<'tcx>DefiningTy<'tcx>{pub fn//{;}; +upvar_tys(self)->&'tcx ty::List>{match self{DefiningTy::Closure(_,args +)=>((args.as_closure()).upvar_tys()),DefiningTy::CoroutineClosure(_,args)=>args. +as_coroutine_closure().upvar_tys(),DefiningTy::Coroutine(_,args)=>args.//*&*&(); +as_coroutine().upvar_tys(),DefiningTy::FnDef(..)|DefiningTy::Const(..)|//*&*&(); +DefiningTy::InlineConst(..)=>{(ty::List::empty())}}}pub fn implicit_inputs(self) +->usize{match self{DefiningTy::Closure(..)|DefiningTy::CoroutineClosure(..)|//3; +DefiningTy::Coroutine(..)=>(((1))),DefiningTy ::FnDef(..)|DefiningTy::Const(..)| +DefiningTy::InlineConst(..)=>(0),}}pub fn is_fn_def(&self)->bool{matches!(*self, +DefiningTy::FnDef(..))}pub fn is_const( &self)->bool{matches!(*self,DefiningTy:: +Const(..)|DefiningTy::InlineConst(..))}pub fn def_id(&self)->DefId{match(*self){ +DefiningTy::Closure(def_id,..)|DefiningTy::CoroutineClosure(def_id,..)|//*&*&(); +DefiningTy::Coroutine(def_id,..)|DefiningTy ::FnDef(def_id,..)|DefiningTy::Const +(def_id,..)|DefiningTy::InlineConst(def_id,..)=>def_id,}}}#[derive(Debug)]//{;}; +struct UniversalRegionIndices<'tcx>{indices:FxIndexMap,//{();}; +RegionVid>,pub fr_static:RegionVid,}#[derive(Debug,PartialEq)]pub enum//((),()); +RegionClassification{Global,External,Local,} const FIRST_GLOBAL_INDEX:usize=(0); +impl<'tcx>UniversalRegions<'tcx>{pub fn new(infcx:&BorrowckInferCtxt<'_,'tcx>,// +mir_def:LocalDefId,param_env:ty::ParamEnv< 'tcx>,)->Self{UniversalRegionsBuilder +{infcx,mir_def,param_env}.build()}pub fn closure_mapping(tcx:TyCtxt<'tcx>,//{;}; +closure_args:GenericArgsRef<'tcx>,expected_num_vars:usize,closure_def_id://({}); +LocalDefId,)->IndexVec>{{();};let mut region_mapping= +IndexVec::with_capacity(expected_num_vars);3;;region_mapping.push(tcx.lifetimes. +re_static);;tcx.for_each_free_region(&closure_args,|fr|{region_mapping.push(fr); +});({});({});for_each_late_bound_region_in_recursive_scope(tcx,tcx.local_parent( +closure_def_id),|r|{;region_mapping.push(r);;});assert_eq!(region_mapping.len(), +expected_num_vars,"index vec had unexpected number of variables");if let _=(){}; +region_mapping}pub fn is_universal_region(&self,r:RegionVid)->bool{(//if true{}; +FIRST_GLOBAL_INDEX..self.num_universals).contains((((&(((r.index())))))))}pub fn +region_classification(&self,r:RegionVid)->Option{{();};let +index=r.index();;if(FIRST_GLOBAL_INDEX..self.first_extern_index).contains(&index +){((Some(RegionClassification::Global)))} else if(self.first_extern_index..self. +first_local_index).contains((&index)) {Some(RegionClassification::External)}else +if(((((self.first_local_index..self.num_universals))).contains((&index)))){Some( +RegionClassification::Local)}else{None}}pub fn universal_regions(&self)->impl//; +Iterator{((((( FIRST_GLOBAL_INDEX..self.num_universals))))).map( +RegionVid::from_usize)}pub fn is_local_free_region(&self,r:RegionVid)->bool{//3; +self.region_classification(r)==(Some(RegionClassification ::Local))}pub fn len(& +self)->usize{self.num_universals}pub fn num_global_and_external_regions(&self)// +->usize{self.first_local_index}pub fn named_universal_regions<'s>(&'s self,)->// +impl Iterator,ty::RegionVid)>+'s{self.indices.indices.//; +iter().map((|(&r,&v)|((r,v) )))}pub fn to_region_vid(&self,r:ty::Region<'tcx>)-> +RegionVid{self.indices.to_region_vid(r)}pub (crate)fn annotate(&self,tcx:TyCtxt< +'tcx>,err:&mut Diag<'_,()>){match self.defining_ty{DefiningTy::Closure(def_id,// +args)=>{3;let v=with_no_trimmed_paths!(args[tcx.generics_of(def_id).parent_count +..].iter().map(|arg|arg.to_string()).collect::>());();3;err.note(format!( +"defining type: {} with closure args [\n {},\n]",tcx .def_path_str_with_args( +def_id,args),v.join(",\n "),));;for_each_late_bound_region_in_recursive_scope +(tcx,def_id.expect_local(),|r|{{;};err.note(format!("late-bound region is {:?}", +self.to_region_vid(r)));({});});{;};}DefiningTy::CoroutineClosure(..)=>{todo!()} +DefiningTy::Coroutine(def_id,args)=>{({});let v=with_no_trimmed_paths!(args[tcx. +generics_of(def_id).parent_count..].iter().map (|arg|arg.to_string()).collect::< +Vec<_>>());loop{break;};loop{break;};loop{break;};loop{break;};err.note(format!( +"defining type: {} with coroutine args [\n {},\n]",tcx.//if true{};if true{}; +def_path_str_with_args(def_id,args),v.join(",\n "),));loop{break};let _=||(); +for_each_late_bound_region_in_recursive_scope(tcx,def_id.expect_local(),|r|{;err +.note(format!("late-bound region is {:?}",self.to_region_vid(r)));({});});({});} +DefiningTy::FnDef(def_id,args)=>{{();};err.note(format!("defining type: {}",tcx. +def_path_str_with_args(def_id,args),));3;}DefiningTy::Const(def_id,args)=>{;err. +note(format!("defining constant type: {}",tcx.def_path_str_with_args(def_id,//3; +args),));*&*&();}DefiningTy::InlineConst(def_id,args)=>{*&*&();err.note(format!( +"defining inline constant type: {}",tcx.def_path_str_with_args(def_id,args),));; +}}}}struct UniversalRegionsBuilder<'cx,'tcx>{infcx:&'cx BorrowckInferCtxt<'cx,// +'tcx>,mir_def:LocalDefId,param_env:ty::ParamEnv<'tcx>,}const FR://if let _=(){}; +NllRegionVariableOrigin=NllRegionVariableOrigin::FreeRegion;impl<'cx,'tcx>//{;}; +UniversalRegionsBuilder<'cx,'tcx>{fn build(self)->UniversalRegions<'tcx>{;debug! +("build(mir_def={:?})",self.mir_def);3;3;let param_env=self.param_env;3;;debug!( +"build: param_env={:?}",param_env);3;3;assert_eq!(FIRST_GLOBAL_INDEX,self.infcx. +num_region_vars());;let fr_static=self.infcx.next_nll_region_var(FR,||RegionCtxt +::Free(kw::Static)).as_var();;let first_extern_index=self.infcx.num_region_vars( +);();();let defining_ty=self.defining_ty();3;3;debug!("build: defining_ty={:?}", +defining_ty);;let mut indices=self.compute_indices(fr_static,defining_ty);debug! +("build: indices={:?}",indices);({});({});let typeck_root_def_id=self.infcx.tcx. +typeck_root_def_id(self.mir_def.to_def_id());();3;let first_local_index=if self. +mir_def.to_def_id()==typeck_root_def_id{first_extern_index}else{((),());((),()); +for_each_late_bound_region_in_recursive_scope(self.infcx.tcx,self.infcx.tcx.//3; +local_parent(self.mir_def),|r|{;debug!(?r);;if!indices.indices.contains_key(&r){ +let region_vid={;let name=r.get_name_or_anon();self.infcx.next_nll_region_var(FR +,||RegionCtxt::LateBound(name))};({});({});debug!(?region_vid);({});{;};indices. +insert_late_bound_region(r,region_vid.as_var());;}},);self.infcx.num_region_vars +()};{;};{;};let bound_inputs_and_output=self.compute_inputs_and_output(&indices, +defining_ty);((),());let _=();((),());let _=();let inputs_and_output=self.infcx. +replace_bound_regions_with_nll_infer_vars(FR,self.mir_def,//if true{};if true{}; +bound_inputs_and_output,&mut indices,);;for_each_late_bound_region_in_item(self. +infcx.tcx,self.mir_def,|r|{;debug!(?r);;if!indices.indices.contains_key(&r){;let +region_vid={;let name=r.get_name_or_anon();;self.infcx.next_nll_region_var(FR,|| +RegionCtxt::LateBound(name))};{();};{();};debug!(?region_vid);({});({});indices. +insert_late_bound_region(r,region_vid.as_var());;}});let(unnormalized_output_ty, +mut unnormalized_input_tys)=inputs_and_output.split_last().unwrap();{();};if let +DefiningTy::FnDef(def_id,_)=defining_ty{if (((self.infcx.tcx.fn_sig(def_id)))). +skip_binder().c_variadic(){{;};let va_list_did=self.infcx.tcx.require_lang_item( +LangItem::VaList,Some(self.infcx.tcx.def_span(self.mir_def)),);;let reg_vid=self +.infcx.next_nll_region_var(FR,||RegionCtxt::Free( Symbol::intern("c-variadic"))) +.as_var();;let region=ty::Region::new_var(self.infcx.tcx,reg_vid);let va_list_ty +=self.infcx.tcx.type_of(va_list_did).instantiate( self.infcx.tcx,&[region.into() +]);((),());((),());unnormalized_input_tys=self.infcx.tcx.mk_type_list_from_iter( +unnormalized_input_tys.iter().copied().chain(iter::once(va_list_ty)),);3;}}3;let +fr_fn_body=self.infcx.next_nll_region_var(FR, ||RegionCtxt::Free(Symbol::intern( +"fn_body"))).as_var();;;let num_universals=self.infcx.num_region_vars();;debug!( +"build: global regions = {}..{}",FIRST_GLOBAL_INDEX,first_extern_index);;debug!( +"build: extern regions = {}..{}",first_extern_index,first_local_index);;;debug!( +"build: local regions = {}..{}",first_local_index,num_universals);({});{;};let( +resume_ty,yield_ty)=match defining_ty{DefiningTy::Coroutine(_,args)=>{3;let tys= +args.as_coroutine();;(Some(tys.resume_ty()),Some(tys.yield_ty()))}_=>(None,None) +,};loop{break};UniversalRegions{indices,fr_static,fr_fn_body,first_extern_index, +first_local_index,num_universals,defining_ty,unnormalized_output_ty:*//let _=(); +unnormalized_output_ty,unnormalized_input_tys,yield_ty,resume_ty,}}fn//let _=(); +defining_ty(&self)->DefiningTy<'tcx>{{();};let tcx=self.infcx.tcx;{();};({});let +typeck_root_def_id=tcx.typeck_root_def_id(self.mir_def.to_def_id());3;match tcx. +hir().body_owner_kind(self.mir_def){BodyOwnerKind::Closure|BodyOwnerKind::Fn=>{; +let defining_ty=tcx.type_of(self.mir_def).instantiate_identity();{;};{;};debug!( +"defining_ty (pre-replacement): {:?}",defining_ty);;;let defining_ty=self.infcx. +replace_free_regions_with_nll_infer_vars(FR,defining_ty);;match*defining_ty.kind +(){ty::Closure(def_id,args)=>((DefiningTy::Closure(def_id,args))),ty::Coroutine( +def_id,args)=>(DefiningTy::Coroutine(def_id ,args)),ty::CoroutineClosure(def_id, +args)=>{(((DefiningTy::CoroutineClosure(def_id,args))))}ty::FnDef(def_id,args)=> +DefiningTy::FnDef(def_id,args),_=>span_bug!(tcx.def_span(self.mir_def),//*&*&(); +"expected defining type for `{:?}`: `{:?}`",self.mir_def,defining_ty),}}//{();}; +BodyOwnerKind::Const{..}|BodyOwnerKind::Static(..)=>{let _=();let identity_args= +GenericArgs::identity_for_item(tcx,typeck_root_def_id);let _=();if self.mir_def. +to_def_id()==typeck_root_def_id{if let _=(){};if let _=(){};let args=self.infcx. +replace_free_regions_with_nll_infer_vars(FR,identity_args);();DefiningTy::Const( +self.mir_def.to_def_id(),args)}else{3;let ty=tcx.typeck(self.mir_def).node_type( +tcx.local_def_id_to_hir_id(self.mir_def));3;3;let args=InlineConstArgs::new(tcx, +InlineConstArgsParts{parent_args:identity_args,ty},).args;;;let args=self.infcx. +replace_free_regions_with_nll_infer_vars(FR,args);;DefiningTy::InlineConst(self. +mir_def.to_def_id(),args)}}}}fn compute_indices(&self,fr_static:RegionVid,//{;}; +defining_ty:DefiningTy<'tcx>,)->UniversalRegionIndices<'tcx>{;let tcx=self.infcx +.tcx;;;let typeck_root_def_id=tcx.typeck_root_def_id(self.mir_def.to_def_id());; +let identity_args=GenericArgs::identity_for_item(tcx,typeck_root_def_id);3;3;let +fr_args=match defining_ty{DefiningTy::Closure(_,args)|DefiningTy:://loop{break}; +CoroutineClosure(_,args)|DefiningTy::Coroutine (_,args)|DefiningTy::InlineConst( +_,args)=>{;assert!(args.len()>=identity_args.len());;;assert_eq!(args.regions(). +count(),identity_args.regions().count());((),());args}DefiningTy::FnDef(_,args)| +DefiningTy::Const(_,args)=>args,};;let global_mapping=iter::once((tcx.lifetimes. +re_static,fr_static));;let arg_mapping=iter::zip(identity_args.regions(),fr_args +.regions().map(|r|r.as_var()));();UniversalRegionIndices{indices:global_mapping. +chain(arg_mapping).collect(),fr_static}}fn compute_inputs_and_output(&self,//(); +indices:&UniversalRegionIndices<'tcx>,defining_ty:DefiningTy<'tcx>,)->ty:://{;}; +Binder<'tcx,&'tcx ty::List>>{;let tcx=self.infcx.tcx;match defining_ty{ +DefiningTy::Closure(def_id,args)=>{;assert_eq!(self.mir_def.to_def_id(),def_id); +let closure_sig=args.as_closure().sig();();();let inputs_and_output=closure_sig. +inputs_and_output();{;};();let bound_vars=tcx.mk_bound_variable_kinds_from_iter( +inputs_and_output.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::BrEnv,};;;let env_region=ty::Region::new_bound(tcx, +ty::INNERMOST,br);;let closure_ty=tcx.closure_env_ty(Ty::new_closure(tcx,def_id, +args),args.as_closure().kind(),env_region,);{;};();let(&output,tuplized_inputs)= +inputs_and_output.skip_binder().split_last().unwrap();((),());*&*&();assert_eq!( +tuplized_inputs.len(),1,"multiple closure inputs");{;};();let&ty::Tuple(inputs)= +tuplized_inputs[0].kind()else{if true{};bug!("closure inputs not a tuple: {:?}", +tuplized_inputs[0]);3;};3;ty::Binder::bind_with_vars(tcx.mk_type_list_from_iter( +iter::once(closure_ty).chain(inputs).chain((iter::once(output))),),bound_vars,)} +DefiningTy::Coroutine(def_id,args)=>{;assert_eq!(self.mir_def.to_def_id(),def_id +);;let resume_ty=args.as_coroutine().resume_ty();let output=args.as_coroutine(). +return_ty();{;};();let coroutine_ty=Ty::new_coroutine(tcx,def_id,args);();();let +inputs_and_output=self.infcx.tcx.mk_type_list( &[coroutine_ty,resume_ty,output]) +;;ty::Binder::dummy(inputs_and_output)}DefiningTy::CoroutineClosure(def_id,args) +=>{{;};assert_eq!(self.mir_def.to_def_id(),def_id);{;};{;};let closure_sig=args. +as_coroutine_closure().coroutine_closure_sig();*&*&();*&*&();let bound_vars=tcx. +mk_bound_variable_kinds_from_iter((closure_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::BrEnv,};;let env_region=ty:: +Region::new_bound(tcx,ty::INNERMOST,br);let _=();let _=();let closure_kind=args. +as_coroutine_closure().kind();{();};{();};let closure_ty=tcx.closure_env_ty(Ty:: +new_coroutine_closure(tcx,def_id,args),closure_kind,env_region,);3;3;let inputs= +closure_sig.skip_binder().tupled_inputs_ty.tuple_fields();{();};({});let output= +closure_sig.skip_binder().to_coroutine_given_kind_and_upvars(tcx,args.//((),()); +as_coroutine_closure().parent_args() ,((((tcx.coroutine_for_closure(def_id))))), +closure_kind,env_region,((args.as_coroutine_closure()).tupled_upvars_ty()),args. +as_coroutine_closure().coroutine_captures_by_ref_ty(),);loop{break};ty::Binder:: +bind_with_vars(tcx.mk_type_list_from_iter(iter:: once(closure_ty).chain(inputs). +chain(iter::once(output)),),bound_vars,)}DefiningTy::FnDef(def_id,_)=>{;let sig= +tcx.fn_sig(def_id).instantiate_identity();;;let sig=indices.fold_to_region_vids( +tcx,sig);;sig.inputs_and_output()}DefiningTy::Const(def_id,_)=>{assert_eq!(self. +mir_def.to_def_id(),def_id);if true{};let _=();let ty=tcx.type_of(self.mir_def). +instantiate_identity();;;let ty=indices.fold_to_region_vids(tcx,ty);ty::Binder:: +dummy(tcx.mk_type_list(&[ty]))}DefiningTy::InlineConst(def_id,args)=>{;assert_eq +!(self.mir_def.to_def_id(),def_id);3;3;let ty=args.as_inline_const().ty();3;ty:: +Binder::dummy(tcx.mk_type_list(&[ty]) )}}}}#[extension(trait InferCtxtExt<'tcx>) +]impl<'cx,'tcx>BorrowckInferCtxt<'cx,'tcx>{#[instrument(skip(self),level=//({}); +"debug")]fn replace_free_regions_with_nll_infer_vars(&self,origin://let _=(); +NllRegionVariableOrigin,value:T,)->T where T:TypeFoldable>,{self.// +infcx.tcx.fold_regions(value,|region,_depth|{;let name=region.get_name_or_anon() +;;debug!(?region,?name);self.next_nll_region_var(origin,||RegionCtxt::Free(name) +)})}#[instrument(level="debug",skip(self,indices))]fn//loop{break};loop{break;}; +replace_bound_regions_with_nll_infer_vars(&self,origin://if true{};if true{}; +NllRegionVariableOrigin,all_outlive_scope:LocalDefId,value:ty::Binder<'tcx,T>,// +indices:&mut UniversalRegionIndices<'tcx>,) ->T where T:TypeFoldable>,{;let(value,_map)=self.tcx.instantiate_bound_regions(value,|br|{;debug!(?br); +let liberated_region=ty::Region::new_late_param(self.tcx,all_outlive_scope.//(); +to_def_id(),br.kind);3;;let region_vid={;let name=match br.kind.get_name(){Some( +name)=>name,_=>sym::anon,};;self.next_nll_region_var(origin,||RegionCtxt::Bound( +name))};;indices.insert_late_bound_region(liberated_region,region_vid.as_var()); +debug!(?liberated_region,?region_vid);{();};region_vid});{();};value}}impl<'tcx> +UniversalRegionIndices<'tcx>{fn insert_late_bound_region( &mut self,r:ty::Region +<'tcx>,vid:ty::RegionVid){;debug!("insert_late_bound_region({:?}, {:?})",r,vid); +self.indices.insert(r,vid);{;};}pub fn to_region_vid(&self,r:ty::Region<'tcx>)-> +RegionVid{if let ty::ReVar(..)=((*r)){(r .as_var())}else if (r.is_error()){self. +fr_static}else{*(((((self.indices.get( (((((&r))))))))))).unwrap_or_else(||bug!( +"cannot convert `{:?}` to a region vid",r))}}pub fn fold_to_region_vids(&//3; +self,tcx:TyCtxt<'tcx>,value:T)->T where T:TypeFoldable>,{tcx.//{;}; +fold_regions(value,|region,_|ty:: Region::new_var(tcx,self.to_region_vid(region) +))}}fn for_each_late_bound_region_in_recursive_scope< 'tcx>(tcx:TyCtxt<'tcx>,mut +mir_def_id:LocalDefId,mut f:impl FnMut(ty::Region<'tcx>),){let _=();let _=();let +typeck_root_def_id=tcx.typeck_root_def_id(mir_def_id.to_def_id());({});loop{{;}; +for_each_late_bound_region_in_item(tcx,mir_def_id,&mut f);((),());if mir_def_id. +to_def_id()==typeck_root_def_id{();break;();}else{3;mir_def_id=tcx.local_parent( +mir_def_id);{;};}}}fn for_each_late_bound_region_in_item<'tcx>(tcx:TyCtxt<'tcx>, +mir_def_id:LocalDefId,mut f:impl FnMut(ty::Region<'tcx>),){if!tcx.def_kind(//(); +mir_def_id).is_fn_like(){();return;();}for bound_var in tcx.late_bound_vars(tcx. +local_def_id_to_hir_id(mir_def_id)){if true{};let ty::BoundVariableKind::Region( +bound_region)=bound_var else{3;continue;3;};3;;let liberated_region=ty::Region:: +new_late_param(tcx,mir_def_id.to_def_id(),bound_region);;;f(liberated_region);}} diff --git a/compiler/rustc_borrowck/src/used_muts.rs b/compiler/rustc_borrowck/src/used_muts.rs index dea1c7823a5c1..dc36758dbfa42 100644 --- a/compiler/rustc_borrowck/src/used_muts.rs +++ b/compiler/rustc_borrowck/src/used_muts.rs @@ -1,108 +1,35 @@ -use rustc_data_structures::fx::FxIndexSet; -use rustc_middle::mir::visit::{PlaceContext, Visitor}; -use rustc_middle::mir::{ - Local, Location, Place, Statement, StatementKind, Terminator, TerminatorKind, -}; - -use crate::MirBorrowckCtxt; - -impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { - /// Walks the MIR adding to the set of `used_mut` locals that will be ignored for the purposes - /// of the `unused_mut` lint. - /// - /// `temporary_used_locals` should contain locals that were found to be temporary, mutable and - /// used from borrow checking. This function looks for assignments into these locals from - /// user-declared locals and adds those user-defined locals to the `used_mut` set. This can - /// occur due to a rare case involving upvars in closures. - /// - /// `never_initialized_mut_locals` should contain the set of user-declared mutable locals - /// (not arguments) that have not already been marked as being used. - /// This function then looks for assignments from statements or the terminator into the locals - /// from this set and removes them from the set. This leaves only those locals that have not - /// been assigned to - this set is used as a proxy for locals that were not initialized due to - /// unreachable code. These locals are then considered "used" to silence the lint for them. - /// See #55344 for context. - pub(crate) fn gather_used_muts( - &mut self, - temporary_used_locals: FxIndexSet, - mut never_initialized_mut_locals: FxIndexSet, - ) { - { - let mut visitor = GatherUsedMutsVisitor { - temporary_used_locals, - never_initialized_mut_locals: &mut never_initialized_mut_locals, - mbcx: self, - }; - visitor.visit_body(visitor.mbcx.body); - } - - // Take the union of the existed `used_mut` set with those variables we've found were - // never initialized. - debug!("gather_used_muts: never_initialized_mut_locals={:?}", never_initialized_mut_locals); - self.used_mut = self.used_mut.union(&never_initialized_mut_locals).cloned().collect(); - } -} - -/// MIR visitor for collecting used mutable variables. -/// The 'visit lifetime represents the duration of the MIR walk. -struct GatherUsedMutsVisitor<'visit, 'cx, 'tcx> { - temporary_used_locals: FxIndexSet, - never_initialized_mut_locals: &'visit mut FxIndexSet, - mbcx: &'visit mut MirBorrowckCtxt<'cx, 'tcx>, -} - -impl GatherUsedMutsVisitor<'_, '_, '_> { - fn remove_never_initialized_mut_locals(&mut self, into: Place<'_>) { - // Remove any locals that we found were initialized from the - // `never_initialized_mut_locals` set. At the end, the only remaining locals will - // be those that were never initialized - we will consider those as being used as - // they will either have been removed by unreachable code optimizations; or linted - // as unused variables. - // FIXME(#120456) - is `swap_remove` correct? - self.never_initialized_mut_locals.swap_remove(&into.local); - } -} - -impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tcx> { - fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { - debug!("visit_terminator: terminator={:?}", terminator); - match &terminator.kind { - TerminatorKind::Call { destination, .. } => { - self.remove_never_initialized_mut_locals(*destination); - } - _ => {} - } - - self.super_terminator(terminator, location); - } - - fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { - if let StatementKind::Assign(box (into, _)) = &statement.kind { - debug!( - "visit_statement: statement={:?} local={:?} \ - never_initialized_mut_locals={:?}", - statement, into.local, self.never_initialized_mut_locals - ); - self.remove_never_initialized_mut_locals(*into); - } - - self.super_statement(statement, location); - } - - fn visit_local(&mut self, local: Local, place_context: PlaceContext, location: Location) { - if place_context.is_place_assignment() && self.temporary_used_locals.contains(&local) { - // Propagate the Local assigned at this Location as a used mutable local variable - for moi in &self.mbcx.move_data.loc_map[location] { - let mpi = &self.mbcx.move_data.moves[*moi].path; - let path = &self.mbcx.move_data.move_paths[*mpi]; - debug!( - "assignment of {:?} to {:?}, adding {:?} to used mutable set", - path.place, local, path.place - ); - if let Some(user_local) = path.place.as_local() { - self.mbcx.used_mut.insert(user_local); - } - } - } - } -} +use rustc_data_structures::fx::FxIndexSet;use rustc_middle::mir::visit::{//({}); +PlaceContext,Visitor};use rustc_middle::mir::{Local,Location,Place,Statement,//; +StatementKind,Terminator,TerminatorKind,};use crate::MirBorrowckCtxt;impl<'cx,// +'tcx>MirBorrowckCtxt<'cx,'tcx>{pub(crate)fn gather_used_muts(&mut self,//*&*&(); +temporary_used_locals:FxIndexSet,mut never_initialized_mut_locals://({}); +FxIndexSet,){{if true{};let _=||();let mut visitor=GatherUsedMutsVisitor{ +temporary_used_locals,never_initialized_mut_locals:&mut//let _=||();loop{break}; +never_initialized_mut_locals,mbcx:self,};;visitor.visit_body(visitor.mbcx.body); +}let _=();let _=();debug!("gather_used_muts: never_initialized_mut_locals={:?}", +never_initialized_mut_locals);((),());*&*&();self.used_mut=self.used_mut.union(& +never_initialized_mut_locals).cloned().collect();;}}struct GatherUsedMutsVisitor +<'visit,'cx,'tcx>{temporary_used_locals:FxIndexSet,//if true{};if true{}; +never_initialized_mut_locals:&'visit mut FxIndexSet,mbcx:&'visit mut//(); +MirBorrowckCtxt<'cx,'tcx>,}impl GatherUsedMutsVisitor<'_,'_,'_>{fn//loop{break}; +remove_never_initialized_mut_locals(&mut self,into:Place<'_>){loop{break;};self. +never_initialized_mut_locals.swap_remove(&into.local);();}}impl<'visit,'cx,'tcx> +Visitor<'tcx>for GatherUsedMutsVisitor<'visit,'cx,'tcx>{fn visit_terminator(&//; +mut self,terminator:&Terminator<'tcx>,location:Location){((),());((),());debug!( +"visit_terminator: terminator={:?}",terminator);if true{};match&terminator.kind{ +TerminatorKind::Call{destination,..}=>{;self.remove_never_initialized_mut_locals +(*destination);{;};}_=>{}}{;};self.super_terminator(terminator,location);{;};}fn +visit_statement(&mut self,statement:&Statement<'tcx>,location:Location){if let// +StatementKind::Assign(box(into,_))=&statement.kind{let _=||();let _=||();debug!( +"visit_statement: statement={:?} local={:?} \ + never_initialized_mut_locals={:?}" +,statement,into.local,self.never_initialized_mut_locals);let _=();let _=();self. +remove_never_initialized_mut_locals(*into);();}3;self.super_statement(statement, +location);({});}fn visit_local(&mut self,local:Local,place_context:PlaceContext, +location:Location){if ((((((((place_context.is_place_assignment()))))))))&&self. +temporary_used_locals.contains((&local)){for moi in&self.mbcx.move_data.loc_map[ +location]{3;let mpi=&self.mbcx.move_data.moves[*moi].path;;;let path=&self.mbcx. +move_data.move_paths[*mpi];let _=||();loop{break};let _=||();loop{break};debug!( +"assignment of {:?} to {:?}, adding {:?} to used mutable set",path. place,local, +path.place);3;if let Some(user_local)=path.place.as_local(){;self.mbcx.used_mut. +insert(user_local);if let _=(){};if let _=(){};if let _=(){};if let _=(){};}}}}} diff --git a/compiler/rustc_borrowck/src/util/collect_writes.rs b/compiler/rustc_borrowck/src/util/collect_writes.rs index 8d92bb3593857..5143d4dbc4579 100644 --- a/compiler/rustc_borrowck/src/util/collect_writes.rs +++ b/compiler/rustc_borrowck/src/util/collect_writes.rs @@ -1,36 +1,11 @@ -use rustc_middle::mir::visit::PlaceContext; -use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{Body, Local, Location}; - -pub trait FindAssignments { - // Finds all statements that assign directly to local (i.e., X = ...) - // and returns their locations. - fn find_assignments(&self, local: Local) -> Vec; -} - -impl<'tcx> FindAssignments for Body<'tcx> { - fn find_assignments(&self, local: Local) -> Vec { - let mut visitor = FindLocalAssignmentVisitor { needle: local, locations: vec![] }; - visitor.visit_body(self); - visitor.locations - } -} - -// The Visitor walks the MIR to return the assignment statements corresponding -// to a Local. -struct FindLocalAssignmentVisitor { - needle: Local, - locations: Vec, -} - -impl<'tcx> Visitor<'tcx> for FindLocalAssignmentVisitor { - fn visit_local(&mut self, local: Local, place_context: PlaceContext, location: Location) { - if self.needle != local { - return; - } - - if place_context.is_place_assignment() { - self.locations.push(location); - } - } -} +use rustc_middle::mir::visit::PlaceContext;use rustc_middle::mir::visit:://({}); +Visitor;use rustc_middle::mir::{Body, Local,Location};pub trait FindAssignments{ +fn find_assignments(&self,local:Local)->Vec;}impl<'tcx>//loop{break;}; +FindAssignments for Body<'tcx>{fn find_assignments(&self,local:Local)->Vec{;let mut visitor=FindLocalAssignmentVisitor{needle:local,locations:vec +![]};let _=();((),());visitor.visit_body(self);((),());visitor.locations}}struct +FindLocalAssignmentVisitor{needle:Local,locations:Vec,}impl<'tcx>//(); +Visitor<'tcx>for FindLocalAssignmentVisitor{fn visit_local(&mut self,local://(); +Local,place_context:PlaceContext,location:Location){if self.needle!=local{{();}; +return;;}if place_context.is_place_assignment(){self.locations.push(location);}} +}//let _=();if true{};let _=();if true{};let _=();if true{};if true{};if true{}; diff --git a/compiler/rustc_borrowck/src/util/mod.rs b/compiler/rustc_borrowck/src/util/mod.rs index 7377d4de7274f..a83b1dd234ca5 100644 --- a/compiler/rustc_borrowck/src/util/mod.rs +++ b/compiler/rustc_borrowck/src/util/mod.rs @@ -1,3 +1 @@ -mod collect_writes; - -pub use collect_writes::FindAssignments; +mod collect_writes;pub use collect_writes::FindAssignments;//let _=();if true{}; diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs index bc94e0b972b47..4347acd989457 100644 --- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs +++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs @@ -1,96 +1,35 @@ -use crate::errors; -use crate::util::check_builtin_macro_attribute; - -use rustc_ast::ptr::P; -use rustc_ast::{self as ast, FnHeader, FnSig, Generics, StmtKind}; -use rustc_ast::{Fn, ItemKind, Stmt, TyKind, Unsafe}; -use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::Span; -use thin_vec::{thin_vec, ThinVec}; - -pub fn expand( - ecx: &mut ExtCtxt<'_>, - _span: Span, - meta_item: &ast::MetaItem, - item: Annotatable, -) -> Vec { - check_builtin_macro_attribute(ecx, meta_item, sym::alloc_error_handler); - - let orig_item = item.clone(); - - // Allow using `#[alloc_error_handler]` on an item statement - // FIXME - if we get deref patterns, use them to reduce duplication here - let (item, is_stmt, sig_span) = if let Annotatable::Item(item) = &item - && let ItemKind::Fn(fn_kind) = &item.kind - { - (item, false, ecx.with_def_site_ctxt(fn_kind.sig.span)) - } else if let Annotatable::Stmt(stmt) = &item - && let StmtKind::Item(item) = &stmt.kind - && let ItemKind::Fn(fn_kind) = &item.kind - { - (item, true, ecx.with_def_site_ctxt(fn_kind.sig.span)) - } else { - ecx.dcx().emit_err(errors::AllocErrorMustBeFn { span: item.span() }); - return vec![orig_item]; - }; - - // Generate a bunch of new items using the AllocFnFactory - let span = ecx.with_def_site_ctxt(item.span); - - // Generate item statements for the allocator methods. - let stmts = thin_vec![generate_handler(ecx, item.ident, span, sig_span)]; - - // Generate anonymous constant serving as container for the allocator methods. - let const_ty = ecx.ty(sig_span, TyKind::Tup(ThinVec::new())); - let const_body = ecx.expr_block(ecx.block(span, stmts)); - let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body); - let const_item = if is_stmt { - Annotatable::Stmt(P(ecx.stmt_item(span, const_item))) - } else { - Annotatable::Item(const_item) - }; - - // Return the original item and the new methods. - vec![orig_item, const_item] -} - -// #[rustc_std_internal_symbol] -// unsafe fn __rg_oom(size: usize, align: usize) -> ! { -// handler(core::alloc::Layout::from_size_align_unchecked(size, align)) -// } -fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span) -> Stmt { - let usize = cx.path_ident(span, Ident::new(sym::usize, span)); - let ty_usize = cx.ty_path(usize); - let size = Ident::from_str_and_span("size", span); - let align = Ident::from_str_and_span("align", span); - - let layout_new = cx.std_path(&[sym::alloc, sym::Layout, sym::from_size_align_unchecked]); - let layout_new = cx.expr_path(cx.path(span, layout_new)); - let layout = cx.expr_call( - span, - layout_new, - thin_vec![cx.expr_ident(span, size), cx.expr_ident(span, align)], - ); - - let call = cx.expr_call_ident(sig_span, handler, thin_vec![layout]); - - let never = ast::FnRetTy::Ty(cx.ty(span, TyKind::Never)); - let params = thin_vec![cx.param(span, size, ty_usize.clone()), cx.param(span, align, ty_usize)]; - let decl = cx.fn_decl(params, never); - let header = FnHeader { unsafety: Unsafe::Yes(span), ..FnHeader::default() }; - let sig = FnSig { decl, header, span: span }; - - let body = Some(cx.block_expr(call)); - let kind = ItemKind::Fn(Box::new(Fn { - defaultness: ast::Defaultness::Final, - sig, - generics: Generics::default(), - body, - })); - - let attrs = thin_vec![cx.attr_word(sym::rustc_std_internal_symbol, span)]; - - let item = cx.item(span, Ident::from_str_and_span("__rg_oom", span), attrs, kind); - cx.stmt_item(sig_span, item) -} +use crate::errors;use crate::util::check_builtin_macro_attribute;use rustc_ast// +::ptr::P;use rustc_ast::{self as ast,FnHeader,FnSig,Generics,StmtKind};use//{;}; +rustc_ast::{Fn,ItemKind,Stmt,TyKind,Unsafe};use rustc_expand::base::{//let _=(); +Annotatable,ExtCtxt};use rustc_span::symbol::{kw,sym,Ident};use rustc_span:://3; +Span;use thin_vec::{thin_vec,ThinVec};pub fn expand(ecx:&mut ExtCtxt<'_>,_span: +Span,meta_item:&ast::MetaItem,item:Annotatable,)->Vec{loop{break;}; +check_builtin_macro_attribute(ecx,meta_item,sym::alloc_error_handler);{;};();let +orig_item=item.clone();;let(item,is_stmt,sig_span)=if let Annotatable::Item(item +)=(((&item)))&&let ItemKind::Fn(fn_kind)=(((&item.kind))){(item,(((false))),ecx. +with_def_site_ctxt(fn_kind.sig.span))}else if let Annotatable::Stmt(stmt)=&item +&&let StmtKind::Item(item)=(&stmt.kind)&& let ItemKind::Fn(fn_kind)=&item.kind{( +item,true,ecx.with_def_site_ctxt(fn_kind.sig.span))}else{{;};ecx.dcx().emit_err( +errors::AllocErrorMustBeFn{span:item.span()});;return vec![orig_item];};let span +=ecx.with_def_site_ctxt(item.span);3;3;let stmts=thin_vec![generate_handler(ecx, +item.ident,span,sig_span)];3;;let const_ty=ecx.ty(sig_span,TyKind::Tup(ThinVec:: +new()));;let const_body=ecx.expr_block(ecx.block(span,stmts));let const_item=ecx +.item_const(span,Ident::new(kw::Underscore,span),const_ty,const_body);{;};();let +const_item=if is_stmt{Annotatable::Stmt(P( ecx.stmt_item(span,const_item)))}else +{Annotatable::Item(const_item)};;vec![orig_item,const_item]}fn generate_handler( +cx:&ExtCtxt<'_>,handler:Ident,span:Span,sig_span:Span)->Stmt{{();};let usize=cx. +path_ident(span,Ident::new(sym::usize,span));;let ty_usize=cx.ty_path(usize);let +size=Ident::from_str_and_span("size",span);;;let align=Ident::from_str_and_span( +"align",span);({});{;};let layout_new=cx.std_path(&[sym::alloc,sym::Layout,sym:: +from_size_align_unchecked]);;let layout_new=cx.expr_path(cx.path(span,layout_new +));;;let layout=cx.expr_call(span,layout_new,thin_vec![cx.expr_ident(span,size), +cx.expr_ident(span,align)],);();();let call=cx.expr_call_ident(sig_span,handler, +thin_vec![layout]);;;let never=ast::FnRetTy::Ty(cx.ty(span,TyKind::Never));;;let +params=thin_vec![cx.param(span,size,ty_usize.clone()),cx.param(span,align,//{;}; +ty_usize)];3;3;let decl=cx.fn_decl(params,never);;;let header=FnHeader{unsafety: +Unsafe::Yes(span),..FnHeader::default()};;;let sig=FnSig{decl,header,span:span}; +let body=Some(cx.block_expr(call));{();};({});let kind=ItemKind::Fn(Box::new(Fn{ +defaultness:ast::Defaultness::Final,sig,generics:Generics::default(),body,}));;; +let attrs=thin_vec![cx.attr_word(sym::rustc_std_internal_symbol,span)];;let item +=cx.item(span,Ident::from_str_and_span("__rg_oom",span),attrs,kind);let _=();cx. +stmt_item(sig_span,item)}//loop{break;};loop{break;};loop{break;};if let _=(){}; diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 137ac44157924..455574a8cfef9 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -1,807 +1,256 @@ -use ast::token::IdentIsRaw; -use rustc_ast as ast; -use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter}; -use rustc_ast::tokenstream::TokenStream; -use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; -use rustc_errors::PResult; -use rustc_expand::base::*; -use rustc_index::bit_set::GrowableBitSet; -use rustc_parse::parser::Parser; -use rustc_parse_format as parse; -use rustc_session::lint; -use rustc_span::symbol::Ident; -use rustc_span::symbol::{kw, sym, Symbol}; -use rustc_span::{ErrorGuaranteed, InnerSpan, Span}; -use rustc_target::asm::InlineAsmArch; -use smallvec::smallvec; - -use crate::errors; - -pub struct AsmArgs { - pub templates: Vec>, - pub operands: Vec<(ast::InlineAsmOperand, Span)>, - named_args: FxIndexMap, - reg_args: GrowableBitSet, - pub clobber_abis: Vec<(Symbol, Span)>, - options: ast::InlineAsmOptions, - pub options_spans: Vec, -} - -fn parse_args<'a>( - ecx: &ExtCtxt<'a>, - sp: Span, - tts: TokenStream, - is_global_asm: bool, -) -> PResult<'a, AsmArgs> { - let mut p = ecx.new_parser_from_tts(tts); - parse_asm_args(&mut p, sp, is_global_asm) -} - -// Primarily public for rustfmt consumption. -// Internal consumers should continue to leverage `expand_asm`/`expand__global_asm` -pub fn parse_asm_args<'a>( - p: &mut Parser<'a>, - sp: Span, - is_global_asm: bool, -) -> PResult<'a, AsmArgs> { - let dcx = &p.psess.dcx; - - if p.token == token::Eof { - return Err(dcx.create_err(errors::AsmRequiresTemplate { span: sp })); - } - - let first_template = p.parse_expr()?; - let mut args = AsmArgs { - templates: vec![first_template], - operands: vec![], - named_args: Default::default(), - reg_args: Default::default(), - clobber_abis: Vec::new(), - options: ast::InlineAsmOptions::empty(), - options_spans: vec![], - }; - - let mut allow_templates = true; - while p.token != token::Eof { - if !p.eat(&token::Comma) { - if allow_templates { - // After a template string, we always expect *only* a comma... - return Err(dcx.create_err(errors::AsmExpectedComma { span: p.token.span })); - } else { - // ...after that delegate to `expect` to also include the other expected tokens. - return Err(p.expect(&token::Comma).err().unwrap()); - } - } - if p.token == token::Eof { - break; - } // accept trailing commas - - // Parse clobber_abi - if p.eat_keyword(sym::clobber_abi) { - parse_clobber_abi(p, &mut args)?; - allow_templates = false; - continue; - } - - // Parse options - if p.eat_keyword(sym::options) { - parse_options(p, &mut args, is_global_asm)?; - allow_templates = false; - continue; - } - - let span_start = p.token.span; - - // Parse operand names - let name = if p.token.is_ident() && p.look_ahead(1, |t| *t == token::Eq) { - let (ident, _) = p.token.ident().unwrap(); - p.bump(); - p.expect(&token::Eq)?; - allow_templates = false; - Some(ident.name) - } else { - None - }; - - let mut explicit_reg = false; - let op = if !is_global_asm && p.eat_keyword(kw::In) { - let reg = parse_reg(p, &mut explicit_reg)?; - if p.eat_keyword(kw::Underscore) { - let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span }); - return Err(err); - } - let expr = p.parse_expr()?; - ast::InlineAsmOperand::In { reg, expr } - } else if !is_global_asm && p.eat_keyword(sym::out) { - let reg = parse_reg(p, &mut explicit_reg)?; - let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) }; - ast::InlineAsmOperand::Out { reg, expr, late: false } - } else if !is_global_asm && p.eat_keyword(sym::lateout) { - let reg = parse_reg(p, &mut explicit_reg)?; - let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) }; - ast::InlineAsmOperand::Out { reg, expr, late: true } - } else if !is_global_asm && p.eat_keyword(sym::inout) { - let reg = parse_reg(p, &mut explicit_reg)?; - if p.eat_keyword(kw::Underscore) { - let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span }); - return Err(err); - } - let expr = p.parse_expr()?; - if p.eat(&token::FatArrow) { - let out_expr = - if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) }; - ast::InlineAsmOperand::SplitInOut { reg, in_expr: expr, out_expr, late: false } - } else { - ast::InlineAsmOperand::InOut { reg, expr, late: false } - } - } else if !is_global_asm && p.eat_keyword(sym::inlateout) { - let reg = parse_reg(p, &mut explicit_reg)?; - if p.eat_keyword(kw::Underscore) { - let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span }); - return Err(err); - } - let expr = p.parse_expr()?; - if p.eat(&token::FatArrow) { - let out_expr = - if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) }; - ast::InlineAsmOperand::SplitInOut { reg, in_expr: expr, out_expr, late: true } - } else { - ast::InlineAsmOperand::InOut { reg, expr, late: true } - } - } else if p.eat_keyword(kw::Const) { - let anon_const = p.parse_expr_anon_const()?; - ast::InlineAsmOperand::Const { anon_const } - } else if p.eat_keyword(sym::sym) { - let expr = p.parse_expr()?; - let ast::ExprKind::Path(qself, path) = &expr.kind else { - let err = dcx.create_err(errors::AsmSymNoPath { span: expr.span }); - return Err(err); - }; - let sym = ast::InlineAsmSym { - id: ast::DUMMY_NODE_ID, - qself: qself.clone(), - path: path.clone(), - }; - ast::InlineAsmOperand::Sym { sym } - } else if !is_global_asm && p.eat_keyword(sym::label) { - let block = p.parse_block()?; - ast::InlineAsmOperand::Label { block } - } else if allow_templates { - let template = p.parse_expr()?; - // If it can't possibly expand to a string, provide diagnostics here to include other - // things it could have been. - match template.kind { - ast::ExprKind::Lit(token_lit) - if matches!( - token_lit.kind, - token::LitKind::Str | token::LitKind::StrRaw(_) - ) => {} - ast::ExprKind::MacCall(..) => {} - _ => { - let err = dcx.create_err(errors::AsmExpectedOther { - span: template.span, - is_global_asm, - }); - return Err(err); - } - } - args.templates.push(template); - continue; - } else { - p.unexpected_any()? - }; - - allow_templates = false; - let span = span_start.to(p.prev_token.span); - let slot = args.operands.len(); - args.operands.push((op, span)); - - // Validate the order of named, positional & explicit register operands and - // clobber_abi/options. We do this at the end once we have the full span - // of the argument available. - if explicit_reg { - if name.is_some() { - dcx.emit_err(errors::AsmExplicitRegisterName { span }); - } - args.reg_args.insert(slot); - } else if let Some(name) = name { - if let Some(&prev) = args.named_args.get(&name) { - dcx.emit_err(errors::AsmDuplicateArg { span, name, prev: args.operands[prev].1 }); - continue; - } - args.named_args.insert(name, slot); - } else { - if !args.named_args.is_empty() || !args.reg_args.is_empty() { - let named = args.named_args.values().map(|p| args.operands[*p].1).collect(); - let explicit = args.reg_args.iter().map(|p| args.operands[p].1).collect(); - - dcx.emit_err(errors::AsmPositionalAfter { span, named, explicit }); - } - } - } - - if args.options.contains(ast::InlineAsmOptions::NOMEM) - && args.options.contains(ast::InlineAsmOptions::READONLY) - { - let spans = args.options_spans.clone(); - dcx.emit_err(errors::AsmMutuallyExclusive { spans, opt1: "nomem", opt2: "readonly" }); - } - if args.options.contains(ast::InlineAsmOptions::PURE) - && args.options.contains(ast::InlineAsmOptions::NORETURN) - { - let spans = args.options_spans.clone(); - dcx.emit_err(errors::AsmMutuallyExclusive { spans, opt1: "pure", opt2: "noreturn" }); - } - if args.options.contains(ast::InlineAsmOptions::PURE) - && !args.options.intersects(ast::InlineAsmOptions::NOMEM | ast::InlineAsmOptions::READONLY) - { - let spans = args.options_spans.clone(); - dcx.emit_err(errors::AsmPureCombine { spans }); - } - - let mut have_real_output = false; - let mut outputs_sp = vec![]; - let mut regclass_outputs = vec![]; - let mut labels_sp = vec![]; - for (op, op_sp) in &args.operands { - match op { - ast::InlineAsmOperand::Out { reg, expr, .. } - | ast::InlineAsmOperand::SplitInOut { reg, out_expr: expr, .. } => { - outputs_sp.push(*op_sp); - have_real_output |= expr.is_some(); - if let ast::InlineAsmRegOrRegClass::RegClass(_) = reg { - regclass_outputs.push(*op_sp); - } - } - ast::InlineAsmOperand::InOut { reg, .. } => { - outputs_sp.push(*op_sp); - have_real_output = true; - if let ast::InlineAsmRegOrRegClass::RegClass(_) = reg { - regclass_outputs.push(*op_sp); - } - } - ast::InlineAsmOperand::Label { .. } => { - labels_sp.push(*op_sp); - } - _ => {} - } - } - if args.options.contains(ast::InlineAsmOptions::PURE) && !have_real_output { - dcx.emit_err(errors::AsmPureNoOutput { spans: args.options_spans.clone() }); - } - if args.options.contains(ast::InlineAsmOptions::NORETURN) && !outputs_sp.is_empty() { - let err = dcx.create_err(errors::AsmNoReturn { outputs_sp }); - // Bail out now since this is likely to confuse MIR - return Err(err); - } - if args.options.contains(ast::InlineAsmOptions::MAY_UNWIND) && !labels_sp.is_empty() { - dcx.emit_err(errors::AsmMayUnwind { labels_sp }); - } - - if args.clobber_abis.len() > 0 { - if is_global_asm { - let err = dcx.create_err(errors::GlobalAsmClobberAbi { - spans: args.clobber_abis.iter().map(|(_, span)| *span).collect(), - }); - - // Bail out now since this is likely to confuse later stages - return Err(err); - } - if !regclass_outputs.is_empty() { - dcx.emit_err(errors::AsmClobberNoReg { - spans: regclass_outputs, - clobbers: args.clobber_abis.iter().map(|(_, span)| *span).collect(), - }); - } - } - - Ok(args) -} - -/// Report a duplicate option error. -/// -/// This function must be called immediately after the option token is parsed. -/// Otherwise, the suggestion will be incorrect. -fn err_duplicate_option(p: &Parser<'_>, symbol: Symbol, span: Span) { - // Tool-only output - let full_span = if p.token.kind == token::Comma { span.to(p.token.span) } else { span }; - p.psess.dcx.emit_err(errors::AsmOptAlreadyprovided { span, symbol, full_span }); -} - -/// Try to set the provided option in the provided `AsmArgs`. -/// If it is already set, report a duplicate option error. -/// -/// This function must be called immediately after the option token is parsed. -/// Otherwise, the error will not point to the correct spot. -fn try_set_option<'a>( - p: &Parser<'a>, - args: &mut AsmArgs, - symbol: Symbol, - option: ast::InlineAsmOptions, -) { - if !args.options.contains(option) { - args.options |= option; - } else { - err_duplicate_option(p, symbol, p.prev_token.span); - } -} - -fn parse_options<'a>( - p: &mut Parser<'a>, - args: &mut AsmArgs, - is_global_asm: bool, -) -> PResult<'a, ()> { - let span_start = p.prev_token.span; - - p.expect(&token::OpenDelim(Delimiter::Parenthesis))?; - - while !p.eat(&token::CloseDelim(Delimiter::Parenthesis)) { - if !is_global_asm && p.eat_keyword(sym::pure) { - try_set_option(p, args, sym::pure, ast::InlineAsmOptions::PURE); - } else if !is_global_asm && p.eat_keyword(sym::nomem) { - try_set_option(p, args, sym::nomem, ast::InlineAsmOptions::NOMEM); - } else if !is_global_asm && p.eat_keyword(sym::readonly) { - try_set_option(p, args, sym::readonly, ast::InlineAsmOptions::READONLY); - } else if !is_global_asm && p.eat_keyword(sym::preserves_flags) { - try_set_option(p, args, sym::preserves_flags, ast::InlineAsmOptions::PRESERVES_FLAGS); - } else if !is_global_asm && p.eat_keyword(sym::noreturn) { - try_set_option(p, args, sym::noreturn, ast::InlineAsmOptions::NORETURN); - } else if !is_global_asm && p.eat_keyword(sym::nostack) { - try_set_option(p, args, sym::nostack, ast::InlineAsmOptions::NOSTACK); - } else if !is_global_asm && p.eat_keyword(sym::may_unwind) { - try_set_option(p, args, kw::Raw, ast::InlineAsmOptions::MAY_UNWIND); - } else if p.eat_keyword(sym::att_syntax) { - try_set_option(p, args, sym::att_syntax, ast::InlineAsmOptions::ATT_SYNTAX); - } else if p.eat_keyword(kw::Raw) { - try_set_option(p, args, kw::Raw, ast::InlineAsmOptions::RAW); - } else { - return p.unexpected(); - } - - // Allow trailing commas - if p.eat(&token::CloseDelim(Delimiter::Parenthesis)) { - break; - } - p.expect(&token::Comma)?; - } - - let new_span = span_start.to(p.prev_token.span); - args.options_spans.push(new_span); - - Ok(()) -} - -fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a, ()> { - let span_start = p.prev_token.span; - - p.expect(&token::OpenDelim(Delimiter::Parenthesis))?; - - if p.eat(&token::CloseDelim(Delimiter::Parenthesis)) { - return Err(p.psess.dcx.create_err(errors::NonABI { span: p.token.span })); - } - - let mut new_abis = Vec::new(); - while !p.eat(&token::CloseDelim(Delimiter::Parenthesis)) { - match p.parse_str_lit() { - Ok(str_lit) => { - new_abis.push((str_lit.symbol_unescaped, str_lit.span)); - } - Err(opt_lit) => { - let span = opt_lit.map_or(p.token.span, |lit| lit.span); - let mut err = p.psess.dcx.struct_span_err(span, "expected string literal"); - err.span_label(span, "not a string literal"); - return Err(err); - } - }; - - // Allow trailing commas - if p.eat(&token::CloseDelim(Delimiter::Parenthesis)) { - break; - } - p.expect(&token::Comma)?; - } - - let full_span = span_start.to(p.prev_token.span); - - match &new_abis[..] { - // should have errored above during parsing - [] => unreachable!(), - [(abi, _span)] => args.clobber_abis.push((*abi, full_span)), - abis => { - for (abi, span) in abis { - args.clobber_abis.push((*abi, *span)); - } - } - } - - Ok(()) -} - -fn parse_reg<'a>( - p: &mut Parser<'a>, - explicit_reg: &mut bool, -) -> PResult<'a, ast::InlineAsmRegOrRegClass> { - p.expect(&token::OpenDelim(Delimiter::Parenthesis))?; - let result = match p.token.uninterpolate().kind { - token::Ident(name, IdentIsRaw::No) => ast::InlineAsmRegOrRegClass::RegClass(name), - token::Literal(token::Lit { kind: token::LitKind::Str, symbol, suffix: _ }) => { - *explicit_reg = true; - ast::InlineAsmRegOrRegClass::Reg(symbol) - } - _ => { - return Err(p.dcx().create_err(errors::ExpectedRegisterClassOrExplicitRegister { - span: p.token.span, - })); - } - }; - p.bump(); - p.expect(&token::CloseDelim(Delimiter::Parenthesis))?; - Ok(result) -} - -fn expand_preparsed_asm( - ecx: &mut ExtCtxt<'_>, - args: AsmArgs, -) -> ExpandResult, ()> { - let mut template = vec![]; - // Register operands are implicitly used since they are not allowed to be - // referenced in the template string. - let mut used = vec![false; args.operands.len()]; - for pos in args.reg_args.iter() { - used[pos] = true; - } - let named_pos: FxHashMap = - args.named_args.iter().map(|(&sym, &idx)| (idx, sym)).collect(); - let mut line_spans = Vec::with_capacity(args.templates.len()); - let mut curarg = 0; - - let mut template_strs = Vec::with_capacity(args.templates.len()); - - for (i, template_expr) in args.templates.into_iter().enumerate() { - if i != 0 { - template.push(ast::InlineAsmTemplatePiece::String("\n".to_string())); - } - - let msg = "asm template must be a string literal"; - let template_sp = template_expr.span; - let (template_str, template_style, template_span) = { - let ExpandResult::Ready(mac) = expr_to_spanned_string(ecx, template_expr, msg) else { - return ExpandResult::Retry(()); - }; - match mac { - Ok(template_part) => template_part, - Err(err) => { - return ExpandResult::Ready(Err(match err { - Ok((err, _)) => err.emit(), - Err(guar) => guar, - })); - } - } - }; - - let str_style = match template_style { - ast::StrStyle::Cooked => None, - ast::StrStyle::Raw(raw) => Some(raw as usize), - }; - - let template_snippet = ecx.source_map().span_to_snippet(template_sp).ok(); - template_strs.push(( - template_str, - template_snippet.as_deref().map(Symbol::intern), - template_sp, - )); - let template_str = template_str.as_str(); - - if let Some(InlineAsmArch::X86 | InlineAsmArch::X86_64) = ecx.sess.asm_arch { - let find_span = |needle: &str| -> Span { - if let Some(snippet) = &template_snippet { - if let Some(pos) = snippet.find(needle) { - let end = pos - + snippet[pos..] - .find(|c| matches!(c, '\n' | ';' | '\\' | '"')) - .unwrap_or(snippet[pos..].len() - 1); - let inner = InnerSpan::new(pos, end); - return template_sp.from_inner(inner); - } - } - template_sp - }; - - if template_str.contains(".intel_syntax") { - ecx.psess().buffer_lint( - lint::builtin::BAD_ASM_STYLE, - find_span(".intel_syntax"), - ecx.current_expansion.lint_node_id, - "avoid using `.intel_syntax`, Intel syntax is the default", - ); - } - if template_str.contains(".att_syntax") { - ecx.psess().buffer_lint( - lint::builtin::BAD_ASM_STYLE, - find_span(".att_syntax"), - ecx.current_expansion.lint_node_id, - "avoid using `.att_syntax`, prefer using `options(att_syntax)` instead", - ); - } - } - - // Don't treat raw asm as a format string. - if args.options.contains(ast::InlineAsmOptions::RAW) { - template.push(ast::InlineAsmTemplatePiece::String(template_str.to_string())); - let template_num_lines = 1 + template_str.matches('\n').count(); - line_spans.extend(std::iter::repeat(template_sp).take(template_num_lines)); - continue; - } - - let mut parser = parse::Parser::new( - template_str, - str_style, - template_snippet, - false, - parse::ParseMode::InlineAsm, - ); - parser.curarg = curarg; - - let mut unverified_pieces = Vec::new(); - while let Some(piece) = parser.next() { - if !parser.errors.is_empty() { - break; - } else { - unverified_pieces.push(piece); - } - } - - if !parser.errors.is_empty() { - let err = parser.errors.remove(0); - let err_sp = template_span.from_inner(InnerSpan::new(err.span.start, err.span.end)); - let msg = format!("invalid asm template string: {}", err.description); - let mut e = ecx.dcx().struct_span_err(err_sp, msg); - e.span_label(err_sp, err.label + " in asm template string"); - if let Some(note) = err.note { - e.note(note); - } - if let Some((label, span)) = err.secondary_label { - let err_sp = template_span.from_inner(InnerSpan::new(span.start, span.end)); - e.span_label(err_sp, label); - } - let guar = e.emit(); - return ExpandResult::Ready(Err(guar)); - } - - curarg = parser.curarg; - - let mut arg_spans = parser - .arg_places - .iter() - .map(|span| template_span.from_inner(InnerSpan::new(span.start, span.end))); - for piece in unverified_pieces { - match piece { - parse::Piece::String(s) => { - template.push(ast::InlineAsmTemplatePiece::String(s.to_string())) - } - parse::Piece::NextArgument(arg) => { - let span = arg_spans.next().unwrap_or(template_sp); - - let operand_idx = match arg.position { - parse::ArgumentIs(idx) | parse::ArgumentImplicitlyIs(idx) => { - if idx >= args.operands.len() - || named_pos.contains_key(&idx) - || args.reg_args.contains(idx) - { - let msg = format!("invalid reference to argument at index {idx}"); - let mut err = ecx.dcx().struct_span_err(span, msg); - err.span_label(span, "from here"); - - let positional_args = args.operands.len() - - args.named_args.len() - - args.reg_args.len(); - let positional = if positional_args != args.operands.len() { - "positional " - } else { - "" - }; - let msg = match positional_args { - 0 => format!("no {positional}arguments were given"), - 1 => format!("there is 1 {positional}argument"), - x => format!("there are {x} {positional}arguments"), - }; - err.note(msg); - - if named_pos.contains_key(&idx) { - err.span_label(args.operands[idx].1, "named argument"); - err.span_note( - args.operands[idx].1, - "named arguments cannot be referenced by position", - ); - } else if args.reg_args.contains(idx) { - err.span_label( - args.operands[idx].1, - "explicit register argument", - ); - err.span_note( - args.operands[idx].1, - "explicit register arguments cannot be used in the asm template", - ); - err.span_help( - args.operands[idx].1, - "use the register name directly in the assembly code", - ); - } - err.emit(); - None - } else { - Some(idx) - } - } - parse::ArgumentNamed(name) => { - match args.named_args.get(&Symbol::intern(name)) { - Some(&idx) => Some(idx), - None => { - let msg = format!("there is no argument named `{name}`"); - let span = arg.position_span; - ecx.dcx() - .struct_span_err( - template_span - .from_inner(InnerSpan::new(span.start, span.end)), - msg, - ) - .emit(); - None - } - } - } - }; - - let mut chars = arg.format.ty.chars(); - let mut modifier = chars.next(); - if chars.next().is_some() { - let span = arg - .format - .ty_span - .map(|sp| template_sp.from_inner(InnerSpan::new(sp.start, sp.end))) - .unwrap_or(template_sp); - ecx.dcx().emit_err(errors::AsmModifierInvalid { span }); - modifier = None; - } - - if let Some(operand_idx) = operand_idx { - used[operand_idx] = true; - template.push(ast::InlineAsmTemplatePiece::Placeholder { - operand_idx, - modifier, - span, - }); - } - } - } - } - - if parser.line_spans.is_empty() { - let template_num_lines = 1 + template_str.matches('\n').count(); - line_spans.extend(std::iter::repeat(template_sp).take(template_num_lines)); - } else { - line_spans.extend( - parser - .line_spans - .iter() - .map(|span| template_span.from_inner(InnerSpan::new(span.start, span.end))), - ); - }; - } - - let mut unused_operands = vec![]; - let mut help_str = String::new(); - for (idx, used) in used.into_iter().enumerate() { - if !used { - let msg = if let Some(sym) = named_pos.get(&idx) { - help_str.push_str(&format!(" {{{}}}", sym)); - "named argument never used" - } else { - help_str.push_str(&format!(" {{{}}}", idx)); - "argument never used" - }; - unused_operands.push((args.operands[idx].1, msg)); - } - } - match unused_operands.len() { - 0 => {} - 1 => { - let (sp, msg) = unused_operands.into_iter().next().unwrap(); - ecx.dcx() - .struct_span_err(sp, msg) - .with_span_label(sp, msg) - .with_help(format!( - "if this argument is intentionally unused, \ +use ast::token::IdentIsRaw;use rustc_ast as ast;use rustc_ast::ptr::P;use//({}); +rustc_ast::token::{self,Delimiter};use rustc_ast::tokenstream::TokenStream;use// +rustc_data_structures::fx::{FxHashMap,FxIndexMap };use rustc_errors::PResult;use +rustc_expand::base::*;use rustc_index::bit_set::GrowableBitSet;use rustc_parse// +::parser::Parser;use rustc_parse_format as parse;use rustc_session::lint;use//3; +rustc_span::symbol::Ident;use rustc_span::symbol::{kw,sym,Symbol};use//let _=(); +rustc_span::{ErrorGuaranteed,InnerSpan,Span};use rustc_target::asm:://if true{}; +InlineAsmArch;use smallvec::smallvec;use crate::errors;pub struct AsmArgs{pub//; +templates:Vec>,pub operands:Vec<(ast::InlineAsmOperand,Span)>,//(); +named_args:FxIndexMap,reg_args:GrowableBitSet,pub//((),()); +clobber_abis:Vec<(Symbol,Span)> ,options:ast::InlineAsmOptions,pub options_spans +:Vec,}fn parse_args<'a>(ecx:&ExtCtxt<'a>,sp:Span,tts:TokenStream,//*&*&(); +is_global_asm:bool,)->PResult<'a,AsmArgs>{;let mut p=ecx.new_parser_from_tts(tts +);{();};parse_asm_args(&mut p,sp,is_global_asm)}pub fn parse_asm_args<'a>(p:&mut +Parser<'a>,sp:Span,is_global_asm:bool,)->PResult<'a,AsmArgs>{3;let dcx=&p.psess. +dcx;if true{};if p.token==token::Eof{let _=();return Err(dcx.create_err(errors:: +AsmRequiresTemplate{span:sp}));;}let first_template=p.parse_expr()?;let mut args +=AsmArgs{templates:(vec![first_template]),operands:(vec![]),named_args:Default:: +default(),reg_args:(Default::default()), clobber_abis:(Vec::new()),options:ast:: +InlineAsmOptions::empty(),options_spans:vec![],};;;let mut allow_templates=true; +while p.token!=token::Eof{if!p.eat(&token::Comma){if allow_templates{;return Err +(dcx.create_err(errors::AsmExpectedComma{span:p.token.span}));;}else{return Err( +p.expect(&token::Comma).err().unwrap());;}}if p.token==token::Eof{;break;;}if p. +eat_keyword(sym::clobber_abi){;parse_clobber_abi(p,&mut args)?;;allow_templates= +false;3;3;continue;3;}if p.eat_keyword(sym::options){;parse_options(p,&mut args, +is_global_asm)?;;allow_templates=false;continue;}let span_start=p.token.span;let +name=if p.token.is_ident()&&p.look_ahead(1,|t|*t==token::Eq){{;};let(ident,_)=p. +token.ident().unwrap();;;p.bump();;;p.expect(&token::Eq)?;allow_templates=false; +Some(ident.name)}else{None};;;let mut explicit_reg=false;let op=if!is_global_asm +&&p.eat_keyword(kw::In){{();};let reg=parse_reg(p,&mut explicit_reg)?;({});if p. +eat_keyword(kw::Underscore){3;let err=dcx.create_err(errors::AsmUnderscoreInput{ +span:p.token.span});();();return Err(err);();}3;let expr=p.parse_expr()?;3;ast:: +InlineAsmOperand::In{reg,expr}}else if!is_global_asm&&p.eat_keyword(sym::out){3; +let reg=parse_reg(p,&mut explicit_reg)?;({});({});let expr=if p.eat_keyword(kw:: +Underscore){None}else{Some(p.parse_expr()?)};{;};ast::InlineAsmOperand::Out{reg, +expr,late:false}}else if!is_global_asm&&p.eat_keyword(sym::lateout){{;};let reg= +parse_reg(p,&mut explicit_reg)?;;let expr=if p.eat_keyword(kw::Underscore){None} +else{Some(p.parse_expr()?)};;ast::InlineAsmOperand::Out{reg,expr,late:true}}else +if!is_global_asm&&p.eat_keyword(sym::inout){loop{break};let reg=parse_reg(p,&mut +explicit_reg)?;;if p.eat_keyword(kw::Underscore){let err=dcx.create_err(errors:: +AsmUnderscoreInput{span:p.token.span});;return Err(err);}let expr=p.parse_expr() +?;;if p.eat(&token::FatArrow){let out_expr=if p.eat_keyword(kw::Underscore){None +}else{Some(p.parse_expr()?)};;ast::InlineAsmOperand::SplitInOut{reg,in_expr:expr +,out_expr,late:(false)}}else{ast::InlineAsmOperand::InOut{reg,expr,late:false}}} +else if!is_global_asm&&p.eat_keyword(sym::inlateout){();let reg=parse_reg(p,&mut +explicit_reg)?;;if p.eat_keyword(kw::Underscore){let err=dcx.create_err(errors:: +AsmUnderscoreInput{span:p.token.span});;return Err(err);}let expr=p.parse_expr() +?;;if p.eat(&token::FatArrow){let out_expr=if p.eat_keyword(kw::Underscore){None +}else{Some(p.parse_expr()?)};;ast::InlineAsmOperand::SplitInOut{reg,in_expr:expr +,out_expr,late:(true)}}else{(ast::InlineAsmOperand::InOut{reg,expr,late:true})}} +else if p.eat_keyword(kw::Const){;let anon_const=p.parse_expr_anon_const()?;;ast +::InlineAsmOperand::Const{anon_const}}else if p.eat_keyword(sym::sym){;let expr= +p.parse_expr()?;;let ast::ExprKind::Path(qself,path)=&expr.kind else{let err=dcx +.create_err(errors::AsmSymNoPath{span:expr.span});;return Err(err);};let sym=ast +::InlineAsmSym{id:ast::DUMMY_NODE_ID,qself:qself.clone(),path:path.clone(),};(); +ast::InlineAsmOperand::Sym{sym}}else if !is_global_asm&&p.eat_keyword(sym::label +){{;};let block=p.parse_block()?;{;};ast::InlineAsmOperand::Label{block}}else if +allow_templates{;let template=p.parse_expr()?;;match template.kind{ast::ExprKind +::Lit(token_lit)if matches!(token_lit .kind,token::LitKind::Str|token::LitKind:: +StrRaw(_))=>{}ast::ExprKind::MacCall(..)=>{}_=>{;let err=dcx.create_err(errors:: +AsmExpectedOther{span:template.span,is_global_asm,});;;return Err(err);;}};args. +templates.push(template);;;continue;;}else{p.unexpected_any()?};allow_templates= +false;;;let span=span_start.to(p.prev_token.span);;let slot=args.operands.len(); +args.operands.push((op,span));3;if explicit_reg{if name.is_some(){;dcx.emit_err( +errors::AsmExplicitRegisterName{span});;}args.reg_args.insert(slot);}else if let +Some(name)=name{if let Some(&prev)=args.named_args.get(&name){({});dcx.emit_err( +errors::AsmDuplicateArg{span,name,prev:args.operands[prev].1});;;continue;}args. +named_args.insert(name,slot);((),());}else{if!args.named_args.is_empty()||!args. +reg_args.is_empty(){;let named=args.named_args.values().map(|p|args.operands[*p] +.1).collect();();3;let explicit=args.reg_args.iter().map(|p|args.operands[p].1). +collect();;;dcx.emit_err(errors::AsmPositionalAfter{span,named,explicit});}}}if +args.options.contains(ast::InlineAsmOptions::NOMEM)&&args.options.contains(ast// +::InlineAsmOptions::READONLY){;let spans=args.options_spans.clone();dcx.emit_err +(errors::AsmMutuallyExclusive{spans,opt1:"nomem",opt2:"readonly"});{;};}if args. +options.contains(ast::InlineAsmOptions::PURE)&&args.options.contains(ast:://{;}; +InlineAsmOptions::NORETURN){;let spans=args.options_spans.clone();;dcx.emit_err( +errors::AsmMutuallyExclusive{spans,opt1:"pure",opt2:"noreturn"});{();};}if args. +options.contains(ast::InlineAsmOptions::PURE)&&!args.options.intersects(ast:://; +InlineAsmOptions::NOMEM|ast::InlineAsmOptions::READONLY){((),());let spans=args. +options_spans.clone();3;3;dcx.emit_err(errors::AsmPureCombine{spans});;};let mut +have_real_output=false;;let mut outputs_sp=vec![];let mut regclass_outputs=vec![ +];();();let mut labels_sp=vec![];();for(op,op_sp)in&args.operands{match op{ast:: +InlineAsmOperand::Out{reg,expr,..}|ast::InlineAsmOperand::SplitInOut{reg,//({}); +out_expr:expr,..}=>{;outputs_sp.push(*op_sp);have_real_output|=expr.is_some();if +let ast::InlineAsmRegOrRegClass::RegClass(_)=reg{3;regclass_outputs.push(*op_sp) +;{;};}}ast::InlineAsmOperand::InOut{reg,..}=>{{;};outputs_sp.push(*op_sp);();(); +have_real_output=true;();if let ast::InlineAsmRegOrRegClass::RegClass(_)=reg{(); +regclass_outputs.push(*op_sp);3;}}ast::InlineAsmOperand::Label{..}=>{;labels_sp. +push(*op_sp);();}_=>{}}}if args.options.contains(ast::InlineAsmOptions::PURE)&&! +have_real_output{;dcx.emit_err(errors::AsmPureNoOutput{spans:args.options_spans. +clone()});let _=();}if args.options.contains(ast::InlineAsmOptions::NORETURN)&&! +outputs_sp.is_empty(){;let err=dcx.create_err(errors::AsmNoReturn{outputs_sp});; +return Err(err);;}if args.options.contains(ast::InlineAsmOptions::MAY_UNWIND)&&! +labels_sp.is_empty(){3;dcx.emit_err(errors::AsmMayUnwind{labels_sp});3;}if args. +clobber_abis.len()>0{if is_global_asm{let _=||();let err=dcx.create_err(errors:: +GlobalAsmClobberAbi{spans:args.clobber_abis.iter().map (|(_,span)|*span).collect +(),});3;;return Err(err);;}if!regclass_outputs.is_empty(){;dcx.emit_err(errors:: +AsmClobberNoReg{spans:regclass_outputs,clobbers:args .clobber_abis.iter().map(|( +_,span)|*span).collect(),});();}}Ok(args)}fn err_duplicate_option(p:&Parser<'_>, +symbol:Symbol,span:Span){;let full_span=if p.token.kind==token::Comma{span.to(p. +token.span)}else{span};;p.psess.dcx.emit_err(errors::AsmOptAlreadyprovided{span, +symbol,full_span});{();};}fn try_set_option<'a>(p:&Parser<'a>,args:&mut AsmArgs, +symbol:Symbol,option:ast::InlineAsmOptions,){if!args.options.contains(option){3; +args.options|=option;;}else{;err_duplicate_option(p,symbol,p.prev_token.span);}} +fn parse_options<'a>(p:&mut Parser<'a >,args:&mut AsmArgs,is_global_asm:bool,)-> +PResult<'a,()>{3;let span_start=p.prev_token.span;3;;p.expect(&token::OpenDelim( +Delimiter::Parenthesis))?;;while!p.eat(&token::CloseDelim(Delimiter::Parenthesis +)){if!is_global_asm&&p.eat_keyword(sym::pure){3;try_set_option(p,args,sym::pure, +ast::InlineAsmOptions::PURE);;}else if!is_global_asm&&p.eat_keyword(sym::nomem){ +try_set_option(p,args,sym::nomem,ast::InlineAsmOptions::NOMEM);((),());}else if! +is_global_asm&&p.eat_keyword(sym::readonly){;try_set_option(p,args,sym::readonly +,ast::InlineAsmOptions::READONLY);();}else if!is_global_asm&&p.eat_keyword(sym:: +preserves_flags){*&*&();((),());try_set_option(p,args,sym::preserves_flags,ast:: +InlineAsmOptions::PRESERVES_FLAGS);3;}else if!is_global_asm&&p.eat_keyword(sym:: +noreturn){;try_set_option(p,args,sym::noreturn,ast::InlineAsmOptions::NORETURN); +}else if!is_global_asm&&p.eat_keyword(sym::nostack){;try_set_option(p,args,sym:: +nostack,ast::InlineAsmOptions::NOSTACK);3;}else if!is_global_asm&&p.eat_keyword( +sym::may_unwind){if true{};try_set_option(p,args,kw::Raw,ast::InlineAsmOptions:: +MAY_UNWIND);;}else if p.eat_keyword(sym::att_syntax){try_set_option(p,args,sym:: +att_syntax,ast::InlineAsmOptions::ATT_SYNTAX);;}else if p.eat_keyword(kw::Raw){; +try_set_option(p,args,kw::Raw,ast::InlineAsmOptions::RAW);{;};}else{();return p. +unexpected();;}if p.eat(&token::CloseDelim(Delimiter::Parenthesis)){;break;;};p. +expect(&token::Comma)?;3;};let new_span=span_start.to(p.prev_token.span);;;args. +options_spans.push(new_span);;Ok(())}fn parse_clobber_abi<'a>(p:&mut Parser<'a>, +args:&mut AsmArgs)->PResult<'a,()>{;let span_start=p.prev_token.span;;p.expect(& +token::OpenDelim(Delimiter::Parenthesis))?;let _=();if p.eat(&token::CloseDelim( +Delimiter::Parenthesis)){;return Err(p.psess.dcx.create_err(errors::NonABI{span: +p.token.span}));3;};let mut new_abis=Vec::new();;while!p.eat(&token::CloseDelim( +Delimiter::Parenthesis)){;match p.parse_str_lit(){Ok(str_lit)=>{;new_abis.push(( +str_lit.symbol_unescaped,str_lit.span));;}Err(opt_lit)=>{let span=opt_lit.map_or +(p.token.span,|lit|lit.span);();();let mut err=p.psess.dcx.struct_span_err(span, +"expected string literal");;;err.span_label(span,"not a string literal");return +Err(err);3;}};;if p.eat(&token::CloseDelim(Delimiter::Parenthesis)){;break;;};p. +expect(&token::Comma)?;;};let full_span=span_start.to(p.prev_token.span);;match& +new_abis[..]{[]=>(unreachable!()),[(abi,_span)]=>args.clobber_abis.push(((*abi), +full_span)),abis=>{for(abi,span)in abis{;args.clobber_abis.push((*abi,*span));}} +}Ok(())}fn parse_reg<'a>(p: &mut Parser<'a>,explicit_reg:&mut bool,)->PResult<'a +,ast::InlineAsmRegOrRegClass>{;p.expect(&token::OpenDelim(Delimiter::Parenthesis +))?;;;let result=match p.token.uninterpolate().kind{token::Ident(name,IdentIsRaw +::No)=>(ast::InlineAsmRegOrRegClass::RegClass( name)),token::Literal(token::Lit{ +kind:token::LitKind::Str,symbol,suffix:_})=>{{();};*explicit_reg=true;({});ast:: +InlineAsmRegOrRegClass::Reg(symbol)}_=>{3;return Err(p.dcx().create_err(errors:: +ExpectedRegisterClassOrExplicitRegister{span:p.token.span,}));;}};;;p.bump();;p. +expect(&token::CloseDelim(Delimiter::Parenthesis))?;*&*&();((),());Ok(result)}fn +expand_preparsed_asm(ecx:&mut ExtCtxt<'_>,args:AsmArgs,)->ExpandResult,()>{;let mut template=vec![];;let mut used=vec![ +false;args.operands.len()];;for pos in args.reg_args.iter(){;used[pos]=true;}let +named_pos:FxHashMap=args.named_args.iter( ).map(|(&sym,&idx)|(idx, +sym)).collect();;let mut line_spans=Vec::with_capacity(args.templates.len());let +mut curarg=0;3;;let mut template_strs=Vec::with_capacity(args.templates.len());; +for(i,template_expr)in args.templates.into_iter().enumerate(){if i!=0{;template. +push(ast::InlineAsmTemplatePiece::String("\n".to_string()));{();};}({});let msg= +"asm template must be a string literal";;let template_sp=template_expr.span;let( +template_str,template_style,template_span)={*&*&();let ExpandResult::Ready(mac)= +expr_to_spanned_string(ecx,template_expr,msg)else{;return ExpandResult::Retry(() +);;};match mac{Ok(template_part)=>template_part,Err(err)=>{return ExpandResult:: +Ready(Err(match err{Ok((err,_))=>err.emit(),Err(guar)=>guar,}));();}}};();();let +str_style=match template_style{ast::StrStyle::Cooked=>None,ast::StrStyle::Raw(// +raw)=>Some(raw as usize),};((),());*&*&();let template_snippet=ecx.source_map(). +span_to_snippet(template_sp).ok();*&*&();{();};template_strs.push((template_str, +template_snippet.as_deref().map(Symbol::intern),template_sp,));;let template_str +=template_str.as_str();();if let Some(InlineAsmArch::X86|InlineAsmArch::X86_64)= +ecx.sess.asm_arch{{();};let find_span=|needle:&str|->Span{if let Some(snippet)=& +template_snippet{if let Some(pos)=snippet.find(needle){3;let end=pos+snippet[pos +..].find(|c|matches!(c,'\n'|';'|'\\'|'"')).unwrap_or(snippet[pos..].len()-1);3;; +let inner=InnerSpan::new(pos,end);();3;return template_sp.from_inner(inner);3;}} +template_sp};;if template_str.contains(".intel_syntax"){ecx.psess().buffer_lint( +lint::builtin::BAD_ASM_STYLE,(find_span(".intel_syntax")),ecx.current_expansion. +lint_node_id,"avoid using `.intel_syntax`, Intel syntax is the default",);3;}if +template_str.contains(".att_syntax"){{;};ecx.psess().buffer_lint(lint::builtin:: +BAD_ASM_STYLE,((find_span((".att_syntax")))),ecx.current_expansion.lint_node_id, +"avoid using `.att_syntax`, prefer using `options(att_syntax)` instead",);;}}if +args.options.contains(ast::InlineAsmOptions::RAW){let _=||();template.push(ast:: +InlineAsmTemplatePiece::String(template_str.to_string()));if true{};let _=();let +template_num_lines=1+template_str.matches('\n').count();;line_spans.extend(std:: +iter::repeat(template_sp).take(template_num_lines));;;continue;;}let mut parser= +parse::Parser::new(template_str,str_style,template_snippet,((((false)))),parse:: +ParseMode::InlineAsm,);;parser.curarg=curarg;let mut unverified_pieces=Vec::new( +);;while let Some(piece)=parser.next(){if!parser.errors.is_empty(){;break;}else{ +unverified_pieces.push(piece);();}}if!parser.errors.is_empty(){3;let err=parser. +errors.remove(0);3;;let err_sp=template_span.from_inner(InnerSpan::new(err.span. +start,err.span.end));();3;let msg=format!("invalid asm template string: {}",err. +description);3;3;let mut e=ecx.dcx().struct_span_err(err_sp,msg);;;e.span_label( +err_sp,err.label+" in asm template string");;if let Some(note)=err.note{;e.note( +note);;}if let Some((label,span))=err.secondary_label{;let err_sp=template_span. +from_inner(InnerSpan::new(span.start,span.end));;e.span_label(err_sp,label);}let +guar=e.emit();;;return ExpandResult::Ready(Err(guar));;}curarg=parser.curarg;let +mut arg_spans=(((parser.arg_places.iter()))).map(|span|template_span.from_inner( +InnerSpan::new(span.start,span.end)));{();};for piece in unverified_pieces{match +piece{parse::Piece::String(s)=>{template.push(ast::InlineAsmTemplatePiece:://(); +String(s.to_string()))}parse::Piece::NextArgument(arg)=>{{;};let span=arg_spans. +next().unwrap_or(template_sp);{;};{;};let operand_idx=match arg.position{parse:: +ArgumentIs(idx)|parse::ArgumentImplicitlyIs(idx)=>{if (idx>=args.operands.len()) +||named_pos.contains_key(&idx)||args.reg_args.contains(idx){{;};let msg=format!( +"invalid reference to argument at index {idx}");({});({});let mut err=ecx.dcx(). +struct_span_err(span,msg);;err.span_label(span,"from here");let positional_args= +args.operands.len()-args.named_args.len()-args.reg_args.len();;let positional=if +positional_args!=args.operands.len(){"positional "}else{""};{;};();let msg=match +positional_args{0=>(format!("no {positional}arguments were given" )),1=>format!( +"there is 1 {positional}argument"),x=>format!(//((),());((),());((),());((),()); +"there are {x} {positional}arguments"),};{;};{;};err.note(msg);{;};if named_pos. +contains_key(&idx){;err.span_label(args.operands[idx].1,"named argument");;;err. +span_note(((((((((((((((((((((((((args.operands[ idx])))))))))))))))))))))))).1, +"named arguments cannot be referenced by position",);{;};}else if args.reg_args. +contains(idx){;err.span_label(args.operands[idx].1,"explicit register argument", +);let _=||();let _=||();if true{};let _=||();err.span_note(args.operands[idx].1, +"explicit register arguments cannot be used in the asm template",);({});{;};err. +span_help(((((((((((((((((((((((((args.operands[ idx])))))))))))))))))))))))).1, +"use the register name directly in the assembly code",);;};err.emit();None}else{ +Some(idx)}}parse::ArgumentNamed(name)=>{match args.named_args.get(&Symbol:://(); +intern(name)){Some(&idx)=>Some(idx),None=>{if true{};let _=||();let msg=format!( +"there is no argument named `{name}`");;;let span=arg.position_span;;;ecx.dcx(). +struct_span_err((template_span.from_inner(InnerSpan::new(span.start,span.end))), +msg,).emit();;None}}}};;;let mut chars=arg.format.ty.chars();;;let mut modifier= +chars.next();();if chars.next().is_some(){3;let span=arg.format.ty_span.map(|sp| +template_sp.from_inner(InnerSpan::new(sp.start,sp .end))).unwrap_or(template_sp) +;;;ecx.dcx().emit_err(errors::AsmModifierInvalid{span});;;modifier=None;;}if let +Some(operand_idx)=operand_idx{();used[operand_idx]=true;();3;template.push(ast:: +InlineAsmTemplatePiece::Placeholder{operand_idx,modifier,span,});;}}}}if parser. +line_spans.is_empty(){;let template_num_lines=1+template_str.matches('\n').count +();;line_spans.extend(std::iter::repeat(template_sp).take(template_num_lines));} +else{((),());line_spans.extend(parser.line_spans.iter().map(|span|template_span. +from_inner(InnerSpan::new(span.start,span.end))),);;};;}let mut unused_operands= +vec![];();();let mut help_str=String::new();();for(idx,used)in used.into_iter(). +enumerate(){if!used{();let msg=if let Some(sym)=named_pos.get(&idx){();help_str. +push_str(&format!(" {{{}}}",sym));3;"named argument never used"}else{3;help_str. +push_str(&format!(" {{{}}}",idx));;"argument never used"};unused_operands.push(( +args.operands[idx].1,msg));;}}match unused_operands.len(){0=>{}1=>{;let(sp,msg)= +unused_operands.into_iter().next().unwrap();;;ecx.dcx().struct_span_err(sp,msg). +with_span_label(sp,msg).with_help(format!(//let _=();let _=();let _=();let _=(); +"if this argument is intentionally unused, \ consider using it in an asm comment: `\"/*{help_str} */\"`" - )) - .emit(); - } - _ => { - let mut err = ecx.dcx().struct_span_err( - unused_operands.iter().map(|&(sp, _)| sp).collect::>(), - "multiple unused asm arguments", - ); - for (sp, msg) in unused_operands { - err.span_label(sp, msg); - } - err.help(format!( - "if these arguments are intentionally unused, \ +)).emit();;}_=>{let mut err=ecx.dcx().struct_span_err(unused_operands.iter().map +(|&(sp,_)|sp).collect::>(),"multiple unused asm arguments",);3;for(sp, +msg)in unused_operands{{();};err.span_label(sp,msg);({});}({});err.help(format!( +"if these arguments are intentionally unused, \ consider using them in an asm comment: `\"/*{help_str} */\"`" - )); - err.emit(); - } - } - - ExpandResult::Ready(Ok(ast::InlineAsm { - template, - template_strs: template_strs.into_boxed_slice(), - operands: args.operands, - clobber_abis: args.clobber_abis, - options: args.options, - line_spans, - })) -} - -pub(super) fn expand_asm<'cx>( - ecx: &'cx mut ExtCtxt<'_>, - sp: Span, - tts: TokenStream, -) -> MacroExpanderResult<'cx> { - ExpandResult::Ready(match parse_args(ecx, sp, tts, false) { - Ok(args) => { - let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, args) else { - return ExpandResult::Retry(()); - }; - let expr = match mac { - Ok(inline_asm) => P(ast::Expr { - id: ast::DUMMY_NODE_ID, - kind: ast::ExprKind::InlineAsm(P(inline_asm)), - span: sp, - attrs: ast::AttrVec::new(), - tokens: None, - }), - Err(guar) => DummyResult::raw_expr(sp, Some(guar)), - }; - MacEager::expr(expr) - } - Err(err) => { - let guar = err.emit(); - DummyResult::any(sp, guar) - } - }) -} - -pub(super) fn expand_global_asm<'cx>( - ecx: &'cx mut ExtCtxt<'_>, - sp: Span, - tts: TokenStream, -) -> MacroExpanderResult<'cx> { - ExpandResult::Ready(match parse_args(ecx, sp, tts, true) { - Ok(args) => { - let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, args) else { - return ExpandResult::Retry(()); - }; - match mac { - Ok(inline_asm) => MacEager::items(smallvec![P(ast::Item { - ident: Ident::empty(), - attrs: ast::AttrVec::new(), - id: ast::DUMMY_NODE_ID, - kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)), - vis: ast::Visibility { - span: sp.shrink_to_lo(), - kind: ast::VisibilityKind::Inherited, - tokens: None, - }, - span: sp, - tokens: None, - })]), - Err(guar) => DummyResult::any(sp, guar), - } - } - Err(err) => { - let guar = err.emit(); - DummyResult::any(sp, guar) - } - }) -} +));;;err.emit();;}}ExpandResult::Ready(Ok(ast::InlineAsm{template,template_strs: +template_strs.into_boxed_slice(),operands:args.operands,clobber_abis:args.//{;}; +clobber_abis,options:args.options,line_spans,}))}pub(super)fn expand_asm<'cx>(// +ecx:&'cx mut ExtCtxt<'_>,sp:Span,tts:TokenStream,)->MacroExpanderResult<'cx>{//; +ExpandResult::Ready(match parse_args(ecx,sp,tts,false){Ok(args)=>{let _=||();let +ExpandResult::Ready(mac)=expand_preparsed_asm(ecx,args)else{;return ExpandResult +::Retry(());{;};};{;};();let expr=match mac{Ok(inline_asm)=>P(ast::Expr{id:ast:: +DUMMY_NODE_ID,kind:(ast::ExprKind::InlineAsm(P(inline_asm))),span:sp,attrs:ast:: +AttrVec::new(),tokens:None,}),Err(guar )=>DummyResult::raw_expr(sp,Some(guar)),} +;;MacEager::expr(expr)}Err(err)=>{let guar=err.emit();DummyResult::any(sp,guar)} +})}pub(super)fn expand_global_asm<'cx>(ecx:&'cx mut ExtCtxt<'_>,sp:Span,tts://3; +TokenStream,)->MacroExpanderResult<'cx>{ExpandResult::Ready(match parse_args(//; +ecx,sp,tts,true){Ok(args)=>{3;let ExpandResult::Ready(mac)=expand_preparsed_asm( +ecx,args)else{();return ExpandResult::Retry(());3;};3;match mac{Ok(inline_asm)=> +MacEager::items(smallvec![P(ast::Item{ ident:Ident::empty(),attrs:ast::AttrVec:: +new(),id:ast::DUMMY_NODE_ID,kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)) +,vis:ast::Visibility{span:sp. shrink_to_lo(),kind:ast::VisibilityKind::Inherited +,tokens:None,},span:sp,tokens:None,})]) ,Err(guar)=>DummyResult::any(sp,guar),}} +Err(err)=>{if true{};let guar=err.emit();if true{};DummyResult::any(sp,guar)}})} diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs index d200179f3a0ae..4630be9029f61 100644 --- a/compiler/rustc_builtin_macros/src/assert.rs +++ b/compiler/rustc_builtin_macros/src/assert.rs @@ -1,163 +1,40 @@ -mod context; - -use crate::edition_panic::use_panic_2021; -use crate::errors; -use rustc_ast::ptr::P; -use rustc_ast::token; -use rustc_ast::token::Delimiter; -use rustc_ast::tokenstream::{DelimSpan, TokenStream}; -use rustc_ast::{DelimArgs, Expr, ExprKind, MacCall, Path, PathSegment, UnOp}; -use rustc_ast_pretty::pprust; -use rustc_errors::PResult; -use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; -use rustc_parse::parser::Parser; -use rustc_span::symbol::{sym, Ident, Symbol}; -use rustc_span::{Span, DUMMY_SP}; -use thin_vec::thin_vec; - -pub fn expand_assert<'cx>( - cx: &'cx mut ExtCtxt<'_>, - span: Span, - tts: TokenStream, -) -> MacroExpanderResult<'cx> { - let Assert { cond_expr, custom_message } = match parse_assert(cx, span, tts) { - Ok(assert) => assert, - Err(err) => { - let guar = err.emit(); - return ExpandResult::Ready(DummyResult::any(span, guar)); - } - }; - - // `core::panic` and `std::panic` are different macros, so we use call-site - // context to pick up whichever is currently in scope. - let call_site_span = cx.with_call_site_ctxt(span); - - let panic_path = || { - if use_panic_2021(span) { - // On edition 2021, we always call `$crate::panic::panic_2021!()`. - Path { - span: call_site_span, - segments: cx - .std_path(&[sym::panic, sym::panic_2021]) - .into_iter() - .map(|ident| PathSegment::from_ident(ident)) - .collect(), - tokens: None, - } - } else { - // Before edition 2021, we call `panic!()` unqualified, - // such that it calls either `std::panic!()` or `core::panic!()`. - Path::from_ident(Ident::new(sym::panic, call_site_span)) - } - }; - - // Simply uses the user provided message instead of generating custom outputs - let expr = if let Some(tokens) = custom_message { - let then = cx.expr( - call_site_span, - ExprKind::MacCall(P(MacCall { - path: panic_path(), - args: P(DelimArgs { - dspan: DelimSpan::from_single(call_site_span), - delim: Delimiter::Parenthesis, - tokens, - }), - })), - ); - expr_if_not(cx, call_site_span, cond_expr, then, None) - } - // If `generic_assert` is enabled, generates rich captured outputs - // - // FIXME(c410-f3r) See https://github.com/rust-lang/rust/issues/96949 - else if cx.ecfg.features.generic_assert { - context::Context::new(cx, call_site_span).build(cond_expr, panic_path()) - } - // If `generic_assert` is not enabled, only outputs a literal "assertion failed: ..." - // string - else { - // Pass our own message directly to $crate::panicking::panic(), - // because it might contain `{` and `}` that should always be - // passed literally. - let then = cx.expr_call_global( - call_site_span, - cx.std_path(&[sym::panicking, sym::panic]), - thin_vec![cx.expr_str( - DUMMY_SP, - Symbol::intern(&format!( - "assertion failed: {}", - pprust::expr_to_string(&cond_expr) - )), - )], - ); - expr_if_not(cx, call_site_span, cond_expr, then, None) - }; - - ExpandResult::Ready(MacEager::expr(expr)) -} - -struct Assert { - cond_expr: P, - custom_message: Option, -} - -// if !{ ... } { ... } else { ... } -fn expr_if_not( - cx: &ExtCtxt<'_>, - span: Span, - cond: P, - then: P, - els: Option>, -) -> P { - cx.expr_if(span, cx.expr(span, ExprKind::Unary(UnOp::Not, cond)), then, els) -} - -fn parse_assert<'a>(cx: &ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PResult<'a, Assert> { - let mut parser = cx.new_parser_from_tts(stream); - - if parser.token == token::Eof { - return Err(cx.dcx().create_err(errors::AssertRequiresBoolean { span: sp })); - } - - let cond_expr = parser.parse_expr()?; - - // Some crates use the `assert!` macro in the following form (note extra semicolon): - // - // assert!( - // my_function(); - // ); - // - // Emit an error about semicolon and suggest removing it. - if parser.token == token::Semi { - cx.dcx().emit_err(errors::AssertRequiresExpression { span: sp, token: parser.token.span }); - parser.bump(); - } - - // Some crates use the `assert!` macro in the following form (note missing comma before - // message): - // - // assert!(true "error message"); - // - // Emit an error and suggest inserting a comma. - let custom_message = - if let token::Literal(token::Lit { kind: token::Str, .. }) = parser.token.kind { - let comma = parser.prev_token.span.shrink_to_hi(); - cx.dcx().emit_err(errors::AssertMissingComma { span: parser.token.span, comma }); - - parse_custom_message(&mut parser) - } else if parser.eat(&token::Comma) { - parse_custom_message(&mut parser) - } else { - None - }; - - if parser.token != token::Eof { - parser.unexpected()?; - } - - Ok(Assert { cond_expr, custom_message }) -} - -fn parse_custom_message(parser: &mut Parser<'_>) -> Option { - let ts = parser.parse_tokens(); - if !ts.is_empty() { Some(ts) } else { None } -} +mod context;use crate::edition_panic::use_panic_2021;use crate::errors;use//{;}; +rustc_ast::ptr::P;use rustc_ast::token;use rustc_ast::token::Delimiter;use//{;}; +rustc_ast::tokenstream::{DelimSpan,TokenStream} ;use rustc_ast::{DelimArgs,Expr, +ExprKind,MacCall,Path,PathSegment,UnOp};use rustc_ast_pretty::pprust;use//{();}; +rustc_errors::PResult;use rustc_expand:: base::{DummyResult,ExpandResult,ExtCtxt +,MacEager,MacroExpanderResult};use rustc_parse ::parser::Parser;use rustc_span:: +symbol::{sym,Ident,Symbol};use rustc_span::{Span,DUMMY_SP};use thin_vec:://({}); +thin_vec;pub fn expand_assert<'cx>(cx:&'cx mut ExtCtxt<'_>,span:Span,tts://({}); +TokenStream,)->MacroExpanderResult<'cx>{();let Assert{cond_expr,custom_message}= +match parse_assert(cx,span,tts){Ok(assert)=>assert,Err(err)=>{;let guar=err.emit +();();();return ExpandResult::Ready(DummyResult::any(span,guar));();}};();();let +call_site_span=cx.with_call_site_ctxt(span);;let panic_path=||{if use_panic_2021 +(span){Path{span:call_site_span,segments:cx.std_path(&[sym::panic,sym:://*&*&(); +panic_2021]).into_iter().map((|ident|PathSegment::from_ident(ident))).collect(), +tokens:None,}}else{Path::from_ident(Ident::new(sym::panic,call_site_span))}};3;; +let expr=if let Some(tokens)=custom_message{{;};let then=cx.expr(call_site_span, +ExprKind::MacCall(P(MacCall{path:(panic_path()),args:P(DelimArgs{dspan:DelimSpan +::from_single(call_site_span),delim:Delimiter::Parenthesis,tokens,}),})),);({}); +expr_if_not(cx,call_site_span,cond_expr,then,None)}else if cx.ecfg.features.//3; +generic_assert{((((context::Context::new(cx,call_site_span))))).build(cond_expr, +panic_path())}else{();let then=cx.expr_call_global(call_site_span,cx.std_path(&[ +sym::panicking,sym::panic]),thin_vec![cx.expr_str(DUMMY_SP,Symbol::intern(&//(); +format!("assertion failed: {}",pprust::expr_to_string(&cond_expr))),)],);*&*&(); +expr_if_not(cx,call_site_span,cond_expr,then,None)};((),());ExpandResult::Ready( +MacEager::expr(expr))}struct Assert{cond_expr:P,custom_message:Option,}fn expr_if_not(cx:&ExtCtxt<'_>, span:Span,cond:P,then:P,els:Option>,)->P{cx.expr_if(span,cx.expr(span,ExprKind::Unary(// +UnOp::Not,cond)),then,els)}fn parse_assert<'a>(cx:&ExtCtxt<'a>,sp:Span,stream:// +TokenStream)->PResult<'a,Assert>{;let mut parser=cx.new_parser_from_tts(stream); +if parser.token==token::Eof{loop{break;};return Err(cx.dcx().create_err(errors:: +AssertRequiresBoolean{span:sp}));;}let cond_expr=parser.parse_expr()?;if parser. +token==token::Semi{3;cx.dcx().emit_err(errors::AssertRequiresExpression{span:sp, +token:parser.token.span});3;3;parser.bump();;};let custom_message=if let token:: +Literal(token::Lit{kind:token::Str,..})=parser.token.kind{({});let comma=parser. +prev_token.span.shrink_to_hi();3;3;cx.dcx().emit_err(errors::AssertMissingComma{ +span:parser.token.span,comma});;parse_custom_message(&mut parser)}else if parser +.eat(&token::Comma){parse_custom_message(&mut parser)}else{None};({});if parser. +token!=token::Eof{;parser.unexpected()?;}Ok(Assert{cond_expr,custom_message})}fn +parse_custom_message(parser:&mut Parser<'_>)->Option{*&*&();let ts= +parser.parse_tokens();if true{};let _=||();if!ts.is_empty(){Some(ts)}else{None}} diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index 92efeab08ebea..5053322c5352b 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -1,460 +1,121 @@ -use rustc_ast::{ - ptr::P, - token::{self, Delimiter, IdentIsRaw}, - tokenstream::{DelimSpan, TokenStream, TokenTree}, - BinOpKind, BorrowKind, DelimArgs, Expr, ExprKind, ItemKind, MacCall, MethodCall, Mutability, - Path, PathSegment, Stmt, StructRest, UnOp, UseTree, UseTreeKind, DUMMY_NODE_ID, -}; -use rustc_ast_pretty::pprust; -use rustc_data_structures::fx::FxHashSet; -use rustc_expand::base::ExtCtxt; -use rustc_span::{ - symbol::{sym, Ident, Symbol}, - Span, -}; -use thin_vec::{thin_vec, ThinVec}; - -pub(super) struct Context<'cx, 'a> { - // An optimization. - // - // Elements that aren't consumed (PartialEq, PartialOrd, ...) can be copied **after** the - // `assert!` expression fails rather than copied on-the-fly. - best_case_captures: Vec, - // Top-level `let captureN = Capture::new()` statements - capture_decls: Vec, - cx: &'cx ExtCtxt<'a>, - // Formatting string used for debugging - fmt_string: String, - // If the current expression being visited consumes itself. Used to construct - // `best_case_captures`. - is_consumed: bool, - // Top-level `let __local_bindN = &expr` statements - local_bind_decls: Vec, - // Used to avoid capturing duplicated paths - // - // ```rust - // let a = 1i32; - // assert!(add(a, a) == 3); - // ``` - paths: FxHashSet, - span: Span, -} - -impl<'cx, 'a> Context<'cx, 'a> { - pub(super) fn new(cx: &'cx ExtCtxt<'a>, span: Span) -> Self { - Self { - best_case_captures: <_>::default(), - capture_decls: <_>::default(), - cx, - fmt_string: <_>::default(), - is_consumed: true, - local_bind_decls: <_>::default(), - paths: <_>::default(), - span, - } - } - - /// 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)] - /// use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable}; - /// let mut __capture0 = ::core::asserting::Capture::new(); - /// let __local_bind0 = &elem; - /// if !( - /// *{ - /// (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); - /// __local_bind0 - /// } == 1 - /// ) { - /// panic!("Assertion failed: elem == 1\nWith captures:\n elem = {:?}", __capture0) - /// } - /// } - /// ``` - pub(super) fn build(mut self, mut cond_expr: P, panic_path: Path) -> P { - let expr_str = pprust::expr_to_string(&cond_expr); - self.manage_cond_expr(&mut cond_expr); - let initial_imports = self.build_initial_imports(); - let panic = self.build_panic(&expr_str, panic_path); - let cond_expr_with_unlikely = self.build_unlikely(cond_expr); - - let Self { best_case_captures, capture_decls, cx, local_bind_decls, span, .. } = self; - - let mut assert_then_stmts = ThinVec::with_capacity(2); - assert_then_stmts.extend(best_case_captures); - assert_then_stmts.push(self.cx.stmt_expr(panic)); - let assert_then = self.cx.block(span, assert_then_stmts); - - let mut stmts = ThinVec::with_capacity(4); - stmts.push(initial_imports); - stmts.extend(capture_decls.into_iter().map(|c| c.decl)); - stmts.extend(local_bind_decls); - stmts.push( - cx.stmt_expr(cx.expr(span, ExprKind::If(cond_expr_with_unlikely, assert_then, None))), - ); - cx.expr_block(cx.block(span, stmts)) - } - - /// Initial **trait** imports - /// - /// use ::core::asserting::{ ... }; - fn build_initial_imports(&self) -> Stmt { - let nested_tree = |this: &Self, sym| { - ( - UseTree { - prefix: this.cx.path(this.span, vec![Ident::with_dummy_span(sym)]), - kind: UseTreeKind::Simple(None), - span: this.span, - }, - DUMMY_NODE_ID, - ) - }; - self.cx.stmt_item( - self.span, - self.cx.item( - self.span, - Ident::empty(), - thin_vec![self.cx.attr_nested_word(sym::allow, sym::unused_imports, self.span)], - ItemKind::Use(UseTree { - prefix: self.cx.path(self.span, self.cx.std_path(&[sym::asserting])), - kind: UseTreeKind::Nested(thin_vec![ - nested_tree(self, sym::TryCaptureGeneric), - nested_tree(self, sym::TryCapturePrintable), - ]), - span: self.span, - }), - ), - ) - } - - /// Takes the conditional expression of `assert!` and then wraps it inside `unlikely` - fn build_unlikely(&self, cond_expr: P) -> P { - let unlikely_path = self.cx.std_path(&[sym::intrinsics, sym::unlikely]); - self.cx.expr_call( - self.span, - self.cx.expr_path(self.cx.path(self.span, unlikely_path)), - thin_vec![self.cx.expr(self.span, ExprKind::Unary(UnOp::Not, cond_expr))], - ) - } - - /// The necessary custom `panic!(...)` expression. - /// - /// panic!( - /// "Assertion failed: ... \n With expansion: ...", - /// __capture0, - /// ... - /// ); - fn build_panic(&self, expr_str: &str, panic_path: Path) -> P { - let escaped_expr_str = escape_to_fmt(expr_str); - let initial = [ - TokenTree::token_joint_hidden( - token::Literal(token::Lit { - kind: token::LitKind::Str, - symbol: Symbol::intern(&if self.fmt_string.is_empty() { - format!("Assertion failed: {escaped_expr_str}") - } else { - format!( - "Assertion failed: {escaped_expr_str}\nWith captures:\n{}", - &self.fmt_string - ) - }), - suffix: None, - }), - self.span, - ), - TokenTree::token_alone(token::Comma, self.span), - ]; - let captures = self.capture_decls.iter().flat_map(|cap| { - [ - TokenTree::token_joint_hidden( - token::Ident(cap.ident.name, IdentIsRaw::No), - cap.ident.span, - ), - TokenTree::token_alone(token::Comma, self.span), - ] - }); - self.cx.expr( - self.span, - ExprKind::MacCall(P(MacCall { - path: panic_path, - args: P(DelimArgs { - dspan: DelimSpan::from_single(self.span), - delim: Delimiter::Parenthesis, - tokens: initial.into_iter().chain(captures).collect::(), - }), - })), - ) - } - - /// Recursive function called until `cond_expr` and `fmt_str` are fully modified. - /// - /// See [Self::manage_initial_capture] and [Self::manage_try_capture] - fn manage_cond_expr(&mut self, expr: &mut P) { - match &mut expr.kind { - ExprKind::AddrOf(_, mutability, local_expr) => { - self.with_is_consumed_management(matches!(mutability, Mutability::Mut), |this| { - this.manage_cond_expr(local_expr) - }); - } - ExprKind::Array(local_exprs) => { - for local_expr in local_exprs { - self.manage_cond_expr(local_expr); - } - } - ExprKind::Binary(op, lhs, rhs) => { - self.with_is_consumed_management( - matches!( - op.node, - BinOpKind::Add - | BinOpKind::And - | BinOpKind::BitAnd - | BinOpKind::BitOr - | BinOpKind::BitXor - | BinOpKind::Div - | BinOpKind::Mul - | BinOpKind::Or - | BinOpKind::Rem - | BinOpKind::Shl - | BinOpKind::Shr - | BinOpKind::Sub - ), - |this| { - this.manage_cond_expr(lhs); - this.manage_cond_expr(rhs); - }, - ); - } - ExprKind::Call(_, local_exprs) => { - for local_expr in local_exprs { - self.manage_cond_expr(local_expr); - } - } - ExprKind::Cast(local_expr, _) => { - self.manage_cond_expr(local_expr); - } - ExprKind::If(local_expr, _, _) => { - self.manage_cond_expr(local_expr); - } - ExprKind::Index(prefix, suffix, _) => { - self.manage_cond_expr(prefix); - self.manage_cond_expr(suffix); - } - ExprKind::Let(_, local_expr, _, _) => { - self.manage_cond_expr(local_expr); - } - ExprKind::Match(local_expr, ..) => { - self.manage_cond_expr(local_expr); - } - ExprKind::MethodCall(call) => { - for arg in &mut call.args { - self.manage_cond_expr(arg); - } - } - ExprKind::Path(_, Path { segments, .. }) if let [path_segment] = &segments[..] => { - let path_ident = path_segment.ident; - self.manage_initial_capture(expr, path_ident); - } - ExprKind::Paren(local_expr) => { - self.manage_cond_expr(local_expr); - } - ExprKind::Range(prefix, suffix, _) => { - if let Some(elem) = prefix { - self.manage_cond_expr(elem); - } - if let Some(elem) = suffix { - self.manage_cond_expr(elem); - } - } - ExprKind::Repeat(local_expr, elem) => { - self.manage_cond_expr(local_expr); - self.manage_cond_expr(&mut elem.value); - } - ExprKind::Struct(elem) => { - for field in &mut elem.fields { - self.manage_cond_expr(&mut field.expr); - } - if let StructRest::Base(local_expr) = &mut elem.rest { - self.manage_cond_expr(local_expr); - } - } - ExprKind::Tup(local_exprs) => { - for local_expr in local_exprs { - self.manage_cond_expr(local_expr); - } - } - ExprKind::Unary(un_op, local_expr) => { - self.with_is_consumed_management(matches!(un_op, UnOp::Neg | UnOp::Not), |this| { - this.manage_cond_expr(local_expr) - }); - } - // Expressions that are not worth or can not be captured. - // - // Full list instead of `_` to catch possible future inclusions and to - // sync with the `rfc-2011-nicer-assert-messages/all-expr-kinds.rs` test. - ExprKind::Assign(_, _, _) - | ExprKind::AssignOp(_, _, _) - | ExprKind::Gen(_, _, _) - | ExprKind::Await(_, _) - | ExprKind::Block(_, _) - | ExprKind::Break(_, _) - | ExprKind::Closure(_) - | ExprKind::ConstBlock(_) - | ExprKind::Continue(_) - | ExprKind::Dummy - | ExprKind::Err(_) - | ExprKind::Field(_, _) - | ExprKind::ForLoop { .. } - | ExprKind::FormatArgs(_) - | ExprKind::IncludedBytes(..) - | ExprKind::InlineAsm(_) - | ExprKind::Lit(_) - | ExprKind::Loop(_, _, _) - | ExprKind::MacCall(_) - | ExprKind::OffsetOf(_, _) - | ExprKind::Path(_, _) - | ExprKind::Ret(_) - | ExprKind::Try(_) - | ExprKind::TryBlock(_) - | ExprKind::Type(_, _) - | ExprKind::Underscore - | ExprKind::While(_, _, _) - | ExprKind::Yeet(_) - | ExprKind::Become(_) - | ExprKind::Yield(_) => {} - } - } - - /// Pushes the top-level declarations and modifies `expr` to try capturing variables. - /// - /// `fmt_str`, the formatting string used for debugging, is constructed to show possible - /// captured variables. - fn manage_initial_capture(&mut self, expr: &mut P, path_ident: Ident) { - if self.paths.contains(&path_ident) { - return; - } else { - self.fmt_string.push_str(" "); - self.fmt_string.push_str(path_ident.as_str()); - self.fmt_string.push_str(" = {:?}\n"); - let _ = self.paths.insert(path_ident); - } - let curr_capture_idx = self.capture_decls.len(); - let capture_string = format!("__capture{curr_capture_idx}"); - let ident = Ident::new(Symbol::intern(&capture_string), self.span); - let init_std_path = self.cx.std_path(&[sym::asserting, sym::Capture, sym::new]); - let init = self.cx.expr_call( - self.span, - self.cx.expr_path(self.cx.path(self.span, init_std_path)), - ThinVec::new(), - ); - let capture = Capture { decl: self.cx.stmt_let(self.span, true, ident, init), ident }; - self.capture_decls.push(capture); - self.manage_try_capture(ident, curr_capture_idx, expr); - } - - /// Tries to copy `__local_bindN` into `__captureN`. - /// - /// *{ - /// (&Wrapper(__local_bindN)).try_capture(&mut __captureN); - /// __local_bindN - /// } - fn manage_try_capture(&mut self, capture: Ident, curr_capture_idx: usize, expr: &mut P) { - let local_bind_string = format!("__local_bind{curr_capture_idx}"); - let local_bind = Ident::new(Symbol::intern(&local_bind_string), self.span); - self.local_bind_decls.push(self.cx.stmt_let( - self.span, - false, - local_bind, - self.cx.expr_addr_of(self.span, expr.clone()), - )); - let wrapper = self.cx.expr_call( - self.span, - self.cx.expr_path( - self.cx.path(self.span, self.cx.std_path(&[sym::asserting, sym::Wrapper])), - ), - thin_vec![self.cx.expr_path(Path::from_ident(local_bind))], - ); - let try_capture_call = self - .cx - .stmt_expr(expr_method_call( - self.cx, - PathSegment { - args: None, - id: DUMMY_NODE_ID, - ident: Ident::new(sym::try_capture, self.span), - }, - expr_paren(self.cx, self.span, self.cx.expr_addr_of(self.span, wrapper)), - thin_vec![expr_addr_of_mut( - self.cx, - self.span, - self.cx.expr_path(Path::from_ident(capture)), - )], - self.span, - )) - .add_trailing_semicolon(); - let local_bind_path = self.cx.expr_path(Path::from_ident(local_bind)); - let rslt = if self.is_consumed { - let ret = self.cx.stmt_expr(local_bind_path); - self.cx.expr_block(self.cx.block(self.span, thin_vec![try_capture_call, ret])) - } else { - self.best_case_captures.push(try_capture_call); - local_bind_path - }; - *expr = self.cx.expr_deref(self.span, rslt); - } - - // Calls `f` with the internal `is_consumed` set to `curr_is_consumed` and then - // sets the internal `is_consumed` back to its original value. - fn with_is_consumed_management(&mut self, curr_is_consumed: bool, f: impl FnOnce(&mut Self)) { - let prev_is_consumed = self.is_consumed; - self.is_consumed = curr_is_consumed; - f(self); - self.is_consumed = prev_is_consumed; - } -} - -/// Information about a captured element. -#[derive(Debug)] -struct Capture { - // Generated indexed `Capture` statement. - // - // `let __capture{} = Capture::new();` - decl: Stmt, - // The name of the generated indexed `Capture` variable. - // - // `__capture{}` - ident: Ident, -} - -/// Escapes to use as a formatting string. -fn escape_to_fmt(s: &str) -> String { - let mut rslt = String::with_capacity(s.len()); - for c in s.chars() { - rslt.extend(c.escape_debug()); - match c { - '{' | '}' => rslt.push(c), - _ => {} - } - } - rslt -} - -fn expr_addr_of_mut(cx: &ExtCtxt<'_>, sp: Span, e: P) -> P { - cx.expr(sp, ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, e)) -} - -fn expr_method_call( - cx: &ExtCtxt<'_>, - seg: PathSegment, - receiver: P, - args: ThinVec>, - span: Span, -) -> P { - cx.expr(span, ExprKind::MethodCall(Box::new(MethodCall { seg, receiver, args, span }))) -} - -fn expr_paren(cx: &ExtCtxt<'_>, sp: Span, e: P) -> P { - cx.expr(sp, ExprKind::Paren(e)) -} +use rustc_ast::{ptr::P,token::{self,Delimiter,IdentIsRaw},tokenstream::{//{();}; +DelimSpan,TokenStream,TokenTree},BinOpKind,BorrowKind,DelimArgs,Expr,ExprKind,// +ItemKind,MacCall,MethodCall,Mutability,Path,PathSegment,Stmt,StructRest,UnOp,//; +UseTree,UseTreeKind,DUMMY_NODE_ID,};use rustc_ast_pretty::pprust;use//if true{}; +rustc_data_structures::fx::FxHashSet;use rustc_expand::base::ExtCtxt;use//{();}; +rustc_span::{symbol::{sym,Ident,Symbol}, Span,};use thin_vec::{thin_vec,ThinVec} +;pub(super)struct Context<'cx,'a>{best_case_captures:Vec,capture_decls://; +Vec,cx:&'cx ExtCtxt<'a>,fmt_string:String,is_consumed:bool,//if true{}; +local_bind_decls:Vec,paths:FxHashSet,span:Span,}impl<'cx,'a>//({}); +Context<'cx,'a>{pub(super)fn new(cx:&'cx ExtCtxt<'a>,span:Span)->Self{Self{//(); +best_case_captures:<_>::default(),capture_decls: <_>::default(),cx,fmt_string:<_ +>::default(),is_consumed:((true)),local_bind_decls:( <_>::default()),paths:<_>:: +default(),span,}}pub(super)fn build(mut self,mut cond_expr:P,panic_path:// +Path)->P{{;};let expr_str=pprust::expr_to_string(&cond_expr);{;};{;};self. +manage_cond_expr(&mut cond_expr);;let initial_imports=self.build_initial_imports +();;let panic=self.build_panic(&expr_str,panic_path);let cond_expr_with_unlikely +=self.build_unlikely(cond_expr);3;;let Self{best_case_captures,capture_decls,cx, +local_bind_decls,span,..}=self;;let mut assert_then_stmts=ThinVec::with_capacity +(2);;assert_then_stmts.extend(best_case_captures);assert_then_stmts.push(self.cx +.stmt_expr(panic));;;let assert_then=self.cx.block(span,assert_then_stmts);;;let +mut stmts=ThinVec::with_capacity(4);;;stmts.push(initial_imports);;stmts.extend( +capture_decls.into_iter().map(|c|c.decl));;stmts.extend(local_bind_decls);stmts. +push(cx.stmt_expr(cx.expr (span,ExprKind::If(cond_expr_with_unlikely,assert_then +,None))),);3;cx.expr_block(cx.block(span,stmts))}fn build_initial_imports(&self) +->Stmt{;let nested_tree=|this:&Self,sym|{(UseTree{prefix:this.cx.path(this.span, +vec![Ident::with_dummy_span(sym)]),kind:((UseTreeKind::Simple(None))),span:this. +span,},DUMMY_NODE_ID,)};({});self.cx.stmt_item(self.span,self.cx.item(self.span, +Ident::empty(),thin_vec![self.cx.attr_nested_word(sym::allow,sym:://loop{break}; +unused_imports,self.span)],ItemKind::Use( UseTree{prefix:self.cx.path(self.span, +self.cx.std_path(((&(([sym::asserting])))))),kind:UseTreeKind::Nested(thin_vec![ +nested_tree(self,sym::TryCaptureGeneric),nested_tree(self,sym:://*&*&();((),()); +TryCapturePrintable),]),span:self.span,} ),),)}fn build_unlikely(&self,cond_expr +:P)->P{();let unlikely_path=self.cx.std_path(&[sym::intrinsics,sym:: +unlikely]);;self.cx.expr_call(self.span,self.cx.expr_path(self.cx.path(self.span +,unlikely_path)),thin_vec![self.cx.expr(self.span,ExprKind::Unary(UnOp::Not,//3; +cond_expr))],)}fn build_panic(&self,expr_str:&str,panic_path:Path)->P{;let +escaped_expr_str=escape_to_fmt(expr_str);((),());*&*&();let initial=[TokenTree:: +token_joint_hidden(token::Literal(token::Lit{kind:token::LitKind::Str,symbol://; +Symbol::intern(&if (((((((((((((self.fmt_string.is_empty()))))))))))))){format!( +"Assertion failed: {escaped_expr_str}")}else{format!(//loop{break};loop{break;}; +"Assertion failed: {escaped_expr_str}\nWith captures:\n{}",&self.fmt_string )}), +suffix:None,}),self.span,),TokenTree::token_alone(token::Comma,self.span),];;let +captures=(((((((((self.capture_decls.iter()))))))))).flat_map(|cap|{[TokenTree:: +token_joint_hidden(token::Ident(cap.ident.name, IdentIsRaw::No),cap.ident.span,) +,TokenTree::token_alone(token::Comma,self.span),]});({});self.cx.expr(self.span, +ExprKind::MacCall(P(MacCall{path:panic_path,args:P(DelimArgs{dspan:DelimSpan::// +from_single(self.span),delim:Delimiter::Parenthesis ,tokens:initial.into_iter(). +chain(captures).collect::(),}) ,})),)}fn manage_cond_expr(&mut self +,expr:&mut P){match(((((&mut expr.kind))))){ExprKind::AddrOf(_,mutability, +local_expr)=>{;self.with_is_consumed_management(matches!(mutability,Mutability:: +Mut),|this|{this.manage_cond_expr(local_expr)});;}ExprKind::Array(local_exprs)=> +{for local_expr in local_exprs{3;self.manage_cond_expr(local_expr);;}}ExprKind:: +Binary(op,lhs,rhs)=>{let _=();self.with_is_consumed_management(matches!(op.node, +BinOpKind::Add|BinOpKind::And|BinOpKind::BitAnd|BinOpKind::BitOr|BinOpKind:://3; +BitXor|BinOpKind::Div|BinOpKind::Mul|BinOpKind::Or|BinOpKind::Rem|BinOpKind:://; +Shl|BinOpKind::Shr|BinOpKind::Sub),|this|{3;this.manage_cond_expr(lhs);3;3;this. +manage_cond_expr(rhs);3;},);3;}ExprKind::Call(_,local_exprs)=>{for local_expr in +local_exprs{;self.manage_cond_expr(local_expr);}}ExprKind::Cast(local_expr,_)=>{ +self.manage_cond_expr(local_expr);({});}ExprKind::If(local_expr,_,_)=>{{;};self. +manage_cond_expr(local_expr);({});}ExprKind::Index(prefix,suffix,_)=>{({});self. +manage_cond_expr(prefix);();();self.manage_cond_expr(suffix);3;}ExprKind::Let(_, +local_expr,_,_)=>{;self.manage_cond_expr(local_expr);}ExprKind::Match(local_expr +,..)=>{;self.manage_cond_expr(local_expr);;}ExprKind::MethodCall(call)=>{for arg +in&mut call.args{;self.manage_cond_expr(arg);}}ExprKind::Path(_,Path{segments,.. +})if let[path_segment]=&segments[..]=>{;let path_ident=path_segment.ident;;self. +manage_initial_capture(expr,path_ident);3;}ExprKind::Paren(local_expr)=>{3;self. +manage_cond_expr(local_expr);();}ExprKind::Range(prefix,suffix,_)=>{if let Some( +elem)=prefix{();self.manage_cond_expr(elem);();}if let Some(elem)=suffix{3;self. +manage_cond_expr(elem);*&*&();}}ExprKind::Repeat(local_expr,elem)=>{*&*&();self. +manage_cond_expr(local_expr);;self.manage_cond_expr(&mut elem.value);}ExprKind:: +Struct(elem)=>{for field in&mut elem.fields{();self.manage_cond_expr(&mut field. +expr);;}if let StructRest::Base(local_expr)=&mut elem.rest{self.manage_cond_expr +(local_expr);;}}ExprKind::Tup(local_exprs)=>{for local_expr in local_exprs{self. +manage_cond_expr(local_expr);{;};}}ExprKind::Unary(un_op,local_expr)=>{{;};self. +with_is_consumed_management(((matches!(un_op,UnOp::Neg|UnOp::Not))),|this|{this. +manage_cond_expr(local_expr)});;}ExprKind::Assign(_,_,_)|ExprKind::AssignOp(_,_, +_)|ExprKind::Gen(_,_,_)|ExprKind::Await(_,_)|ExprKind::Block(_,_)|ExprKind:://3; +Break(_,_)|ExprKind::Closure(_)|ExprKind::ConstBlock(_)|ExprKind::Continue(_)|// +ExprKind::Dummy|ExprKind::Err(_)|ExprKind::Field(_,_)|ExprKind::ForLoop{..}|//3; +ExprKind::FormatArgs(_)|ExprKind::IncludedBytes(..)|ExprKind::InlineAsm(_)|//(); +ExprKind::Lit(_)|ExprKind::Loop(_,_ ,_)|ExprKind::MacCall(_)|ExprKind::OffsetOf( +_,_)|ExprKind::Path(_,_)|ExprKind:: Ret(_)|ExprKind::Try(_)|ExprKind::TryBlock(_ +)|ExprKind::Type(_,_)|ExprKind::Underscore|ExprKind::While(_,_,_)|ExprKind:://3; +Yeet(_)|ExprKind::Become(_)|ExprKind:: Yield(_)=>{}}}fn manage_initial_capture(& +mut self,expr:&mut P,path_ident: Ident){if self.paths.contains(&path_ident +){3;return;3;}else{3;self.fmt_string.push_str(" ");3;;self.fmt_string.push_str( +path_ident.as_str());;;self.fmt_string.push_str(" = {:?}\n");;;let _=self.paths. +insert(path_ident);();}();let curr_capture_idx=self.capture_decls.len();();3;let +capture_string=format!("__capture{curr_capture_idx}");();3;let ident=Ident::new( +Symbol::intern(&capture_string),self.span);;let init_std_path=self.cx.std_path(& +[sym::asserting,sym::Capture,sym::new]);3;;let init=self.cx.expr_call(self.span, +self.cx.expr_path(self.cx.path(self.span,init_std_path)),ThinVec::new(),);3;;let +capture=Capture{decl:self.cx.stmt_let(self.span,true,ident,init),ident};3;;self. +capture_decls.push(capture);;self.manage_try_capture(ident,curr_capture_idx,expr +);3;}fn manage_try_capture(&mut self,capture:Ident,curr_capture_idx:usize,expr:& +mut P){;let local_bind_string=format!("__local_bind{curr_capture_idx}");;; +let local_bind=Ident::new(Symbol::intern(&local_bind_string),self.span);3;;self. +local_bind_decls.push(self.cx.stmt_let(self.span,(((false))),local_bind,self.cx. +expr_addr_of(self.span,expr.clone()),));;let wrapper=self.cx.expr_call(self.span +,self.cx.expr_path(self.cx.path(self. span,self.cx.std_path(&[sym::asserting,sym +::Wrapper])),),thin_vec![self.cx.expr_path(Path::from_ident(local_bind))],);;let +try_capture_call=self.cx.stmt_expr(expr_method_call(self.cx,PathSegment{args://; +None,id:DUMMY_NODE_ID,ident:Ident::new(sym ::try_capture,self.span),},expr_paren +(self.cx,self.span,(((((self.cx.expr_addr_of(self.span,wrapper))))))),thin_vec![ +expr_addr_of_mut(self.cx,self.span,self .cx.expr_path(Path::from_ident(capture)) +,)],self.span,)).add_trailing_semicolon();;let local_bind_path=self.cx.expr_path +(Path::from_ident(local_bind));3;;let rslt=if self.is_consumed{;let ret=self.cx. +stmt_expr(local_bind_path);;self.cx.expr_block(self.cx.block(self.span,thin_vec! +[try_capture_call,ret]))}else{3;self.best_case_captures.push(try_capture_call);; +local_bind_path};*&*&();{();};*expr=self.cx.expr_deref(self.span,rslt);{();};}fn +with_is_consumed_management(&mut self,curr_is_consumed:bool,f:impl FnOnce(&mut// +Self)){;let prev_is_consumed=self.is_consumed;self.is_consumed=curr_is_consumed; +f(self);;self.is_consumed=prev_is_consumed;}}#[derive(Debug)]struct Capture{decl +:Stmt,ident:Ident,}fn escape_to_fmt(s:&str)->String{*&*&();let mut rslt=String:: +with_capacity(s.len());;for c in s.chars(){rslt.extend(c.escape_debug());match c +{'{'|'}'=>rslt.push(c),_=>{}} }rslt}fn expr_addr_of_mut(cx:&ExtCtxt<'_>,sp:Span, +e:P)->P{cx. expr(sp,ExprKind::AddrOf(BorrowKind::Ref,Mutability::Mut +,e))}fn expr_method_call(cx:&ExtCtxt< '_>,seg:PathSegment,receiver:P,args: +ThinVec>,span:Span,)->P{cx.expr(span,ExprKind::MethodCall(Box:://; +new(MethodCall{seg,receiver,args,span})) )}fn expr_paren(cx:&ExtCtxt<'_>,sp:Span +,e:P)->P{(((((((cx.expr(sp,(((((((ExprKind::Paren(e))))))))))))))))} diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index 5dc9bbacd0629..dfec2da3f433c 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -1,54 +1,14 @@ -//! The compiler code necessary to support the cfg! extension, which expands to -//! a literal `true` or `false` based on whether the given cfg matches the -//! current compilation environment. - -use crate::errors; -use rustc_ast as ast; -use rustc_ast::token; -use rustc_ast::tokenstream::TokenStream; -use rustc_attr as attr; -use rustc_errors::PResult; -use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; -use rustc_span::Span; - -pub fn expand_cfg( - cx: &mut ExtCtxt<'_>, - sp: Span, - tts: TokenStream, -) -> MacroExpanderResult<'static> { - let sp = cx.with_def_site_ctxt(sp); - - ExpandResult::Ready(match parse_cfg(cx, sp, tts) { - Ok(cfg) => { - let matches_cfg = attr::cfg_matches( - &cfg, - &cx.sess, - cx.current_expansion.lint_node_id, - Some(cx.ecfg.features), - ); - MacEager::expr(cx.expr_bool(sp, matches_cfg)) - } - Err(err) => { - let guar = err.emit(); - DummyResult::any(sp, guar) - } - }) -} - -fn parse_cfg<'a>(cx: &ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> { - let mut p = cx.new_parser_from_tts(tts); - - if p.token == token::Eof { - return Err(cx.dcx().create_err(errors::RequiresCfgPattern { span })); - } - - let cfg = p.parse_meta_item()?; - - let _ = p.eat(&token::Comma); - - if !p.eat(&token::Eof) { - return Err(cx.dcx().create_err(errors::OneCfgPattern { span })); - } - - Ok(cfg) -} +use crate::errors;use rustc_ast as ast;use rustc_ast::token;use rustc_ast:://(); +tokenstream::TokenStream;use rustc_attr as attr;use rustc_errors::PResult;use//; +rustc_expand::base::{DummyResult,ExpandResult,ExtCtxt,MacEager,//*&*&();((),()); +MacroExpanderResult};use rustc_span::Span;pub fn expand_cfg(cx:&mut ExtCtxt<'_> +,sp:Span,tts:TokenStream,)->MacroExpanderResult<'static>{loop{break;};let sp=cx. +with_def_site_ctxt(sp);;ExpandResult::Ready(match parse_cfg(cx,sp,tts){Ok(cfg)=> +{if true{};let matches_cfg=attr::cfg_matches(&cfg,&cx.sess,cx.current_expansion. +lint_node_id,Some(cx.ecfg.features),);let _=||();MacEager::expr(cx.expr_bool(sp, +matches_cfg))}Err(err)=>{3;let guar=err.emit();3;DummyResult::any(sp,guar)}})}fn +parse_cfg<'a>(cx:&ExtCtxt<'a>,span:Span,tts:TokenStream)->PResult<'a,ast:://{;}; +MetaItem>{;let mut p=cx.new_parser_from_tts(tts);;if p.token==token::Eof{return +Err(cx.dcx().create_err(errors::RequiresCfgPattern{span}));({});}({});let cfg=p. +parse_meta_item()?;;let _=p.eat(&token::Comma);if!p.eat(&token::Eof){return Err( +cx.dcx().create_err(errors::OneCfgPattern{span}));if true{};let _=||();}Ok(cfg)} diff --git a/compiler/rustc_builtin_macros/src/cfg_accessible.rs b/compiler/rustc_builtin_macros/src/cfg_accessible.rs index 98c0ca3a526b8..dcb69413f6ef0 100644 --- a/compiler/rustc_builtin_macros/src/cfg_accessible.rs +++ b/compiler/rustc_builtin_macros/src/cfg_accessible.rs @@ -1,70 +1,21 @@ -//! Implementation of the `#[cfg_accessible(path)]` attribute macro. - -use crate::errors; -use rustc_ast as ast; -use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier}; -use rustc_feature::AttributeTemplate; -use rustc_parse::validate_attr; -use rustc_span::symbol::sym; -use rustc_span::Span; - -pub(crate) struct Expander; - -fn validate_input<'a>(ecx: &ExtCtxt<'_>, mi: &'a ast::MetaItem) -> Option<&'a ast::Path> { - use errors::CfgAccessibleInvalid::*; - match mi.meta_item_list() { - None => {} - Some([]) => { - ecx.dcx().emit_err(UnspecifiedPath(mi.span)); - } - Some([_, .., l]) => { - ecx.dcx().emit_err(MultiplePaths(l.span())); - } - Some([nmi]) => match nmi.meta_item() { - None => { - ecx.dcx().emit_err(LiteralPath(nmi.span())); - } - Some(mi) => { - if !mi.is_word() { - ecx.dcx().emit_err(HasArguments(mi.span)); - } - return Some(&mi.path); - } - }, - } - None -} - -impl MultiItemModifier for Expander { - fn expand( - &self, - ecx: &mut ExtCtxt<'_>, - span: Span, - meta_item: &ast::MetaItem, - item: Annotatable, - _is_derive_const: bool, - ) -> ExpandResult, Annotatable> { - let template = AttributeTemplate { list: Some("path"), ..Default::default() }; - validate_attr::check_builtin_meta_item( - &ecx.sess.psess, - meta_item, - ast::AttrStyle::Outer, - sym::cfg_accessible, - template, - ); - - let Some(path) = validate_input(ecx, meta_item) else { - return ExpandResult::Ready(Vec::new()); - }; - - match ecx.resolver.cfg_accessible(ecx.current_expansion.id, path) { - Ok(true) => ExpandResult::Ready(vec![item]), - Ok(false) => ExpandResult::Ready(Vec::new()), - Err(Indeterminate) if ecx.force_mode => { - ecx.dcx().emit_err(errors::CfgAccessibleIndeterminate { span }); - ExpandResult::Ready(vec![item]) - } - Err(Indeterminate) => ExpandResult::Retry(item), - } - } -} +use crate::errors;use rustc_ast as ast;use rustc_expand::base::{Annotatable,//3; +ExpandResult,ExtCtxt,Indeterminate,MultiItemModifier};use rustc_feature:://({}); +AttributeTemplate;use rustc_parse::validate_attr;use rustc_span::symbol::sym;//; +use rustc_span::Span;pub(crate)struct Expander;fn validate_input<'a>(ecx:&//{;}; +ExtCtxt<'_>,mi:&'a ast::MetaItem)->Option<&'a ast::Path>{let _=||();use errors:: +CfgAccessibleInvalid::*;;match mi.meta_item_list(){None=>{}Some([])=>{ecx.dcx(). +emit_err(UnspecifiedPath(mi.span));{;};}Some([_,..,l])=>{{;};ecx.dcx().emit_err( +MultiplePaths(l.span()));;}Some([nmi])=>match nmi.meta_item(){None=>{;ecx.dcx(). +emit_err(LiteralPath(nmi.span()));{;};}Some(mi)=>{if!mi.is_word(){{;};ecx.dcx(). +emit_err(HasArguments(mi.span));{;};}{;};return Some(&mi.path);{;};}},}None}impl +MultiItemModifier for Expander{fn expand(&self,ecx:&mut ExtCtxt<'_>,span:Span,// +meta_item:&ast::MetaItem,item: Annotatable,_is_derive_const:bool,)->ExpandResult +,Annotatable>{;let template=AttributeTemplate{list:Some("path") +,..Default::default()};;;validate_attr::check_builtin_meta_item(&ecx.sess.psess, +meta_item,ast::AttrStyle::Outer,sym::cfg_accessible,template,);;;let Some(path)= +validate_input(ecx,meta_item)else{3;return ExpandResult::Ready(Vec::new());3;};; +match ((ecx.resolver.cfg_accessible(ecx.current_expansion .id,path))){Ok(true)=> +ExpandResult::Ready(vec![item]),Ok(false) =>ExpandResult::Ready(Vec::new()),Err( +Indeterminate)if ecx.force_mode=>{let _=();if true{};ecx.dcx().emit_err(errors:: +CfgAccessibleIndeterminate{span});if true{};ExpandResult::Ready(vec![item])}Err( +Indeterminate)=>(((((((((((((((((ExpandResult::Retry (item)))))))))))))))))),}}} diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index 93f7d09546b70..d433ed1ffa47d 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -1,286 +1,101 @@ -use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute}; - -use core::ops::ControlFlow; -use rustc_ast as ast; -use rustc_ast::mut_visit::MutVisitor; -use rustc_ast::ptr::P; -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; -use rustc_feature::Features; -use rustc_parse::parser::{ForceCollect, Parser}; -use rustc_session::Session; -use rustc_span::symbol::sym; -use rustc_span::Span; -use smallvec::SmallVec; - -pub(crate) fn expand( - ecx: &mut ExtCtxt<'_>, - _span: Span, - meta_item: &ast::MetaItem, - annotatable: Annotatable, -) -> Vec { - check_builtin_macro_attribute(ecx, meta_item, sym::cfg_eval); - warn_on_duplicate_attribute(ecx, &annotatable, sym::cfg_eval); - vec![cfg_eval(ecx.sess, ecx.ecfg.features, annotatable, ecx.current_expansion.lint_node_id)] -} - -pub(crate) fn cfg_eval( - sess: &Session, - features: &Features, - annotatable: Annotatable, - lint_node_id: NodeId, -) -> Annotatable { - let features = Some(features); - CfgEval { cfg: &mut StripUnconfigured { sess, features, config_tokens: true, lint_node_id } } - .configure_annotatable(annotatable) - // Since the item itself has already been configured by the `InvocationCollector`, - // we know that fold result vector will contain exactly one element. - .unwrap() -} - -struct CfgEval<'a, 'b> { - cfg: &'a mut StripUnconfigured<'b>, -} - -fn flat_map_annotatable( - vis: &mut impl MutVisitor, - annotatable: Annotatable, -) -> Option { - match annotatable { - Annotatable::Item(item) => vis.flat_map_item(item).pop().map(Annotatable::Item), - Annotatable::TraitItem(item) => { - vis.flat_map_trait_item(item).pop().map(Annotatable::TraitItem) - } - Annotatable::ImplItem(item) => { - vis.flat_map_impl_item(item).pop().map(Annotatable::ImplItem) - } - Annotatable::ForeignItem(item) => { - vis.flat_map_foreign_item(item).pop().map(Annotatable::ForeignItem) - } - Annotatable::Stmt(stmt) => { - vis.flat_map_stmt(stmt.into_inner()).pop().map(P).map(Annotatable::Stmt) - } - Annotatable::Expr(mut expr) => { - vis.visit_expr(&mut expr); - Some(Annotatable::Expr(expr)) - } - Annotatable::Arm(arm) => vis.flat_map_arm(arm).pop().map(Annotatable::Arm), - Annotatable::ExprField(field) => { - vis.flat_map_expr_field(field).pop().map(Annotatable::ExprField) - } - Annotatable::PatField(fp) => vis.flat_map_pat_field(fp).pop().map(Annotatable::PatField), - Annotatable::GenericParam(param) => { - vis.flat_map_generic_param(param).pop().map(Annotatable::GenericParam) - } - Annotatable::Param(param) => vis.flat_map_param(param).pop().map(Annotatable::Param), - Annotatable::FieldDef(sf) => vis.flat_map_field_def(sf).pop().map(Annotatable::FieldDef), - Annotatable::Variant(v) => vis.flat_map_variant(v).pop().map(Annotatable::Variant), - Annotatable::Crate(mut krate) => { - vis.visit_crate(&mut krate); - Some(Annotatable::Crate(krate)) - } - } -} - -fn has_cfg_or_cfg_attr(annotatable: &Annotatable) -> bool { - struct CfgFinder; - - impl<'ast> visit::Visitor<'ast> for CfgFinder { - type Result = ControlFlow<()>; - fn visit_attribute(&mut self, attr: &'ast Attribute) -> ControlFlow<()> { - if attr - .ident() - .is_some_and(|ident| ident.name == sym::cfg || ident.name == sym::cfg_attr) - { - ControlFlow::Break(()) - } else { - ControlFlow::Continue(()) - } - } - } - - let res = match annotatable { - Annotatable::Item(item) => CfgFinder.visit_item(item), - Annotatable::TraitItem(item) => CfgFinder.visit_assoc_item(item, visit::AssocCtxt::Trait), - Annotatable::ImplItem(item) => CfgFinder.visit_assoc_item(item, visit::AssocCtxt::Impl), - Annotatable::ForeignItem(item) => CfgFinder.visit_foreign_item(item), - Annotatable::Stmt(stmt) => CfgFinder.visit_stmt(stmt), - Annotatable::Expr(expr) => CfgFinder.visit_expr(expr), - Annotatable::Arm(arm) => CfgFinder.visit_arm(arm), - Annotatable::ExprField(field) => CfgFinder.visit_expr_field(field), - Annotatable::PatField(field) => CfgFinder.visit_pat_field(field), - Annotatable::GenericParam(param) => CfgFinder.visit_generic_param(param), - Annotatable::Param(param) => CfgFinder.visit_param(param), - Annotatable::FieldDef(field) => CfgFinder.visit_field_def(field), - Annotatable::Variant(variant) => CfgFinder.visit_variant(variant), - Annotatable::Crate(krate) => CfgFinder.visit_crate(krate), - }; - res.is_break() -} - -impl CfgEval<'_, '_> { - fn configure(&mut self, node: T) -> Option { - self.cfg.configure(node) - } - - fn configure_annotatable(&mut self, mut annotatable: Annotatable) -> Option { - // Tokenizing and re-parsing the `Annotatable` can have a significant - // performance impact, so try to avoid it if possible - if !has_cfg_or_cfg_attr(&annotatable) { - return Some(annotatable); - } - - // The majority of parsed attribute targets will never need to have early cfg-expansion - // run (e.g. they are not part of a `#[derive]` or `#[cfg_eval]` macro input). - // Therefore, we normally do not capture the necessary information about `#[cfg]` - // and `#[cfg_attr]` attributes during parsing. - // - // Therefore, when we actually *do* run early cfg-expansion, we need to tokenize - // and re-parse the attribute target, this time capturing information about - // 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: 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_without_recovery(false, 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 - // is normally delayed until the proc-macro server actually needs to - // provide a `TokenKind::Interpolated` to a proc-macro. We do this earlier, - // so that we can handle cases like: - // - // ```rust - // #[cfg_eval] #[cfg] $item - //``` - // - // where `$item` is `#[cfg_attr] struct Foo {}`. We want to make - // sure to evaluate *all* `#[cfg]` and `#[cfg_attr]` attributes - the simplest - // way to do this is to do a single parse of a stream without any nonterminals. - let orig_tokens = annotatable.to_tokens().flattened(); - - // Re-parse the tokens, setting the `capture_cfg` flag to save extra information - // to the captured `AttrTokenStream` (specifically, we capture - // `AttrTokenTree::AttributesData` for all occurrences of `#[cfg]` and `#[cfg_attr]`) - let mut parser = rustc_parse::stream_to_parser(&self.cfg.sess.psess, orig_tokens, None); - parser.capture_cfg = true; - match parse_annotatable_with(&mut parser) { - Ok(a) => annotatable = a, - Err(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. - flat_map_annotatable(self, annotatable) - } -} - -impl MutVisitor for CfgEval<'_, '_> { - #[instrument(level = "trace", skip(self))] - fn visit_expr(&mut self, expr: &mut P) { - 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) { - self.cfg.configure_expr(expr, true); - mut_visit::noop_visit_expr(expr, self); - } - - fn filter_map_expr(&mut self, expr: P) -> Option> { - let mut expr = configure!(self, expr); - mut_visit::noop_visit_expr(&mut expr, self); - Some(expr) - } - - fn flat_map_generic_param( - &mut self, - param: ast::GenericParam, - ) -> SmallVec<[ast::GenericParam; 1]> { - mut_visit::noop_flat_map_generic_param(configure!(self, param), self) - } - - fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> { - mut_visit::noop_flat_map_stmt(configure!(self, stmt), self) - } - - fn flat_map_item(&mut self, item: P) -> SmallVec<[P; 1]> { - mut_visit::noop_flat_map_item(configure!(self, item), self) - } - - fn flat_map_impl_item(&mut self, item: P) -> SmallVec<[P; 1]> { - mut_visit::noop_flat_map_assoc_item(configure!(self, item), self) - } - - fn flat_map_trait_item(&mut self, item: P) -> SmallVec<[P; 1]> { - mut_visit::noop_flat_map_assoc_item(configure!(self, item), self) - } - - fn flat_map_foreign_item( - &mut self, - foreign_item: P, - ) -> SmallVec<[P; 1]> { - mut_visit::noop_flat_map_foreign_item(configure!(self, foreign_item), self) - } - - fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> { - mut_visit::noop_flat_map_arm(configure!(self, arm), self) - } - - fn flat_map_expr_field(&mut self, field: ast::ExprField) -> SmallVec<[ast::ExprField; 1]> { - mut_visit::noop_flat_map_expr_field(configure!(self, field), self) - } - - fn flat_map_pat_field(&mut self, fp: ast::PatField) -> SmallVec<[ast::PatField; 1]> { - mut_visit::noop_flat_map_pat_field(configure!(self, fp), self) - } - - fn flat_map_param(&mut self, p: ast::Param) -> SmallVec<[ast::Param; 1]> { - mut_visit::noop_flat_map_param(configure!(self, p), self) - } - - fn flat_map_field_def(&mut self, sf: ast::FieldDef) -> SmallVec<[ast::FieldDef; 1]> { - mut_visit::noop_flat_map_field_def(configure!(self, sf), self) - } - - fn flat_map_variant(&mut self, variant: ast::Variant) -> SmallVec<[ast::Variant; 1]> { - mut_visit::noop_flat_map_variant(configure!(self, variant), self) - } -} +use crate::util::{check_builtin_macro_attribute,warn_on_duplicate_attribute};//; +use core::ops::ControlFlow;use rustc_ast as ast;use rustc_ast::mut_visit:://{;}; +MutVisitor;use rustc_ast::ptr::P;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;use rustc_feature::Features;use rustc_parse::parser::{ForceCollect,//; +Parser};use rustc_session::Session;use rustc_span::symbol::sym;use rustc_span:: +Span;use smallvec::SmallVec;pub(crate)fn expand(ecx:&mut ExtCtxt<'_>,_span:Span +,meta_item:&ast::MetaItem,annotatable:Annotatable,)->Vec{if true{}; +check_builtin_macro_attribute(ecx,meta_item,sym::cfg_eval);let _=||();if true{}; +warn_on_duplicate_attribute(ecx,&annotatable,sym::cfg_eval);3;vec![cfg_eval(ecx. +sess,ecx.ecfg.features,annotatable,ecx.current_expansion.lint_node_id)]}pub(//3; +crate)fn cfg_eval(sess:&Session,features:&Features,annotatable:Annotatable,//(); +lint_node_id:NodeId,)->Annotatable{;let features=Some(features);CfgEval{cfg:&mut +((((StripUnconfigured{sess,features,config_tokens:(((true))),lint_node_id}))))}. +configure_annotatable(annotatable).unwrap()}struct CfgEval<'a,'b>{cfg:&'a mut//; +StripUnconfigured<'b>,}fn flat_map_annotatable(vis:&mut impl MutVisitor,//{();}; +annotatable:Annotatable,)->Option{match annotatable{Annotatable::// +Item(item)=>(vis.flat_map_item(item).pop().map(Annotatable::Item)),Annotatable:: +TraitItem(item)=>{((((vis.flat_map_trait_item( item))).pop())).map(Annotatable:: +TraitItem)}Annotatable::ImplItem(item)=>{ vis.flat_map_impl_item(item).pop().map +(Annotatable::ImplItem)}Annotatable::ForeignItem(item)=>{vis.//((),());let _=(); +flat_map_foreign_item(item).pop().map(Annotatable::ForeignItem)}Annotatable:://; +Stmt(stmt)=>{(vis.flat_map_stmt(stmt.into_inner()).pop().map(P)).map(Annotatable +::Stmt)}Annotatable::Expr(mut expr)=>{{();};vis.visit_expr(&mut expr);({});Some( +Annotatable::Expr(expr))}Annotatable::Arm(arm)=> vis.flat_map_arm(arm).pop().map +(Annotatable::Arm),Annotatable::ExprField(field)=>{vis.flat_map_expr_field(//(); +field).pop().map(Annotatable::ExprField)}Annotatable::PatField(fp)=>vis.//{();}; +flat_map_pat_field(fp).pop().map(Annotatable::PatField),Annotatable:://let _=(); +GenericParam(param)=>{vis.flat_map_generic_param( param).pop().map(Annotatable:: +GenericParam)}Annotatable::Param(param)=>( vis.flat_map_param(param).pop()).map( +Annotatable::Param),Annotatable::FieldDef(sf)=> vis.flat_map_field_def(sf).pop() +.map(Annotatable::FieldDef),Annotatable::Variant( v)=>(vis.flat_map_variant(v)). +pop().map(Annotatable::Variant),Annotatable::Crate(mut krate)=>{;vis.visit_crate +(&mut krate);if true{};Some(Annotatable::Crate(krate))}}}fn has_cfg_or_cfg_attr( +annotatable:&Annotatable)->bool{;struct CfgFinder;impl<'ast>visit::Visitor<'ast> +for CfgFinder{type Result=ControlFlow<()>;fn visit_attribute(&mut self,attr:&//; +'ast Attribute)->ControlFlow<()>{if (attr.ident()).is_some_and(|ident|ident.name +==sym::cfg||(ident.name==sym::cfg_attr)){ControlFlow::Break(())}else{ControlFlow +::Continue(())}}};;let res=match annotatable{Annotatable::Item(item)=>CfgFinder. +visit_item(item),Annotatable::TraitItem( item)=>CfgFinder.visit_assoc_item(item, +visit::AssocCtxt::Trait),Annotatable::ImplItem(item)=>CfgFinder.//if let _=(){}; +visit_assoc_item(item,visit::AssocCtxt::Impl),Annotatable::ForeignItem(item)=>// +CfgFinder.visit_foreign_item(item),Annotatable::Stmt(stmt)=>CfgFinder.//((),()); +visit_stmt(stmt),Annotatable::Expr(expr )=>(((((CfgFinder.visit_expr(expr)))))), +Annotatable::Arm(arm)=>CfgFinder.visit_arm( arm),Annotatable::ExprField(field)=> +CfgFinder.visit_expr_field(field),Annotatable::PatField(field)=>CfgFinder.//{;}; +visit_pat_field(field),Annotatable::GenericParam(param)=>CfgFinder.//let _=||(); +visit_generic_param(param),Annotatable::Param(param)=>CfgFinder.visit_param(//3; +param),Annotatable::FieldDef(field)=>(((((CfgFinder.visit_field_def(field)))))), +Annotatable::Variant(variant)=>(CfgFinder .visit_variant(variant)),Annotatable:: +Crate(krate)=>CfgFinder.visit_crate(krate),};;res.is_break()}impl CfgEval<'_,'_> +{fn configure(&mut self,node:T)->Option{self.cfg.//{;}; +configure(node)}fn configure_annotatable( &mut self,mut annotatable:Annotatable) +->Option{if!has_cfg_or_cfg_attr(&annotatable){let _=();return Some( +annotatable);;}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_without_recovery((false), +ForceCollect::Yes)?.unwrap())))},Annotatable::Expr(_)=>{|parser|Ok(Annotatable// +::Expr(parser.parse_expr_force_collect()?))}_=>unreachable!(),};;let orig_tokens +=annotatable.to_tokens().flattened();((),());*&*&();let mut parser=rustc_parse:: +stream_to_parser(&self.cfg.sess.psess,orig_tokens,None);;parser.capture_cfg=true +;;match parse_annotatable_with(&mut parser){Ok(a)=>annotatable=a,Err(err)=>{err. +emit();;;return Some(annotatable);}}flat_map_annotatable(self,annotatable)}}impl +MutVisitor for CfgEval<'_,'_>{#[instrument(level="trace",skip(self))]fn//*&*&(); +visit_expr(&mut self,expr:&mut P){;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){{();};self.cfg. +configure_expr(expr,true);({});{;};mut_visit::noop_visit_expr(expr,self);{;};}fn +filter_map_expr(&mut self,expr:P)->Option>{;let mut expr +=configure!(self,expr);;mut_visit::noop_visit_expr(&mut expr,self);Some(expr)}fn +flat_map_generic_param(&mut self,param:ast::GenericParam,)->SmallVec<[ast:://(); +GenericParam;1]>{mut_visit:: noop_flat_map_generic_param(configure!(self,param), +self)}fn flat_map_stmt(&mut self,stmt:ast::Stmt)->SmallVec<[ast::Stmt;(((1)))]>{ +mut_visit::noop_flat_map_stmt(configure!(self,stmt) ,self)}fn flat_map_item(&mut +self,item:P)->SmallVec<[ P;((((((((1))))))))]>{mut_visit:: +noop_flat_map_item(configure!(self,item), self)}fn flat_map_impl_item(&mut self, +item:P)->SmallVec<[P;((((((1))))))]>{mut_visit:: +noop_flat_map_assoc_item((configure!(self,item) ),self)}fn flat_map_trait_item(& +mut self,item:P)->SmallVec< [P;(1)]>{mut_visit:: +noop_flat_map_assoc_item(configure!(self,item) ,self)}fn flat_map_foreign_item(& +mut self,foreign_item:P,)->SmallVec <[P;1]>{ +mut_visit::noop_flat_map_foreign_item(((configure!(self,foreign_item))),self)}fn +flat_map_arm(&mut self,arm:ast::Arm)->SmallVec<[ast::Arm;((((1))))]>{mut_visit:: +noop_flat_map_arm((configure!(self,arm)),self)}fn flat_map_expr_field(&mut self, +field:ast::ExprField)->SmallVec<[ast ::ExprField;((((((((1))))))))]>{mut_visit:: +noop_flat_map_expr_field((configure!(self,field) ),self)}fn flat_map_pat_field(& +mut self,fp:ast::PatField)->SmallVec< [ast::PatField;((((((1))))))]>{mut_visit:: +noop_flat_map_pat_field(configure!(self,fp),self )}fn flat_map_param(&mut self,p +:ast::Param)->SmallVec<[ast::Param; 1]>{mut_visit::noop_flat_map_param(configure +!(self,p),self)}fn flat_map_field_def(&mut self,sf:ast::FieldDef)->SmallVec<[//; +ast::FieldDef;1]>{mut_visit::noop_flat_map_field_def (configure!(self,sf),self)} +fn flat_map_variant(&mut self,variant:ast::Variant )->SmallVec<[ast::Variant;1]> +{((((mut_visit::noop_flat_map_variant((((configure!(self,variant)))),self)))))}} diff --git a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs index ada82e45712d8..c7d74e32d19dc 100644 --- a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs +++ b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs @@ -1,40 +1,11 @@ -//! Attributes injected into the crate root from command line using `-Z crate-attr`. - -use crate::errors; -use rustc_ast::attr::mk_attr; -use rustc_ast::token; -use rustc_ast::{self as ast, AttrItem, AttrStyle}; -use rustc_session::parse::ParseSess; -use rustc_span::FileName; - -pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) { - for raw_attr in attrs { - let mut parser = rustc_parse::new_parser_from_source_str( - psess, - FileName::cli_crate_attr_source_code(raw_attr), - raw_attr.clone(), - ); - - let start_span = parser.token.span; - let AttrItem { path, args, tokens: _ } = match parser.parse_attr_item(false) { - Ok(ai) => ai, - Err(err) => { - err.emit(); - continue; - } - }; - let end_span = parser.token.span; - if parser.token != token::Eof { - psess.dcx.emit_err(errors::InvalidCrateAttr { span: start_span.to(end_span) }); - continue; - } - - krate.attrs.push(mk_attr( - &psess.attr_id_generator, - AttrStyle::Inner, - path, - args, - start_span.to(end_span), - )); - } -} +use crate::errors;use rustc_ast::attr::mk_attr;use rustc_ast::token;use//*&*&(); +rustc_ast::{self as ast,AttrItem ,AttrStyle};use rustc_session::parse::ParseSess +;use rustc_span::FileName;pub fn inject( krate:&mut ast::Crate,psess:&ParseSess, +attrs:&[String]){for raw_attr in attrs{loop{break;};let mut parser=rustc_parse:: +new_parser_from_source_str(psess,FileName ::cli_crate_attr_source_code(raw_attr) +,raw_attr.clone(),);;;let start_span=parser.token.span;;;let AttrItem{path,args, +tokens:_}=match parser.parse_attr_item(false){Ok(ai)=>ai,Err(err)=>{;err.emit(); +continue;;}};;;let end_span=parser.token.span;if parser.token!=token::Eof{psess. +dcx.emit_err(errors::InvalidCrateAttr{span:start_span.to(end_span)});;continue;} +krate.attrs.push(mk_attr((&psess .attr_id_generator),AttrStyle::Inner,path,args, +start_span.to(end_span),));loop{break};loop{break;};loop{break;};loop{break;};}} diff --git a/compiler/rustc_builtin_macros/src/compile_error.rs b/compiler/rustc_builtin_macros/src/compile_error.rs index 2f2a87fc9aa00..657b96281790b 100644 --- a/compiler/rustc_builtin_macros/src/compile_error.rs +++ b/compiler/rustc_builtin_macros/src/compile_error.rs @@ -1,26 +1,12 @@ -// The compiler code necessary to support the compile_error! extension. - -use rustc_ast::tokenstream::TokenStream; -use rustc_expand::base::get_single_str_from_tts; -use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; -use rustc_span::Span; - -pub fn expand_compile_error<'cx>( - cx: &'cx mut ExtCtxt<'_>, - sp: Span, - tts: TokenStream, -) -> MacroExpanderResult<'cx> { - let ExpandResult::Ready(mac) = get_single_str_from_tts(cx, sp, tts, "compile_error!") else { - return ExpandResult::Retry(()); - }; - let var = match mac { - Ok(var) => var, - Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)), - }; - - #[expect(rustc::diagnostic_outside_of_impl, reason = "diagnostic message is specified by user")] - #[expect(rustc::untranslatable_diagnostic, reason = "diagnostic message is specified by user")] - let guar = cx.dcx().span_err(sp, var.to_string()); - - ExpandResult::Ready(DummyResult::any(sp, guar)) -} +use rustc_ast::tokenstream::TokenStream;use rustc_expand::base:://if let _=(){}; +get_single_str_from_tts;use rustc_expand::base::{DummyResult,ExpandResult,//{;}; +ExtCtxt,MacroExpanderResult};use rustc_span::Span;pub fn expand_compile_error(cx:&'cx mut ExtCtxt<'_> ,sp:Span,tts:TokenStream,)->MacroExpanderResult<'cx +>{*&*&();((),());let ExpandResult::Ready(mac)=get_single_str_from_tts(cx,sp,tts, +"compile_error!")else{;return ExpandResult::Retry(());};let var=match mac{Ok(var +)=>var,Err(guar)=>return ExpandResult::Ready(DummyResult::any(sp,guar)),};3;3;#[ +expect(rustc::diagnostic_outside_of_impl,reason=//*&*&();((),());*&*&();((),()); +"diagnostic message is specified by user")]#[expect(rustc:://let _=();if true{}; +untranslatable_diagnostic,reason= "diagnostic message is specified by user")]let +guar=cx.dcx().span_err(sp,var.to_string());{;};ExpandResult::Ready(DummyResult:: +any(sp,guar))}//((),());((),());((),());((),());((),());((),());((),());((),()); diff --git a/compiler/rustc_builtin_macros/src/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs index 93a7ac05a9bef..f982c7acbe5cf 100644 --- a/compiler/rustc_builtin_macros/src/concat.rs +++ b/compiler/rustc_builtin_macros/src/concat.rs @@ -1,86 +1,30 @@ -use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{ExprKind, LitKind, UnOp}; -use rustc_expand::base::get_exprs_from_tts; -use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; -use rustc_session::errors::report_lit_error; -use rustc_span::symbol::Symbol; - -use crate::errors; - -pub fn expand_concat( - cx: &mut ExtCtxt<'_>, - sp: rustc_span::Span, - tts: TokenStream, -) -> MacroExpanderResult<'static> { - let ExpandResult::Ready(mac) = get_exprs_from_tts(cx, tts) else { - return ExpandResult::Retry(()); - }; - let es = match mac { - Ok(es) => es, - Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)), - }; - let mut accumulator = String::new(); - let mut missing_literal = vec![]; - let mut guar = None; - for e in es { - match e.kind { - ExprKind::Lit(token_lit) => match LitKind::from_token_lit(token_lit) { - Ok(LitKind::Str(s, _) | LitKind::Float(s, _)) => { - accumulator.push_str(s.as_str()); - } - Ok(LitKind::Char(c)) => { - accumulator.push(c); - } - Ok(LitKind::Int(i, _)) => { - accumulator.push_str(&i.to_string()); - } - Ok(LitKind::Bool(b)) => { - accumulator.push_str(&b.to_string()); - } - Ok(LitKind::CStr(..)) => { - guar = Some(cx.dcx().emit_err(errors::ConcatCStrLit { span: e.span })); - } - Ok(LitKind::Byte(..) | LitKind::ByteStr(..)) => { - guar = Some(cx.dcx().emit_err(errors::ConcatBytestr { span: e.span })); - } - Ok(LitKind::Err(guarantee)) => { - guar = Some(guarantee); - } - Err(err) => { - guar = Some(report_lit_error(&cx.sess.psess, err, token_lit, e.span)); - } - }, - // We also want to allow negative numeric literals. - ExprKind::Unary(UnOp::Neg, ref expr) if let ExprKind::Lit(token_lit) = expr.kind => { - match LitKind::from_token_lit(token_lit) { - Ok(LitKind::Int(i, _)) => accumulator.push_str(&format!("-{i}")), - Ok(LitKind::Float(f, _)) => accumulator.push_str(&format!("-{f}")), - Err(err) => { - guar = Some(report_lit_error(&cx.sess.psess, err, token_lit, e.span)); - } - _ => missing_literal.push(e.span), - } - } - ExprKind::IncludedBytes(..) => { - cx.dcx().emit_err(errors::ConcatBytestr { span: e.span }); - } - ExprKind::Err(guarantee) => { - guar = Some(guarantee); - } - ExprKind::Dummy => cx.dcx().span_bug(e.span, "concatenating `ExprKind::Dummy`"), - _ => { - missing_literal.push(e.span); - } - } - } - - ExpandResult::Ready(if !missing_literal.is_empty() { - let guar = cx.dcx().emit_err(errors::ConcatMissingLiteral { spans: missing_literal }); - DummyResult::any(sp, guar) - } else if let Some(guar) = guar { - DummyResult::any(sp, guar) - } else { - let sp = cx.with_def_site_ctxt(sp); - MacEager::expr(cx.expr_str(sp, Symbol::intern(&accumulator))) - }) -} +use rustc_ast::tokenstream::TokenStream;use rustc_ast::{ExprKind,LitKind,UnOp}; +use rustc_expand::base::get_exprs_from_tts; use rustc_expand::base::{DummyResult +,ExpandResult,ExtCtxt,MacEager,MacroExpanderResult };use rustc_session::errors:: +report_lit_error;use rustc_span::symbol::Symbol;use crate::errors;pub fn//{();}; +expand_concat(cx:&mut ExtCtxt<'_>,sp:rustc_span::Span,tts:TokenStream,)->//({}); +MacroExpanderResult<'static>{;let ExpandResult::Ready(mac)=get_exprs_from_tts(cx +,tts)else{;return ExpandResult::Retry(());};let es=match mac{Ok(es)=>es,Err(guar +)=>return ExpandResult::Ready(DummyResult::any(sp,guar)),};;let mut accumulator= +String::new();;;let mut missing_literal=vec![];;;let mut guar=None;;for e in es{ +match e.kind{ExprKind::Lit(token_lit )=>match LitKind::from_token_lit(token_lit) +{Ok(LitKind::Str(s,_)|LitKind::Float(s,_))=>{;accumulator.push_str(s.as_str());} +Ok(LitKind::Char(c))=>{;accumulator.push(c);}Ok(LitKind::Int(i,_))=>{accumulator +.push_str(&i.to_string());();}Ok(LitKind::Bool(b))=>{();accumulator.push_str(&b. +to_string());();}Ok(LitKind::CStr(..))=>{();guar=Some(cx.dcx().emit_err(errors:: +ConcatCStrLit{span:e.span}));;}Ok(LitKind::Byte(..)|LitKind::ByteStr(..))=>{guar +=Some(cx.dcx().emit_err(errors::ConcatBytestr{span:e.span}));3;}Ok(LitKind::Err( +guarantee))=>{;guar=Some(guarantee);;}Err(err)=>{guar=Some(report_lit_error(&cx. +sess.psess,err,token_lit,e.span));3;}},ExprKind::Unary(UnOp::Neg,ref expr)if let +ExprKind::Lit(token_lit)=expr.kind=>{match (LitKind::from_token_lit(token_lit)){ +Ok(LitKind::Int(i,_))=>accumulator.push_str( &format!("-{i}")),Ok(LitKind::Float +(f,_))=>accumulator.push_str(&format!("-{f}")),Err(err)=>{loop{break};guar=Some( +report_lit_error(&cx.sess.psess,err,token_lit,e.span));;}_=>missing_literal.push +(e.span),}}ExprKind::IncludedBytes(..)=>{loop{break;};cx.dcx().emit_err(errors:: +ConcatBytestr{span:e.span});;}ExprKind::Err(guarantee)=>{;guar=Some(guarantee);} +ExprKind::Dummy=>(cx.dcx().span_bug(e.span,"concatenating `ExprKind::Dummy`")),_ +=>{();missing_literal.push(e.span);();}}}ExpandResult::Ready(if!missing_literal. +is_empty(){*&*&();let guar=cx.dcx().emit_err(errors::ConcatMissingLiteral{spans: +missing_literal});((),());DummyResult::any(sp,guar)}else if let Some(guar)=guar{ +DummyResult::any(sp,guar)}else{;let sp=cx.with_def_site_ctxt(sp);MacEager::expr( +cx.expr_str(sp,((((((((Symbol::intern(((((((((&accumulator)))))))))))))))))))})} diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs index 45fec2945788b..72f2c029b8f02 100644 --- a/compiler/rustc_builtin_macros/src/concat_bytes.rs +++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs @@ -1,186 +1,60 @@ -use rustc_ast::{ptr::P, token, tokenstream::TokenStream, ExprKind, LitIntType, LitKind, UintTy}; -use rustc_expand::base::get_exprs_from_tts; -use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; -use rustc_session::errors::report_lit_error; -use rustc_span::{ErrorGuaranteed, Span}; - -use crate::errors; - -/// Emits errors for literal expressions that are invalid inside and outside of an array. -fn invalid_type_err( - cx: &ExtCtxt<'_>, - token_lit: token::Lit, - span: Span, - is_nested: bool, -) -> ErrorGuaranteed { - use errors::{ - ConcatBytesInvalid, ConcatBytesInvalidSuggestion, ConcatBytesNonU8, ConcatBytesOob, - }; - let snippet = cx.sess.source_map().span_to_snippet(span).ok(); - let dcx = cx.dcx(); - match LitKind::from_token_lit(token_lit) { - Ok(LitKind::CStr(_, _)) => { - // Avoid ambiguity in handling of terminal `NUL` by refusing to - // concatenate C string literals as bytes. - dcx.emit_err(errors::ConcatCStrLit { span }) - } - Ok(LitKind::Char(_)) => { - let sugg = - snippet.map(|snippet| ConcatBytesInvalidSuggestion::CharLit { span, snippet }); - dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "character", sugg }) - } - Ok(LitKind::Str(_, _)) => { - // suggestion would be invalid if we are nested - let sugg = if !is_nested { - snippet.map(|snippet| ConcatBytesInvalidSuggestion::StrLit { span, snippet }) - } else { - None - }; - dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "string", sugg }) - } - Ok(LitKind::Float(_, _)) => { - dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "float", sugg: None }) - } - Ok(LitKind::Bool(_)) => { - dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "boolean", sugg: None }) - } - Ok(LitKind::Int(_, _)) if !is_nested => { - let sugg = - snippet.map(|snippet| ConcatBytesInvalidSuggestion::IntLit { span, snippet }); - dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "numeric", sugg }) - } - Ok(LitKind::Int(val, LitIntType::Unsuffixed | LitIntType::Unsigned(UintTy::U8))) => { - assert!(val.get() > u8::MAX.into()); // must be an error - dcx.emit_err(ConcatBytesOob { span }) - } - Ok(LitKind::Int(_, _)) => dcx.emit_err(ConcatBytesNonU8 { span }), - Ok(LitKind::ByteStr(..) | LitKind::Byte(_)) => unreachable!(), - Ok(LitKind::Err(guar)) => guar, - Err(err) => report_lit_error(&cx.sess.psess, err, token_lit, span), - } -} - -/// Returns `expr` as a *single* byte literal if applicable. -/// -/// Otherwise, returns `None`, and either pushes the `expr`'s span to `missing_literals` or -/// updates `guar` accordingly. -fn handle_array_element( - cx: &ExtCtxt<'_>, - guar: &mut Option, - missing_literals: &mut Vec, - expr: &P, -) -> Option { - let dcx = cx.dcx(); - - match expr.kind { - ExprKind::Lit(token_lit) => { - match LitKind::from_token_lit(token_lit) { - Ok(LitKind::Int( - val, - LitIntType::Unsuffixed | LitIntType::Unsigned(UintTy::U8), - )) if let Ok(val) = u8::try_from(val.get()) => { - return Some(val); - } - Ok(LitKind::Byte(val)) => return Some(val), - Ok(LitKind::ByteStr(..)) => { - guar.get_or_insert_with(|| { - dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: true }) - }); - } - _ => { - guar.get_or_insert_with(|| invalid_type_err(cx, token_lit, expr.span, true)); - } - }; - } - ExprKind::Array(_) | ExprKind::Repeat(_, _) => { - guar.get_or_insert_with(|| { - dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false }) - }); - } - ExprKind::IncludedBytes(..) => { - guar.get_or_insert_with(|| { - dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false }) - }); - } - _ => missing_literals.push(expr.span), - } - - None -} - -pub fn expand_concat_bytes( - cx: &mut ExtCtxt<'_>, - sp: Span, - tts: TokenStream, -) -> MacroExpanderResult<'static> { - let ExpandResult::Ready(mac) = get_exprs_from_tts(cx, tts) else { - return ExpandResult::Retry(()); - }; - let es = match mac { - Ok(es) => es, - Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)), - }; - let mut accumulator = Vec::new(); - let mut missing_literals = vec![]; - let mut guar = None; - for e in es { - match &e.kind { - ExprKind::Array(exprs) => { - for expr in exprs { - if let Some(elem) = - handle_array_element(cx, &mut guar, &mut missing_literals, expr) - { - accumulator.push(elem); - } - } - } - ExprKind::Repeat(expr, count) => { - if let ExprKind::Lit(token_lit) = count.value.kind - && let Ok(LitKind::Int(count_val, _)) = LitKind::from_token_lit(token_lit) - { - if let Some(elem) = - handle_array_element(cx, &mut guar, &mut missing_literals, expr) - { - for _ in 0..count_val.get() { - accumulator.push(elem); - } - } - } else { - guar = Some( - cx.dcx().emit_err(errors::ConcatBytesBadRepeat { span: count.value.span }), - ); - } - } - &ExprKind::Lit(token_lit) => match LitKind::from_token_lit(token_lit) { - Ok(LitKind::Byte(val)) => { - accumulator.push(val); - } - Ok(LitKind::ByteStr(ref bytes, _)) => { - accumulator.extend_from_slice(bytes); - } - _ => { - guar.get_or_insert_with(|| invalid_type_err(cx, token_lit, e.span, false)); - } - }, - ExprKind::IncludedBytes(bytes) => { - accumulator.extend_from_slice(bytes); - } - ExprKind::Err(guarantee) => { - guar = Some(*guarantee); - } - ExprKind::Dummy => cx.dcx().span_bug(e.span, "concatenating `ExprKind::Dummy`"), - _ => { - missing_literals.push(e.span); - } - } - } - ExpandResult::Ready(if !missing_literals.is_empty() { - let guar = cx.dcx().emit_err(errors::ConcatBytesMissingLiteral { spans: missing_literals }); - MacEager::expr(DummyResult::raw_expr(sp, Some(guar))) - } else if let Some(guar) = guar { - MacEager::expr(DummyResult::raw_expr(sp, Some(guar))) - } else { - let sp = cx.with_def_site_ctxt(sp); - MacEager::expr(cx.expr_byte_str(sp, accumulator)) - }) -} +use rustc_ast::{ptr::P,token,tokenstream::TokenStream,ExprKind,LitIntType,//{;}; +LitKind,UintTy};use rustc_expand::base::get_exprs_from_tts;use rustc_expand:://; +base::{DummyResult,ExpandResult,ExtCtxt,MacEager,MacroExpanderResult};use//({}); +rustc_session::errors::report_lit_error;use rustc_span::{ErrorGuaranteed,Span}; +use crate::errors;fn invalid_type_err(cx: &ExtCtxt<'_>,token_lit:token::Lit,span +:Span,is_nested:bool,)->ErrorGuaranteed{((),());use errors::{ConcatBytesInvalid, +ConcatBytesInvalidSuggestion,ConcatBytesNonU8,ConcatBytesOob,};;;let snippet=cx. +sess.source_map().span_to_snippet(span).ok();;;let dcx=cx.dcx();;match LitKind:: +from_token_lit(token_lit){Ok(LitKind::CStr(_,_))=>{dcx.emit_err(errors:://{();}; +ConcatCStrLit{span})}Ok(LitKind::Char(_))=>{{();};let sugg=snippet.map(|snippet| +ConcatBytesInvalidSuggestion::CharLit{span,snippet});if let _=(){};dcx.emit_err( +ConcatBytesInvalid{span,lit_kind:"character",sugg})}Ok(LitKind::Str(_,_))=>{;let +sugg=if((!is_nested)){snippet.map(|snippet|ConcatBytesInvalidSuggestion::StrLit{ +span,snippet})}else{None};((),());dcx.emit_err(ConcatBytesInvalid{span,lit_kind: +"string",sugg})}Ok(LitKind::Float(_ ,_))=>{dcx.emit_err(ConcatBytesInvalid{span, +lit_kind:((((((("float"))))))),sugg:None})}Ok (LitKind::Bool(_))=>{dcx.emit_err( +ConcatBytesInvalid{span,lit_kind:"boolean",sugg:None}) }Ok(LitKind::Int(_,_))if! +is_nested=>{;let sugg=snippet.map(|snippet|ConcatBytesInvalidSuggestion::IntLit{ +span,snippet});3;dcx.emit_err(ConcatBytesInvalid{span,lit_kind:"numeric",sugg})} +Ok(LitKind::Int(val,LitIntType::Unsuffixed |LitIntType::Unsigned(UintTy::U8)))=> +{{;};assert!(val.get()>u8::MAX.into());();dcx.emit_err(ConcatBytesOob{span})}Ok( +LitKind::Int(_,_))=>dcx.emit_err( ConcatBytesNonU8{span}),Ok(LitKind::ByteStr(.. +)|LitKind::Byte(_))=>((unreachable!())), Ok(LitKind::Err(guar))=>guar,Err(err)=> +report_lit_error((&cx.sess.psess),err,token_lit,span),}}fn handle_array_element( +cx:&ExtCtxt<'_>,guar:&mut Option,missing_literals:&mut Vec,expr:&P,)->Option{;let dcx=cx.dcx();match +expr.kind{ExprKind::Lit(token_lit)=>{3;match LitKind::from_token_lit(token_lit){ +Ok(LitKind::Int(val,LitIntType::Unsuffixed|LitIntType::Unsigned(UintTy::U8),))// +if let Ok(val)=u8::try_from(val.get())=>{;return Some(val);}Ok(LitKind::Byte(val +))=>return Some(val),Ok(LitKind::ByteStr(..))=>{;guar.get_or_insert_with(||{dcx. +emit_err(errors::ConcatBytesArray{span:expr.span,bytestr:true})});3;}_=>{3;guar. +get_or_insert_with(||invalid_type_err(cx,token_lit,expr.span,true));{;};}};{;};} +ExprKind::Array(_)|ExprKind::Repeat(_,_)=>{{();};guar.get_or_insert_with(||{dcx. +emit_err(errors::ConcatBytesArray{span:expr.span,bytestr:false})});3;}ExprKind:: +IncludedBytes(..)=>{loop{break};guar.get_or_insert_with(||{dcx.emit_err(errors:: +ConcatBytesArray{span:expr.span,bytestr:false})});{;};}_=>missing_literals.push( +expr.span),}None}pub fn expand_concat_bytes(cx:&mut ExtCtxt<'_>,sp:Span,tts://3; +TokenStream,)->MacroExpanderResult<'static>{*&*&();let ExpandResult::Ready(mac)= +get_exprs_from_tts(cx,tts)else{;return ExpandResult::Retry(());;};;;let es=match +mac{Ok(es)=>es,Err(guar)=>return ExpandResult::Ready(DummyResult::any(sp,guar)) +,};;let mut accumulator=Vec::new();let mut missing_literals=vec![];let mut guar= +None;;for e in es{match&e.kind{ExprKind::Array(exprs)=>{for expr in exprs{if let +Some(elem)=handle_array_element(cx,&mut guar,&mut missing_literals,expr){*&*&(); +accumulator.push(elem);3;}}}ExprKind::Repeat(expr,count)=>{if let ExprKind::Lit( +token_lit)=count.value.kind&&let Ok(LitKind::Int(count_val,_))=LitKind:://{();}; +from_token_lit(token_lit){if let Some(elem) =handle_array_element(cx,&mut guar,& +mut missing_literals,expr){for _ in 0..count_val.get(){;accumulator.push(elem);} +}}else{({});guar=Some(cx.dcx().emit_err(errors::ConcatBytesBadRepeat{span:count. +value.span}),);{();};}}&ExprKind::Lit(token_lit)=>match LitKind::from_token_lit( +token_lit){Ok(LitKind::Byte(val))=>{;accumulator.push(val);}Ok(LitKind::ByteStr( +ref bytes,_))=>{{();};accumulator.extend_from_slice(bytes);{();};}_=>{({});guar. +get_or_insert_with(||invalid_type_err(cx,token_lit,e.span,false));;}},ExprKind:: +IncludedBytes(bytes)=>{();accumulator.extend_from_slice(bytes);3;}ExprKind::Err( +guarantee)=>{;guar=Some(*guarantee);;}ExprKind::Dummy=>cx.dcx().span_bug(e.span, +"concatenating `ExprKind::Dummy`"),_=>{{;};missing_literals.push(e.span);{;};}}} +ExpandResult::Ready(if!missing_literals.is_empty(){3;let guar=cx.dcx().emit_err( +errors::ConcatBytesMissingLiteral{spans:missing_literals});{();};MacEager::expr( +DummyResult::raw_expr(sp,((Some(guar)))))}else if let Some(guar)=guar{MacEager:: +expr(DummyResult::raw_expr(sp,Some(guar)))}else{;let sp=cx.with_def_site_ctxt(sp +);loop{break;};if let _=(){};MacEager::expr(cx.expr_byte_str(sp,accumulator))})} diff --git a/compiler/rustc_builtin_macros/src/concat_idents.rs b/compiler/rustc_builtin_macros/src/concat_idents.rs index 3ddb0ae45b51a..ea1c2f936d6a6 100644 --- a/compiler/rustc_builtin_macros/src/concat_idents.rs +++ b/compiler/rustc_builtin_macros/src/concat_idents.rs @@ -1,72 +1,22 @@ -use rustc_ast::ptr::P; -use rustc_ast::token::{self, Token}; -use rustc_ast::tokenstream::{TokenStream, TokenTree}; -use rustc_ast::{AttrVec, Expr, ExprKind, Path, Ty, TyKind, DUMMY_NODE_ID}; -use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult}; -use rustc_span::symbol::{Ident, Symbol}; -use rustc_span::Span; - -use crate::errors; - -pub fn expand_concat_idents<'cx>( - cx: &'cx mut ExtCtxt<'_>, - sp: Span, - tts: TokenStream, -) -> MacroExpanderResult<'cx> { - if tts.is_empty() { - let guar = cx.dcx().emit_err(errors::ConcatIdentsMissingArgs { span: sp }); - return ExpandResult::Ready(DummyResult::any(sp, guar)); - } - - let mut res_str = String::new(); - for (i, e) in tts.trees().enumerate() { - if i & 1 == 1 { - match e { - TokenTree::Token(Token { kind: token::Comma, .. }, _) => {} - _ => { - let guar = cx.dcx().emit_err(errors::ConcatIdentsMissingComma { span: sp }); - return ExpandResult::Ready(DummyResult::any(sp, guar)); - } - } - } else { - if let TokenTree::Token(token, _) = e { - if let Some((ident, _)) = token.ident() { - res_str.push_str(ident.name.as_str()); - continue; - } - } - - let guar = cx.dcx().emit_err(errors::ConcatIdentsIdentArgs { span: sp }); - return ExpandResult::Ready(DummyResult::any(sp, guar)); - } - } - - let ident = Ident::new(Symbol::intern(&res_str), cx.with_call_site_ctxt(sp)); - - struct ConcatIdentsResult { - ident: Ident, - } - - impl MacResult for ConcatIdentsResult { - fn make_expr(self: Box) -> Option> { - Some(P(Expr { - id: DUMMY_NODE_ID, - kind: ExprKind::Path(None, Path::from_ident(self.ident)), - span: self.ident.span, - attrs: AttrVec::new(), - tokens: None, - })) - } - - fn make_ty(self: Box) -> Option> { - Some(P(Ty { - id: DUMMY_NODE_ID, - kind: TyKind::Path(None, Path::from_ident(self.ident)), - span: self.ident.span, - tokens: None, - })) - } - } - - ExpandResult::Ready(Box::new(ConcatIdentsResult { ident })) -} +use rustc_ast::ptr::P;use rustc_ast::token::{self,Token};use rustc_ast:://{();}; +tokenstream::{TokenStream,TokenTree};use rustc_ast::{AttrVec,Expr,ExprKind,Path +,Ty,TyKind,DUMMY_NODE_ID};use rustc_expand::base::{DummyResult,ExpandResult,//3; +ExtCtxt,MacResult,MacroExpanderResult};use rustc_span::symbol::{Ident,Symbol};// +use rustc_span::Span;use crate::errors; pub fn expand_concat_idents<'cx>(cx:&'cx +mut ExtCtxt<'_>,sp:Span,tts:TokenStream,)->MacroExpanderResult<'cx>{if tts.//(); +is_empty(){;let guar=cx.dcx().emit_err(errors::ConcatIdentsMissingArgs{span:sp}) +;;;return ExpandResult::Ready(DummyResult::any(sp,guar));}let mut res_str=String +::new();3;for(i,e)in tts.trees().enumerate(){if i&1==1{match e{TokenTree::Token( +Token{kind:token::Comma,..},_)=>{}_=>{*&*&();let guar=cx.dcx().emit_err(errors:: +ConcatIdentsMissingComma{span:sp});;return ExpandResult::Ready(DummyResult::any( +sp,guar));{;};}}}else{if let TokenTree::Token(token,_)=e{if let Some((ident,_))= +token.ident(){;res_str.push_str(ident.name.as_str());continue;}}let guar=cx.dcx( +).emit_err(errors::ConcatIdentsIdentArgs{span:sp});;;return ExpandResult::Ready( +DummyResult::any(sp,guar));;}};let ident=Ident::new(Symbol::intern(&res_str),cx. +with_call_site_ctxt(sp));;;struct ConcatIdentsResult{ident:Ident,}impl MacResult +for ConcatIdentsResult{fn make_expr(self:Box)->Option>{Some(P(//3; +Expr{id:DUMMY_NODE_ID,kind:(ExprKind::Path(None ,Path::from_ident(self.ident))), +span:self.ident.span,attrs:(AttrVec::new()),tokens:None,}))}fn make_ty(self:Box< +Self>)->Option>{Some(P(Ty{id:DUMMY_NODE_ID,kind:TyKind::Path(None,Path::// +from_ident(self.ident)),span:self.ident.span,tokens:None,}))}}{;};ExpandResult:: +Ready((((((((((Box::new((((((((((ConcatIdentsResult {ident}))))))))))))))))))))} diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs index 4f412cf79d91f..d0126f617df89 100644 --- a/compiler/rustc_builtin_macros/src/derive.rs +++ b/compiler/rustc_builtin_macros/src/derive.rs @@ -1,152 +1,42 @@ -use crate::cfg_eval::cfg_eval; -use crate::errors; - -use rustc_ast as ast; -use rustc_ast::{GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind}; -use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier}; -use rustc_feature::AttributeTemplate; -use rustc_parse::validate_attr; -use rustc_session::Session; -use rustc_span::symbol::{sym, Ident}; -use rustc_span::{ErrorGuaranteed, Span}; - -pub(crate) struct Expander(pub bool); - -impl MultiItemModifier for Expander { - fn expand( - &self, - ecx: &mut ExtCtxt<'_>, - span: Span, - meta_item: &ast::MetaItem, - item: Annotatable, - _: bool, - ) -> ExpandResult, Annotatable> { - let sess = ecx.sess; - if report_bad_target(sess, &item, span).is_err() { - // We don't want to pass inappropriate targets to derive macros to avoid - // follow up errors, all other errors below are recoverable. - return ExpandResult::Ready(vec![item]); - } - - let (sess, features) = (ecx.sess, ecx.ecfg.features); - let result = - ecx.resolver.resolve_derives(ecx.current_expansion.id, ecx.force_mode, &|| { - let template = - AttributeTemplate { list: Some("Trait1, Trait2, ..."), ..Default::default() }; - validate_attr::check_builtin_meta_item( - &sess.psess, - meta_item, - ast::AttrStyle::Outer, - sym::derive, - template, - ); - - let mut resolutions = match &meta_item.kind { - MetaItemKind::List(list) => { - list.iter() - .filter_map(|nested_meta| match nested_meta { - NestedMetaItem::MetaItem(meta) => Some(meta), - NestedMetaItem::Lit(lit) => { - // Reject `#[derive("Debug")]`. - report_unexpected_meta_item_lit(sess, lit); - None - } - }) - .map(|meta| { - // Reject `#[derive(Debug = "value", Debug(abc))]`, but recover the - // paths. - report_path_args(sess, meta); - meta.path.clone() - }) - .map(|path| (path, dummy_annotatable(), None, self.0)) - .collect() - } - _ => vec![], - }; - - // Do not configure or clone items unless necessary. - match &mut resolutions[..] { - [] => {} - [(_, first_item, ..), others @ ..] => { - *first_item = cfg_eval( - sess, - features, - item.clone(), - ecx.current_expansion.lint_node_id, - ); - for (_, item, _, _) in others { - *item = first_item.clone(); - } - } - } - - resolutions - }); - - match result { - Ok(()) => ExpandResult::Ready(vec![item]), - Err(Indeterminate) => ExpandResult::Retry(item), - } - } -} - -// The cheapest `Annotatable` to construct. -fn dummy_annotatable() -> Annotatable { - Annotatable::GenericParam(ast::GenericParam { - id: ast::DUMMY_NODE_ID, - ident: Ident::empty(), - attrs: Default::default(), - bounds: Default::default(), - is_placeholder: false, - kind: GenericParamKind::Lifetime, - colon_span: None, - }) -} - -fn report_bad_target( - sess: &Session, - item: &Annotatable, - span: Span, -) -> Result<(), ErrorGuaranteed> { - let item_kind = match item { - Annotatable::Item(item) => Some(&item.kind), - Annotatable::Stmt(stmt) => match &stmt.kind { - StmtKind::Item(item) => Some(&item.kind), - _ => None, - }, - _ => None, - }; - - let bad_target = - !matches!(item_kind, Some(ItemKind::Struct(..) | ItemKind::Enum(..) | ItemKind::Union(..))); - if bad_target { - return Err(sess.dcx().emit_err(errors::BadDeriveTarget { span, item: item.span() })); - } - Ok(()) -} - -fn report_unexpected_meta_item_lit(sess: &Session, lit: &ast::MetaItemLit) { - let help = match lit.kind { - ast::LitKind::Str(_, ast::StrStyle::Cooked) - if rustc_lexer::is_ident(lit.symbol.as_str()) => - { - errors::BadDeriveLitHelp::StrLit { sym: lit.symbol } - } - _ => errors::BadDeriveLitHelp::Other, - }; - sess.dcx().emit_err(errors::BadDeriveLit { span: lit.span, help }); -} - -fn report_path_args(sess: &Session, meta: &ast::MetaItem) { - let span = meta.span.with_lo(meta.path.span.hi()); - - match meta.kind { - MetaItemKind::Word => {} - MetaItemKind::List(..) => { - sess.dcx().emit_err(errors::DerivePathArgsList { span }); - } - MetaItemKind::NameValue(..) => { - sess.dcx().emit_err(errors::DerivePathArgsValue { span }); - } - } -} +use crate::cfg_eval::cfg_eval;use crate::errors;use rustc_ast as ast;use//{();}; +rustc_ast::{GenericParamKind,ItemKind, MetaItemKind,NestedMetaItem,StmtKind};use +rustc_expand::base::{Annotatable,ExpandResult,ExtCtxt,Indeterminate,//if true{}; +MultiItemModifier};use rustc_feature::AttributeTemplate;use rustc_parse:://({}); +validate_attr;use rustc_session::Session;use rustc_span::symbol::{sym,Ident};//; +use rustc_span::{ErrorGuaranteed,Span};pub( crate)struct Expander(pub bool);impl +MultiItemModifier for Expander{fn expand(&self,ecx:&mut ExtCtxt<'_>,span:Span,// +meta_item:&ast::MetaItem,item:Annotatable,_:bool,)->ExpandResult,Annotatable>{3;let sess=ecx.sess;3;if report_bad_target(sess,&item, +span).is_err(){;return ExpandResult::Ready(vec![item]);}let(sess,features)=(ecx. +sess,ecx.ecfg.features);{();};{();};let result=ecx.resolver.resolve_derives(ecx. +current_expansion.id,ecx.force_mode,&||{{;};let template=AttributeTemplate{list: +Some("Trait1, Trait2, ..."),..Default::default()};((),());*&*&();validate_attr:: +check_builtin_meta_item(&sess.psess,meta_item ,ast::AttrStyle::Outer,sym::derive +,template,);;let mut resolutions=match&meta_item.kind{MetaItemKind::List(list)=> +{list.iter(). filter_map(|nested_meta|match nested_meta{NestedMetaItem::MetaItem +(meta)=>Some(meta),NestedMetaItem::Lit(lit)=>{3;report_unexpected_meta_item_lit( +sess,lit);;None}}).map(|meta|{;report_path_args(sess,meta);;meta.path.clone()}). +map(|path|(path,dummy_annotatable(),None,self.0)).collect()}_=>vec![],};3;match& +mut resolutions[..]{[]=>{}[(_,first_item,..),others@..]=>{;*first_item=cfg_eval( +sess,features,item.clone(),ecx.current_expansion.lint_node_id,);;for(_,item,_,_) +in others{();*item=first_item.clone();3;}}}resolutions});3;match result{Ok(())=> +ExpandResult::Ready(vec![item]), Err(Indeterminate)=>ExpandResult::Retry(item),} +}}fn dummy_annotatable()->Annotatable{Annotatable::GenericParam(ast:://let _=(); +GenericParam{id:ast::DUMMY_NODE_ID,ident:Ident ::empty(),attrs:Default::default( +),bounds:((Default::default())),is_placeholder:((false)),kind:GenericParamKind:: +Lifetime,colon_span:None,})}fn report_bad_target(sess:&Session,item:&//let _=(); +Annotatable,span:Span,)->Result<(),ErrorGuaranteed>{();let item_kind=match item{ +Annotatable::Item(item)=>(Some(&item.kind)),Annotatable::Stmt(stmt)=>match&stmt. +kind{StmtKind::Item(item)=>Some(&item.kind),_=>None,},_=>None,};;let bad_target= +!matches!(item_kind,Some(ItemKind::Struct(..)|ItemKind::Enum(..)|ItemKind:://(); +Union(..)));((),());if bad_target{*&*&();return Err(sess.dcx().emit_err(errors:: +BadDeriveTarget{span,item:item.span()}));if let _=(){};*&*&();((),());}Ok(())}fn +report_unexpected_meta_item_lit(sess:&Session,lit:&ast::MetaItemLit){3;let help= +match lit.kind{ast::LitKind::Str(_,ast::StrStyle::Cooked)if rustc_lexer:://({}); +is_ident(lit.symbol.as_str()) =>{errors::BadDeriveLitHelp::StrLit{sym:lit.symbol +}}_=>errors::BadDeriveLitHelp::Other,};;sess.dcx().emit_err(errors::BadDeriveLit +{span:lit.span,help});;}fn report_path_args(sess:&Session,meta:&ast::MetaItem){; +let span=meta.span.with_lo(meta.path.span.hi());3;match meta.kind{MetaItemKind:: +Word=>{}MetaItemKind::List(..)=>{;sess.dcx().emit_err(errors::DerivePathArgsList +{span});*&*&();}MetaItemKind::NameValue(..)=>{{();};sess.dcx().emit_err(errors:: +DerivePathArgsValue{span});loop{break};loop{break;};loop{break};loop{break;};}}} diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs index 26ef3da3a915c..0700730ae1e67 100644 --- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs +++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs @@ -1,52 +1,14 @@ -use crate::deriving::generic::*; -use crate::deriving::path_std; - -use rustc_ast::MetaItem; -use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::Span; - -pub fn expand_deriving_copy( - cx: &ExtCtxt<'_>, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), - is_const: bool, -) { - let trait_def = TraitDef { - span, - path: path_std!(marker::Copy), - skip_path_as_bound: false, - needs_copy_as_bound_if_packed: false, - additional_bounds: Vec::new(), - supports_unions: true, - methods: Vec::new(), - associated_types: Vec::new(), - is_const, - }; - - trait_def.expand(cx, mitem, item, push); -} - -pub fn expand_deriving_const_param_ty( - cx: &ExtCtxt<'_>, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), - is_const: bool, -) { - let trait_def = TraitDef { - span, - path: path_std!(marker::ConstParamTy), - skip_path_as_bound: false, - needs_copy_as_bound_if_packed: false, - additional_bounds: vec![ty::Ty::Path(path_std!(cmp::Eq))], - supports_unions: false, - methods: Vec::new(), - associated_types: Vec::new(), - is_const, - }; - - trait_def.expand(cx, mitem, item, push); -} +use crate::deriving::generic::*;use crate::deriving::path_std;use rustc_ast:://; +MetaItem;use rustc_expand::base::{Annotatable ,ExtCtxt};use rustc_span::Span;pub +fn expand_deriving_copy(cx:&ExtCtxt<'_>,span:Span,mitem:&MetaItem,item:&//{();}; +Annotatable,push:&mut dyn FnMut(Annotatable),is_const:bool,){({});let trait_def= +TraitDef{span,path:(((path_std!(marker::Copy)))),skip_path_as_bound:(((false))), +needs_copy_as_bound_if_packed:((((false)))),additional_bounds: (((Vec::new()))), +supports_unions:true,methods:Vec::new(),associated_types:Vec::new(),is_const,};; +trait_def.expand(cx,mitem,item,push);;}pub fn expand_deriving_const_param_ty(cx: +&ExtCtxt<'_>,span:Span,mitem:&MetaItem,item:&Annotatable,push:&mut dyn FnMut(//; +Annotatable),is_const:bool,){3;let trait_def=TraitDef{span,path:path_std!(marker +::ConstParamTy),skip_path_as_bound:( false),needs_copy_as_bound_if_packed:false, +additional_bounds:vec![ty::Ty::Path(path_std! (cmp::Eq))],supports_unions:false, +methods:Vec::new(),associated_types:Vec::new(),is_const,};;;trait_def.expand(cx, +mitem,item,push);*&*&();((),());((),());((),());*&*&();((),());((),());((),());} diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index 0a44bd42b9173..6a98c26303c35 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -1,218 +1,60 @@ -use crate::deriving::generic::ty::*; -use crate::deriving::generic::*; -use crate::deriving::path_std; -use rustc_ast::{self as ast, Generics, ItemKind, MetaItem, VariantData}; -use rustc_data_structures::fx::FxHashSet; -use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::Span; -use thin_vec::{thin_vec, ThinVec}; - -pub fn expand_deriving_clone( - cx: &ExtCtxt<'_>, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), - is_const: bool, -) { - // The simple form is `fn clone(&self) -> Self { *self }`, possibly with - // some additional `AssertParamIsClone` assertions. - // - // We can use the simple form if either of the following are true. - // - The type derives Copy and there are no generic parameters. (If we - // used the simple form with generics, we'd have to bound the generics - // with Clone + Copy, and then there'd be no Clone impl at all if the - // user fills in something that is Clone but not Copy. After - // specialization we can remove this no-generics limitation.) - // - The item is a union. (Unions with generic parameters still can derive - // Clone because they require Copy for deriving, Clone alone is not - // enough. Whether Clone is implemented for fields is irrelevant so we - // don't assert it.) - let bounds; - let substructure; - let is_simple; - match item { - Annotatable::Item(annitem) => match &annitem.kind { - ItemKind::Struct(_, Generics { params, .. }) - | ItemKind::Enum(_, Generics { params, .. }) => { - let container_id = cx.current_expansion.id.expn_data().parent.expect_local(); - let has_derive_copy = cx.resolver.has_derive_copy(container_id); - if has_derive_copy - && !params - .iter() - .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })) - { - bounds = vec![]; - is_simple = true; - substructure = combine_substructure(Box::new(|c, s, sub| { - cs_clone_simple("Clone", c, s, sub, false) - })); - } else { - bounds = vec![]; - is_simple = false; - substructure = - combine_substructure(Box::new(|c, s, sub| cs_clone("Clone", c, s, sub))); - } - } - ItemKind::Union(..) => { - bounds = vec![Path(path_std!(marker::Copy))]; - is_simple = true; - substructure = combine_substructure(Box::new(|c, s, sub| { - cs_clone_simple("Clone", c, s, sub, true) - })); - } - _ => cx.dcx().span_bug(span, "`#[derive(Clone)]` on wrong item kind"), - }, - - _ => cx.dcx().span_bug(span, "`#[derive(Clone)]` on trait item or impl item"), - } - - let trait_def = TraitDef { - span, - path: path_std!(clone::Clone), - skip_path_as_bound: false, - needs_copy_as_bound_if_packed: true, - additional_bounds: bounds, - supports_unions: true, - methods: vec![MethodDef { - name: sym::clone, - generics: Bounds::empty(), - explicit_self: true, - nonself_args: Vec::new(), - ret_ty: Self_, - attributes: thin_vec![cx.attr_word(sym::inline, span)], - fieldless_variants_strategy: FieldlessVariantsStrategy::Default, - combine_substructure: substructure, - }], - associated_types: Vec::new(), - is_const, - }; - - trait_def.expand_ext(cx, mitem, item, push, is_simple) -} - -fn cs_clone_simple( - name: &str, - cx: &ExtCtxt<'_>, - trait_span: Span, - substr: &Substructure<'_>, - is_union: bool, -) -> BlockOrExpr { - let mut stmts = ThinVec::new(); - let mut seen_type_names = FxHashSet::default(); - let mut process_variant = |variant: &VariantData| { - for field in variant.fields() { - // This basic redundancy checking only prevents duplication of - // assertions like `AssertParamIsClone` where the type is a - // simple name. That's enough to get a lot of cases, though. - if let Some(name) = field.ty.kind.is_simple_path() - && !seen_type_names.insert(name) - { - // Already produced an assertion for this type. - // Anonymous structs or unions must be eliminated as they cannot be - // type parameters. - } else if !field.ty.kind.is_anon_adt() { - // let _: AssertParamIsClone; - super::assert_ty_bounds( - cx, - &mut stmts, - field.ty.clone(), - field.span, - &[sym::clone, sym::AssertParamIsClone], - ); - } - } - }; - - if is_union { - // Just a single assertion for unions, that the union impls `Copy`. - // let _: AssertParamIsCopy; - let self_ty = cx.ty_path(cx.path_ident(trait_span, Ident::with_dummy_span(kw::SelfUpper))); - super::assert_ty_bounds( - cx, - &mut stmts, - self_ty, - trait_span, - &[sym::clone, sym::AssertParamIsCopy], - ); - } else { - match *substr.fields { - StaticStruct(vdata, ..) => { - process_variant(vdata); - } - StaticEnum(enum_def, ..) => { - for variant in &enum_def.variants { - process_variant(&variant.data); - } - } - _ => cx.dcx().span_bug( - trait_span, - format!("unexpected substructure in simple `derive({name})`"), - ), - } - } - BlockOrExpr::new_mixed(stmts, Some(cx.expr_deref(trait_span, cx.expr_self(trait_span)))) -} - -fn cs_clone( - name: &str, - cx: &ExtCtxt<'_>, - trait_span: Span, - substr: &Substructure<'_>, -) -> BlockOrExpr { - let ctor_path; - let all_fields; - let fn_path = cx.std_path(&[sym::clone, sym::Clone, sym::clone]); - let subcall = |cx: &ExtCtxt<'_>, field: &FieldInfo| { - let args = thin_vec![field.self_expr.clone()]; - cx.expr_call_global(field.span, fn_path.clone(), args) - }; - - let vdata; - match substr.fields { - Struct(vdata_, af) => { - ctor_path = cx.path(trait_span, vec![substr.type_ident]); - all_fields = af; - vdata = *vdata_; - } - EnumMatching(.., variant, af) => { - ctor_path = cx.path(trait_span, vec![substr.type_ident, variant.ident]); - all_fields = af; - vdata = &variant.data; - } - EnumTag(..) | AllFieldlessEnum(..) => { - cx.dcx().span_bug(trait_span, format!("enum tags in `derive({name})`",)) - } - StaticEnum(..) | StaticStruct(..) => { - cx.dcx().span_bug(trait_span, format!("associated function in `derive({name})`")) - } - } - - let expr = match *vdata { - VariantData::Struct { .. } => { - let fields = all_fields - .iter() - .map(|field| { - let Some(ident) = field.name else { - cx.dcx().span_bug( - trait_span, - format!("unnamed field in normal struct in `derive({name})`",), - ); - }; - let call = subcall(cx, field); - cx.field_imm(field.span, ident, call) - }) - .collect::>(); - - cx.expr_struct(trait_span, ctor_path, fields) - } - VariantData::Tuple(..) => { - let subcalls = all_fields.iter().map(|f| subcall(cx, f)).collect(); - let path = cx.expr_path(ctor_path); - cx.expr_call(trait_span, path, subcalls) - } - VariantData::Unit(..) => cx.expr_path(ctor_path), - }; - BlockOrExpr::new_expr(expr) -} +use crate::deriving::generic::ty::*;use crate::deriving::generic::*;use crate:: +deriving::path_std;use rustc_ast::{self as ast,Generics,ItemKind,MetaItem,//{;}; +VariantData};use rustc_data_structures::fx:: FxHashSet;use rustc_expand::base::{ +Annotatable,ExtCtxt};use rustc_span::symbol::{kw,sym,Ident};use rustc_span:://3; +Span;use thin_vec::{thin_vec,ThinVec} ;pub fn expand_deriving_clone(cx:&ExtCtxt< +'_>,span:Span,mitem:&MetaItem,item :&Annotatable,push:&mut dyn FnMut(Annotatable +),is_const:bool,){3;let bounds;3;3;let substructure;;;let is_simple;;match item{ +Annotatable::Item(annitem)=>match((&annitem .kind)){ItemKind::Struct(_,Generics{ +params,..})|ItemKind::Enum(_,Generics{params,..})=>{((),());let container_id=cx. +current_expansion.id.expn_data().parent.expect_local();;;let has_derive_copy=cx. +resolver.has_derive_copy(container_id);;if has_derive_copy&&!params.iter().any(| +param|matches!(param.kind,ast::GenericParamKind::Type{..})){3;bounds=vec![];3;3; +is_simple=true;{();};{();};substructure=combine_substructure(Box::new(|c,s,sub|{ +cs_clone_simple("Clone",c,s,sub,false)}));;}else{;bounds=vec![];is_simple=false; +substructure=combine_substructure(Box::new(|c,s,sub| cs_clone("Clone",c,s,sub))) +;;}}ItemKind::Union(..)=>{;bounds=vec![Path(path_std!(marker::Copy))];is_simple= +true;();();substructure=combine_substructure(Box::new(|c,s,sub|{cs_clone_simple( +"Clone",c,s,sub,true)}));if let _=(){};if let _=(){};}_=>cx.dcx().span_bug(span, +"`#[derive(Clone)]` on wrong item kind"),},_=>((((( cx.dcx()))))).span_bug(span, +"`#[derive(Clone)]` on trait item or impl item"),}3;let trait_def=TraitDef{span, +path:(((((((path_std!(clone::Clone)))))))),skip_path_as_bound:((((((false)))))), +needs_copy_as_bound_if_packed:((true)),additional_bounds:bounds,supports_unions: +true,methods:vec![MethodDef{name:sym::clone,generics:Bounds::empty(),//let _=(); +explicit_self:true,nonself_args:Vec::new() ,ret_ty:Self_,attributes:thin_vec![cx +.attr_word(sym::inline,span)],fieldless_variants_strategy://if true{};if true{}; +FieldlessVariantsStrategy::Default,combine_substructure:substructure,}],//{();}; +associated_types:Vec::new(),is_const,};;trait_def.expand_ext(cx,mitem,item,push, +is_simple)}fn cs_clone_simple(name:&str, cx:&ExtCtxt<'_>,trait_span:Span,substr: +&Substructure<'_>,is_union:bool,)->BlockOrExpr{;let mut stmts=ThinVec::new();let +mut seen_type_names=FxHashSet::default();();3;let mut process_variant=|variant:& +VariantData|{for field in ((variant.fields())){ if let Some(name)=field.ty.kind. +is_simple_path()&&((!((seen_type_names.insert(name))) )){}else if!field.ty.kind. +is_anon_adt(){;super::assert_ty_bounds(cx,&mut stmts,field.ty.clone(),field.span +,&[sym::clone,sym::AssertParamIsClone],);;}}};if is_union{let self_ty=cx.ty_path +(cx.path_ident(trait_span,Ident::with_dummy_span(kw::SelfUpper)));{;};();super:: +assert_ty_bounds(cx,((((((&mut stmts)))))),self_ty,trait_span,&[sym::clone,sym:: +AssertParamIsCopy],);{;};}else{match*substr.fields{StaticStruct(vdata,..)=>{{;}; +process_variant(vdata);{();};}StaticEnum(enum_def,..)=>{for variant in&enum_def. +variants{();process_variant(&variant.data);();}}_=>cx.dcx().span_bug(trait_span, +format!("unexpected substructure in simple `derive({name})`"), ),}}BlockOrExpr:: +new_mixed(stmts,(Some((cx.expr_deref(trait_span,cx.expr_self(trait_span))))))}fn +cs_clone(name:&str,cx:&ExtCtxt<'_> ,trait_span:Span,substr:&Substructure<'_>,)-> +BlockOrExpr{;let ctor_path;;let all_fields;let fn_path=cx.std_path(&[sym::clone, +sym::Clone,sym::clone]);;let subcall=|cx:&ExtCtxt<'_>,field:&FieldInfo|{let args +=thin_vec![field.self_expr.clone()];({});cx.expr_call_global(field.span,fn_path. +clone(),args)};;;let vdata;match substr.fields{Struct(vdata_,af)=>{ctor_path=cx. +path(trait_span,vec![substr.type_ident]);3;3;all_fields=af;3;3;vdata=*vdata_;3;} +EnumMatching(..,variant,af)=>{let _=();ctor_path=cx.path(trait_span,vec![substr. +type_ident,variant.ident]);3;;all_fields=af;;;vdata=&variant.data;;}EnumTag(..)| +AllFieldlessEnum(..)=>{((((((((((cx.dcx())))))))))).span_bug(trait_span,format!( +"enum tags in `derive({name})`",))}StaticEnum(..)|StaticStruct(..)=>{(cx.dcx()). +span_bug(trait_span,format!("associated function in `derive({name})`"))}}{;};let +expr=match*vdata{VariantData::Struct{..}=>{();let fields=all_fields.iter().map(| +field|{3;let Some(ident)=field.name else{3;cx.dcx().span_bug(trait_span,format!( +"unnamed field in normal struct in `derive({name})`",),);;};let call=subcall(cx, +field);{;};cx.field_imm(field.span,ident,call)}).collect::>();{;};cx. +expr_struct(trait_span,ctor_path,fields)}VariantData::Tuple(..)=>{;let subcalls= +all_fields.iter().map(|f|subcall(cx,f)).collect();{;};{;};let path=cx.expr_path( +ctor_path);{;};cx.expr_call(trait_span,path,subcalls)}VariantData::Unit(..)=>cx. +expr_path(ctor_path),};if let _=(){};*&*&();((),());BlockOrExpr::new_expr(expr)} diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index 45c4467a1097c..26756463d9478 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -1,92 +1,25 @@ -use crate::deriving::generic::ty::*; -use crate::deriving::generic::*; -use crate::deriving::path_std; - -use rustc_ast::{self as ast, MetaItem}; -use rustc_data_structures::fx::FxHashSet; -use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::symbol::sym; -use rustc_span::Span; -use thin_vec::{thin_vec, ThinVec}; - -pub fn expand_deriving_eq( - cx: &ExtCtxt<'_>, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), - is_const: bool, -) { - let span = cx.with_def_site_ctxt(span); - - let trait_def = TraitDef { - span, - path: path_std!(cmp::Eq), - skip_path_as_bound: false, - needs_copy_as_bound_if_packed: true, - additional_bounds: Vec::new(), - supports_unions: true, - methods: vec![MethodDef { - name: sym::assert_receiver_is_total_eq, - generics: Bounds::empty(), - explicit_self: true, - nonself_args: vec![], - ret_ty: Unit, - attributes: thin_vec![ - cx.attr_word(sym::inline, span), - cx.attr_nested_word(sym::doc, sym::hidden, span), - cx.attr_nested_word(sym::coverage, sym::off, span) - ], - fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - cs_total_eq_assert(a, b, c) - })), - }], - associated_types: Vec::new(), - is_const, - }; - trait_def.expand_ext(cx, mitem, item, push, true) -} - -fn cs_total_eq_assert( - cx: &ExtCtxt<'_>, - trait_span: Span, - substr: &Substructure<'_>, -) -> BlockOrExpr { - let mut stmts = ThinVec::new(); - let mut seen_type_names = FxHashSet::default(); - let mut process_variant = |variant: &ast::VariantData| { - for field in variant.fields() { - // This basic redundancy checking only prevents duplication of - // assertions like `AssertParamIsEq` where the type is a - // simple name. That's enough to get a lot of cases, though. - if let Some(name) = field.ty.kind.is_simple_path() - && !seen_type_names.insert(name) - { - // Already produced an assertion for this type. - } else { - // let _: AssertParamIsEq; - super::assert_ty_bounds( - cx, - &mut stmts, - field.ty.clone(), - field.span, - &[sym::cmp, sym::AssertParamIsEq], - ); - } - } - }; - - match *substr.fields { - StaticStruct(vdata, ..) => { - process_variant(vdata); - } - StaticEnum(enum_def, ..) => { - for variant in &enum_def.variants { - process_variant(&variant.data); - } - } - _ => cx.dcx().span_bug(trait_span, "unexpected substructure in `derive(Eq)`"), - } - BlockOrExpr::new_stmts(stmts) -} +use crate::deriving::generic::ty::*;use crate::deriving::generic::*;use crate:: +deriving::path_std;use rustc_ast::{self as ast,MetaItem};use//let _=();let _=(); +rustc_data_structures::fx::FxHashSet;use rustc_expand::base::{Annotatable,//{;}; +ExtCtxt};use rustc_span::symbol::sym;use rustc_span::Span;use thin_vec::{//({}); +thin_vec,ThinVec};pub fn expand_deriving_eq(cx:&ExtCtxt<'_>,span:Span,mitem:&//; +MetaItem,item:&Annotatable,push:&mut dyn FnMut(Annotatable),is_const:bool,){;let +span=cx.with_def_site_ctxt(span);3;3;let trait_def=TraitDef{span,path:path_std!( +cmp::Eq),skip_path_as_bound:((( false))),needs_copy_as_bound_if_packed:((true)), +additional_bounds:(Vec::new()),supports_unions:true,methods:vec![MethodDef{name: +sym::assert_receiver_is_total_eq,generics:Bounds::empty(),explicit_self:true,//; +nonself_args:vec![],ret_ty:Unit,attributes:thin_vec![cx.attr_word(sym::inline,// +span),cx.attr_nested_word(sym::doc,sym::hidden,span),cx.attr_nested_word(sym::// +coverage,sym::off,span)],fieldless_variants_strategy:FieldlessVariantsStrategy// +::Unify,combine_substructure:combine_substructure(Box::new(|a,b,c|{//let _=||(); +cs_total_eq_assert(a,b,c)})),}],associated_types:Vec::new(),is_const,};let _=(); +trait_def.expand_ext(cx,mitem,item,push, true)}fn cs_total_eq_assert(cx:&ExtCtxt +<'_>,trait_span:Span,substr:&Substructure<'_>,)->BlockOrExpr{({});let mut stmts= +ThinVec::new();{;};();let mut seen_type_names=FxHashSet::default();();();let mut +process_variant=|variant:&ast::VariantData|{for field in (variant.fields()){if +let Some(name)=(field.ty.kind.is_simple_path())&&!seen_type_names.insert(name){} +else{3;super::assert_ty_bounds(cx,&mut stmts,field.ty.clone(),field.span,&[sym:: +cmp,sym::AssertParamIsEq],);;}}};;match*substr.fields{StaticStruct(vdata,..)=>{; +process_variant(vdata);{();};}StaticEnum(enum_def,..)=>{for variant in&enum_def. +variants{();process_variant(&variant.data);();}}_=>cx.dcx().span_bug(trait_span, +"unexpected substructure in `derive(Eq)`"),}(((BlockOrExpr::new_stmts(stmts))))} diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs index 1d7a69540ab89..99490d8dbea16 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs @@ -1,79 +1,25 @@ -use crate::deriving::generic::ty::*; -use crate::deriving::generic::*; -use crate::deriving::path_std; -use rustc_ast::MetaItem; -use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::symbol::{sym, Ident}; -use rustc_span::Span; -use thin_vec::thin_vec; - -pub fn expand_deriving_ord( - cx: &ExtCtxt<'_>, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), - is_const: bool, -) { - let trait_def = TraitDef { - span, - path: path_std!(cmp::Ord), - skip_path_as_bound: false, - needs_copy_as_bound_if_packed: true, - additional_bounds: Vec::new(), - supports_unions: false, - methods: vec![MethodDef { - name: sym::cmp, - generics: Bounds::empty(), - explicit_self: true, - nonself_args: vec![(self_ref(), sym::other)], - ret_ty: Path(path_std!(cmp::Ordering)), - attributes: thin_vec![cx.attr_word(sym::inline, span)], - fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, - combine_substructure: combine_substructure(Box::new(|a, b, c| cs_cmp(a, b, c))), - }], - associated_types: Vec::new(), - is_const, - }; - - trait_def.expand(cx, mitem, item, push) -} - -pub fn cs_cmp(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr { - let test_id = Ident::new(sym::cmp, span); - let equal_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal])); - let cmp_path = cx.std_path(&[sym::cmp, sym::Ord, sym::cmp]); - - // Builds: - // - // match ::core::cmp::Ord::cmp(&self.x, &other.x) { - // ::std::cmp::Ordering::Equal => - // ::core::cmp::Ord::cmp(&self.y, &other.y), - // cmp => cmp, - // } - let expr = cs_fold( - // foldr nests the if-elses correctly, leaving the first field - // as the outermost one, and the last as the innermost. - false, - cx, - span, - substr, - |cx, fold| match fold { - CsFold::Single(field) => { - let [other_expr] = &field.other_selflike_exprs[..] else { - cx.dcx().span_bug(field.span, "not exactly 2 arguments in `derive(Ord)`"); - }; - let args = thin_vec![field.self_expr.clone(), other_expr.clone()]; - cx.expr_call_global(field.span, cmp_path.clone(), args) - } - CsFold::Combine(span, expr1, expr2) => { - let eq_arm = cx.arm(span, cx.pat_path(span, equal_path.clone()), expr1); - let neq_arm = - cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id)); - cx.expr_match(span, expr2, thin_vec![eq_arm, neq_arm]) - } - CsFold::Fieldless => cx.expr_path(equal_path.clone()), - }, - ); - BlockOrExpr::new_expr(expr) -} +use crate::deriving::generic::ty::*;use crate::deriving::generic::*;use crate:: +deriving::path_std;use rustc_ast::MetaItem ;use rustc_expand::base::{Annotatable +,ExtCtxt};use rustc_span::symbol::{sym ,Ident};use rustc_span::Span;use thin_vec +::thin_vec;pub fn expand_deriving_ord(cx:& ExtCtxt<'_>,span:Span,mitem:&MetaItem +,item:&Annotatable,push:&mut dyn FnMut(Annotatable),is_const:bool,){let _=();let +trait_def=TraitDef{span,path:((path_std!(cmp::Ord))),skip_path_as_bound:(false), +needs_copy_as_bound_if_packed:true,additional_bounds: Vec::new(),supports_unions +:(((((false))))),methods:vec![MethodDef{ name:sym::cmp,generics:Bounds::empty(), +explicit_self:true,nonself_args:vec![(self_ref(),sym::other)],ret_ty:Path(//{;}; +path_std!(cmp::Ordering)),attributes:thin_vec! [cx.attr_word(sym::inline,span)], +fieldless_variants_strategy:FieldlessVariantsStrategy::Unify,//((),());let _=(); +combine_substructure:combine_substructure(Box::new(|a,b,c|cs_cmp(a,b,c))),}],//; +associated_types:Vec::new(),is_const,};;trait_def.expand(cx,mitem,item,push)}pub +fn cs_cmp(cx:&ExtCtxt<'_>,span:Span,substr:&Substructure<'_>)->BlockOrExpr{3;let +test_id=Ident::new(sym::cmp,span);{;};{;};let equal_path=cx.path_global(span,cx. +std_path(&[sym::cmp,sym::Ordering,sym::Equal]));;;let cmp_path=cx.std_path(&[sym +::cmp,sym::Ord,sym::cmp]);;;let expr=cs_fold(false,cx,span,substr,|cx,fold|match +fold{CsFold::Single(field)=>{{;};let[other_expr]=&field.other_selflike_exprs[..] +else{;cx.dcx().span_bug(field.span,"not exactly 2 arguments in `derive(Ord)`");} +;({});{;};let args=thin_vec![field.self_expr.clone(),other_expr.clone()];{;};cx. +expr_call_global(field.span,(cmp_path.clone()),args)}CsFold::Combine(span,expr1, +expr2)=>{;let eq_arm=cx.arm(span,cx.pat_path(span,equal_path.clone()),expr1);let +neq_arm=cx.arm(span,cx.pat_ident(span,test_id),cx.expr_ident(span,test_id));3;cx +.expr_match(span,expr2,((((thin_vec![eq_arm,neq_arm])))))}CsFold::Fieldless=>cx. +expr_path(equal_path.clone()),},);let _=();let _=();BlockOrExpr::new_expr(expr)} 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 234918ae42961..ee49312afbafe 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -1,116 +1,30 @@ -use crate::deriving::generic::ty::*; -use crate::deriving::generic::*; -use crate::deriving::{path_local, path_std}; -use rustc_ast::ptr::P; -use rustc_ast::{BinOpKind, BorrowKind, Expr, ExprKind, MetaItem, Mutability}; -use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::symbol::sym; -use rustc_span::Span; -use thin_vec::thin_vec; - -pub fn expand_deriving_partial_eq( - cx: &ExtCtxt<'_>, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), - is_const: bool, -) { - fn cs_eq(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr { - let base = true; - let expr = cs_fold( - true, // use foldl - cx, - span, - substr, - |cx, fold| match fold { - CsFold::Single(field) => { - let [other_expr] = &field.other_selflike_exprs[..] else { - cx.dcx() - .span_bug(field.span, "not exactly 2 arguments in `derive(PartialEq)`"); - }; - - // We received arguments of type `&T`. Convert them to type `T` by stripping - // any leading `&` or adding `*`. This isn't necessary for type checking, but - // it results in better error messages if something goes wrong. - // - // Note: for arguments that look like `&{ x }`, which occur with packed - // structs, this would cause expressions like `{ self.x } == { other.x }`, - // which isn't valid Rust syntax. This wouldn't break compilation because these - // AST nodes are constructed within the compiler. But it would mean that code - // printed by `-Zunpretty=expanded` (or `cargo expand`) would have invalid - // syntax, which would be suboptimal. So we wrap these in parens, giving - // `({ self.x }) == ({ other.x })`, which is valid syntax. - let convert = |expr: &P| { - if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = - &expr.kind - { - if let ExprKind::Block(..) = &inner.kind { - // `&{ x }` form: remove the `&`, add parens. - cx.expr_paren(field.span, inner.clone()) - } else { - // `&x` form: remove the `&`. - inner.clone() - } - } else { - // No leading `&`: add a leading `*`. - cx.expr_deref(field.span, expr.clone()) - } - }; - cx.expr_binary( - field.span, - BinOpKind::Eq, - convert(&field.self_expr), - convert(other_expr), - ) - } - CsFold::Combine(span, expr1, expr2) => { - cx.expr_binary(span, BinOpKind::And, expr1, expr2) - } - CsFold::Fieldless => cx.expr_bool(span, base), - }, - ); - BlockOrExpr::new_expr(expr) - } - - let structural_trait_def = TraitDef { - span, - path: path_std!(marker::StructuralPartialEq), - skip_path_as_bound: true, // crucial! - needs_copy_as_bound_if_packed: false, - additional_bounds: Vec::new(), - // We really don't support unions, but that's already checked by the impl generated below; - // a second check here would lead to redundant error messages. - supports_unions: true, - methods: Vec::new(), - associated_types: Vec::new(), - is_const: false, - }; - structural_trait_def.expand(cx, mitem, item, push); - - // No need to generate `ne`, the default suffices, and not generating it is - // faster. - let methods = vec![MethodDef { - name: sym::eq, - generics: Bounds::empty(), - explicit_self: true, - nonself_args: vec![(self_ref(), sym::other)], - ret_ty: Path(path_local!(bool)), - attributes: thin_vec![cx.attr_word(sym::inline, span)], - fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, - combine_substructure: combine_substructure(Box::new(|a, b, c| cs_eq(a, b, c))), - }]; - - let trait_def = TraitDef { - span, - path: path_std!(cmp::PartialEq), - skip_path_as_bound: false, - needs_copy_as_bound_if_packed: true, - additional_bounds: Vec::new(), - supports_unions: false, - methods, - associated_types: Vec::new(), - is_const, - }; - trait_def.expand(cx, mitem, item, push) -} +use crate::deriving::generic::ty::*;use crate::deriving::generic::*;use crate:: +deriving::{path_local,path_std};use rustc_ast ::ptr::P;use rustc_ast::{BinOpKind +,BorrowKind,Expr,ExprKind,MetaItem,Mutability};use rustc_expand::base::{//{();}; +Annotatable,ExtCtxt};use rustc_span::symbol::sym;use rustc_span::Span;use//({}); +thin_vec::thin_vec;pub fn expand_deriving_partial_eq(cx :&ExtCtxt<'_>,span:Span, +mitem:&MetaItem,item:&Annotatable,push:&mut dyn FnMut(Annotatable),is_const://3; +bool,){let _=||();fn cs_eq(cx:&ExtCtxt<'_>,span:Span,substr:&Substructure<'_>)-> +BlockOrExpr{;let base=true;;;let expr=cs_fold(true,cx,span,substr,|cx,fold|match +fold{CsFold::Single(field)=>{{;};let[other_expr]=&field.other_selflike_exprs[..] +else{let _=||();loop{break};let _=||();loop{break};cx.dcx().span_bug(field.span, +"not exactly 2 arguments in `derive(PartialEq)`");;};let convert=|expr:&P| +{if let ExprKind::AddrOf(BorrowKind::Ref,Mutability ::Not,inner)=(&expr.kind){if +let ExprKind::Block(..)=(&inner.kind){(cx.expr_paren(field.span,inner.clone()))} +else{inner.clone()}}else{cx.expr_deref(field.span,expr.clone())}};let _=||();cx. +expr_binary(field.span,BinOpKind::Eq,((convert (((&field.self_expr))))),convert( +other_expr),)}CsFold::Combine(span, expr1,expr2)=>{cx.expr_binary(span,BinOpKind +::And,expr1,expr2)}CsFold::Fieldless=>cx.expr_bool(span,base),},);;BlockOrExpr:: +new_expr(expr)}3;;let structural_trait_def=TraitDef{span,path:path_std!(marker:: +StructuralPartialEq),skip_path_as_bound: ((true)),needs_copy_as_bound_if_packed: +false,additional_bounds:(Vec::new()),supports_unions :(true),methods:Vec::new(), +associated_types:Vec::new(),is_const:false,};3;3;structural_trait_def.expand(cx, +mitem,item,push);;let methods=vec![MethodDef{name:sym::eq,generics:Bounds::empty +(),explicit_self:true,nonself_args:vec![(self_ref(),sym::other)],ret_ty:Path(//; +path_local!(bool)),attributes:thin_vec![cx.attr_word(sym::inline,span)],//{();}; +fieldless_variants_strategy:FieldlessVariantsStrategy::Unify,//((),());let _=(); +combine_substructure:combine_substructure(Box::new(|a,b,c|cs_eq(a,b,c))),}];;let +trait_def=TraitDef{span,path:(((path_std!(cmp::PartialEq)))),skip_path_as_bound: +false,needs_copy_as_bound_if_packed:(((true))),additional_bounds:((Vec::new())), +supports_unions:false,methods,associated_types:Vec::new(),is_const,};;trait_def. +expand(cx,mitem,item,push)}//loop{break};loop{break;};loop{break;};loop{break;}; 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 49fe89b18b091..d230528559334 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -1,156 +1,38 @@ -use crate::deriving::generic::ty::*; -use crate::deriving::generic::*; -use crate::deriving::{path_std, pathvec_std}; -use rustc_ast::{ExprKind, ItemKind, MetaItem, PatKind}; -use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::symbol::{sym, Ident}; -use rustc_span::Span; -use thin_vec::thin_vec; - -pub fn expand_deriving_partial_ord( - cx: &ExtCtxt<'_>, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), - is_const: bool, -) { - let ordering_ty = Path(path_std!(cmp::Ordering)); - let ret_ty = - Path(Path::new_(pathvec_std!(option::Option), vec![Box::new(ordering_ty)], PathKind::Std)); - - // Order in which to perform matching - let tag_then_data = if let Annotatable::Item(item) = item - && let ItemKind::Enum(def, _) = &item.kind - { - let dataful: Vec = def.variants.iter().map(|v| !v.data.fields().is_empty()).collect(); - match dataful.iter().filter(|&&b| b).count() { - // No data, placing the tag check first makes codegen simpler - 0 => true, - 1..=2 => false, - _ => (0..dataful.len() - 1).any(|i| { - if dataful[i] - && let Some(idx) = dataful[i + 1..].iter().position(|v| *v) - { - idx >= 2 - } else { - false - } - }), - } - } else { - true - }; - let partial_cmp_def = MethodDef { - name: sym::partial_cmp, - generics: Bounds::empty(), - explicit_self: true, - nonself_args: vec![(self_ref(), sym::other)], - ret_ty, - attributes: thin_vec![cx.attr_word(sym::inline, span)], - fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, - combine_substructure: combine_substructure(Box::new(|cx, span, substr| { - cs_partial_cmp(cx, span, substr, tag_then_data) - })), - }; - - let trait_def = TraitDef { - span, - path: path_std!(cmp::PartialOrd), - skip_path_as_bound: false, - needs_copy_as_bound_if_packed: true, - additional_bounds: vec![], - supports_unions: false, - methods: vec![partial_cmp_def], - associated_types: Vec::new(), - is_const, - }; - trait_def.expand(cx, mitem, item, push) -} - -fn cs_partial_cmp( - cx: &ExtCtxt<'_>, - span: Span, - substr: &Substructure<'_>, - tag_then_data: bool, -) -> BlockOrExpr { - let test_id = Ident::new(sym::cmp, span); - let equal_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal])); - let partial_cmp_path = cx.std_path(&[sym::cmp, sym::PartialOrd, sym::partial_cmp]); - - // Builds: - // - // match ::core::cmp::PartialOrd::partial_cmp(&self.x, &other.x) { - // ::core::option::Option::Some(::core::cmp::Ordering::Equal) => - // ::core::cmp::PartialOrd::partial_cmp(&self.y, &other.y), - // cmp => cmp, - // } - let expr = cs_fold( - // foldr nests the if-elses correctly, leaving the first field - // as the outermost one, and the last as the innermost. - false, - cx, - span, - substr, - |cx, fold| match fold { - CsFold::Single(field) => { - let [other_expr] = &field.other_selflike_exprs[..] else { - cx.dcx().span_bug(field.span, "not exactly 2 arguments in `derive(Ord)`"); - }; - let args = thin_vec![field.self_expr.clone(), other_expr.clone()]; - cx.expr_call_global(field.span, partial_cmp_path.clone(), args) - } - CsFold::Combine(span, mut expr1, expr2) => { - // When the item is an enum, this expands to - // ``` - // match (expr2) { - // Some(Ordering::Equal) => expr1, - // cmp => cmp - // } - // ``` - // where `expr2` is `partial_cmp(self_tag, other_tag)`, and `expr1` is a `match` - // against the enum variants. This means that we begin by comparing the enum tags, - // before either inspecting their contents (if they match), or returning - // the `cmp::Ordering` of comparing the enum tags. - // ``` - // match partial_cmp(self_tag, other_tag) { - // Some(Ordering::Equal) => match (self, other) { - // (Self::A(self_0), Self::A(other_0)) => partial_cmp(self_0, other_0), - // (Self::B(self_0), Self::B(other_0)) => partial_cmp(self_0, other_0), - // _ => Some(Ordering::Equal) - // } - // cmp => cmp - // } - // ``` - // If we have any certain enum layouts, flipping this results in better codegen - // ``` - // match (self, other) { - // (Self::A(self_0), Self::A(other_0)) => partial_cmp(self_0, other_0), - // _ => partial_cmp(self_tag, other_tag) - // } - // ``` - // Reference: https://github.com/rust-lang/rust/pull/103659#issuecomment-1328126354 - - if !tag_then_data - && let ExprKind::Match(_, arms, _) = &mut expr1.kind - && let Some(last) = arms.last_mut() - && let PatKind::Wild = last.pat.kind - { - last.body = Some(expr2); - expr1 - } else { - let eq_arm = cx.arm( - span, - cx.pat_some(span, cx.pat_path(span, equal_path.clone())), - expr1, - ); - let neq_arm = - cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id)); - cx.expr_match(span, expr2, thin_vec![eq_arm, neq_arm]) - } - } - CsFold::Fieldless => cx.expr_some(span, cx.expr_path(equal_path.clone())), - }, - ); - BlockOrExpr::new_expr(expr) -} +use crate::deriving::generic::ty::*;use crate::deriving::generic::*;use crate:: +deriving::{path_std,pathvec_std};use rustc_ast::{ExprKind,ItemKind,MetaItem,//3; +PatKind};use rustc_expand::base::{ Annotatable,ExtCtxt};use rustc_span::symbol:: +{sym,Ident};use rustc_span::Span;use thin_vec::thin_vec;pub fn//((),());((),()); +expand_deriving_partial_ord(cx:&ExtCtxt<'_>,span:Span,mitem:&MetaItem,item:&//3; +Annotatable,push:&mut dyn FnMut(Annotatable),is_const:bool,){();let ordering_ty= +Path(path_std!(cmp::Ordering));;let ret_ty=Path(Path::new_(pathvec_std!(option:: +Option),vec![Box::new(ordering_ty)],PathKind::Std));3;3;let tag_then_data=if let +Annotatable::Item(item)=item&&let ItemKind::Enum(def,_)=&item.kind{;let dataful: +Vec=def.variants.iter().map(|v|!v.data.fields().is_empty()).collect();{;}; +match dataful.iter().filter(|&&b|b).count(){ 0=>true,1..=2=>false,_=>(0..dataful +.len()-1).any(|i|{if dataful[i]&&let Some(idx)=dataful[i+1..].iter().position(| +v|*v){idx>=2}else{false}}),}}else{true};;;let partial_cmp_def=MethodDef{name:sym +::partial_cmp,generics:(Bounds::empty()), explicit_self:true,nonself_args:vec![( +self_ref(),sym::other)],ret_ty,attributes:thin_vec![cx.attr_word(sym::inline,//; +span)],fieldless_variants_strategy:FieldlessVariantsStrategy::Unify,//if true{}; +combine_substructure:combine_substructure(Box::new(|cx,span,substr|{//if true{}; +cs_partial_cmp(cx,span,substr,tag_then_data)})),};;;let trait_def=TraitDef{span, +path:((((((path_std!(cmp::PartialOrd ))))))),skip_path_as_bound:(((((false))))), +needs_copy_as_bound_if_packed:(true),additional_bounds:(vec![]),supports_unions: +false,methods:vec![partial_cmp_def],associated_types:Vec::new(),is_const,};({}); +trait_def.expand(cx,mitem,item,push)}fn cs_partial_cmp(cx:&ExtCtxt<'_>,span://3; +Span,substr:&Substructure<'_>,tag_then_data:bool,)->BlockOrExpr{{;};let test_id= +Ident::new(sym::cmp,span);;;let equal_path=cx.path_global(span,cx.std_path(&[sym +::cmp,sym::Ordering,sym::Equal]));;;let partial_cmp_path=cx.std_path(&[sym::cmp, +sym::PartialOrd,sym::partial_cmp]);3;;let expr=cs_fold(false,cx,span,substr,|cx, +fold|match fold{CsFold::Single(field)=>{((),());let _=();let[other_expr]=&field. +other_selflike_exprs[..]else{let _=||();let _=||();cx.dcx().span_bug(field.span, +"not exactly 2 arguments in `derive(Ord)`");();};();();let args=thin_vec![field. +self_expr.clone(),other_expr.clone()];let _=||();cx.expr_call_global(field.span, +partial_cmp_path.clone(),args)}CsFold::Combine(span,mut expr1,expr2)=>{if!//{;}; +tag_then_data&&let ExprKind::Match(_,arms,_)=( &mut expr1.kind)&&let Some(last)= +arms.last_mut()&&let PatKind::Wild=last.pat.kind{3;last.body=Some(expr2);;expr1} +else{;let eq_arm=cx.arm(span,cx.pat_some(span,cx.pat_path(span,equal_path.clone( +))),expr1,);3;;let neq_arm=cx.arm(span,cx.pat_ident(span,test_id),cx.expr_ident( +span,test_id));{;};cx.expr_match(span,expr2,thin_vec![eq_arm,neq_arm])}}CsFold:: +Fieldless=>cx.expr_some(span,cx.expr_path(equal_path.clone())),},);3;BlockOrExpr +::new_expr(expr)}//*&*&();((),());*&*&();((),());*&*&();((),());((),());((),()); diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index e442b3520b275..b11b5b1d49a0b 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -1,240 +1,73 @@ -use crate::deriving::generic::ty::*; -use crate::deriving::generic::*; -use crate::deriving::path_std; - -use rustc_ast::{self as ast, EnumDef, MetaItem}; -use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::symbol::{sym, Ident, Symbol}; -use rustc_span::Span; -use thin_vec::{thin_vec, ThinVec}; - -pub fn expand_deriving_debug( - cx: &ExtCtxt<'_>, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), - is_const: bool, -) { - // &mut ::std::fmt::Formatter - let fmtr = Ref(Box::new(Path(path_std!(fmt::Formatter))), ast::Mutability::Mut); - - let trait_def = TraitDef { - span, - path: path_std!(fmt::Debug), - skip_path_as_bound: false, - needs_copy_as_bound_if_packed: true, - additional_bounds: Vec::new(), - supports_unions: false, - methods: vec![MethodDef { - name: sym::fmt, - generics: Bounds::empty(), - explicit_self: true, - nonself_args: vec![(fmtr, sym::f)], - ret_ty: Path(path_std!(fmt::Result)), - attributes: thin_vec![cx.attr_word(sym::inline, span)], - fieldless_variants_strategy: - FieldlessVariantsStrategy::SpecializeIfAllVariantsFieldless, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - show_substructure(a, b, c) - })), - }], - associated_types: Vec::new(), - is_const, - }; - trait_def.expand(cx, mitem, item, push) -} - -fn show_substructure(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr { - // We want to make sure we have the ctxt set so that we can use unstable methods - let span = cx.with_def_site_ctxt(span); - - let (ident, vdata, fields) = match substr.fields { - Struct(vdata, fields) => (substr.type_ident, *vdata, fields), - EnumMatching(_, v, fields) => (v.ident, &v.data, fields), - AllFieldlessEnum(enum_def) => return show_fieldless_enum(cx, span, enum_def, substr), - EnumTag(..) | StaticStruct(..) | StaticEnum(..) => { - cx.dcx().span_bug(span, "nonsensical .fields in `#[derive(Debug)]`") - } - }; - - let name = cx.expr_str(span, ident.name); - let fmt = substr.nonselflike_args[0].clone(); - - // Struct and tuples are similar enough that we use the same code for both, - // with some extra pieces for structs due to the field names. - let (is_struct, args_per_field) = match vdata { - ast::VariantData::Unit(..) => { - // Special fast path for unit variants. - assert!(fields.is_empty()); - (false, 0) - } - ast::VariantData::Tuple(..) => (false, 1), - ast::VariantData::Struct { .. } => (true, 2), - }; - - // The number of fields that can be handled without an array. - const CUTOFF: usize = 5; - - fn expr_for_field( - cx: &ExtCtxt<'_>, - field: &FieldInfo, - index: usize, - len: usize, - ) -> ast::ptr::P { - if index < len - 1 { - field.self_expr.clone() - } else { - // Unsized types need an extra indirection, but only the last field - // may be unsized. - cx.expr_addr_of(field.span, field.self_expr.clone()) - } - } - - if fields.is_empty() { - // Special case for no fields. - let fn_path_write_str = cx.std_path(&[sym::fmt, sym::Formatter, sym::write_str]); - let expr = cx.expr_call_global(span, fn_path_write_str, thin_vec![fmt, name]); - BlockOrExpr::new_expr(expr) - } else if fields.len() <= CUTOFF { - // Few enough fields that we can use a specific-length method. - let debug = if is_struct { - format!("debug_struct_field{}_finish", fields.len()) - } else { - format!("debug_tuple_field{}_finish", fields.len()) - }; - let fn_path_debug = cx.std_path(&[sym::fmt, sym::Formatter, Symbol::intern(&debug)]); - - let mut args = ThinVec::with_capacity(2 + fields.len() * args_per_field); - args.extend([fmt, name]); - for i in 0..fields.len() { - let field = &fields[i]; - if is_struct { - let name = cx.expr_str(field.span, field.name.unwrap().name); - args.push(name); - } - - let field = expr_for_field(cx, field, i, fields.len()); - args.push(field); - } - let expr = cx.expr_call_global(span, fn_path_debug, args); - BlockOrExpr::new_expr(expr) - } else { - // Enough fields that we must use the any-length method. - let mut name_exprs = ThinVec::with_capacity(fields.len()); - let mut value_exprs = ThinVec::with_capacity(fields.len()); - - for i in 0..fields.len() { - let field = &fields[i]; - if is_struct { - name_exprs.push(cx.expr_str(field.span, field.name.unwrap().name)); - } - - let field = expr_for_field(cx, field, i, fields.len()); - value_exprs.push(field); - } - - // `let names: &'static _ = &["field1", "field2"];` - let names_let = is_struct.then(|| { - let lt_static = Some(cx.lifetime_static(span)); - let ty_static_ref = cx.ty_ref(span, cx.ty_infer(span), lt_static, ast::Mutability::Not); - cx.stmt_let_ty( - span, - false, - Ident::new(sym::names, span), - Some(ty_static_ref), - cx.expr_array_ref(span, name_exprs), - ) - }); - - // `let values: &[&dyn Debug] = &[&&self.field1, &&self.field2];` - let path_debug = cx.path_global(span, cx.std_path(&[sym::fmt, sym::Debug])); - let ty_dyn_debug = cx.ty( - span, - ast::TyKind::TraitObject( - vec![cx.trait_bound(path_debug, false)], - ast::TraitObjectSyntax::Dyn, - ), - ); - let ty_slice = cx.ty( - span, - ast::TyKind::Slice(cx.ty_ref(span, ty_dyn_debug, None, ast::Mutability::Not)), - ); - let values_let = cx.stmt_let_ty( - span, - false, - Ident::new(sym::values, span), - Some(cx.ty_ref(span, ty_slice, None, ast::Mutability::Not)), - cx.expr_array_ref(span, value_exprs), - ); - - // `fmt::Formatter::debug_struct_fields_finish(fmt, name, names, values)` or - // `fmt::Formatter::debug_tuple_fields_finish(fmt, name, values)` - let sym_debug = if is_struct { - sym::debug_struct_fields_finish - } else { - sym::debug_tuple_fields_finish - }; - let fn_path_debug_internal = cx.std_path(&[sym::fmt, sym::Formatter, sym_debug]); - - let mut args = ThinVec::with_capacity(4); - args.push(fmt); - args.push(name); - if is_struct { - args.push(cx.expr_ident(span, Ident::new(sym::names, span))); - } - args.push(cx.expr_ident(span, Ident::new(sym::values, span))); - let expr = cx.expr_call_global(span, fn_path_debug_internal, args); - - let mut stmts = ThinVec::with_capacity(2); - if is_struct { - stmts.push(names_let.unwrap()); - } - stmts.push(values_let); - BlockOrExpr::new_mixed(stmts, Some(expr)) - } -} - -/// Special case for enums with no fields. Builds: -/// ```text -/// impl ::core::fmt::Debug for A { -/// fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { -/// ::core::fmt::Formatter::write_str(f, -/// match self { -/// A::A => "A", -/// A::B() => "B", -/// A::C {} => "C", -/// }) -/// } -/// } -/// ``` -fn show_fieldless_enum( - cx: &ExtCtxt<'_>, - span: Span, - def: &EnumDef, - substr: &Substructure<'_>, -) -> BlockOrExpr { - let fmt = substr.nonselflike_args[0].clone(); - let arms = def - .variants - .iter() - .map(|v| { - let variant_path = cx.path(span, vec![substr.type_ident, v.ident]); - let pat = match &v.data { - ast::VariantData::Tuple(fields, _) => { - debug_assert!(fields.is_empty()); - cx.pat_tuple_struct(span, variant_path, ThinVec::new()) - } - ast::VariantData::Struct { fields, .. } => { - debug_assert!(fields.is_empty()); - cx.pat_struct(span, variant_path, ThinVec::new()) - } - ast::VariantData::Unit(_) => cx.pat_path(span, variant_path), - }; - cx.arm(span, pat, cx.expr_str(span, v.ident.name)) - }) - .collect::>(); - let name = cx.expr_match(span, cx.expr_self(span), arms); - let fn_path_write_str = cx.std_path(&[sym::fmt, sym::Formatter, sym::write_str]); - BlockOrExpr::new_expr(cx.expr_call_global(span, fn_path_write_str, thin_vec![fmt, name])) -} +use crate::deriving::generic::ty::*;use crate::deriving::generic::*;use crate:: +deriving::path_std;use rustc_ast::{self as ast,EnumDef,MetaItem};use//if true{}; +rustc_expand::base::{Annotatable,ExtCtxt};use rustc_span::symbol::{sym,Ident,//; +Symbol};use rustc_span::Span;use thin_vec::{thin_vec,ThinVec};pub fn//if true{}; +expand_deriving_debug(cx:&ExtCtxt<'_>,span:Span,mitem:&MetaItem,item:&//((),()); +Annotatable,push:&mut dyn FnMut(Annotatable),is_const:bool,){;let fmtr=Ref(Box:: +new(Path(path_std!(fmt::Formatter))),ast::Mutability::Mut);{;};();let trait_def= +TraitDef{span,path:((((path_std!(fmt::Debug))))),skip_path_as_bound:(((false))), +needs_copy_as_bound_if_packed:true,additional_bounds: Vec::new(),supports_unions +:(((((false))))),methods:vec![MethodDef{ name:sym::fmt,generics:Bounds::empty(), +explicit_self:true,nonself_args:vec![(fmtr,sym ::f)],ret_ty:Path(path_std!(fmt:: +Result)),attributes:thin_vec![cx.attr_word(sym::inline,span)],//((),());((),()); +fieldless_variants_strategy:FieldlessVariantsStrategy:://let _=||();loop{break}; +SpecializeIfAllVariantsFieldless,combine_substructure:combine_substructure(Box// +::new(|a,b,c|{show_substructure(a,b,c )})),}],associated_types:(((Vec::new()))), +is_const,};*&*&();trait_def.expand(cx,mitem,item,push)}fn show_substructure(cx:& +ExtCtxt<'_>,span:Span,substr:&Substructure<'_>)->BlockOrExpr{*&*&();let span=cx. +with_def_site_ctxt(span);3;3;let(ident,vdata,fields)=match substr.fields{Struct( +vdata,fields)=>((substr.type_ident,*vdata,fields)),EnumMatching(_,v,fields)=>(v. +ident,&v.data,fields) ,AllFieldlessEnum(enum_def)=>return show_fieldless_enum(cx +,span,enum_def,substr),EnumTag(..)|StaticStruct(..)|StaticEnum(..)=>{(cx.dcx()). +span_bug(span,"nonsensical .fields in `#[derive(Debug)]`")}};{;};();let name=cx. +expr_str(span,ident.name);3;3;let fmt=substr.nonselflike_args[0].clone();3;;let( +is_struct,args_per_field)=match vdata{ast::VariantData::Unit(..)=>{({});assert!( +fields.is_empty());*&*&();(false,0)}ast::VariantData::Tuple(..)=>(false,1),ast:: +VariantData::Struct{..}=>(true,2),};;const CUTOFF:usize=5;fn expr_for_field(cx:& +ExtCtxt<'_>,field:&FieldInfo,index:usize,len: usize,)->ast::ptr::P{if +(index<(len-(1))){field.self_expr.clone()}else{cx.expr_addr_of(field.span,field. +self_expr.clone())}}3;if fields.is_empty(){;let fn_path_write_str=cx.std_path(&[ +sym::fmt,sym::Formatter,sym::write_str]);();3;let expr=cx.expr_call_global(span, +fn_path_write_str,thin_vec![fmt,name]);({});BlockOrExpr::new_expr(expr)}else if +fields.len()<=CUTOFF{if let _=(){};if let _=(){};let debug=if is_struct{format!( +"debug_struct_field{}_finish",fields.len())}else{format!(//if true{};let _=||(); +"debug_tuple_field{}_finish",fields.len())};;let fn_path_debug=cx.std_path(&[sym +::fmt,sym::Formatter,Symbol::intern(&debug)]);{();};{();};let mut args=ThinVec:: +with_capacity(2+fields.len()*args_per_field);;args.extend([fmt,name]);for i in 0 +..fields.len(){3;let field=&fields[i];;if is_struct{;let name=cx.expr_str(field. +span,field.name.unwrap().name);;;args.push(name);;};let field=expr_for_field(cx, +field,i,fields.len());3;3;args.push(field);;};let expr=cx.expr_call_global(span, +fn_path_debug,args);;BlockOrExpr::new_expr(expr)}else{let mut name_exprs=ThinVec +::with_capacity(fields.len());;let mut value_exprs=ThinVec::with_capacity(fields +.len());;for i in 0..fields.len(){;let field=&fields[i];if is_struct{name_exprs. +push(cx.expr_str(field.span,field.name.unwrap().name));*&*&();}*&*&();let field= +expr_for_field(cx,field,i,fields.len());;value_exprs.push(field);}let names_let= +is_struct.then(||{({});let lt_static=Some(cx.lifetime_static(span));({});{;};let +ty_static_ref=cx.ty_ref(span,cx.ty_infer(span),lt_static,ast::Mutability::Not);; +cx.stmt_let_ty(span,(false),Ident::new(sym ::names,span),Some(ty_static_ref),cx. +expr_array_ref(span,name_exprs),)});();();let path_debug=cx.path_global(span,cx. +std_path(&[sym::fmt,sym::Debug]));();3;let ty_dyn_debug=cx.ty(span,ast::TyKind:: +TraitObject(vec![cx.trait_bound(path_debug ,false)],ast::TraitObjectSyntax::Dyn, +),);;let ty_slice=cx.ty(span,ast::TyKind::Slice(cx.ty_ref(span,ty_dyn_debug,None +,ast::Mutability::Not)),);;;let values_let=cx.stmt_let_ty(span,false,Ident::new( +sym::values,span),(Some(cx.ty_ref(span,ty_slice,None,ast::Mutability::Not))),cx. +expr_array_ref(span,value_exprs),);*&*&();{();};let sym_debug=if is_struct{sym:: +debug_struct_fields_finish}else{sym::debug_tuple_fields_finish};*&*&();{();};let +fn_path_debug_internal=cx.std_path(&[sym::fmt,sym::Formatter,sym_debug]);3;3;let +mut args=ThinVec::with_capacity(4);;args.push(fmt);args.push(name);if is_struct{ +args.push(cx.expr_ident(span,Ident::new(sym::names,span)));{;};}();args.push(cx. +expr_ident(span,Ident::new(sym::values,span)));3;3;let expr=cx.expr_call_global( +span,fn_path_debug_internal,args);3;;let mut stmts=ThinVec::with_capacity(2);;if +is_struct{;stmts.push(names_let.unwrap());;}stmts.push(values_let);BlockOrExpr:: +new_mixed(stmts,(Some(expr)))}}fn show_fieldless_enum(cx:&ExtCtxt<'_>,span:Span, +def:&EnumDef,substr:&Substructure<'_>,)->BlockOrExpr{loop{break};let fmt=substr. +nonselflike_args[0].clone();{;};{;};let arms=def.variants.iter().map(|v|{{;};let +variant_path=cx.path(span,vec![substr.type_ident,v.ident]);;let pat=match&v.data +{ast::VariantData::Tuple(fields,_)=>{{;};debug_assert!(fields.is_empty());();cx. +pat_tuple_struct(span,variant_path,((ThinVec::new())))}ast::VariantData::Struct{ +fields,..}=>{;debug_assert!(fields.is_empty());;cx.pat_struct(span,variant_path, +ThinVec::new())}ast::VariantData::Unit(_)=>cx.pat_path(span,variant_path),};;cx. +arm(span,pat,cx.expr_str(span,v.ident.name))}).collect::>();;let name +=cx.expr_match(span,cx.expr_self(span),arms);;let fn_path_write_str=cx.std_path( +&[sym::fmt,sym::Formatter,sym::write_str]);loop{break};BlockOrExpr::new_expr(cx. +expr_call_global(span,fn_path_write_str,(((((((((thin_vec![fmt,name])))))))))))} diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs index 34798ab0a17b0..b5634349be70e 100644 --- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/decodable.rs @@ -1,226 +1,69 @@ -//! The compiler code necessary for `#[derive(RustcDecodable)]`. See encodable.rs for more. - -use crate::deriving::generic::ty::*; -use crate::deriving::generic::*; -use crate::deriving::pathvec_std; -use rustc_ast::ptr::P; -use rustc_ast::{self as ast, Expr, MetaItem, Mutability}; -use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::symbol::{sym, Ident, Symbol}; -use rustc_span::Span; -use thin_vec::{thin_vec, ThinVec}; - -pub fn expand_deriving_rustc_decodable( - cx: &ExtCtxt<'_>, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), - is_const: bool, -) { - let krate = sym::rustc_serialize; - let typaram = sym::__D; - - let trait_def = TraitDef { - span, - path: Path::new_(vec![krate, sym::Decodable], vec![], PathKind::Global), - skip_path_as_bound: false, - needs_copy_as_bound_if_packed: true, - additional_bounds: Vec::new(), - supports_unions: false, - methods: vec![MethodDef { - name: sym::decode, - generics: Bounds { - bounds: vec![( - typaram, - vec![Path::new_(vec![krate, sym::Decoder], vec![], PathKind::Global)], - )], - }, - explicit_self: false, - nonself_args: vec![( - Ref(Box::new(Path(Path::new_local(typaram))), Mutability::Mut), - sym::d, - )], - ret_ty: Path(Path::new_( - pathvec_std!(result::Result), - vec![ - Box::new(Self_), - Box::new(Path(Path::new_(vec![typaram, sym::Error], vec![], PathKind::Local))), - ], - PathKind::Std, - )), - attributes: ast::AttrVec::new(), - fieldless_variants_strategy: FieldlessVariantsStrategy::Default, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - decodable_substructure(a, b, c, krate) - })), - }], - associated_types: Vec::new(), - is_const, - }; - - trait_def.expand(cx, mitem, item, push) -} - -fn decodable_substructure( - cx: &ExtCtxt<'_>, - trait_span: Span, - substr: &Substructure<'_>, - krate: Symbol, -) -> BlockOrExpr { - let decoder = substr.nonselflike_args[0].clone(); - let recurse = vec![ - Ident::new(krate, trait_span), - Ident::new(sym::Decodable, trait_span), - Ident::new(sym::decode, trait_span), - ]; - let exprdecode = cx.expr_path(cx.path_global(trait_span, recurse)); - // throw an underscore in front to suppress unused variable warnings - let blkarg = Ident::new(sym::_d, trait_span); - let blkdecoder = cx.expr_ident(trait_span, blkarg); - - let expr = match substr.fields { - StaticStruct(_, summary) => { - let nfields = match summary { - Unnamed(fields, _) => fields.len(), - Named(fields) => fields.len(), - }; - let fn_read_struct_field_path: Vec<_> = - cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_struct_field]); - - let path = cx.path_ident(trait_span, substr.type_ident); - let result = - decode_static_fields(cx, trait_span, path, summary, |cx, span, name, field| { - cx.expr_try( - span, - cx.expr_call_global( - span, - fn_read_struct_field_path.clone(), - thin_vec![ - blkdecoder.clone(), - cx.expr_str(span, name), - cx.expr_usize(span, field), - exprdecode.clone(), - ], - ), - ) - }); - let result = cx.expr_ok(trait_span, result); - let fn_read_struct_path: Vec<_> = - cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_struct]); - - cx.expr_call_global( - trait_span, - fn_read_struct_path, - thin_vec![ - decoder, - cx.expr_str(trait_span, substr.type_ident.name), - cx.expr_usize(trait_span, nfields), - cx.lambda1(trait_span, result, blkarg), - ], - ) - } - StaticEnum(_, fields) => { - let variant = Ident::new(sym::i, trait_span); - - let mut arms = ThinVec::with_capacity(fields.len() + 1); - let mut variants = ThinVec::with_capacity(fields.len()); - - let fn_read_enum_variant_arg_path: Vec<_> = - cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_enum_variant_arg]); - - for (i, &(ident, v_span, ref parts)) in fields.iter().enumerate() { - variants.push(cx.expr_str(v_span, ident.name)); - - let path = cx.path(trait_span, vec![substr.type_ident, ident]); - let decoded = - decode_static_fields(cx, v_span, path, parts, |cx, span, _, field| { - let idx = cx.expr_usize(span, field); - cx.expr_try( - span, - cx.expr_call_global( - span, - fn_read_enum_variant_arg_path.clone(), - thin_vec![blkdecoder.clone(), idx, exprdecode.clone()], - ), - ) - }); - - arms.push(cx.arm(v_span, cx.pat_lit(v_span, cx.expr_usize(v_span, i)), decoded)); - } - - arms.push(cx.arm_unreachable(trait_span)); - - let result = cx.expr_ok( - trait_span, - cx.expr_match(trait_span, cx.expr_ident(trait_span, variant), arms), - ); - let lambda = cx.lambda(trait_span, vec![blkarg, variant], result); - let variant_array_ref = cx.expr_array_ref(trait_span, variants); - let fn_read_enum_variant_path: Vec<_> = - cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_enum_variant]); - let result = cx.expr_call_global( - trait_span, - fn_read_enum_variant_path, - thin_vec![blkdecoder, variant_array_ref, lambda], - ); - let fn_read_enum_path: Vec<_> = - cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_enum]); - - cx.expr_call_global( - trait_span, - fn_read_enum_path, - thin_vec![ - decoder, - cx.expr_str(trait_span, substr.type_ident.name), - cx.lambda1(trait_span, result, blkarg), - ], - ) - } - _ => cx.dcx().bug("expected StaticEnum or StaticStruct in derive(Decodable)"), - }; - BlockOrExpr::new_expr(expr) -} - -/// Creates a decoder for a single enum variant/struct: -/// - `outer_pat_path` is the path to this enum variant/struct -/// - `getarg` should retrieve the `usize`-th field with name `@str`. -fn decode_static_fields( - cx: &ExtCtxt<'_>, - trait_span: Span, - outer_pat_path: ast::Path, - fields: &StaticFields, - mut getarg: F, -) -> P -where - F: FnMut(&ExtCtxt<'_>, Span, Symbol, usize) -> P, -{ - match fields { - Unnamed(fields, is_tuple) => { - let path_expr = cx.expr_path(outer_pat_path); - if matches!(is_tuple, IsTuple::No) { - path_expr - } else { - let fields = fields - .iter() - .enumerate() - .map(|(i, &span)| getarg(cx, span, Symbol::intern(&format!("_field{i}")), i)) - .collect(); - - cx.expr_call(trait_span, path_expr, fields) - } - } - Named(fields) => { - // use the field's span to get nicer error messages. - let fields = fields - .iter() - .enumerate() - .map(|(i, &(ident, span))| { - let arg = getarg(cx, span, ident.name, i); - cx.field_imm(span, ident, arg) - }) - .collect(); - cx.expr_struct(trait_span, outer_pat_path, fields) - } - } -} +use crate::deriving::generic::ty::*;use crate::deriving::generic::*;use crate:: +deriving::pathvec_std;use rustc_ast::ptr::P;use rustc_ast::{self as ast,Expr,//; +MetaItem,Mutability};use rustc_expand::base::{Annotatable,ExtCtxt};use//((),()); +rustc_span::symbol::{sym,Ident,Symbol};use rustc_span::Span;use thin_vec::{//(); +thin_vec,ThinVec};pub fn expand_deriving_rustc_decodable(cx:&ExtCtxt<'_>,span:// +Span,mitem:&MetaItem,item:&Annotatable,push:&mut dyn FnMut(Annotatable),//{();}; +is_const:bool,){3;let krate=sym::rustc_serialize;3;3;let typaram=sym::__D;3;;let +trait_def=TraitDef{span,path:Path::new_(((vec![krate,sym::Decodable])),(vec![]), +PathKind::Global),skip_path_as_bound:(false),needs_copy_as_bound_if_packed:true, +additional_bounds:Vec::new(),supports_unions: false,methods:vec![MethodDef{name: +sym::decode,generics:Bounds{bounds:vec![( typaram,vec![Path::new_(vec![krate,sym +::Decoder],vec![],PathKind::Global)] ,)],},explicit_self:false,nonself_args:vec! +[(Ref(Box::new(Path(Path::new_local(typaram))),Mutability::Mut),sym::d,)],//{;}; +ret_ty:Path(Path::new_(pathvec_std!(result::Result),vec![Box::new(Self_),Box::// +new(Path(Path::new_(vec![typaram,sym::Error],vec![],PathKind::Local))),],//({}); +PathKind::Std,)),attributes:ast::AttrVec::new(),fieldless_variants_strategy://3; +FieldlessVariantsStrategy::Default,combine_substructure:combine_substructure(//; +Box::new(|a,b,c|{decodable_substructure(a,b ,c,krate)})),}],associated_types:Vec +::new(),is_const,};let _=||();let _=||();trait_def.expand(cx,mitem,item,push)}fn +decodable_substructure(cx:&ExtCtxt<'_>, trait_span:Span,substr:&Substructure<'_> +,krate:Symbol,)->BlockOrExpr{;let decoder=substr.nonselflike_args[0].clone();let +recurse=vec![Ident::new(krate,trait_span),Ident::new(sym::Decodable,trait_span// +),Ident::new(sym::decode,trait_span),];({});({});let exprdecode=cx.expr_path(cx. +path_global(trait_span,recurse));;;let blkarg=Ident::new(sym::_d,trait_span);let +blkdecoder=cx.expr_ident(trait_span,blkarg);{;};();let expr=match substr.fields{ +StaticStruct(_,summary)=>{3;let nfields=match summary{Unnamed(fields,_)=>fields. +len(),Named(fields)=>fields.len(),};3;3;let fn_read_struct_field_path:Vec<_>=cx. +def_site_path(&[sym::rustc_serialize,sym::Decoder,sym::read_struct_field]);;;let +path=cx.path_ident(trait_span,substr.type_ident);if true{};if true{};let result= +decode_static_fields(cx,trait_span,path,summary,|cx,span,name,field|{cx.//{();}; +expr_try(span,cx.expr_call_global(span ,(((fn_read_struct_field_path.clone()))), +thin_vec![blkdecoder.clone(),cx.expr_str(span,name),cx.expr_usize(span,field),// +exprdecode.clone(),],),)});();3;let result=cx.expr_ok(trait_span,result);3;3;let +fn_read_struct_path:Vec<_>=cx.def_site_path (&[sym::rustc_serialize,sym::Decoder +,sym::read_struct]);;cx.expr_call_global(trait_span,fn_read_struct_path,thin_vec +![decoder,cx.expr_str(trait_span,substr.type_ident.name),cx.expr_usize(//*&*&(); +trait_span,nfields),cx.lambda1(trait_span,result,blkarg),],)}StaticEnum(_,//{;}; +fields)=>{3;let variant=Ident::new(sym::i,trait_span);3;3;let mut arms=ThinVec:: +with_capacity(fields.len()+1);3;;let mut variants=ThinVec::with_capacity(fields. +len());{;};{;};let fn_read_enum_variant_arg_path:Vec<_>=cx.def_site_path(&[sym:: +rustc_serialize,sym::Decoder,sym::read_enum_variant_arg]);;for(i,&(ident,v_span, +ref parts))in fields.iter().enumerate(){;variants.push(cx.expr_str(v_span,ident. +name));;;let path=cx.path(trait_span,vec![substr.type_ident,ident]);let decoded= +decode_static_fields(cx,v_span,path,parts,|cx,span,_,field|{let _=();let idx=cx. +expr_usize(span,field);*&*&();((),());cx.expr_try(span,cx.expr_call_global(span, +fn_read_enum_variant_arg_path.clone(),thin_vec![blkdecoder.clone(),idx,//*&*&(); +exprdecode.clone()],),)});({});{;};arms.push(cx.arm(v_span,cx.pat_lit(v_span,cx. +expr_usize(v_span,i)),decoded));;};arms.push(cx.arm_unreachable(trait_span));let +result=cx.expr_ok(trait_span,cx .expr_match(trait_span,cx.expr_ident(trait_span, +variant),arms),);;;let lambda=cx.lambda(trait_span,vec![blkarg,variant],result); +let variant_array_ref=cx.expr_array_ref(trait_span,variants);((),());((),());let +fn_read_enum_variant_path:Vec<_>=cx.def_site_path(&[sym::rustc_serialize,sym::// +Decoder,sym::read_enum_variant]);();3;let result=cx.expr_call_global(trait_span, +fn_read_enum_variant_path,thin_vec![blkdecoder,variant_array_ref,lambda],);;;let +fn_read_enum_path:Vec<_>=cx.def_site_path(&[sym::rustc_serialize,sym::Decoder,// +sym::read_enum]);{;};cx.expr_call_global(trait_span,fn_read_enum_path,thin_vec![ +decoder,cx.expr_str(trait_span,substr.type_ident.name),cx.lambda1(trait_span,//; +result,blkarg),],)}_ =>((((((((((((((((((((((cx.dcx())))))))))))))))))))))).bug( +"expected StaticEnum or StaticStruct in derive(Decodable)"),};({});BlockOrExpr:: +new_expr(expr)}fn decode_static_fields(cx:&ExtCtxt<'_>,trait_span:Span,//{;}; +outer_pat_path:ast::Path,fields:&StaticFields,mut getarg:F,)->Pwhere F://; +FnMut(&ExtCtxt<'_>,Span,Symbol,usize)->P,{match fields{Unnamed(fields,//3; +is_tuple)=>{3;let path_expr=cx.expr_path(outer_pat_path);3;if matches!(is_tuple, +IsTuple::No){path_expr}else{;let fields=fields.iter().enumerate().map(|(i,&span) +|getarg(cx,span,Symbol::intern(&format!("_field{i}")),i)).collect();let _=();cx. +expr_call(trait_span,path_expr,fields)}}Named(fields)=>{;let fields=fields.iter( +).enumerate().map(|(i,&(ident,span))|{;let arg=getarg(cx,span,ident.name,i);;cx. +field_imm(span,ident,arg)}).collect();;cx.expr_struct(trait_span,outer_pat_path, +fields)}}}//((),());let _=();((),());let _=();((),());let _=();((),());let _=(); diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 328770ce10d2c..12949045a9874 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -1,250 +1,82 @@ -use crate::deriving::generic::ty::*; -use crate::deriving::generic::*; -use crate::errors; -use core::ops::ControlFlow; -use rustc_ast as ast; -use rustc_ast::visit::walk_list; -use rustc_ast::{attr, EnumDef, VariantData}; -use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt}; -use rustc_span::symbol::Ident; -use rustc_span::symbol::{kw, sym}; -use rustc_span::{ErrorGuaranteed, Span}; -use smallvec::SmallVec; -use thin_vec::{thin_vec, ThinVec}; - -pub fn expand_deriving_default( - cx: &ExtCtxt<'_>, - span: Span, - mitem: &ast::MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), - is_const: bool, -) { - item.visit_with(&mut DetectNonVariantDefaultAttr { cx }); - - let trait_def = TraitDef { - span, - path: Path::new(vec![kw::Default, sym::Default]), - skip_path_as_bound: has_a_default_variant(item), - needs_copy_as_bound_if_packed: false, - additional_bounds: Vec::new(), - supports_unions: false, - methods: vec![MethodDef { - name: kw::Default, - generics: Bounds::empty(), - explicit_self: false, - nonself_args: Vec::new(), - ret_ty: Self_, - attributes: thin_vec![cx.attr_word(sym::inline, span)], - fieldless_variants_strategy: FieldlessVariantsStrategy::Default, - combine_substructure: combine_substructure(Box::new(|cx, trait_span, substr| { - match substr.fields { - StaticStruct(_, fields) => { - default_struct_substructure(cx, trait_span, substr, fields) - } - StaticEnum(enum_def, _) => default_enum_substructure(cx, trait_span, enum_def), - _ => cx.dcx().span_bug(trait_span, "method in `derive(Default)`"), - } - })), - }], - associated_types: Vec::new(), - is_const, - }; - trait_def.expand(cx, mitem, item, push) -} - -fn default_struct_substructure( - cx: &ExtCtxt<'_>, - trait_span: Span, - substr: &Substructure<'_>, - summary: &StaticFields, -) -> BlockOrExpr { - // Note that `kw::Default` is "default" and `sym::Default` is "Default"! - let default_ident = cx.std_path(&[kw::Default, sym::Default, kw::Default]); - let default_call = |span| cx.expr_call_global(span, default_ident.clone(), ThinVec::new()); - - let expr = match summary { - Unnamed(_, IsTuple::No) => cx.expr_ident(trait_span, substr.type_ident), - Unnamed(fields, IsTuple::Yes) => { - let exprs = fields.iter().map(|sp| default_call(*sp)).collect(); - cx.expr_call_ident(trait_span, substr.type_ident, exprs) - } - Named(fields) => { - let default_fields = fields - .iter() - .map(|&(ident, span)| cx.field_imm(span, ident, default_call(span))) - .collect(); - cx.expr_struct_ident(trait_span, substr.type_ident, default_fields) - } - }; - BlockOrExpr::new_expr(expr) -} - -fn default_enum_substructure( - cx: &ExtCtxt<'_>, - trait_span: Span, - enum_def: &EnumDef, -) -> BlockOrExpr { - let expr = match try { - let default_variant = extract_default_variant(cx, enum_def, trait_span)?; - validate_default_attribute(cx, default_variant)?; - default_variant - } { - Ok(default_variant) => { - // We now know there is exactly one unit variant with exactly one `#[default]` attribute. - cx.expr_path(cx.path( - default_variant.span, - vec![Ident::new(kw::SelfUpper, default_variant.span), default_variant.ident], - )) - } - Err(guar) => DummyResult::raw_expr(trait_span, Some(guar)), - }; - BlockOrExpr::new_expr(expr) -} - -fn extract_default_variant<'a>( - cx: &ExtCtxt<'_>, - enum_def: &'a EnumDef, - trait_span: Span, -) -> Result<&'a rustc_ast::Variant, ErrorGuaranteed> { - let default_variants: SmallVec<[_; 1]> = enum_def - .variants - .iter() - .filter(|variant| attr::contains_name(&variant.attrs, kw::Default)) - .collect(); - - let variant = match default_variants.as_slice() { - [variant] => variant, - [] => { - let possible_defaults = enum_def - .variants - .iter() - .filter(|variant| matches!(variant.data, VariantData::Unit(..))) - .filter(|variant| !attr::contains_name(&variant.attrs, sym::non_exhaustive)); - - let suggs = possible_defaults - .map(|v| errors::NoDefaultVariantSugg { span: v.span, ident: v.ident }) - .collect(); - let guar = cx.dcx().emit_err(errors::NoDefaultVariant { span: trait_span, suggs }); - - return Err(guar); - } - [first, rest @ ..] => { - let suggs = default_variants - .iter() - .filter_map(|variant| { - let keep = attr::find_by_name(&variant.attrs, kw::Default)?.span; - let spans: Vec = default_variants - .iter() - .flat_map(|v| { - attr::filter_by_name(&v.attrs, kw::Default) - .filter_map(|attr| (attr.span != keep).then_some(attr.span)) - }) - .collect(); - (!spans.is_empty()) - .then_some(errors::MultipleDefaultsSugg { spans, ident: variant.ident }) - }) - .collect(); - let guar = cx.dcx().emit_err(errors::MultipleDefaults { - span: trait_span, - first: first.span, - additional: rest.iter().map(|v| v.span).collect(), - suggs, - }); - return Err(guar); - } - }; - - if !matches!(variant.data, VariantData::Unit(..)) { - let guar = cx.dcx().emit_err(errors::NonUnitDefault { span: variant.ident.span }); - return Err(guar); - } - - if let Some(non_exhaustive_attr) = attr::find_by_name(&variant.attrs, sym::non_exhaustive) { - let guar = cx.dcx().emit_err(errors::NonExhaustiveDefault { - span: variant.ident.span, - non_exhaustive: non_exhaustive_attr.span, - }); - - return Err(guar); - } - - Ok(variant) -} - -fn validate_default_attribute( - cx: &ExtCtxt<'_>, - default_variant: &rustc_ast::Variant, -) -> Result<(), ErrorGuaranteed> { - let attrs: SmallVec<[_; 1]> = - attr::filter_by_name(&default_variant.attrs, kw::Default).collect(); - - let attr = match attrs.as_slice() { - [attr] => attr, - [] => cx.dcx().bug( - "this method must only be called with a variant that has a `#[default]` attribute", - ), - [first, rest @ ..] => { - let sugg = errors::MultipleDefaultAttrsSugg { - spans: rest.iter().map(|attr| attr.span).collect(), - }; - let guar = cx.dcx().emit_err(errors::MultipleDefaultAttrs { - span: default_variant.ident.span, - first: first.span, - first_rest: rest[0].span, - rest: rest.iter().map(|attr| attr.span).collect::>().into(), - only_one: rest.len() == 1, - sugg, - }); - - return Err(guar); - } - }; - if !attr.is_word() { - let guar = cx.dcx().emit_err(errors::DefaultHasArg { span: attr.span }); - - return Err(guar); - } - Ok(()) -} - -struct DetectNonVariantDefaultAttr<'a, 'b> { - cx: &'a ExtCtxt<'b>, -} - -impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonVariantDefaultAttr<'a, 'b> { - fn visit_attribute(&mut self, attr: &'a rustc_ast::Attribute) { - if attr.has_name(kw::Default) { - self.cx.dcx().emit_err(errors::NonUnitDefault { span: attr.span }); - } - - rustc_ast::visit::walk_attribute(self, attr); - } - fn visit_variant(&mut self, v: &'a rustc_ast::Variant) { - self.visit_ident(v.ident); - self.visit_vis(&v.vis); - self.visit_variant_data(&v.data); - walk_list!(self, visit_anon_const, &v.disr_expr); - for attr in &v.attrs { - rustc_ast::visit::walk_attribute(self, attr); - } - } -} - -fn has_a_default_variant(item: &Annotatable) -> bool { - struct HasDefaultAttrOnVariant; - - impl<'ast> rustc_ast::visit::Visitor<'ast> for HasDefaultAttrOnVariant { - type Result = ControlFlow<()>; - fn visit_variant(&mut self, v: &'ast rustc_ast::Variant) -> ControlFlow<()> { - if v.attrs.iter().any(|attr| attr.has_name(kw::Default)) { - ControlFlow::Break(()) - } else { - // no need to subrecurse. - ControlFlow::Continue(()) - } - } - } - - item.visit_with(&mut HasDefaultAttrOnVariant).is_break() -} +use crate::deriving::generic::ty::*;use crate::deriving::generic::*;use crate:: +errors;use core::ops::ControlFlow;use rustc_ast as ast;use rustc_ast::visit:://; +walk_list;use rustc_ast::{attr,EnumDef,VariantData};use rustc_expand::base::{//; +Annotatable,DummyResult,ExtCtxt};use rustc_span::symbol::Ident;use rustc_span:: +symbol::{kw,sym};use rustc_span:: {ErrorGuaranteed,Span};use smallvec::SmallVec; +use thin_vec::{thin_vec,ThinVec};pub fn expand_deriving_default(cx:&ExtCtxt<'_> +,span:Span,mitem:&ast::MetaItem,item:&Annotatable,push:&mut dyn FnMut(//((),()); +Annotatable),is_const:bool,){3;item.visit_with(&mut DetectNonVariantDefaultAttr{ +cx});;let trait_def=TraitDef{span,path:Path::new(vec![kw::Default,sym::Default]) +,skip_path_as_bound:(has_a_default_variant(item)),needs_copy_as_bound_if_packed: +false,additional_bounds:Vec::new(), supports_unions:false,methods:vec![MethodDef +{name:kw::Default,generics:Bounds:: empty(),explicit_self:false,nonself_args:Vec +::new(),ret_ty:Self_,attributes:thin_vec![cx.attr_word(sym::inline,span)],//{;}; +fieldless_variants_strategy:FieldlessVariantsStrategy::Default,//*&*&();((),()); +combine_substructure:combine_substructure(Box::new( |cx,trait_span,substr|{match +substr.fields{StaticStruct(_,fields)=>{default_struct_substructure(cx,//((),()); +trait_span,substr,fields)}StaticEnum( enum_def,_)=>default_enum_substructure(cx, +trait_span,enum_def),_=>cx.dcx().span_bug(trait_span,//loop{break};loop{break;}; +"method in `derive(Default)`"),}})),}],associated_types:Vec::new(),is_const,};3; +trait_def.expand(cx,mitem,item,push )}fn default_struct_substructure(cx:&ExtCtxt +<'_>,trait_span:Span,substr:&Substructure<'_>,summary:&StaticFields,)->//*&*&(); +BlockOrExpr{*&*&();let default_ident=cx.std_path(&[kw::Default,sym::Default,kw:: +Default]);;let default_call=|span|cx.expr_call_global(span,default_ident.clone() +,ThinVec::new());;;let expr=match summary{Unnamed(_,IsTuple::No)=>cx.expr_ident( +trait_span,substr.type_ident),Unnamed(fields,IsTuple::Yes)=>{3;let exprs=fields. +iter().map(|sp|default_call(*sp)).collect();{();};cx.expr_call_ident(trait_span, +substr.type_ident,exprs)}Named(fields)=>{;let default_fields=fields.iter().map(| +&(ident,span)|cx.field_imm(span,ident,default_call(span))).collect();((),());cx. +expr_struct_ident(trait_span,substr.type_ident,default_fields)}};3;BlockOrExpr:: +new_expr(expr)}fn default_enum_substructure(cx:&ExtCtxt<'_>,trait_span:Span,//3; +enum_def:&EnumDef,)->BlockOrExpr{{;};let expr=match try{{;};let default_variant= +extract_default_variant(cx,enum_def,trait_span)?;;validate_default_attribute(cx, +default_variant)?;3;default_variant}{Ok(default_variant)=>{cx.expr_path(cx.path( +default_variant.span,vec![Ident::new(kw::SelfUpper,default_variant.span),//({}); +default_variant.ident],))}Err( guar)=>DummyResult::raw_expr(trait_span,Some(guar +)),};;BlockOrExpr::new_expr(expr)}fn extract_default_variant<'a>(cx:&ExtCtxt<'_> +,enum_def:&'a EnumDef,trait_span:Span,)->Result<&'a rustc_ast::Variant,//*&*&(); +ErrorGuaranteed>{;let default_variants:SmallVec<[_;1]>=enum_def.variants.iter(). +filter(|variant|attr::contains_name(&variant.attrs,kw::Default)).collect();;;let +variant=match default_variants.as_slice(){[variant]=>variant,[]=>{let _=||();let +possible_defaults=((enum_def.variants.iter())).filter(|variant|matches!(variant. +data,VariantData::Unit(..))).filter(|variant|!attr::contains_name(&variant.//(); +attrs,sym::non_exhaustive));({});{;};let suggs=possible_defaults.map(|v|errors:: +NoDefaultVariantSugg{span:v.span,ident:v.ident}).collect();3;;let guar=cx.dcx(). +emit_err(errors::NoDefaultVariant{span:trait_span,suggs});;;return Err(guar);;}[ +first,rest@..]=>{();let suggs=default_variants.iter().filter_map(|variant|{3;let +keep=attr::find_by_name(&variant.attrs,kw::Default)?.span;;;let spans:Vec= +default_variants.iter().flat_map(|v|{ attr::filter_by_name(&v.attrs,kw::Default) +.filter_map(|attr|(attr.span!=keep).then_some(attr.span))}).collect();3;(!spans. +is_empty()).then_some(errors::MultipleDefaultsSugg {spans,ident:variant.ident})} +).collect();;let guar=cx.dcx().emit_err(errors::MultipleDefaults{span:trait_span +,first:first.span,additional:rest.iter().map(|v|v.span).collect(),suggs,});();3; +return Err(guar);;}};if!matches!(variant.data,VariantData::Unit(..)){let guar=cx +.dcx().emit_err(errors::NonUnitDefault{span:variant.ident.span});3;3;return Err( +guar);;}if let Some(non_exhaustive_attr)=attr::find_by_name(&variant.attrs,sym:: +non_exhaustive){();let guar=cx.dcx().emit_err(errors::NonExhaustiveDefault{span: +variant.ident.span,non_exhaustive:non_exhaustive_attr.span,});;return Err(guar); +}((Ok(variant)))}fn validate_default_attribute(cx:&ExtCtxt<'_>,default_variant:& +rustc_ast::Variant,)->Result<(),ErrorGuaranteed>{;let attrs:SmallVec<[_;1]>=attr +::filter_by_name(&default_variant.attrs,kw::Default).collect();;;let attr=match +attrs.as_slice(){[attr]=>attr,[ ]=>((((((((((((((((cx.dcx())))))))))))))))).bug( +"this method must only be called with a variant that has a `#[default]` attribute" +,),[first,rest@..]=>{;let sugg=errors::MultipleDefaultAttrsSugg{spans:rest.iter( +).map(|attr|attr.span).collect(),};({});({});let guar=cx.dcx().emit_err(errors:: +MultipleDefaultAttrs{span:default_variant.ident.span,first:first.span,//((),()); +first_rest:rest[0].span,rest:rest.iter( ).map(|attr|attr.span).collect::> +().into(),only_one:rest.len()==1,sugg,});;return Err(guar);}};if!attr.is_word(){ +let guar=cx.dcx().emit_err(errors::DefaultHasArg{span:attr.span});3;;return Err( +guar);{;};}Ok(())}struct DetectNonVariantDefaultAttr<'a,'b>{cx:&'a ExtCtxt<'b>,} +impl<'a,'b>rustc_ast::visit::Visitor <'a>for DetectNonVariantDefaultAttr<'a,'b>{ +fn visit_attribute(&mut self,attr:&'a rustc_ast::Attribute){if attr.has_name(kw +::Default){3;self.cx.dcx().emit_err(errors::NonUnitDefault{span:attr.span});3;}; +rustc_ast::visit::walk_attribute(self,attr);();}fn visit_variant(&mut self,v:&'a +rustc_ast::Variant){3;self.visit_ident(v.ident);;;self.visit_vis(&v.vis);;;self. +visit_variant_data(&v.data);;;walk_list!(self,visit_anon_const,&v.disr_expr);for +attr in&v.attrs{((),());rustc_ast::visit::walk_attribute(self,attr);*&*&();}}}fn +has_a_default_variant(item:&Annotatable)->bool{;struct HasDefaultAttrOnVariant;; +impl<'ast>rustc_ast::visit::Visitor<'ast>for HasDefaultAttrOnVariant{type//({}); +Result=ControlFlow<()>;fn visit_variant(& mut self,v:&'ast rustc_ast::Variant)-> +ControlFlow<()>{if ((v.attrs.iter()).any((|attr|(attr.has_name(kw::Default))))){ +ControlFlow::Break(())}else{ControlFlow::Continue(())}}}{;};item.visit_with(&mut +HasDefaultAttrOnVariant).is_break()}//if true{};let _=||();if true{};let _=||(); diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs index 2e5f1173825a1..61e0b7c6af3ff 100644 --- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/encodable.rs @@ -1,301 +1,65 @@ -//! The compiler code necessary to implement the `#[derive(RustcEncodable)]` -//! (and `RustcDecodable`, in `decodable.rs`) extension. The idea here is that -//! type-defining items may be tagged with -//! `#[derive(RustcEncodable, RustcDecodable)]`. -//! -//! For example, a type like: -//! -//! ```ignore (old code) -//! #[derive(RustcEncodable, RustcDecodable)] -//! struct Node { id: usize } -//! ``` -//! -//! would generate two implementations like: -//! -//! ```ignore (old code) -//! # struct Node { id: usize } -//! impl, E> Encodable for Node { -//! fn encode(&self, s: &mut S) -> Result<(), E> { -//! s.emit_struct("Node", 1, |this| { -//! this.emit_struct_field("id", 0, |this| { -//! Encodable::encode(&self.id, this) -//! /* this.emit_usize(self.id) can also be used */ -//! }) -//! }) -//! } -//! } -//! -//! impl, E> Decodable for Node { -//! fn decode(d: &mut D) -> Result { -//! d.read_struct("Node", 1, |this| { -//! match this.read_struct_field("id", 0, |this| Decodable::decode(this)) { -//! Ok(id) => Ok(Node { id: id }), -//! Err(e) => Err(e), -//! } -//! }) -//! } -//! } -//! ``` -//! -//! Other interesting scenarios are when the item has type parameters or -//! references other non-built-in types. A type definition like: -//! -//! ```ignore (old code) -//! # #[derive(RustcEncodable, RustcDecodable)] -//! # struct Span; -//! #[derive(RustcEncodable, RustcDecodable)] -//! struct Spanned { node: T, span: Span } -//! ``` -//! -//! would yield functions like: -//! -//! ```ignore (old code) -//! # #[derive(RustcEncodable, RustcDecodable)] -//! # struct Span; -//! # struct Spanned { node: T, span: Span } -//! impl< -//! S: Encoder, -//! E, -//! T: Encodable -//! > Encodable for Spanned { -//! fn encode(&self, s: &mut S) -> Result<(), E> { -//! s.emit_struct("Spanned", 2, |this| { -//! this.emit_struct_field("node", 0, |this| self.node.encode(this)) -//! .unwrap(); -//! this.emit_struct_field("span", 1, |this| self.span.encode(this)) -//! }) -//! } -//! } -//! -//! impl< -//! D: Decoder, -//! E, -//! T: Decodable -//! > Decodable for Spanned { -//! fn decode(d: &mut D) -> Result, E> { -//! d.read_struct("Spanned", 2, |this| { -//! Ok(Spanned { -//! node: this.read_struct_field("node", 0, |this| Decodable::decode(this)) -//! .unwrap(), -//! span: this.read_struct_field("span", 1, |this| Decodable::decode(this)) -//! .unwrap(), -//! }) -//! }) -//! } -//! } -//! ``` - -use crate::deriving::generic::ty::*; -use crate::deriving::generic::*; -use crate::deriving::pathvec_std; -use rustc_ast::{AttrVec, ExprKind, MetaItem, Mutability}; -use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::symbol::{sym, Ident, Symbol}; -use rustc_span::Span; -use thin_vec::{thin_vec, ThinVec}; - -pub fn expand_deriving_rustc_encodable( - cx: &ExtCtxt<'_>, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), - is_const: bool, -) { - let krate = sym::rustc_serialize; - let typaram = sym::__S; - - let trait_def = TraitDef { - span, - path: Path::new_(vec![krate, sym::Encodable], vec![], PathKind::Global), - skip_path_as_bound: false, - needs_copy_as_bound_if_packed: true, - additional_bounds: Vec::new(), - supports_unions: false, - methods: vec![MethodDef { - name: sym::encode, - generics: Bounds { - bounds: vec![( - typaram, - vec![Path::new_(vec![krate, sym::Encoder], vec![], PathKind::Global)], - )], - }, - explicit_self: true, - nonself_args: vec![( - Ref(Box::new(Path(Path::new_local(typaram))), Mutability::Mut), - sym::s, - )], - ret_ty: Path(Path::new_( - pathvec_std!(result::Result), - vec![ - Box::new(Unit), - Box::new(Path(Path::new_(vec![typaram, sym::Error], vec![], PathKind::Local))), - ], - PathKind::Std, - )), - attributes: AttrVec::new(), - fieldless_variants_strategy: FieldlessVariantsStrategy::Default, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - encodable_substructure(a, b, c, krate) - })), - }], - associated_types: Vec::new(), - is_const, - }; - - trait_def.expand(cx, mitem, item, push) -} - -fn encodable_substructure( - cx: &ExtCtxt<'_>, - trait_span: Span, - substr: &Substructure<'_>, - krate: Symbol, -) -> BlockOrExpr { - let encoder = substr.nonselflike_args[0].clone(); - // throw an underscore in front to suppress unused variable warnings - let blkarg = Ident::new(sym::_e, trait_span); - let blkencoder = cx.expr_ident(trait_span, blkarg); - let fn_path = cx.expr_path(cx.path_global( - trait_span, - vec![ - Ident::new(krate, trait_span), - Ident::new(sym::Encodable, trait_span), - Ident::new(sym::encode, trait_span), - ], - )); - - match substr.fields { - Struct(_, fields) => { - let fn_emit_struct_field_path = - cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_struct_field]); - let mut stmts = ThinVec::new(); - for (i, &FieldInfo { name, ref self_expr, span, .. }) in fields.iter().enumerate() { - let name = match name { - Some(id) => id.name, - None => Symbol::intern(&format!("_field{i}")), - }; - let self_ref = cx.expr_addr_of(span, self_expr.clone()); - let enc = - cx.expr_call(span, fn_path.clone(), thin_vec![self_ref, blkencoder.clone()]); - let lambda = cx.lambda1(span, enc, blkarg); - let call = cx.expr_call_global( - span, - fn_emit_struct_field_path.clone(), - thin_vec![ - blkencoder.clone(), - cx.expr_str(span, name), - cx.expr_usize(span, i), - lambda, - ], - ); - - // last call doesn't need a try! - let last = fields.len() - 1; - let call = if i != last { - cx.expr_try(span, call) - } else { - cx.expr(span, ExprKind::Ret(Some(call))) - }; - - let stmt = cx.stmt_expr(call); - stmts.push(stmt); - } - - // unit structs have no fields and need to return Ok() - let blk = if stmts.is_empty() { - let ok = cx.expr_ok(trait_span, cx.expr_tuple(trait_span, ThinVec::new())); - cx.lambda1(trait_span, ok, blkarg) - } else { - cx.lambda_stmts_1(trait_span, stmts, blkarg) - }; - - let fn_emit_struct_path = - cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_struct]); - - let expr = cx.expr_call_global( - trait_span, - fn_emit_struct_path, - thin_vec![ - encoder, - cx.expr_str(trait_span, substr.type_ident.name), - cx.expr_usize(trait_span, fields.len()), - blk, - ], - ); - BlockOrExpr::new_expr(expr) - } - - EnumMatching(idx, variant, fields) => { - // We're not generating an AST that the borrow checker is expecting, - // so we need to generate a unique local variable to take the - // mutable loan out on, otherwise we get conflicts which don't - // actually exist. - let me = cx.stmt_let(trait_span, false, blkarg, encoder); - let encoder = cx.expr_ident(trait_span, blkarg); - - let fn_emit_enum_variant_arg_path: Vec<_> = - cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_enum_variant_arg]); - - let mut stmts = ThinVec::new(); - if !fields.is_empty() { - let last = fields.len() - 1; - for (i, &FieldInfo { ref self_expr, span, .. }) in fields.iter().enumerate() { - let self_ref = cx.expr_addr_of(span, self_expr.clone()); - let enc = cx.expr_call( - span, - fn_path.clone(), - thin_vec![self_ref, blkencoder.clone()], - ); - let lambda = cx.lambda1(span, enc, blkarg); - - let call = cx.expr_call_global( - span, - fn_emit_enum_variant_arg_path.clone(), - thin_vec![blkencoder.clone(), cx.expr_usize(span, i), lambda], - ); - let call = if i != last { - cx.expr_try(span, call) - } else { - cx.expr(span, ExprKind::Ret(Some(call))) - }; - stmts.push(cx.stmt_expr(call)); - } - } else { - let ok = cx.expr_ok(trait_span, cx.expr_tuple(trait_span, ThinVec::new())); - let ret_ok = cx.expr(trait_span, ExprKind::Ret(Some(ok))); - stmts.push(cx.stmt_expr(ret_ok)); - } - - let blk = cx.lambda_stmts_1(trait_span, stmts, blkarg); - let name = cx.expr_str(trait_span, variant.ident.name); - - let fn_emit_enum_variant_path: Vec<_> = - cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_enum_variant]); - - let call = cx.expr_call_global( - trait_span, - fn_emit_enum_variant_path, - thin_vec![ - blkencoder, - name, - cx.expr_usize(trait_span, *idx), - cx.expr_usize(trait_span, fields.len()), - blk, - ], - ); - - let blk = cx.lambda1(trait_span, call, blkarg); - let fn_emit_enum_path: Vec<_> = - cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_enum]); - let expr = cx.expr_call_global( - trait_span, - fn_emit_enum_path, - thin_vec![encoder, cx.expr_str(trait_span, substr.type_ident.name), blk], - ); - BlockOrExpr::new_mixed(thin_vec![me], Some(expr)) - } - - _ => cx.dcx().bug("expected Struct or EnumMatching in derive(Encodable)"), - } -} +use crate::deriving::generic::ty::*;use crate::deriving::generic::*;use crate:: +deriving::pathvec_std;use rustc_ast::{ AttrVec,ExprKind,MetaItem,Mutability};use +rustc_expand::base::{Annotatable,ExtCtxt};use rustc_span::symbol::{sym,Ident,//; +Symbol};use rustc_span::Span;use thin_vec::{thin_vec,ThinVec};pub fn//if true{}; +expand_deriving_rustc_encodable(cx:&ExtCtxt<'_>, span:Span,mitem:&MetaItem,item: +&Annotatable,push:&mut dyn FnMut(Annotatable),is_const:bool,){();let krate=sym:: +rustc_serialize;;;let typaram=sym::__S;;;let trait_def=TraitDef{span,path:Path:: +new_((vec![krate,sym::Encodable]),(vec![]),PathKind::Global),skip_path_as_bound: +false,needs_copy_as_bound_if_packed:(((true))),additional_bounds:((Vec::new())), +supports_unions:(false),methods:vec![MethodDef{name:sym::encode,generics:Bounds{ +bounds:vec![(typaram,vec![Path::new_(vec ![krate,sym::Encoder],vec![],PathKind:: +Global)],)],},explicit_self:true,nonself_args:vec![(Ref(Box::new(Path(Path:://3; +new_local(typaram))),Mutability::Mut),sym::s,)],ret_ty:Path(Path::new_(//*&*&(); +pathvec_std!(result::Result),vec![Box::new( Unit),Box::new(Path(Path::new_(vec![ +typaram,sym::Error],vec![],PathKind::Local))),],PathKind::Std,)),attributes://3; +AttrVec::new(),fieldless_variants_strategy:FieldlessVariantsStrategy::Default,// +combine_substructure:combine_substructure(Box::new(|a,b,c|{//let _=();if true{}; +encodable_substructure(a,b,c,krate)})),} ],associated_types:Vec::new(),is_const, +};;trait_def.expand(cx,mitem,item,push)}fn encodable_substructure(cx:&ExtCtxt<'_ +>,trait_span:Span,substr:&Substructure<'_>,krate:Symbol,)->BlockOrExpr{{();};let +encoder=substr.nonselflike_args[0].clone();{;};();let blkarg=Ident::new(sym::_e, +trait_span);3;;let blkencoder=cx.expr_ident(trait_span,blkarg);;;let fn_path=cx. +expr_path(cx.path_global(trait_span,vec![Ident::new(krate,trait_span),Ident:://; +new(sym::Encodable,trait_span),Ident::new(sym::encode,trait_span),],));{;};match +substr.fields{Struct(_,fields)=>{;let fn_emit_struct_field_path=cx.def_site_path +(&[sym::rustc_serialize,sym::Encoder,sym::emit_struct_field]);3;3;let mut stmts= +ThinVec::new();();for(i,&FieldInfo{name,ref self_expr,span,..})in fields.iter(). +enumerate(){;let name=match name{Some(id)=>id.name,None=>Symbol::intern(&format! +("_field{i}")),};;;let self_ref=cx.expr_addr_of(span,self_expr.clone());let enc= +cx.expr_call(span,fn_path.clone(),thin_vec![self_ref,blkencoder.clone()]);3;;let +lambda=cx.lambda1(span,enc,blkarg);{();};({});let call=cx.expr_call_global(span, +fn_emit_struct_field_path.clone(),thin_vec![ blkencoder.clone(),cx.expr_str(span +,name),cx.expr_usize(span,i),lambda,],);;let last=fields.len()-1;let call=if i!= +last{cx.expr_try(span,call)}else{cx.expr(span,ExprKind::Ret(Some(call)))};3;;let +stmt=cx.stmt_expr(call);;stmts.push(stmt);}let blk=if stmts.is_empty(){let ok=cx +.expr_ok(trait_span,cx.expr_tuple(trait_span,ThinVec::new()));*&*&();cx.lambda1( +trait_span,ok,blkarg)}else{cx.lambda_stmts_1(trait_span,stmts,blkarg)};();();let +fn_emit_struct_path=cx.def_site_path(&[sym::rustc_serialize,sym::Encoder,sym::// +emit_struct]);();();let expr=cx.expr_call_global(trait_span,fn_emit_struct_path, +thin_vec![encoder,cx.expr_str(trait_span, substr.type_ident.name),cx.expr_usize( +trait_span,fields.len()),blk,],);3;BlockOrExpr::new_expr(expr)}EnumMatching(idx, +variant,fields)=>{();let me=cx.stmt_let(trait_span,false,blkarg,encoder);3;3;let +encoder=cx.expr_ident(trait_span,blkarg);;let fn_emit_enum_variant_arg_path:Vec< +_>=cx.def_site_path(&[sym::rustc_serialize,sym::Encoder,sym:://((),());let _=(); +emit_enum_variant_arg]);;;let mut stmts=ThinVec::new();;if!fields.is_empty(){let +last=fields.len()-1;();for(i,&FieldInfo{ref self_expr,span,..})in fields.iter(). +enumerate(){3;let self_ref=cx.expr_addr_of(span,self_expr.clone());;;let enc=cx. +expr_call(span,fn_path.clone(),thin_vec![self_ref,blkencoder.clone()],);();3;let +lambda=cx.lambda1(span,enc,blkarg);{();};({});let call=cx.expr_call_global(span, +fn_emit_enum_variant_arg_path.clone(),thin_vec![blkencoder.clone(),cx.//((),()); +expr_usize(span,i),lambda],);;let call=if i!=last{cx.expr_try(span,call)}else{cx +.expr(span,ExprKind::Ret(Some(call)))};;;stmts.push(cx.stmt_expr(call));;}}else{ +let ok=cx.expr_ok(trait_span,cx.expr_tuple(trait_span,ThinVec::new()));();();let +ret_ok=cx.expr(trait_span,ExprKind::Ret(Some(ok)));();3;stmts.push(cx.stmt_expr( +ret_ok));3;}3;let blk=cx.lambda_stmts_1(trait_span,stmts,blkarg);3;;let name=cx. +expr_str(trait_span,variant.ident.name);;let fn_emit_enum_variant_path:Vec<_>=cx +.def_site_path(&[sym::rustc_serialize,sym::Encoder,sym::emit_enum_variant]);;let +call=cx.expr_call_global(trait_span,fn_emit_enum_variant_path,thin_vec![//{();}; +blkencoder,name,cx.expr_usize(trait_span,* idx),cx.expr_usize(trait_span,fields. +len()),blk,],);;let blk=cx.lambda1(trait_span,call,blkarg);let fn_emit_enum_path +:Vec<_>=cx.def_site_path(&[sym::rustc_serialize,sym::Encoder,sym::emit_enum]);;; +let expr=cx.expr_call_global(trait_span ,fn_emit_enum_path,thin_vec![encoder,cx. +expr_str(trait_span,substr.type_ident.name),blk],);{();};BlockOrExpr::new_mixed( +thin_vec![me],((((((((((Some(expr))))))))))))}_=>(((((((((cx.dcx()))))))))).bug( +"expected Struct or EnumMatching in derive(Encodable)"),}}//if true{};if true{}; diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index e16d74eed4e07..7f22ebba4c1d1 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -1,1721 +1,336 @@ -//! Some code that abstracts away much of the boilerplate of writing -//! `derive` instances for traits. Among other things it manages getting -//! access to the fields of the 4 different sorts of structs and enum -//! variants, as well as creating the method and impl ast instances. -//! -//! Supported features (fairly exhaustive): -//! -//! - Methods taking any number of parameters of any type, and returning -//! any type, other than vectors, bottom and closures. -//! - Generating `impl`s for types with type parameters and lifetimes -//! (e.g., `Option`), the parameters are automatically given the -//! current trait as a bound. (This includes separate type parameters -//! and lifetimes for methods.) -//! - Additional bounds on the type parameters (`TraitDef.additional_bounds`) -//! -//! The most important thing for implementors is the `Substructure` and -//! `SubstructureFields` objects. The latter groups 5 possibilities of the -//! arguments: -//! -//! - `Struct`, when `Self` is a struct (including tuple structs, e.g -//! `struct T(i32, char)`). -//! - `EnumMatching`, when `Self` is an enum and all the arguments are the -//! same variant of the enum (e.g., `Some(1)`, `Some(3)` and `Some(4)`) -//! - `EnumTag` when `Self` is an enum, for comparing the enum tags. -//! - `StaticEnum` and `StaticStruct` for static methods, where the type -//! being derived upon is either an enum or struct respectively. (Any -//! argument with type Self is just grouped among the non-self -//! arguments.) -//! -//! In the first two cases, the values from the corresponding fields in -//! all the arguments are grouped together. -//! -//! The non-static cases have `Option` in several places associated -//! with field `expr`s. This represents the name of the field it is -//! associated with. It is only not `None` when the associated field has -//! an identifier in the source code. For example, the `x`s in the -//! following snippet -//! -//! ```rust -//! struct A { -//! x: i32, -//! } -//! -//! struct B(i32); -//! -//! enum C { -//! C0(i32), -//! C1 { x: i32 } -//! } -//! ``` -//! -//! The `i32`s in `B` and `C0` don't have an identifier, so the -//! `Option`s would be `None` for them. -//! -//! In the static cases, the structure is summarized, either into the just -//! spans of the fields or a list of spans and the field idents (for tuple -//! structs and record structs, respectively), or a list of these, for -//! enums (one for each variant). For empty struct and empty enum -//! variants, it is represented as a count of 0. -//! -//! # "`cs`" functions -//! -//! The `cs_...` functions ("combine substructure") are designed to -//! make life easier by providing some pre-made recipes for common -//! threads; mostly calling the function being derived on all the -//! arguments and then combining them back together in some way (or -//! letting the user chose that). They are not meant to be the only -//! way to handle the structures that this code creates. -//! -//! # Examples -//! -//! The following simplified `PartialEq` is used for in-code examples: -//! -//! ```rust -//! trait PartialEq { -//! fn eq(&self, other: &Self) -> bool; -//! } -//! -//! impl PartialEq for i32 { -//! fn eq(&self, other: &i32) -> bool { -//! *self == *other -//! } -//! } -//! ``` -//! -//! Some examples of the values of `SubstructureFields` follow, using the -//! above `PartialEq`, `A`, `B` and `C`. -//! -//! ## Structs -//! -//! When generating the `expr` for the `A` impl, the `SubstructureFields` is -//! -//! ```text -//! Struct(vec![FieldInfo { -//! span: , -//! name: Some(), -//! self_: , -//! other: vec![], -//! }]) -//! ``` -//! -//! For the `B` impl, called with `B(a)` and `B(b)`, -//! -//! ```text -//! Struct(vec![FieldInfo { -//! span: , -//! name: None, -//! self_: , -//! other: vec![], -//! }]) -//! ``` -//! -//! ## Enums -//! -//! When generating the `expr` for a call with `self == C0(a)` and `other -//! == C0(b)`, the SubstructureFields is -//! -//! ```text -//! EnumMatching( -//! 0, -//! , -//! vec![FieldInfo { -//! span: , -//! name: None, -//! self_: , -//! other: vec![], -//! }], -//! ) -//! ``` -//! -//! For `C1 {x}` and `C1 {x}`, -//! -//! ```text -//! EnumMatching( -//! 1, -//! , -//! vec![FieldInfo { -//! span: , -//! name: Some(), -//! self_: , -//! other: vec![], -//! }], -//! ) -//! ``` -//! -//! For the tags, -//! -//! ```text -//! EnumTag( -//! &[, ], -//! , -//! ) -//! ``` -//! -//! Note that this setup doesn't allow for the brute-force "match every variant -//! against every other variant" approach, which is bad because it produces a -//! quadratic amount of code (see #15375). -//! -//! ## Static -//! -//! A static method on the types above would result in, -//! -//! ```text -//! StaticStruct(, Named(vec![(, )])) -//! -//! StaticStruct(, Unnamed(vec![])) -//! -//! StaticEnum( -//! , -//! vec![ -//! (, , Unnamed(vec![])), -//! (, , Named(vec![(, )])), -//! ], -//! ) -//! ``` - -pub use StaticFields::*; -pub use SubstructureFields::*; - -use crate::{deriving, errors}; -use rustc_ast::ptr::P; -use rustc_ast::{ - self as ast, BindingAnnotation, ByRef, EnumDef, Expr, GenericArg, GenericParamKind, Generics, - Mutability, PatKind, TyKind, VariantData, -}; -use rustc_attr as attr; -use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_session::lint::builtin::BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{Span, DUMMY_SP}; -use std::cell::RefCell; -use std::iter; -use std::ops::Not; -use std::vec; -use thin_vec::{thin_vec, ThinVec}; -use ty::{Bounds, Path, Ref, Self_, Ty}; - -pub mod ty; - -pub struct TraitDef<'a> { - /// The span for the current #[derive(Foo)] header. - pub span: Span, - - /// 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, - - /// Whether `Copy` is needed as an additional bound on type parameters in a packed struct. - pub needs_copy_as_bound_if_packed: bool, - - /// Additional bounds required of any type parameters of the type, - /// other than the current trait - pub additional_bounds: Vec, - - /// Can this trait be derived for unions? - pub supports_unions: bool, - - pub methods: Vec>, - - pub associated_types: Vec<(Ident, Ty)>, - - pub is_const: bool, -} - -pub struct MethodDef<'a> { - /// name of the method - pub name: Symbol, - /// List of generics, e.g., `R: rand::Rng` - pub generics: Bounds, - - /// Is there is a `&self` argument? If not, it is a static function. - pub explicit_self: bool, - - /// Arguments other than the self argument. - pub nonself_args: Vec<(Ty, Symbol)>, - - /// Returns type - pub ret_ty: Ty, - - pub attributes: ast::AttrVec, - - pub fieldless_variants_strategy: FieldlessVariantsStrategy, - - pub combine_substructure: RefCell>, -} - -/// How to handle fieldless enum variants. -#[derive(PartialEq)] -pub enum FieldlessVariantsStrategy { - /// Combine fieldless variants into a single match arm. - /// This assumes that relevant information has been handled - /// by looking at the enum's discriminant. - Unify, - /// Don't do anything special about fieldless variants. They are - /// handled like any other variant. - Default, - /// If all variants of the enum are fieldless, expand the special - /// `AllFieldLessEnum` substructure, so that the entire enum can be handled - /// at once. - SpecializeIfAllVariantsFieldless, -} - -/// All the data about the data structure/method being derived upon. -pub struct Substructure<'a> { - /// ident of self - pub type_ident: Ident, - /// Verbatim access to any non-selflike arguments, i.e. arguments that - /// don't have type `&Self`. - pub nonselflike_args: &'a [P], - pub fields: &'a SubstructureFields<'a>, -} - -/// Summary of the relevant parts of a struct/enum field. -pub struct FieldInfo { - pub span: Span, - /// None for tuple structs/normal enum variants, Some for normal - /// structs/struct enum variants. - pub name: Option, - /// The expression corresponding to this field of `self` - /// (specifically, a reference to it). - pub self_expr: P, - /// The expressions corresponding to references to this field in - /// the other selflike arguments. - pub other_selflike_exprs: Vec>, -} - -#[derive(Copy, Clone)] -pub enum IsTuple { - No, - Yes, -} - -/// Fields for a static method -pub enum StaticFields { - /// Tuple and unit structs/enum variants like this. - Unnamed(Vec, IsTuple), - /// Normal structs/struct variants. - Named(Vec<(Ident, Span)>), -} - -/// A summary of the possible sets of fields. -pub enum SubstructureFields<'a> { - /// A non-static method where `Self` is a struct. - Struct(&'a ast::VariantData, Vec), - - /// A non-static method handling the entire enum at once - /// (after it has been determined that none of the enum - /// variants has any fields). - AllFieldlessEnum(&'a ast::EnumDef), - - /// Matching variants of the enum: variant index, ast::Variant, - /// fields: the field name is only non-`None` in the case of a struct - /// variant. - EnumMatching(usize, &'a ast::Variant, Vec), - - /// The tag of an enum. The first field is a `FieldInfo` for the tags, as - /// if they were fields. The second field is the expression to combine the - /// tag expression with; it will be `None` if no match is necessary. - EnumTag(FieldInfo, Option>), - - /// A static method where `Self` is a struct. - StaticStruct(&'a ast::VariantData, StaticFields), - - /// A static method where `Self` is an enum. - StaticEnum(&'a ast::EnumDef, Vec<(Ident, Span, StaticFields)>), -} - -/// Combine the values of all the fields together. The last argument is -/// all the fields of all the structures. -pub type CombineSubstructureFunc<'a> = - Box, Span, &Substructure<'_>) -> BlockOrExpr + 'a>; - -pub fn combine_substructure( - f: CombineSubstructureFunc<'_>, -) -> RefCell> { - RefCell::new(f) -} - -struct TypeParameter { - bound_generic_params: ThinVec, - ty: P, -} - -/// The code snippets built up for derived code are sometimes used as blocks -/// (e.g. in a function body) and sometimes used as expressions (e.g. in a match -/// arm). This structure avoids committing to either form until necessary, -/// avoiding the insertion of any unnecessary blocks. -/// -/// The statements come before the expression. -pub struct BlockOrExpr(ThinVec, Option>); - -impl BlockOrExpr { - pub fn new_stmts(stmts: ThinVec) -> BlockOrExpr { - BlockOrExpr(stmts, None) - } - - pub fn new_expr(expr: P) -> BlockOrExpr { - BlockOrExpr(ThinVec::new(), Some(expr)) - } - - pub fn new_mixed(stmts: ThinVec, expr: Option>) -> BlockOrExpr { - BlockOrExpr(stmts, expr) - } - - // Converts it into a block. - fn into_block(mut self, cx: &ExtCtxt<'_>, span: Span) -> P { - if let Some(expr) = self.1 { - self.0.push(cx.stmt_expr(expr)); - } - cx.block(span, self.0) - } - - // Converts it into an expression. - fn into_expr(self, cx: &ExtCtxt<'_>, span: Span) -> P { - if self.0.is_empty() { - match self.1 { - None => cx.expr_block(cx.block(span, ThinVec::new())), - Some(expr) => expr, - } - } else if self.0.len() == 1 - && let ast::StmtKind::Expr(expr) = &self.0[0].kind - && self.1.is_none() - { - // There's only a single statement expression. Pull it out. - expr.clone() - } else { - // Multiple statements and/or expressions. - cx.expr_block(self.into_block(cx, span)) - } - } -} - -/// This method helps to extract all the type parameters referenced from a -/// type. For a type parameter ``, it looks for either a `TyPath` that -/// is not global and starts with `T`, or a `TyQPath`. -/// Also include bound generic params from the input type. -fn find_type_parameters( - ty: &ast::Ty, - ty_param_names: &[Symbol], - cx: &ExtCtxt<'_>, -) -> Vec { - use rustc_ast::visit; - - struct Visitor<'a, 'b> { - cx: &'a ExtCtxt<'b>, - ty_param_names: &'a [Symbol], - bound_generic_params_stack: ThinVec, - type_params: Vec, - } - - impl<'a, 'b> visit::Visitor<'a> for Visitor<'a, 'b> { - fn visit_ty(&mut self, ty: &'a ast::Ty) { - if let ast::TyKind::Path(_, path) = &ty.kind - && let Some(segment) = path.segments.first() - && self.ty_param_names.contains(&segment.ident.name) - { - self.type_params.push(TypeParameter { - bound_generic_params: self.bound_generic_params_stack.clone(), - ty: P(ty.clone()), - }); - } - - visit::walk_ty(self, ty) - } - - // Place bound generic params on a stack, to extract them when a type is encountered. - fn visit_poly_trait_ref(&mut self, trait_ref: &'a ast::PolyTraitRef) { - let stack_len = self.bound_generic_params_stack.len(); - self.bound_generic_params_stack.extend(trait_ref.bound_generic_params.iter().cloned()); - - visit::walk_poly_trait_ref(self, trait_ref); - - self.bound_generic_params_stack.truncate(stack_len); - } - - fn visit_mac_call(&mut self, mac: &ast::MacCall) { - self.cx.dcx().emit_err(errors::DeriveMacroCall { span: mac.span() }); - } - } - - let mut visitor = Visitor { - cx, - ty_param_names, - bound_generic_params_stack: ThinVec::new(), - type_params: Vec::new(), - }; - visit::Visitor::visit_ty(&mut visitor, ty); - - visitor.type_params -} - -impl<'a> TraitDef<'a> { - pub fn expand( - self, - cx: &ExtCtxt<'_>, - mitem: &ast::MetaItem, - item: &'a Annotatable, - push: &mut dyn FnMut(Annotatable), - ) { - self.expand_ext(cx, mitem, item, push, false); - } - - pub fn expand_ext( - self, - cx: &ExtCtxt<'_>, - mitem: &ast::MetaItem, - item: &'a Annotatable, - push: &mut dyn FnMut(Annotatable), - from_scratch: bool, - ) { - match item { - Annotatable::Item(item) => { - let is_packed = item.attrs.iter().any(|attr| { - for r in attr::find_repr_attrs(cx.sess, attr) { - if let attr::ReprPacked(_) = r { - return true; - } - } - false - }); - - let newitem = match &item.kind { - ast::ItemKind::Struct(struct_def, generics) => self.expand_struct_def( - cx, - struct_def, - item.ident, - generics, - from_scratch, - is_packed, - ), - ast::ItemKind::Enum(enum_def, generics) => { - // We ignore `is_packed` here, because `repr(packed)` - // enums cause an error later on. - // - // This can only cause further compilation errors - // downstream in blatantly illegal code, so it is fine. - self.expand_enum_def(cx, enum_def, item.ident, generics, from_scratch) - } - ast::ItemKind::Union(struct_def, generics) => { - if self.supports_unions { - self.expand_struct_def( - cx, - struct_def, - item.ident, - generics, - from_scratch, - is_packed, - ) - } else { - cx.dcx().emit_err(errors::DeriveUnion { span: mitem.span }); - return; - } - } - _ => unreachable!(), - }; - // Keep the lint attributes of the previous item to control how the - // generated implementations are linted - let mut attrs = newitem.attrs.clone(); - attrs.extend( - item.attrs - .iter() - .filter(|a| { - [ - sym::allow, - sym::warn, - sym::deny, - sym::forbid, - sym::stable, - sym::unstable, - ] - .contains(&a.name_or_empty()) - }) - .cloned(), - ); - push(Annotatable::Item(P(ast::Item { attrs, ..(*newitem).clone() }))) - } - _ => unreachable!(), - } - } - - /// Given that we are deriving a trait `DerivedTrait` for a type like: - /// - /// ```ignore (only-for-syntax-highlight) - /// struct Struct<'a, ..., 'z, A, B: DeclaredTrait, C, ..., Z> - /// where - /// C: WhereTrait, - /// { - /// a: A, - /// b: B::Item, - /// b1: ::Item, - /// c1: ::Item, - /// c2: Option<::Item>, - /// ... - /// } - /// ``` - /// - /// create an impl like: - /// - /// ```ignore (only-for-syntax-highlight) - /// impl<'a, ..., 'z, A, B: DeclaredTrait, C, ..., Z> - /// where - /// C: WhereTrait, - /// A: DerivedTrait + B1 + ... + BN, - /// B: DerivedTrait + B1 + ... + BN, - /// C: DerivedTrait + B1 + ... + BN, - /// B::Item: DerivedTrait + B1 + ... + BN, - /// ::Item: DerivedTrait + B1 + ... + BN, - /// ... - /// { - /// ... - /// } - /// ``` - /// - /// where B1, ..., BN are the bounds given by `bounds_paths`.'. Z is a phantom type, and - /// therefore does not get bound by the derived trait. - fn create_derived_impl( - &self, - cx: &ExtCtxt<'_>, - type_ident: Ident, - generics: &Generics, - field_tys: Vec>, - methods: Vec>, - is_packed: bool, - ) -> P { - let trait_path = self.path.to_path(cx, self.span, type_ident, generics); - - // Transform associated types from `deriving::ty::Ty` into `ast::AssocItem` - let associated_types = self.associated_types.iter().map(|&(ident, ref type_def)| { - P(ast::AssocItem { - id: ast::DUMMY_NODE_ID, - span: self.span, - ident, - vis: ast::Visibility { - span: self.span.shrink_to_lo(), - kind: ast::VisibilityKind::Inherited, - tokens: None, - }, - attrs: ast::AttrVec::new(), - kind: ast::AssocItemKind::Type(Box::new(ast::TyAlias { - defaultness: ast::Defaultness::Final, - generics: Generics::default(), - where_clauses: ast::TyAliasWhereClauses::default(), - bounds: Vec::new(), - ty: Some(type_def.to_ty(cx, self.span, type_ident, generics)), - })), - tokens: None, - }) - }); - - let mut where_clause = ast::WhereClause::default(); - where_clause.span = generics.where_clause.span; - let ctxt = self.span.ctxt(); - let span = generics.span.with_ctxt(ctxt); - - // Create the generic parameters - let params: ThinVec<_> = generics - .params - .iter() - .map(|param| match ¶m.kind { - GenericParamKind::Lifetime { .. } => param.clone(), - GenericParamKind::Type { .. } => { - // Extra restrictions on the generics parameters to the - // type being derived upon. - let bounds: Vec<_> = self - .additional_bounds - .iter() - .map(|p| { - cx.trait_bound( - p.to_path(cx, self.span, type_ident, generics), - self.is_const, - ) - }) - .chain( - // Add a bound for the current trait. - self.skip_path_as_bound - .not() - .then(|| cx.trait_bound(trait_path.clone(), self.is_const)), - ) - .chain({ - // Add a `Copy` bound if required. - if is_packed && self.needs_copy_as_bound_if_packed { - let p = deriving::path_std!(marker::Copy); - Some(cx.trait_bound( - p.to_path(cx, self.span, type_ident, generics), - self.is_const, - )) - } else { - None - } - }) - .chain( - // Also add in any bounds from the declaration. - param.bounds.iter().cloned(), - ) - .collect(); - - cx.typaram(param.ident.span.with_ctxt(ctxt), param.ident, bounds, None) - } - GenericParamKind::Const { ty, kw_span, .. } => { - let const_nodefault_kind = GenericParamKind::Const { - ty: ty.clone(), - kw_span: kw_span.with_ctxt(ctxt), - - // We can't have default values inside impl block - default: None, - }; - let mut param_clone = param.clone(); - param_clone.kind = const_nodefault_kind; - param_clone - } - }) - .collect(); - - // and similarly for where clauses - where_clause.predicates.extend(generics.where_clause.predicates.iter().map(|clause| { - match clause { - ast::WherePredicate::BoundPredicate(wb) => { - let span = wb.span.with_ctxt(ctxt); - ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate { - span, - ..wb.clone() - }) - } - ast::WherePredicate::RegionPredicate(wr) => { - let span = wr.span.with_ctxt(ctxt); - ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate { - span, - ..wr.clone() - }) - } - ast::WherePredicate::EqPredicate(we) => { - let span = we.span.with_ctxt(ctxt); - ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { span, ..we.clone() }) - } - } - })); - - let ty_param_names: Vec = params - .iter() - .filter(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })) - .map(|ty_param| ty_param.ident.name) - .collect(); - - if !ty_param_names.is_empty() { - for field_ty in field_tys { - let field_ty_params = find_type_parameters(&field_ty, &ty_param_names, cx); - - for field_ty_param in field_ty_params { - // if we have already handled this type, skip it - if let ast::TyKind::Path(_, p) = &field_ty_param.ty.kind - && let [sole_segment] = &*p.segments - && ty_param_names.contains(&sole_segment.ident.name) - { - continue; - } - let mut bounds: Vec<_> = self - .additional_bounds - .iter() - .map(|p| { - cx.trait_bound( - p.to_path(cx, self.span, type_ident, generics), - self.is_const, - ) - }) - .collect(); - - // Require the current trait. - if !self.skip_path_as_bound { - bounds.push(cx.trait_bound(trait_path.clone(), self.is_const)); - } - - // Add a `Copy` bound if required. - if is_packed && self.needs_copy_as_bound_if_packed { - let p = deriving::path_std!(marker::Copy); - bounds.push(cx.trait_bound( - p.to_path(cx, self.span, type_ident, generics), - self.is_const, - )); - } - - if !bounds.is_empty() { - let predicate = ast::WhereBoundPredicate { - span: self.span, - bound_generic_params: field_ty_param.bound_generic_params, - bounded_ty: field_ty_param.ty, - bounds, - }; - - let predicate = ast::WherePredicate::BoundPredicate(predicate); - where_clause.predicates.push(predicate); - } - } - } - } - - let trait_generics = Generics { params, where_clause, span }; - - // Create the reference to the trait. - let trait_ref = cx.trait_ref(trait_path); - - let self_params: Vec<_> = generics - .params - .iter() - .map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - GenericArg::Lifetime(cx.lifetime(param.ident.span.with_ctxt(ctxt), param.ident)) - } - GenericParamKind::Type { .. } => { - GenericArg::Type(cx.ty_ident(param.ident.span.with_ctxt(ctxt), param.ident)) - } - GenericParamKind::Const { .. } => { - GenericArg::Const(cx.const_ident(param.ident.span.with_ctxt(ctxt), param.ident)) - } - }) - .collect(); - - // Create the type of `self`. - let path = cx.path_all(self.span, false, vec![type_ident], self_params); - let self_type = cx.ty_path(path); - - let attrs = thin_vec![cx.attr_word(sym::automatically_derived, self.span),]; - let opt_trait_ref = Some(trait_ref); - - cx.item( - self.span, - Ident::empty(), - attrs, - ast::ItemKind::Impl(Box::new(ast::Impl { - unsafety: ast::Unsafe::No, - polarity: ast::ImplPolarity::Positive, - defaultness: ast::Defaultness::Final, - constness: if self.is_const { ast::Const::Yes(DUMMY_SP) } else { ast::Const::No }, - generics: trait_generics, - of_trait: opt_trait_ref, - self_ty: self_type, - items: methods.into_iter().chain(associated_types).collect(), - })), - ) - } - - fn expand_struct_def( - &self, - cx: &ExtCtxt<'_>, - struct_def: &'a VariantData, - type_ident: Ident, - generics: &Generics, - from_scratch: bool, - is_packed: bool, - ) -> P { - let field_tys: Vec> = - struct_def.fields().iter().map(|field| field.ty.clone()).collect(); - - let methods = self - .methods - .iter() - .map(|method_def| { - let (explicit_self, selflike_args, nonselflike_args, nonself_arg_tys) = - method_def.extract_arg_details(cx, self, type_ident, generics); - - let body = if from_scratch || method_def.is_static() { - method_def.expand_static_struct_method_body( - cx, - self, - struct_def, - type_ident, - &nonselflike_args, - ) - } else { - method_def.expand_struct_method_body( - cx, - self, - struct_def, - type_ident, - &selflike_args, - &nonselflike_args, - is_packed, - ) - }; - - method_def.create_method( - cx, - self, - type_ident, - generics, - explicit_self, - nonself_arg_tys, - body, - ) - }) - .collect(); - - self.create_derived_impl(cx, type_ident, generics, field_tys, methods, is_packed) - } - - fn expand_enum_def( - &self, - cx: &ExtCtxt<'_>, - enum_def: &'a EnumDef, - type_ident: Ident, - generics: &Generics, - from_scratch: bool, - ) -> P { - let mut field_tys = Vec::new(); - - for variant in &enum_def.variants { - field_tys.extend(variant.data.fields().iter().map(|field| field.ty.clone())); - } - - let methods = self - .methods - .iter() - .map(|method_def| { - let (explicit_self, selflike_args, nonselflike_args, nonself_arg_tys) = - method_def.extract_arg_details(cx, self, type_ident, generics); - - let body = if from_scratch || method_def.is_static() { - method_def.expand_static_enum_method_body( - cx, - self, - enum_def, - type_ident, - &nonselflike_args, - ) - } else { - method_def.expand_enum_method_body( - cx, - self, - enum_def, - type_ident, - selflike_args, - &nonselflike_args, - ) - }; - - method_def.create_method( - cx, - self, - type_ident, - generics, - explicit_self, - nonself_arg_tys, - body, - ) - }) - .collect(); - - let is_packed = false; // enums are never packed - self.create_derived_impl(cx, type_ident, generics, field_tys, methods, is_packed) - } -} - -impl<'a> MethodDef<'a> { - fn call_substructure_method( - &self, - cx: &ExtCtxt<'_>, - trait_: &TraitDef<'_>, - type_ident: Ident, - nonselflike_args: &[P], - fields: &SubstructureFields<'_>, - ) -> BlockOrExpr { - let span = trait_.span; - let substructure = Substructure { type_ident, nonselflike_args, fields }; - let mut f = self.combine_substructure.borrow_mut(); - let f: &mut CombineSubstructureFunc<'_> = &mut *f; - f(cx, span, &substructure) - } - - fn get_ret_ty( - &self, - cx: &ExtCtxt<'_>, - trait_: &TraitDef<'_>, - generics: &Generics, - type_ident: Ident, - ) -> P { - self.ret_ty.to_ty(cx, trait_.span, type_ident, generics) - } - - fn is_static(&self) -> bool { - !self.explicit_self - } - - // The return value includes: - // - explicit_self: The `&self` arg, if present. - // - selflike_args: Expressions for `&self` (if present) and also any other - // args with the same type (e.g. the `other` arg in `PartialEq::eq`). - // - nonselflike_args: Expressions for all the remaining args. - // - nonself_arg_tys: Additional information about all the args other than - // `&self`. - fn extract_arg_details( - &self, - cx: &ExtCtxt<'_>, - trait_: &TraitDef<'_>, - type_ident: Ident, - generics: &Generics, - ) -> (Option, ThinVec>, Vec>, Vec<(Ident, P)>) { - let mut selflike_args = ThinVec::new(); - let mut nonselflike_args = Vec::new(); - let mut nonself_arg_tys = Vec::new(); - let span = trait_.span; - - let explicit_self = self.explicit_self.then(|| { - let (self_expr, explicit_self) = ty::get_explicit_self(cx, span); - selflike_args.push(self_expr); - explicit_self - }); - - for (ty, name) in self.nonself_args.iter() { - let ast_ty = ty.to_ty(cx, span, type_ident, generics); - let ident = Ident::new(*name, span); - nonself_arg_tys.push((ident, ast_ty)); - - let arg_expr = cx.expr_ident(span, ident); - - match ty { - // Selflike (`&Self`) arguments only occur in non-static methods. - Ref(box Self_, _) if !self.is_static() => selflike_args.push(arg_expr), - Self_ => cx.dcx().span_bug(span, "`Self` in non-return position"), - _ => nonselflike_args.push(arg_expr), - } - } - - (explicit_self, selflike_args, nonselflike_args, nonself_arg_tys) - } - - fn create_method( - &self, - cx: &ExtCtxt<'_>, - trait_: &TraitDef<'_>, - type_ident: Ident, - generics: &Generics, - explicit_self: Option, - nonself_arg_tys: Vec<(Ident, P)>, - body: BlockOrExpr, - ) -> P { - let span = trait_.span; - // Create the generics that aren't for `Self`. - let fn_generics = self.generics.to_generics(cx, span, type_ident, generics); - - let args = { - let self_arg = explicit_self.map(|explicit_self| { - let ident = Ident::with_dummy_span(kw::SelfLower).with_span_pos(span); - ast::Param::from_self(ast::AttrVec::default(), explicit_self, ident) - }); - let nonself_args = - nonself_arg_tys.into_iter().map(|(name, ty)| cx.param(span, name, ty)); - self_arg.into_iter().chain(nonself_args).collect() - }; - - let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident); - - let method_ident = Ident::new(self.name, span); - let fn_decl = cx.fn_decl(args, ast::FnRetTy::Ty(ret_type)); - let body_block = body.into_block(cx, span); - - let trait_lo_sp = span.shrink_to_lo(); - - let sig = ast::FnSig { header: ast::FnHeader::default(), decl: fn_decl, span }; - let defaultness = ast::Defaultness::Final; - - // Create the method. - P(ast::AssocItem { - id: ast::DUMMY_NODE_ID, - attrs: self.attributes.clone(), - span, - vis: ast::Visibility { - span: trait_lo_sp, - kind: ast::VisibilityKind::Inherited, - tokens: None, - }, - ident: method_ident, - kind: ast::AssocItemKind::Fn(Box::new(ast::Fn { - defaultness, - sig, - generics: fn_generics, - body: Some(body_block), - })), - tokens: None, - }) - } - - /// The normal case uses field access. - /// - /// ``` - /// #[derive(PartialEq)] - /// # struct Dummy; - /// struct A { x: u8, y: u8 } - /// - /// // equivalent to: - /// impl PartialEq for A { - /// fn eq(&self, other: &A) -> bool { - /// self.x == other.x && self.y == other.y - /// } - /// } - /// ``` - /// - /// But if the struct is `repr(packed)`, we can't use something like - /// `&self.x` because that might cause an unaligned ref. So for any trait - /// method that takes a reference, we use a local block to force a copy. - /// This requires that the field impl `Copy`. - /// - /// ```rust,ignore (example) - /// # struct A { x: u8, y: u8 } - /// impl PartialEq for A { - /// fn eq(&self, other: &A) -> bool { - /// // Desugars to `{ self.x }.eq(&{ other.y }) && ...` - /// { self.x } == { other.y } && { self.y } == { other.y } - /// } - /// } - /// impl Hash for A { - /// fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { - /// ::core::hash::Hash::hash(&{ self.x }, state); - /// ::core::hash::Hash::hash(&{ self.y }, state); - /// } - /// } - /// ``` - fn expand_struct_method_body<'b>( - &self, - cx: &ExtCtxt<'_>, - trait_: &TraitDef<'b>, - struct_def: &'b VariantData, - type_ident: Ident, - selflike_args: &[P], - nonselflike_args: &[P], - is_packed: bool, - ) -> BlockOrExpr { - assert!(selflike_args.len() == 1 || selflike_args.len() == 2); - - let selflike_fields = - trait_.create_struct_field_access_fields(cx, selflike_args, struct_def, is_packed); - self.call_substructure_method( - cx, - trait_, - type_ident, - nonselflike_args, - &Struct(struct_def, selflike_fields), - ) - } - - fn expand_static_struct_method_body( - &self, - cx: &ExtCtxt<'_>, - trait_: &TraitDef<'_>, - struct_def: &VariantData, - type_ident: Ident, - nonselflike_args: &[P], - ) -> BlockOrExpr { - let summary = trait_.summarise_struct(cx, struct_def); - - self.call_substructure_method( - cx, - trait_, - type_ident, - nonselflike_args, - &StaticStruct(struct_def, summary), - ) - } - - /// ``` - /// #[derive(PartialEq)] - /// # struct Dummy; - /// enum A { - /// A1, - /// A2(i32) - /// } - /// ``` - /// - /// is equivalent to: - /// - /// ``` - /// #![feature(core_intrinsics)] - /// enum A { - /// A1, - /// A2(i32) - /// } - /// impl ::core::cmp::PartialEq for A { - /// #[inline] - /// fn eq(&self, other: &A) -> bool { - /// let __self_tag = ::core::intrinsics::discriminant_value(self); - /// let __arg1_tag = ::core::intrinsics::discriminant_value(other); - /// __self_tag == __arg1_tag - /// && match (self, other) { - /// (A::A2(__self_0), A::A2(__arg1_0)) => *__self_0 == *__arg1_0, - /// _ => true, - /// } - /// } - /// } - /// ``` - /// - /// Creates a tag check combined with a match for a tuple of all - /// `selflike_args`, with an arm for each variant with fields, possibly an - /// arm for each fieldless variant (if `unify_fieldless_variants` is not - /// `Unify`), and possibly a default arm. - fn expand_enum_method_body<'b>( - &self, - cx: &ExtCtxt<'_>, - trait_: &TraitDef<'b>, - enum_def: &'b EnumDef, - type_ident: Ident, - mut selflike_args: ThinVec>, - nonselflike_args: &[P], - ) -> BlockOrExpr { - assert!( - !selflike_args.is_empty(), - "static methods must use `expand_static_enum_method_body`", - ); - - let span = trait_.span; - let variants = &enum_def.variants; - - // Traits that unify fieldless variants always use the tag(s). - let unify_fieldless_variants = - self.fieldless_variants_strategy == FieldlessVariantsStrategy::Unify; - - // For zero-variant enum, this function body is unreachable. Generate - // `match *self {}`. This produces machine code identical to `unsafe { - // core::intrinsics::unreachable() }` while being safe and stable. - if variants.is_empty() { - selflike_args.truncate(1); - let match_arg = cx.expr_deref(span, selflike_args.pop().unwrap()); - let match_arms = ThinVec::new(); - let expr = cx.expr_match(span, match_arg, match_arms); - return BlockOrExpr(ThinVec::new(), Some(expr)); - } - - let prefixes = iter::once("__self".to_string()) - .chain( - selflike_args - .iter() - .enumerate() - .skip(1) - .map(|(arg_count, _selflike_arg)| format!("__arg{arg_count}")), - ) - .collect::>(); - - // Build a series of let statements mapping each selflike_arg - // to its discriminant value. - // - // e.g. for `PartialEq::eq` builds two statements: - // ``` - // let __self_tag = ::core::intrinsics::discriminant_value(self); - // let __arg1_tag = ::core::intrinsics::discriminant_value(other); - // ``` - let get_tag_pieces = |cx: &ExtCtxt<'_>| { - let tag_idents: Vec<_> = prefixes - .iter() - .map(|name| Ident::from_str_and_span(&format!("{name}_tag"), span)) - .collect(); - - let mut tag_exprs: Vec<_> = tag_idents - .iter() - .map(|&ident| cx.expr_addr_of(span, cx.expr_ident(span, ident))) - .collect(); - - let self_expr = tag_exprs.remove(0); - let other_selflike_exprs = tag_exprs; - let tag_field = FieldInfo { span, name: None, self_expr, other_selflike_exprs }; - - let tag_let_stmts: ThinVec<_> = iter::zip(&tag_idents, &selflike_args) - .map(|(&ident, selflike_arg)| { - let variant_value = deriving::call_intrinsic( - cx, - span, - sym::discriminant_value, - thin_vec![selflike_arg.clone()], - ); - cx.stmt_let(span, false, ident, variant_value) - }) - .collect(); - - (tag_field, tag_let_stmts) - }; - - // There are some special cases involving fieldless enums where no - // match is necessary. - let all_fieldless = variants.iter().all(|v| v.data.fields().is_empty()); - if all_fieldless { - if variants.len() > 1 { - match self.fieldless_variants_strategy { - FieldlessVariantsStrategy::Unify => { - // If the type is fieldless and the trait uses the tag and - // there are multiple variants, we need just an operation on - // the tag(s). - let (tag_field, mut tag_let_stmts) = get_tag_pieces(cx); - let mut tag_check = self.call_substructure_method( - cx, - trait_, - type_ident, - nonselflike_args, - &EnumTag(tag_field, None), - ); - tag_let_stmts.append(&mut tag_check.0); - return BlockOrExpr(tag_let_stmts, tag_check.1); - } - FieldlessVariantsStrategy::SpecializeIfAllVariantsFieldless => { - return self.call_substructure_method( - cx, - trait_, - type_ident, - nonselflike_args, - &AllFieldlessEnum(enum_def), - ); - } - FieldlessVariantsStrategy::Default => (), - } - } else if variants.len() == 1 { - // If there is a single variant, we don't need an operation on - // the tag(s). Just use the most degenerate result. - return self.call_substructure_method( - cx, - trait_, - type_ident, - nonselflike_args, - &EnumMatching(0, &variants[0], Vec::new()), - ); - } - } - - // These arms are of the form: - // (Variant1, Variant1, ...) => Body1 - // (Variant2, Variant2, ...) => Body2 - // ... - // where each tuple has length = selflike_args.len() - let mut match_arms: ThinVec = variants - .iter() - .enumerate() - .filter(|&(_, v)| !(unify_fieldless_variants && v.data.fields().is_empty())) - .map(|(index, variant)| { - // A single arm has form (&VariantK, &VariantK, ...) => BodyK - // (see "Final wrinkle" note below for why.) - - let fields = trait_.create_struct_pattern_fields(cx, &variant.data, &prefixes); - - let sp = variant.span.with_ctxt(trait_.span.ctxt()); - let variant_path = cx.path(sp, vec![type_ident, variant.ident]); - let by_ref = ByRef::No; // because enums can't be repr(packed) - let mut subpats = trait_.create_struct_patterns( - cx, - variant_path, - &variant.data, - &prefixes, - by_ref, - ); - - // `(VariantK, VariantK, ...)` or just `VariantK`. - let single_pat = if subpats.len() == 1 { - subpats.pop().unwrap() - } else { - cx.pat_tuple(span, subpats) - }; - - // For the BodyK, we need to delegate to our caller, - // passing it an EnumMatching to indicate which case - // we are in. - // - // Now, for some given VariantK, we have built up - // expressions for referencing every field of every - // Self arg, assuming all are instances of VariantK. - // Build up code associated with such a case. - let substructure = EnumMatching(index, variant, fields); - let arm_expr = self - .call_substructure_method( - cx, - trait_, - type_ident, - nonselflike_args, - &substructure, - ) - .into_expr(cx, span); - - cx.arm(span, single_pat, arm_expr) - }) - .collect(); - - // Add a default arm to the match, if necessary. - let first_fieldless = variants.iter().find(|v| v.data.fields().is_empty()); - let default = match first_fieldless { - Some(v) if unify_fieldless_variants => { - // We need a default case that handles all the fieldless - // variants. The index and actual variant aren't meaningful in - // this case, so just use dummy values. - Some( - self.call_substructure_method( - cx, - trait_, - type_ident, - nonselflike_args, - &EnumMatching(0, v, Vec::new()), - ) - .into_expr(cx, span), - ) - } - _ if variants.len() > 1 && selflike_args.len() > 1 => { - // Because we know that all the arguments will match if we reach - // the match expression we add the unreachable intrinsics as the - // result of the default which should help llvm in optimizing it. - Some(deriving::call_unreachable(cx, span)) - } - _ => None, - }; - if let Some(arm) = default { - match_arms.push(cx.arm(span, cx.pat_wild(span), arm)); - } - - // Create a match expression with one arm per discriminant plus - // possibly a default arm, e.g.: - // match (self, other) { - // (Variant1, Variant1, ...) => Body1 - // (Variant2, Variant2, ...) => Body2, - // ... - // _ => ::core::intrinsics::unreachable(), - // } - let get_match_expr = |mut selflike_args: ThinVec>| { - let match_arg = if selflike_args.len() == 1 { - selflike_args.pop().unwrap() - } else { - cx.expr(span, ast::ExprKind::Tup(selflike_args)) - }; - cx.expr_match(span, match_arg, match_arms) - }; - - // If the trait uses the tag and there are multiple variants, we need - // to add a tag check operation before the match. Otherwise, the match - // is enough. - if unify_fieldless_variants && variants.len() > 1 { - let (tag_field, mut tag_let_stmts) = get_tag_pieces(cx); - - // Combine a tag check with the match. - let mut tag_check_plus_match = self.call_substructure_method( - cx, - trait_, - type_ident, - nonselflike_args, - &EnumTag(tag_field, Some(get_match_expr(selflike_args))), - ); - tag_let_stmts.append(&mut tag_check_plus_match.0); - BlockOrExpr(tag_let_stmts, tag_check_plus_match.1) - } else { - BlockOrExpr(ThinVec::new(), Some(get_match_expr(selflike_args))) - } - } - - fn expand_static_enum_method_body( - &self, - cx: &ExtCtxt<'_>, - trait_: &TraitDef<'_>, - enum_def: &EnumDef, - type_ident: Ident, - nonselflike_args: &[P], - ) -> BlockOrExpr { - let summary = enum_def - .variants - .iter() - .map(|v| { - let sp = v.span.with_ctxt(trait_.span.ctxt()); - let summary = trait_.summarise_struct(cx, &v.data); - (v.ident, sp, summary) - }) - .collect(); - self.call_substructure_method( - cx, - trait_, - type_ident, - nonselflike_args, - &StaticEnum(enum_def, summary), - ) - } -} - -// general helper methods. -impl<'a> TraitDef<'a> { - fn summarise_struct(&self, cx: &ExtCtxt<'_>, struct_def: &VariantData) -> StaticFields { - let mut named_idents = Vec::new(); - let mut just_spans = Vec::new(); - for field in struct_def.fields() { - let sp = field.span.with_ctxt(self.span.ctxt()); - match field.ident { - Some(ident) => named_idents.push((ident, sp)), - _ => just_spans.push(sp), - } - } - - let is_tuple = match struct_def { - ast::VariantData::Tuple(..) => IsTuple::Yes, - _ => IsTuple::No, - }; - match (just_spans.is_empty(), named_idents.is_empty()) { - (false, false) => cx - .dcx() - .span_bug(self.span, "a struct with named and unnamed fields in generic `derive`"), - // named fields - (_, false) => Named(named_idents), - // unnamed fields - (false, _) => Unnamed(just_spans, is_tuple), - // empty - _ => Named(Vec::new()), - } - } - - fn create_struct_patterns( - &self, - cx: &ExtCtxt<'_>, - struct_path: ast::Path, - struct_def: &'a VariantData, - prefixes: &[String], - by_ref: ByRef, - ) -> ThinVec> { - prefixes - .iter() - .map(|prefix| { - let pieces_iter = - struct_def.fields().iter().enumerate().map(|(i, struct_field)| { - let sp = struct_field.span.with_ctxt(self.span.ctxt()); - let ident = self.mk_pattern_ident(prefix, i); - let path = ident.with_span_pos(sp); - ( - sp, - struct_field.ident, - cx.pat( - path.span, - PatKind::Ident( - BindingAnnotation(by_ref, Mutability::Not), - path, - None, - ), - ), - ) - }); - - let struct_path = struct_path.clone(); - match *struct_def { - VariantData::Struct { .. } => { - let field_pats = pieces_iter - .map(|(sp, ident, pat)| { - if ident.is_none() { - cx.dcx().span_bug( - sp, - "a braced struct with unnamed fields in `derive`", - ); - } - ast::PatField { - ident: ident.unwrap(), - is_shorthand: false, - attrs: ast::AttrVec::new(), - id: ast::DUMMY_NODE_ID, - span: pat.span.with_ctxt(self.span.ctxt()), - pat, - is_placeholder: false, - } - }) - .collect(); - cx.pat_struct(self.span, struct_path, field_pats) - } - VariantData::Tuple(..) => { - let subpats = pieces_iter.map(|(_, _, subpat)| subpat).collect(); - cx.pat_tuple_struct(self.span, struct_path, subpats) - } - VariantData::Unit(..) => cx.pat_path(self.span, struct_path), - } - }) - .collect() - } - - fn create_fields(&self, struct_def: &'a VariantData, mk_exprs: F) -> Vec - where - F: Fn(usize, &ast::FieldDef, Span) -> Vec>, - { - struct_def - .fields() - .iter() - .enumerate() - .map(|(i, struct_field)| { - // For this field, get an expr for each selflike_arg. E.g. for - // `PartialEq::eq`, one for each of `&self` and `other`. - let sp = struct_field.span.with_ctxt(self.span.ctxt()); - let mut exprs: Vec<_> = mk_exprs(i, struct_field, sp); - let self_expr = exprs.remove(0); - let other_selflike_exprs = exprs; - FieldInfo { - span: sp.with_ctxt(self.span.ctxt()), - name: struct_field.ident, - self_expr, - other_selflike_exprs, - } - }) - .collect() - } - - fn mk_pattern_ident(&self, prefix: &str, i: usize) -> Ident { - Ident::from_str_and_span(&format!("{prefix}_{i}"), self.span) - } - - fn create_struct_pattern_fields( - &self, - cx: &ExtCtxt<'_>, - struct_def: &'a VariantData, - prefixes: &[String], - ) -> Vec { - self.create_fields(struct_def, |i, _struct_field, sp| { - prefixes - .iter() - .map(|prefix| { - let ident = self.mk_pattern_ident(prefix, i); - cx.expr_path(cx.path_ident(sp, ident)) - }) - .collect() - }) - } - - fn create_struct_field_access_fields( - &self, - cx: &ExtCtxt<'_>, - selflike_args: &[P], - struct_def: &'a VariantData, - is_packed: bool, - ) -> Vec { - self.create_fields(struct_def, |i, struct_field, sp| { - selflike_args - .iter() - .map(|selflike_arg| { - // Note: we must use `struct_field.span` rather than `sp` in the - // `unwrap_or_else` case otherwise the hygiene is wrong and we get - // "field `0` of struct `Point` is private" errors on tuple - // structs. - let mut field_expr = cx.expr( - sp, - ast::ExprKind::Field( - selflike_arg.clone(), - struct_field.ident.unwrap_or_else(|| { - Ident::from_str_and_span(&i.to_string(), struct_field.span) - }), - ), - ); - if is_packed { - // In general, fields in packed structs are copied via a - // block, e.g. `&{self.0}`. The two exceptions are `[u8]` - // and `str` fields, which cannot be copied and also never - // cause unaligned references. These exceptions are allowed - // to handle the `FlexZeroSlice` type in the `zerovec` - // crate within `icu4x-0.9.0`. - // - // Once use of `icu4x-0.9.0` has dropped sufficiently, this - // exception should be removed. - let is_simple_path = |ty: &P, sym| { - if let TyKind::Path(None, ast::Path { segments, .. }) = &ty.kind - && let [seg] = segments.as_slice() - && seg.ident.name == sym - && seg.args.is_none() - { - true - } else { - false - } - }; - - let exception = if let TyKind::Slice(ty) = &struct_field.ty.kind - && is_simple_path(ty, sym::u8) - { - Some("byte") - } else if is_simple_path(&struct_field.ty, sym::str) { - Some("string") - } else { - None - }; - - if let Some(ty) = exception { - cx.sess.psess.buffer_lint_with_diagnostic( - BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE, - sp, - ast::CRATE_NODE_ID, - format!( - "{ty} slice in a packed struct that derives a built-in trait" - ), - rustc_lint_defs::BuiltinLintDiag::ByteSliceInPackedStructWithDerive, - ); - } else { - // Wrap the expression in `{...}`, causing a copy. - field_expr = cx.expr_block( - cx.block(struct_field.span, thin_vec![cx.stmt_expr(field_expr)]), - ); - } - } - cx.expr_addr_of(sp, field_expr) - }) - .collect() - }) - } -} - -/// The function passed to `cs_fold` is called repeatedly with a value of this -/// type. It describes one part of the code generation. The result is always an -/// expression. -pub enum CsFold<'a> { - /// The basic case: a field expression for one or more selflike args. E.g. - /// for `PartialEq::eq` this is something like `self.x == other.x`. - Single(&'a FieldInfo), - - /// The combination of two field expressions. E.g. for `PartialEq::eq` this - /// is something like ` && `. - Combine(Span, P, P), - - // The fallback case for a struct or enum variant with no fields. - Fieldless, -} - -/// Folds over fields, combining the expressions for each field in a sequence. -/// Statics may not be folded over. -pub fn cs_fold( - use_foldl: bool, - cx: &ExtCtxt<'_>, - trait_span: Span, - substructure: &Substructure<'_>, - mut f: F, -) -> P -where - F: FnMut(&ExtCtxt<'_>, CsFold<'_>) -> P, -{ - match substructure.fields { - EnumMatching(.., all_fields) | Struct(_, all_fields) => { - if all_fields.is_empty() { - return f(cx, CsFold::Fieldless); - } - - let (base_field, rest) = if use_foldl { - all_fields.split_first().unwrap() - } else { - all_fields.split_last().unwrap() - }; - - let base_expr = f(cx, CsFold::Single(base_field)); - - let op = |old, field: &FieldInfo| { - let new = f(cx, CsFold::Single(field)); - f(cx, CsFold::Combine(field.span, old, new)) - }; - - if use_foldl { - rest.iter().fold(base_expr, op) - } else { - rest.iter().rfold(base_expr, op) - } - } - EnumTag(tag_field, match_expr) => { - let tag_check_expr = f(cx, CsFold::Single(tag_field)); - if let Some(match_expr) = match_expr { - if use_foldl { - f(cx, CsFold::Combine(trait_span, tag_check_expr, match_expr.clone())) - } else { - f(cx, CsFold::Combine(trait_span, match_expr.clone(), tag_check_expr)) - } - } else { - tag_check_expr - } - } - StaticEnum(..) | StaticStruct(..) => { - cx.dcx().span_bug(trait_span, "static function in `derive`") - } - AllFieldlessEnum(..) => cx.dcx().span_bug(trait_span, "fieldless enum in `derive`"), - } -} +pub use StaticFields::*;pub use SubstructureFields::*;use crate::{deriving,//(); +errors};use rustc_ast::ptr::P;use rustc_ast::{self as ast,BindingAnnotation,//3; +ByRef,EnumDef,Expr,GenericArg,GenericParamKind,Generics,Mutability,PatKind,//(); +TyKind,VariantData,};use rustc_attr as attr;use rustc_expand::base::{//let _=(); +Annotatable,ExtCtxt};use rustc_session::lint::builtin:://let _=||();loop{break}; +BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE;use rustc_span::symbol::{kw,sym,Ident,// +Symbol};use rustc_span::{Span,DUMMY_SP};use std::cell::RefCell;use std::iter;//; +use std::ops::Not;use std::vec;use thin_vec::{thin_vec,ThinVec};use ty::{Bounds +,Path,Ref,Self_,Ty};pub mod ty;pub struct TraitDef<'a>{pub span:Span,pub path:// +Path,pub skip_path_as_bound:bool,pub needs_copy_as_bound_if_packed:bool,pub//(); +additional_bounds:Vec,pub supports_unions: bool,pub methods:Vec>,pub associated_types:Vec<(Ident,Ty) >,pub is_const:bool,}pub struct MethodDef +<'a>{pub name:Symbol,pub generics:Bounds,pub explicit_self:bool,pub//let _=||(); +nonself_args:Vec<(Ty,Symbol)>,pub ret_ty:Ty,pub attributes:ast::AttrVec,pub//(); +fieldless_variants_strategy:FieldlessVariantsStrategy, pub combine_substructure: +RefCell>,}#[derive(PartialEq)]pub enum//loop{break}; +FieldlessVariantsStrategy{Unify,Default,SpecializeIfAllVariantsFieldless,}pub//; +struct Substructure<'a>{pub type_ident:Ident, pub nonselflike_args:&'a[P], +pub fields:&'a SubstructureFields<'a>,}pub struct FieldInfo{pub span:Span,pub//; +name:Option,pub self_expr:P< Expr>,pub other_selflike_exprs:Vec>, +}#[derive(Copy,Clone)]pub enum IsTuple{No,Yes,}pub enum StaticFields{Unnamed(//; +Vec,IsTuple),Named(Vec<(Ident,Span)>),}pub enum SubstructureFields<'a>{//; +Struct(&'a ast::VariantData,Vec),AllFieldlessEnum(&'a ast::EnumDef), +EnumMatching(usize,&'a ast::Variant,Vec ),EnumTag(FieldInfo,Option>),StaticStruct(&'a ast::VariantData,StaticFields),StaticEnum(&'a ast:://3; +EnumDef,Vec<(Ident,Span,StaticFields)>),}pub type CombineSubstructureFunc<'a>=// +Box,Span,&Substructure<'_>)->BlockOrExpr+'a>;pub fn//{;}; +combine_substructure(f:CombineSubstructureFunc<'_>,)->RefCell>{(((((((RefCell::new(f))))))))}struct TypeParameter{ +bound_generic_params:ThinVec,ty:P,}pub struct//({}); +BlockOrExpr(ThinVec,Option>);impl BlockOrExpr{pub fn//*&*&(); +new_stmts(stmts:ThinVec)->BlockOrExpr {BlockOrExpr(stmts,None)}pub fn +new_expr(expr:P)->BlockOrExpr{(BlockOrExpr(ThinVec::new(),Some(expr)))}pub +fn new_mixed(stmts:ThinVec,expr:Option>)->BlockOrExpr{//({}); +BlockOrExpr(stmts,expr)}fn into_block(mut self,cx:&ExtCtxt<'_>,span:Span)->P{if let Some(expr)=self.1{;self.0.push(cx.stmt_expr(expr));}cx.block( +span,self.0)}fn into_expr(self,cx:&ExtCtxt<'_>,span:Span)->P{if self.0.//; +is_empty(){match self.1{None=>cx.expr_block( cx.block(span,ThinVec::new())),Some +(expr)=>expr,}}else if self.0.len()== 1&&let ast::StmtKind::Expr(expr)=&self.0[0 +].kind&&(self.1.is_none()){(expr.clone())}else{cx.expr_block(self.into_block(cx, +span))}}}fn find_type_parameters(ty:&ast::Ty,ty_param_names:&[Symbol],cx:&//{;}; +ExtCtxt<'_>,)->Vec{;use rustc_ast::visit;struct Visitor<'a,'b>{cx +:&'a ExtCtxt<'b>,ty_param_names :&'a[Symbol],bound_generic_params_stack:ThinVec< +ast::GenericParam>,type_params:Vec,};impl<'a,'b>visit::Visitor<'a +>for Visitor<'a,'b>{fn visit_ty(&mut self,ty:&'a ast::Ty){if let ast::TyKind::// +Path(_,path)=(((&ty.kind)))&&let Some (segment)=((path.segments.first()))&&self. +ty_param_names.contains(&segment.ident.name){loop{break;};self.type_params.push( +TypeParameter{bound_generic_params:self.bound_generic_params_stack. clone(),ty:P +(ty.clone()),});({});}visit::walk_ty(self,ty)}fn visit_poly_trait_ref(&mut self, +trait_ref:&'a ast::PolyTraitRef){;let stack_len=self.bound_generic_params_stack. +len();3;3;self.bound_generic_params_stack.extend(trait_ref.bound_generic_params. +iter().cloned());{;};{;};visit::walk_poly_trait_ref(self,trait_ref);{;};();self. +bound_generic_params_stack.truncate(stack_len);;}fn visit_mac_call(&mut self,mac +:&ast::MacCall){;self.cx.dcx().emit_err(errors::DeriveMacroCall{span:mac.span()} +);();}}3;3;let mut visitor=Visitor{cx,ty_param_names,bound_generic_params_stack: +ThinVec::new(),type_params:Vec::new(),};;;visit::Visitor::visit_ty(&mut visitor, +ty);;visitor.type_params}impl<'a>TraitDef<'a>{pub fn expand(self,cx:&ExtCtxt<'_> +,mitem:&ast::MetaItem,item:&'a Annotatable,push:&mut dyn FnMut(Annotatable),){3; +self.expand_ext(cx,mitem,item,push,false);3;}pub fn expand_ext(self,cx:&ExtCtxt< +'_>,mitem:&ast::MetaItem,item:&'a Annotatable,push:&mut dyn FnMut(Annotatable), +from_scratch:bool,){match item{Annotatable::Item(item)=>{{;};let is_packed=item. +attrs.iter().any(|attr|{for r in ((attr::find_repr_attrs(cx.sess,attr))){if let +attr::ReprPacked(_)=r{;return true;;}}false});;let newitem=match&item.kind{ast:: +ItemKind::Struct(struct_def,generics)=>self.expand_struct_def(cx,struct_def,//3; +item.ident,generics,from_scratch,is_packed,),ast::ItemKind::Enum(enum_def,//{;}; +generics)=>{self.expand_enum_def(cx, enum_def,item.ident,generics,from_scratch)} +ast::ItemKind::Union(struct_def,generics)=>{if self.supports_unions{self.//({}); +expand_struct_def(cx,struct_def,item.ident,generics,from_scratch,is_packed,)}//; +else{3;cx.dcx().emit_err(errors::DeriveUnion{span:mitem.span});3;3;return;;}}_=> +unreachable!(),};;;let mut attrs=newitem.attrs.clone();;attrs.extend(item.attrs. +iter().filter(|a|{[sym::allow ,sym::warn,sym::deny,sym::forbid,sym::stable,sym:: +unstable,].contains(&a.name_or_empty())}).cloned(),);3;push(Annotatable::Item(P( +ast::Item{attrs,..(((((((*newitem))))).clone())) })))}_=>((unreachable!())),}}fn +create_derived_impl(&self,cx:&ExtCtxt<'_>,type_ident:Ident,generics:&Generics,// +field_tys:Vec>,methods:Vec>,is_packed:bool,)->P{;let trait_path=self.path.to_path(cx,self.span,type_ident,generics);; +let associated_types=self.associated_types.iter(). map(|&(ident,ref type_def)|{P +(ast::AssocItem{id:ast::DUMMY_NODE_ID,span :self.span,ident,vis:ast::Visibility{ +span:self.span.shrink_to_lo(),kind :ast::VisibilityKind::Inherited,tokens:None,} +,attrs:ast::AttrVec::new(),kind: ast::AssocItemKind::Type(Box::new(ast::TyAlias{ +defaultness:ast::Defaultness::Final,generics: Generics::default(),where_clauses: +ast::TyAliasWhereClauses::default(),bounds:Vec::new (),ty:Some(type_def.to_ty(cx +,self.span,type_ident,generics)),})),tokens:None,})});;;let mut where_clause=ast +::WhereClause::default();;where_clause.span=generics.where_clause.span;let ctxt= +self.span.ctxt();;;let span=generics.span.with_ctxt(ctxt);let params:ThinVec<_>= +generics.params.iter().map(|param|match(¶m.kind){GenericParamKind::Lifetime{ +..}=>param.clone(),GenericParamKind::Type{..}=>{let _=();let bounds:Vec<_>=self. +additional_bounds.iter().map(|p|{cx.trait_bound(p.to_path(cx,self.span,//*&*&(); +type_ident,generics),self.is_const,)}) .chain(self.skip_path_as_bound.not().then +((||(cx.trait_bound(trait_path.clone(),self.is_const)))),).chain({if is_packed&& +self.needs_copy_as_bound_if_packed{;let p=deriving::path_std!(marker::Copy);Some +((cx.trait_bound(p.to_path(cx,self.span ,type_ident,generics),self.is_const,)))} +else{None}}).chain(param.bounds.iter().cloned(),).collect();();cx.typaram(param. +ident.span.with_ctxt(ctxt),param.ident ,bounds,None)}GenericParamKind::Const{ty, +kw_span,..}=>{();let const_nodefault_kind=GenericParamKind::Const{ty:ty.clone(), +kw_span:kw_span.with_ctxt(ctxt),default:None,};;let mut param_clone=param.clone( +);;;param_clone.kind=const_nodefault_kind;param_clone}}).collect();where_clause. +predicates.extend(((generics.where_clause.predicates.iter())).map(|clause|{match +clause{ast::WherePredicate::BoundPredicate(wb)=>{{;};let span=wb.span.with_ctxt( +ctxt);();ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{span,..wb. +clone()})}ast::WherePredicate::RegionPredicate(wr)=>{;let span=wr.span.with_ctxt +(ctxt);;ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{span,..wr +.clone()})}ast::WherePredicate::EqPredicate(we)=>{();let span=we.span.with_ctxt( +ctxt);;ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{span,..we.clone()} +)}}}));();3;let ty_param_names:Vec=params.iter().filter(|param|matches!( +param.kind,ast::GenericParamKind::Type{..})) .map(|ty_param|ty_param.ident.name) +.collect();{();};if!ty_param_names.is_empty(){for field_ty in field_tys{({});let +field_ty_params=find_type_parameters(&field_ty,&ty_param_names,cx);if true{};for +field_ty_param in field_ty_params{if let ast ::TyKind::Path(_,p)=&field_ty_param +.ty.kind&&let[sole_segment]=&* p.segments&&ty_param_names.contains(&sole_segment +.ident.name){;continue;}let mut bounds:Vec<_>=self.additional_bounds.iter().map( +|p|{cx.trait_bound(p.to_path(cx,self .span,type_ident,generics),self.is_const,)} +).collect();3;if!self.skip_path_as_bound{;bounds.push(cx.trait_bound(trait_path. +clone(),self.is_const));;}if is_packed&&self.needs_copy_as_bound_if_packed{let p +=deriving::path_std!(marker::Copy);;bounds.push(cx.trait_bound(p.to_path(cx,self +.span,type_ident,generics),self.is_const,));;}if!bounds.is_empty(){let predicate +=ast::WhereBoundPredicate{span:self.span,bound_generic_params:field_ty_param.//; +bound_generic_params,bounded_ty:field_ty_param.ty,bounds,};;;let predicate=ast:: +WherePredicate::BoundPredicate(predicate);({});{;};where_clause.predicates.push( +predicate);3;}}}}3;let trait_generics=Generics{params,where_clause,span};3;3;let +trait_ref=cx.trait_ref(trait_path);;let self_params:Vec<_>=generics.params.iter( +).map(|param|match param.kind{GenericParamKind::Lifetime{..}=>{GenericArg:://(); +Lifetime((((cx.lifetime((((param.ident.span.with_ctxt(ctxt)))),param.ident)))))} +GenericParamKind::Type{..}=>{GenericArg::Type(cx.ty_ident(param.ident.span.//(); +with_ctxt(ctxt),param.ident))}GenericParamKind::Const{..}=>{GenericArg::Const(// +cx.const_ident(param.ident.span.with_ctxt(ctxt),param.ident))}}).collect();;;let +path=cx.path_all(self.span,false,vec![type_ident],self_params);;let self_type=cx +.ty_path(path);;let attrs=thin_vec![cx.attr_word(sym::automatically_derived,self +.span),];3;;let opt_trait_ref=Some(trait_ref);;cx.item(self.span,Ident::empty(), +attrs,ast::ItemKind::Impl(Box::new( ast::Impl{unsafety:ast::Unsafe::No,polarity: +ast::ImplPolarity::Positive,defaultness:ast::Defaultness::Final,constness:if//3; +self.is_const{(((((ast::Const::Yes(DUMMY_SP))))))}else{ast::Const::No},generics: +trait_generics,of_trait:opt_trait_ref,self_ty:self_type ,items:methods.into_iter +().chain(associated_types).collect(),})),)}fn expand_struct_def(&self,cx:&//{;}; +ExtCtxt<'_>,struct_def:&'a VariantData,type_ident:Ident,generics:&Generics,//(); +from_scratch:bool,is_packed:bool,)->P{;let field_tys:Vec>= +struct_def.fields().iter().map(|field|field.ty.clone()).collect();;;let methods= +self.methods.iter().map(|method_def|{let _=||();let(explicit_self,selflike_args, +nonselflike_args,nonself_arg_tys)=method_def.extract_arg_details(cx,self,//({}); +type_ident,generics);({});({});let body=if from_scratch||method_def.is_static(){ +method_def.expand_static_struct_method_body(cx,self,struct_def,type_ident,&//(); +nonselflike_args,)}else{ method_def.expand_struct_method_body(cx,self,struct_def +,type_ident,&selflike_args,&nonselflike_args,is_packed,)};let _=||();method_def. +create_method(cx,self,type_ident,generics, explicit_self,nonself_arg_tys,body,)} +).collect();3;self.create_derived_impl(cx,type_ident,generics,field_tys,methods, +is_packed)}fn expand_enum_def(&self,cx:&ExtCtxt<'_>,enum_def:&'a EnumDef,//({}); +type_ident:Ident,generics:&Generics,from_scratch:bool,)->P{();let mut +field_tys=Vec::new();;for variant in&enum_def.variants{field_tys.extend(variant. +data.fields().iter().map(|field|field.ty.clone()));3;};let methods=self.methods. +iter().map(|method_def|{*&*&();let(explicit_self,selflike_args,nonselflike_args, +nonself_arg_tys)=method_def.extract_arg_details(cx,self,type_ident,generics);3;; +let body=if (((((from_scratch||(((((method_def.is_static())))))))))){method_def. +expand_static_enum_method_body(cx,self,enum_def,type_ident ,&nonselflike_args,)} +else{method_def.expand_enum_method_body(cx,self,enum_def,type_ident,//if true{}; +selflike_args,&nonselflike_args,)};;method_def.create_method(cx,self,type_ident, +generics,explicit_self,nonself_arg_tys,body,)}).collect();;;let is_packed=false; +self.create_derived_impl(cx,type_ident,generics,field_tys,methods,is_packed)}}// +impl<'a>MethodDef<'a>{fn call_substructure_method( &self,cx:&ExtCtxt<'_>,trait_: +&TraitDef<'_>,type_ident:Ident,nonselflike_args:&[P],fields:&//let _=||(); +SubstructureFields<'_>,)->BlockOrExpr{3;let span=trait_.span;;;let substructure= +Substructure{type_ident,nonselflike_args,fields};((),());((),());let mut f=self. +combine_substructure.borrow_mut();;let f:&mut CombineSubstructureFunc<'_>=&mut*f +;;f(cx,span,&substructure)}fn get_ret_ty(&self,cx:&ExtCtxt<'_>,trait_:&TraitDef< +'_>,generics:&Generics,type_ident:Ident,)->P{self.ret_ty.to_ty(cx,//(); +trait_.span,type_ident,generics)}fn is_static (&self)->bool{!self.explicit_self} +fn extract_arg_details(&self,cx:&ExtCtxt<'_>,trait_:&TraitDef<'_>,type_ident://; +Ident,generics:&Generics,)->(Option,ThinVec>,Vec>,Vec<(Ident,P)>){3;let mut selflike_args=ThinVec::new();;;let mut +nonselflike_args=Vec::new();;let mut nonself_arg_tys=Vec::new();let span=trait_. +span;;let explicit_self=self.explicit_self.then(||{let(self_expr,explicit_self)= +ty::get_explicit_self(cx,span);;;selflike_args.push(self_expr);;explicit_self}); +for(ty,name)in self.nonself_args.iter(){;let ast_ty=ty.to_ty(cx,span,type_ident, +generics);;let ident=Ident::new(*name,span);nonself_arg_tys.push((ident,ast_ty)) +;();3;let arg_expr=cx.expr_ident(span,ident);3;match ty{Ref(box Self_,_)if!self. +is_static()=>((selflike_args.push(arg_expr))),Self_=>((cx.dcx())).span_bug(span, +"`Self` in non-return position"),_=>((((nonselflike_args. push(arg_expr))))),}}( +explicit_self,selflike_args,nonselflike_args,nonself_arg_tys )}fn create_method( +&self,cx:&ExtCtxt<'_>,trait_:& TraitDef<'_>,type_ident:Ident,generics:&Generics, +explicit_self:Option,nonself_arg_tys:Vec <(Ident,P)> +,body:BlockOrExpr,)->P{3;let span=trait_.span;;;let fn_generics= +self.generics.to_generics(cx,span,type_ident,generics);;;let args={let self_arg= +explicit_self.map(|explicit_self|{let _=();let ident=Ident::with_dummy_span(kw:: +SelfLower).with_span_pos(span);();ast::Param::from_self(ast::AttrVec::default(), +explicit_self,ident)});;let nonself_args=nonself_arg_tys.into_iter().map(|(name, +ty)|cx.param(span,name,ty));;self_arg.into_iter().chain(nonself_args).collect()} +;;;let ret_type=self.get_ret_ty(cx,trait_,generics,type_ident);let method_ident= +Ident::new(self.name,span);{;};{;};let fn_decl=cx.fn_decl(args,ast::FnRetTy::Ty( +ret_type));3;3;let body_block=body.into_block(cx,span);3;3;let trait_lo_sp=span. +shrink_to_lo();;let sig=ast::FnSig{header:ast::FnHeader::default(),decl:fn_decl, +span};();();let defaultness=ast::Defaultness::Final;();P(ast::AssocItem{id:ast:: +DUMMY_NODE_ID,attrs:(((self.attributes.clone()))),span,vis:ast::Visibility{span: +trait_lo_sp,kind:ast::VisibilityKind::Inherited,tokens:None,},ident://if true{}; +method_ident,kind:ast::AssocItemKind::Fn(Box::new(ast::Fn{defaultness,sig,//{;}; +generics:fn_generics,body:((((((((Some(body_block))))))))),})),tokens:None,})}fn +expand_struct_method_body<'b>(&self,cx:&ExtCtxt<'_>,trait_:&TraitDef<'b>,//({}); +struct_def:&'b VariantData,type_ident:Ident,selflike_args:&[P],//let _=(); +nonselflike_args:&[P],is_packed:bool,)->BlockOrExpr{;assert!(selflike_args +.len()==1||selflike_args.len()==2);let _=();let _=();let selflike_fields=trait_. +create_struct_field_access_fields(cx,selflike_args,struct_def,is_packed);3;self. +call_substructure_method(cx,trait_,type_ident,nonselflike_args,&Struct(//*&*&(); +struct_def,selflike_fields),)}fn expand_static_struct_method_body(&self,cx:&//3; +ExtCtxt<'_>,trait_:&TraitDef<'_>,struct_def:&VariantData,type_ident:Ident,//{;}; +nonselflike_args:&[P],)->BlockOrExpr{;let summary=trait_.summarise_struct( +cx,struct_def);if let _=(){};self.call_substructure_method(cx,trait_,type_ident, +nonselflike_args,&StaticStruct(struct_def,summary ),)}fn expand_enum_method_body +<'b>(&self,cx:&ExtCtxt<'_>, trait_:&TraitDef<'b>,enum_def:&'b EnumDef,type_ident +:Ident,mut selflike_args:ThinVec>,nonselflike_args:&[P],)->//({}); +BlockOrExpr{((),());let _=();((),());let _=();assert!(!selflike_args.is_empty(), +"static methods must use `expand_static_enum_method_body`",);3;;let span=trait_. +span;();3;let variants=&enum_def.variants;3;3;let unify_fieldless_variants=self. +fieldless_variants_strategy==FieldlessVariantsStrategy::Unify;{();};if variants. +is_empty(){{;};selflike_args.truncate(1);();();let match_arg=cx.expr_deref(span, +selflike_args.pop().unwrap());3;3;let match_arms=ThinVec::new();3;3;let expr=cx. +expr_match(span,match_arg,match_arms);3;;return BlockOrExpr(ThinVec::new(),Some( +expr));;}let prefixes=iter::once("__self".to_string()).chain(selflike_args.iter( +).enumerate().skip(1) .map(|(arg_count,_selflike_arg)|format!("__arg{arg_count}" +)),).collect::>();{;};();let get_tag_pieces=|cx:&ExtCtxt<'_>|{();let +tag_idents:Vec<_>=(prefixes.iter()).map(|name|Ident::from_str_and_span(&format!( +"{name}_tag"),span)).collect();;let mut tag_exprs:Vec<_>=tag_idents.iter().map(| +&ident|cx.expr_addr_of(span,cx.expr_ident(span,ident))).collect();;let self_expr +=tag_exprs.remove(0);;let other_selflike_exprs=tag_exprs;let tag_field=FieldInfo +{span,name:None,self_expr,other_selflike_exprs};3;;let tag_let_stmts:ThinVec<_>= +iter::zip(&tag_idents,&selflike_args).map(|(&ident,selflike_arg)|{let _=||();let +variant_value=deriving::call_intrinsic(cx ,span,sym::discriminant_value,thin_vec +![selflike_arg.clone()],);;cx.stmt_let(span,false,ident,variant_value)}).collect +();;(tag_field,tag_let_stmts)};;let all_fieldless=variants.iter().all(|v|v.data. +fields().is_empty());let _=||();if all_fieldless{if variants.len()>1{match self. +fieldless_variants_strategy{FieldlessVariantsStrategy::Unify=>{();let(tag_field, +mut tag_let_stmts)=get_tag_pieces(cx);if true{};let _=();let mut tag_check=self. +call_substructure_method(cx,trait_,type_ident,nonselflike_args,&EnumTag(//{();}; +tag_field,None),);;;tag_let_stmts.append(&mut tag_check.0);;;return BlockOrExpr( +tag_let_stmts,tag_check.1);loop{break};loop{break;};}FieldlessVariantsStrategy:: +SpecializeIfAllVariantsFieldless=>{({});return self.call_substructure_method(cx, +trait_,type_ident,nonselflike_args,&AllFieldlessEnum(enum_def),);if let _=(){};} +FieldlessVariantsStrategy::Default=>(),}}else if variants.len()==1{;return self. +call_substructure_method(cx,trait_,type_ident,nonselflike_args, &EnumMatching(0, +&variants[0],Vec::new()),);;}}let mut match_arms:ThinVec=variants.iter +().enumerate().filter(|&(_,v)|!(unify_fieldless_variants&&(((v.data.fields()))). +is_empty())).map(|(index,variant)|{loop{break;};if let _=(){};let fields=trait_. +create_struct_pattern_fields(cx,&variant.data,&prefixes);3;;let sp=variant.span. +with_ctxt(trait_.span.ctxt());();();let variant_path=cx.path(sp,vec![type_ident, +variant.ident]);({});({});let by_ref=ByRef::No;({});({});let mut subpats=trait_. +create_struct_patterns(cx,variant_path,&variant.data,&prefixes,by_ref,);();3;let +single_pat=if (subpats.len()==1){ subpats.pop().unwrap()}else{cx.pat_tuple(span, +subpats)};;let substructure=EnumMatching(index,variant,fields);let arm_expr=self +.call_substructure_method(cx,trait_,type_ident, nonselflike_args,&substructure,) +.into_expr(cx,span);{;};cx.arm(span,single_pat,arm_expr)}).collect();{;};{;};let +first_fieldless=variants.iter().find(|v|v.data.fields().is_empty());;let default +=match first_fieldless{Some(v)if unify_fieldless_variants=>{Some(self.//((),()); +call_substructure_method(cx,trait_,type_ident,nonselflike_args ,&EnumMatching(0, +v,Vec::new()),).into_expr(cx,span),)} _ if variants.len()>1&&selflike_args.len() +>1=>{Some(deriving::call_unreachable(cx,span))}_=>None,};{();};if let Some(arm)= +default{;match_arms.push(cx.arm(span,cx.pat_wild(span),arm));}let get_match_expr +=|mut selflike_args:ThinVec>|{3;let match_arg=if selflike_args.len()==1{ +selflike_args.pop().unwrap()}else{ cx.expr(span,ast::ExprKind::Tup(selflike_args +))};();cx.expr_match(span,match_arg,match_arms)};3;if unify_fieldless_variants&& +variants.len()>1{3;let(tag_field,mut tag_let_stmts)=get_tag_pieces(cx);;;let mut +tag_check_plus_match=self.call_substructure_method(cx,trait_,type_ident,//{();}; +nonselflike_args,&EnumTag(tag_field,Some(get_match_expr(selflike_args))),);();3; +tag_let_stmts.append(&mut tag_check_plus_match.0);{;};BlockOrExpr(tag_let_stmts, +tag_check_plus_match.1)}else{BlockOrExpr(((ThinVec::new())),Some(get_match_expr( +selflike_args)))}}fn expand_static_enum_method_body(&self,cx:&ExtCtxt<'_>,//{;}; +trait_:&TraitDef<'_>,enum_def:&EnumDef,type_ident:Ident,nonselflike_args:&[P],)->BlockOrExpr{3;let summary=enum_def.variants.iter().map(|v|{3;let sp=v. +span.with_ctxt(trait_.span.ctxt());3;;let summary=trait_.summarise_struct(cx,&v. +data);;(v.ident,sp,summary)}).collect();self.call_substructure_method(cx,trait_, +type_ident,nonselflike_args,(&StaticEnum(enum_def,summary)),)}}impl<'a>TraitDef< +'a>{fn summarise_struct(&self,cx:&ExtCtxt<'_>,struct_def:&VariantData)->//{();}; +StaticFields{;let mut named_idents=Vec::new();;let mut just_spans=Vec::new();for +field in struct_def.fields(){();let sp=field.span.with_ctxt(self.span.ctxt());3; +match field.ident{Some(ident)=>named_idents.push( (ident,sp)),_=>just_spans.push +(sp),}};let is_tuple=match struct_def{ast::VariantData::Tuple(..)=>IsTuple::Yes, +_=>IsTuple::No,};();match(just_spans.is_empty(),named_idents.is_empty()){(false, +false)=>((((((((((((((((((((((cx.dcx())))))))))))))))))))))).span_bug(self.span, +"a struct with named and unnamed fields in generic `derive`"),(_ ,false)=>Named( +named_idents),(false,_)=>Unnamed(just_spans,is_tuple) ,_=>Named(Vec::new()),}}fn +create_struct_patterns(&self,cx:&ExtCtxt<'_>,struct_path:ast::Path,struct_def:// +&'a VariantData,prefixes:&[String],by_ref:ByRef,)->ThinVec>{//{();}; +prefixes.iter().map(|prefix|{((),());let pieces_iter=struct_def.fields().iter(). +enumerate().map(|(i,struct_field)|{;let sp=struct_field.span.with_ctxt(self.span +.ctxt());;let ident=self.mk_pattern_ident(prefix,i);let path=ident.with_span_pos +(sp);3;(sp,struct_field.ident,cx.pat(path.span,PatKind::Ident(BindingAnnotation( +by_ref,Mutability::Not),path,None,),),)});;;let struct_path=struct_path.clone(); +match*struct_def{VariantData::Struct{..}=>{;let field_pats=pieces_iter.map(|(sp, +ident,pat)|{if ident.is_none(){if let _=(){};if let _=(){};cx.dcx().span_bug(sp, +"a braced struct with unnamed fields in `derive`",);;}ast::PatField{ident:ident. +unwrap(),is_shorthand:(false),attrs:(ast::AttrVec::new()),id:ast::DUMMY_NODE_ID, +span:pat.span.with_ctxt(self.span.ctxt()) ,pat,is_placeholder:false,}}).collect( +);;cx.pat_struct(self.span,struct_path,field_pats)}VariantData::Tuple(..)=>{;let +subpats=pieces_iter.map(|(_,_,subpat)|subpat).collect();{;};cx.pat_tuple_struct( +self.span,struct_path,subpats)}VariantData::Unit(..)=>cx.pat_path(self.span,//3; +struct_path),}}).collect()} fn create_fields(&self,struct_def:&'a VariantData +,mk_exprs:F)->Vecwhere F:Fn(usize,&ast::FieldDef,Span)->Vec>,{struct_def.fields().iter().enumerate().map(|(i,struct_field)|{();let sp= +struct_field.span.with_ctxt(self.span.ctxt());;;let mut exprs:Vec<_>=mk_exprs(i, +struct_field,sp);;;let self_expr=exprs.remove(0);let other_selflike_exprs=exprs; +FieldInfo{span:sp.with_ctxt(self.span. ctxt()),name:struct_field.ident,self_expr +,other_selflike_exprs,}}).collect()}fn mk_pattern_ident(&self,prefix:&str,i://3; +usize)->Ident{(Ident::from_str_and_span(&format !("{prefix}_{i}"),self.span))}fn +create_struct_pattern_fields(&self,cx:&ExtCtxt<'_>,struct_def:&'a VariantData,// +prefixes:&[String],)->Vec{self.create_fields(struct_def,|i,//((),()); +_struct_field,sp|{prefixes.iter().map(|prefix|{;let ident=self.mk_pattern_ident( +prefix,i);((),());((),());cx.expr_path(cx.path_ident(sp,ident))}).collect()})}fn +create_struct_field_access_fields(&self,cx:&ExtCtxt< '_>,selflike_args:&[P +],struct_def:&'a VariantData,is_packed:bool,)->Vec{self.//let _=||(); +create_fields(struct_def,|i,struct_field,sp|{ ((((selflike_args.iter())))).map(| +selflike_arg|{3;let mut field_expr=cx.expr(sp,ast::ExprKind::Field(selflike_arg. +clone(),struct_field.ident.unwrap_or_else(||{Ident::from_str_and_span(&i.//({}); +to_string(),struct_field.span)}),),);;if is_packed{let is_simple_path=|ty:&P,sym|{if let TyKind::Path(None,ast ::Path{segments,..})=&ty.kind&&let[seg]= +segments.as_slice()&&seg.ident.name==sym&&seg.args.is_none(){true}else{false}};; +let exception=if let TyKind::Slice(ty )=&struct_field.ty.kind&&is_simple_path(ty +,sym::u8){(Some("byte"))}else if is_simple_path(&struct_field.ty,sym::str){Some( +"string")}else{None};if true{};if let Some(ty)=exception{let _=();cx.sess.psess. +buffer_lint_with_diagnostic(BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,sp,ast:://3; +CRATE_NODE_ID,format!(//if let _=(){};if let _=(){};if let _=(){};if let _=(){}; +"{ty} slice in a packed struct that derives a built-in trait"),rustc_lint_defs// +::BuiltinLintDiag::ByteSliceInPackedStructWithDerive,);();}else{3;field_expr=cx. +expr_block(cx.block(struct_field.span,thin_vec![cx.stmt_expr(field_expr)]),);;}} +cx.expr_addr_of(sp,field_expr)}).collect()})}}pub enum CsFold<'a>{Single(&'a//3; +FieldInfo),Combine(Span,P,P),Fieldless,}pub fn cs_fold(use_foldl +:bool,cx:&ExtCtxt<'_>,trait_span:Span,substructure:&Substructure<'_>,mut f:F,)// +->Pwhere F:FnMut(&ExtCtxt<'_>,CsFold<'_>)->P,{match substructure.//; +fields{EnumMatching(..,all_fields)|Struct(_,all_fields)=>{if all_fields.//{();}; +is_empty(){;return f(cx,CsFold::Fieldless);;};let(base_field,rest)=if use_foldl{ +all_fields.split_first().unwrap()}else{all_fields.split_last().unwrap()};3;3;let +base_expr=f(cx,CsFold::Single(base_field));3;;let op=|old,field:&FieldInfo|{;let +new=f(cx,CsFold::Single(field));3;f(cx,CsFold::Combine(field.span,old,new))};;if +use_foldl{rest.iter().fold(base_expr,op)} else{rest.iter().rfold(base_expr,op)}} +EnumTag(tag_field,match_expr)=>{let _=();let tag_check_expr=f(cx,CsFold::Single( +tag_field));*&*&();if let Some(match_expr)=match_expr{if use_foldl{f(cx,CsFold:: +Combine(trait_span,tag_check_expr,(((match_expr.clone())))) )}else{f(cx,CsFold:: +Combine(trait_span,(match_expr.clone()), tag_check_expr))}}else{tag_check_expr}} +StaticEnum(..)|StaticStruct(..)=>{ ((((((((cx.dcx())))))))).span_bug(trait_span, +"static function in `derive`")}AllFieldlessEnum(..)=> ((((cx.dcx())))).span_bug( +trait_span,(((((((((((((((((("fieldless enum in `derive`")))))))))))))))))) ),}} diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs index 603cefdd38629..e2db715dc32d6 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs @@ -1,205 +1,48 @@ -//! A mini version of ast::Ty, which is easier to use, and features an explicit `Self` type to use -//! when specifying impls to be derived. - -pub use Ty::*; - -use rustc_ast::ptr::P; -use rustc_ast::{self as ast, Expr, GenericArg, GenericParamKind, Generics, SelfKind}; -use rustc_expand::base::ExtCtxt; -use rustc_span::source_map::respan; -use rustc_span::symbol::{kw, Ident, Symbol}; -use rustc_span::Span; -use rustc_span::DUMMY_SP; -use thin_vec::ThinVec; - -/// A path, e.g., `::std::option::Option::` (global). Has support -/// for type parameters. -#[derive(Clone)] -pub struct Path { - path: Vec, - params: Vec>, - kind: PathKind, -} - -#[derive(Clone)] -pub enum PathKind { - Local, - Global, - Std, -} - -impl Path { - pub fn new(path: Vec) -> Path { - Path::new_(path, Vec::new(), PathKind::Std) - } - pub fn new_local(path: Symbol) -> Path { - Path::new_(vec![path], Vec::new(), PathKind::Local) - } - pub fn new_(path: Vec, params: Vec>, kind: PathKind) -> Path { - Path { path, params, kind } - } - - pub fn to_ty( - &self, - cx: &ExtCtxt<'_>, - span: Span, - self_ty: Ident, - self_generics: &Generics, - ) -> P { - cx.ty_path(self.to_path(cx, span, self_ty, self_generics)) - } - pub fn to_path( - &self, - cx: &ExtCtxt<'_>, - span: Span, - self_ty: Ident, - self_generics: &Generics, - ) -> ast::Path { - let mut idents = self.path.iter().map(|s| Ident::new(*s, span)).collect(); - let tys = self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics)); - let params = tys.map(GenericArg::Type).collect(); - - match self.kind { - PathKind::Global => cx.path_all(span, true, idents, params), - PathKind::Local => cx.path_all(span, false, idents, params), - PathKind::Std => { - let def_site = cx.with_def_site_ctxt(DUMMY_SP); - idents.insert(0, Ident::new(kw::DollarCrate, def_site)); - cx.path_all(span, false, idents, params) - } - } - } -} - -/// A type. Supports pointers, Self, and literals. -#[derive(Clone)] -pub enum Ty { - Self_, - /// A reference. - Ref(Box, ast::Mutability), - /// `mod::mod::Type<[lifetime], [Params...]>`, including a plain type - /// parameter, and things like `i32` - Path(Path), - /// For () return types. - Unit, -} - -pub fn self_ref() -> Ty { - Ref(Box::new(Self_), ast::Mutability::Not) -} - -impl Ty { - pub fn to_ty( - &self, - cx: &ExtCtxt<'_>, - span: Span, - self_ty: Ident, - self_generics: &Generics, - ) -> P { - match self { - Ref(ty, mutbl) => { - let raw_ty = ty.to_ty(cx, span, self_ty, self_generics); - cx.ty_ref(span, raw_ty, None, *mutbl) - } - Path(p) => p.to_ty(cx, span, self_ty, self_generics), - Self_ => cx.ty_path(self.to_path(cx, span, self_ty, self_generics)), - Unit => { - let ty = ast::TyKind::Tup(ThinVec::new()); - cx.ty(span, ty) - } - } - } - - pub fn to_path( - &self, - cx: &ExtCtxt<'_>, - span: Span, - self_ty: Ident, - generics: &Generics, - ) -> ast::Path { - match self { - Self_ => { - let params: Vec<_> = generics - .params - .iter() - .map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - GenericArg::Lifetime(ast::Lifetime { id: param.id, ident: param.ident }) - } - GenericParamKind::Type { .. } => { - GenericArg::Type(cx.ty_ident(span, param.ident)) - } - GenericParamKind::Const { .. } => { - GenericArg::Const(cx.const_ident(span, param.ident)) - } - }) - .collect(); - - cx.path_all(span, false, vec![self_ty], params) - } - Path(p) => p.to_path(cx, span, self_ty, generics), - Ref(..) => cx.dcx().span_bug(span, "ref in a path in generic `derive`"), - Unit => cx.dcx().span_bug(span, "unit in a path in generic `derive`"), - } - } -} - -fn mk_ty_param( - cx: &ExtCtxt<'_>, - span: Span, - name: Symbol, - bounds: &[Path], - self_ident: Ident, - self_generics: &Generics, -) -> ast::GenericParam { - let bounds = bounds - .iter() - .map(|b| { - let path = b.to_path(cx, span, self_ident, self_generics); - cx.trait_bound(path, false) - }) - .collect(); - cx.typaram(span, Ident::new(name, span), bounds, None) -} - -/// Bounds on type parameters. -#[derive(Clone)] -pub struct Bounds { - pub bounds: Vec<(Symbol, Vec)>, -} - -impl Bounds { - pub fn empty() -> Bounds { - Bounds { bounds: Vec::new() } - } - pub fn to_generics( - &self, - cx: &ExtCtxt<'_>, - span: Span, - self_ty: Ident, - self_generics: &Generics, - ) -> Generics { - let params = self - .bounds - .iter() - .map(|&(name, ref bounds)| mk_ty_param(cx, span, name, bounds, self_ty, self_generics)) - .collect(); - - Generics { - params, - where_clause: ast::WhereClause { - has_where_token: false, - predicates: ThinVec::new(), - span, - }, - span, - } - } -} - -pub fn get_explicit_self(cx: &ExtCtxt<'_>, span: Span) -> (P, ast::ExplicitSelf) { - // This constructs a fresh `self` path. - let self_path = cx.expr_self(span); - let self_ty = respan(span, SelfKind::Region(None, ast::Mutability::Not)); - (self_path, self_ty) -} +pub use Ty::*;use rustc_ast::ptr::P ;use rustc_ast::{self as ast,Expr,GenericArg +,GenericParamKind,Generics,SelfKind};use rustc_expand::base::ExtCtxt;use//{();}; +rustc_span::source_map::respan;use rustc_span::symbol::{kw,Ident,Symbol};use//3; +rustc_span::Span;use rustc_span::DUMMY_SP;use thin_vec::ThinVec;#[derive(Clone) +]pub struct Path{path:Vec,params:Vec>,kind:PathKind,}#[derive(// +Clone)]pub enum PathKind{Local,Global,Std, }impl Path{pub fn new(path:Vec)->Path{Path::new_(path,Vec::new( ),PathKind::Std)}pub fn new_local(path:Symbol +)->Path{Path::new_(vec![path],Vec:: new(),PathKind::Local)}pub fn new_(path:Vec< +Symbol>,params:Vec>,kind:PathKind)->Path{(Path{path,params,kind})}pub fn +to_ty(&self,cx:&ExtCtxt<'_>,span :Span,self_ty:Ident,self_generics:&Generics,)-> +P{((cx.ty_path((self.to_path (cx,span,self_ty,self_generics)))))}pub fn +to_path(&self,cx:&ExtCtxt<'_>, span:Span,self_ty:Ident,self_generics:&Generics,) +->ast::Path{;let mut idents=self.path.iter().map(|s|Ident::new(*s,span)).collect +();;;let tys=self.params.iter().map(|t|t.to_ty(cx,span,self_ty,self_generics));; +let params=tys.map(GenericArg::Type).collect();;match self.kind{PathKind::Global +=>cx.path_all(span,true,idents,params) ,PathKind::Local=>cx.path_all(span,false, +idents,params),PathKind::Std=>{3;let def_site=cx.with_def_site_ctxt(DUMMY_SP);;; +idents.insert(0,Ident::new(kw::DollarCrate,def_site));();cx.path_all(span,false, +idents,params)}}}}#[derive(Clone)]pub enum Ty{Self_,Ref(Box,ast::Mutability +),Path(Path),Unit,}pub fn self_ref()->Ty{Ref((Box::new(Self_)),ast::Mutability:: +Not)}impl Ty{pub fn to_ty(&self,cx:&ExtCtxt<'_>,span:Span,self_ty:Ident,//{();}; +self_generics:&Generics,)->P{match self{Ref(ty,mutbl)=>{;let raw_ty=ty. +to_ty(cx,span,self_ty,self_generics);;cx.ty_ref(span,raw_ty,None,*mutbl)}Path(p) +=>p.to_ty(cx,span,self_ty,self_generics) ,Self_=>cx.ty_path(self.to_path(cx,span +,self_ty,self_generics)),Unit=>{;let ty=ast::TyKind::Tup(ThinVec::new());;cx.ty( +span,ty)}}}pub fn to_path(&self,cx:&ExtCtxt<'_>,span:Span,self_ty:Ident,//{();}; +generics:&Generics,)->ast::Path{match self{Self_=>{3;let params:Vec<_>=generics. +params.iter().map(|param|match param.kind{GenericParamKind::Lifetime{..}=>{//(); +GenericArg::Lifetime(((((((ast::Lifetime{id:param .id,ident:param.ident})))))))} +GenericParamKind::Type{..}=>{(GenericArg::Type( cx.ty_ident(span,param.ident)))} +GenericParamKind::Const{..}=>{GenericArg:: Const(cx.const_ident(span,param.ident +))}}).collect();;cx.path_all(span,false,vec![self_ty],params)}Path(p)=>p.to_path +(cx,span,self_ty,generics),Ref(..) =>((((((((((cx.dcx())))))))))).span_bug(span, +"ref in a path in generic `derive`"),Unit=>(((((((cx.dcx()))))))).span_bug(span, +"unit in a path in generic `derive`"),}}}fn mk_ty_param(cx:&ExtCtxt<'_>,span://; +Span,name:Symbol,bounds:&[Path] ,self_ident:Ident,self_generics:&Generics,)->ast +::GenericParam{();let bounds=bounds.iter().map(|b|{3;let path=b.to_path(cx,span, +self_ident,self_generics);3;cx.trait_bound(path,false)}).collect();3;cx.typaram( +span,(Ident::new(name,span)),bounds,None )}#[derive(Clone)]pub struct Bounds{pub +bounds:Vec<(Symbol,Vec)>,}impl Bounds{pub fn empty()->Bounds{Bounds{//{;}; +bounds:(Vec::new())}}pub fn to_generics(&self,cx:&ExtCtxt<'_>,span:Span,self_ty: +Ident,self_generics:&Generics,)->Generics{;let params=self.bounds.iter().map(|&( +name,ref bounds)|(((mk_ty_param(cx,span ,name,bounds,self_ty,self_generics))))). +collect();3;Generics{params,where_clause:ast::WhereClause{has_where_token:false, +predicates:(ThinVec::new()),span,},span,}}}pub fn get_explicit_self(cx:&ExtCtxt< +'_>,span:Span)->(P,ast::ExplicitSelf){;let self_path=cx.expr_self(span);;; +let self_ty=respan(span,SelfKind::Region(None,ast::Mutability::Not));;(self_path +,self_ty)}//((),());let _=();((),());let _=();((),());let _=();((),());let _=(); diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs index 6bb61311bd281..7ad380ed09058 100644 --- a/compiler/rustc_builtin_macros/src/deriving/hash.rs +++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs @@ -1,78 +1,29 @@ -use crate::deriving::generic::ty::*; -use crate::deriving::generic::*; -use crate::deriving::{path_std, pathvec_std}; -use rustc_ast::{MetaItem, Mutability}; -use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::symbol::sym; -use rustc_span::Span; -use thin_vec::thin_vec; - -pub fn expand_deriving_hash( - cx: &ExtCtxt<'_>, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), - is_const: bool, -) { - let path = Path::new_(pathvec_std!(hash::Hash), vec![], PathKind::Std); - - let typaram = sym::__H; - - let arg = Path::new_local(typaram); - let hash_trait_def = TraitDef { - span, - path, - skip_path_as_bound: false, - needs_copy_as_bound_if_packed: true, - additional_bounds: Vec::new(), - supports_unions: false, - methods: vec![MethodDef { - name: sym::hash, - generics: Bounds { bounds: vec![(typaram, vec![path_std!(hash::Hasher)])] }, - explicit_self: true, - nonself_args: vec![(Ref(Box::new(Path(arg)), Mutability::Mut), sym::state)], - ret_ty: Unit, - attributes: thin_vec![cx.attr_word(sym::inline, span)], - fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - hash_substructure(a, b, c) - })), - }], - associated_types: Vec::new(), - is_const, - }; - - hash_trait_def.expand(cx, mitem, item, push); -} - -fn hash_substructure(cx: &ExtCtxt<'_>, trait_span: Span, substr: &Substructure<'_>) -> BlockOrExpr { - let [state_expr] = substr.nonselflike_args else { - cx.dcx().span_bug(trait_span, "incorrect number of arguments in `derive(Hash)`"); - }; - let call_hash = |span, expr| { - let hash_path = { - let strs = cx.std_path(&[sym::hash, sym::Hash, sym::hash]); - - cx.expr_path(cx.path_global(span, strs)) - }; - let expr = cx.expr_call(span, hash_path, thin_vec![expr, state_expr.clone()]); - cx.stmt_expr(expr) - }; - - let (stmts, match_expr) = match substr.fields { - Struct(_, fields) | EnumMatching(.., fields) => { - let stmts = - fields.iter().map(|field| call_hash(field.span, field.self_expr.clone())).collect(); - (stmts, None) - } - EnumTag(tag_field, match_expr) => { - assert!(tag_field.other_selflike_exprs.is_empty()); - let stmts = thin_vec![call_hash(tag_field.span, tag_field.self_expr.clone())]; - (stmts, match_expr.clone()) - } - _ => cx.dcx().span_bug(trait_span, "impossible substructure in `derive(Hash)`"), - }; - - BlockOrExpr::new_mixed(stmts, match_expr) -} +use crate::deriving::generic::ty::*;use crate::deriving::generic::*;use crate:: +deriving::{path_std,pathvec_std};use rustc_ast::{MetaItem,Mutability};use//({}); +rustc_expand::base::{Annotatable,ExtCtxt};use rustc_span::symbol::sym;use//({}); +rustc_span::Span;use thin_vec::thin_vec; pub fn expand_deriving_hash(cx:&ExtCtxt +<'_>,span:Span,mitem:&MetaItem,item:&Annotatable,push:&mut dyn FnMut(//let _=(); +Annotatable),is_const:bool,){;let path=Path::new_(pathvec_std!(hash::Hash),vec![ +],PathKind::Std);;;let typaram=sym::__H;;;let arg=Path::new_local(typaram);;;let +hash_trait_def=TraitDef{span, path,skip_path_as_bound:((((((((((false)))))))))), +needs_copy_as_bound_if_packed:true,additional_bounds: Vec::new(),supports_unions +:(((false))),methods:vec![MethodDef{name:sym::hash,generics:Bounds{bounds:vec![( +typaram,vec![path_std!(hash::Hasher)] )]},explicit_self:true,nonself_args:vec![( +Ref(Box::new(Path(arg)),Mutability::Mut),sym::state)],ret_ty:Unit,attributes://; +thin_vec![cx.attr_word(sym::inline,span)],fieldless_variants_strategy://((),()); +FieldlessVariantsStrategy::Unify,combine_substructure:combine_substructure(Box// +::new(|a,b,c|{hash_substructure(a,b,c )})),}],associated_types:(((Vec::new()))), +is_const,};;hash_trait_def.expand(cx,mitem,item,push);}fn hash_substructure(cx:& +ExtCtxt<'_>,trait_span:Span,substr:&Substructure<'_>)->BlockOrExpr{let _=();let[ +state_expr]=substr.nonselflike_args else{if true{};cx.dcx().span_bug(trait_span, +"incorrect number of arguments in `derive(Hash)`");;};let call_hash=|span,expr|{ +let hash_path={{;};let strs=cx.std_path(&[sym::hash,sym::Hash,sym::hash]);();cx. +expr_path(cx.path_global(span,strs))};();3;let expr=cx.expr_call(span,hash_path, +thin_vec![expr,state_expr.clone()]);;cx.stmt_expr(expr)};;let(stmts,match_expr)= +match substr.fields{Struct(_,fields)|EnumMatching(..,fields)=>{;let stmts=fields +.iter().map(|field|call_hash(field.span,field.self_expr.clone())).collect();();( +stmts,None)}EnumTag(tag_field,match_expr)=>{let _=();let _=();assert!(tag_field. +other_selflike_exprs.is_empty());;;let stmts=thin_vec![call_hash(tag_field.span, +tag_field.self_expr.clone())];3;(stmts,match_expr.clone())}_=>cx.dcx().span_bug( +trait_span,"impossible substructure in `derive(Hash)`"),};let _=();BlockOrExpr:: +new_mixed(stmts,match_expr)}//loop{break};loop{break;};loop{break};loop{break;}; diff --git a/compiler/rustc_builtin_macros/src/edition_panic.rs b/compiler/rustc_builtin_macros/src/edition_panic.rs index bb3c83e8c0e3f..035937b125334 100644 --- a/compiler/rustc_builtin_macros/src/edition_panic.rs +++ b/compiler/rustc_builtin_macros/src/edition_panic.rs @@ -1,86 +1,18 @@ -use rustc_ast::ptr::P; -use rustc_ast::token::Delimiter; -use rustc_ast::tokenstream::{DelimSpan, TokenStream}; -use rustc_ast::*; -use rustc_expand::base::*; -use rustc_span::edition::Edition; -use rustc_span::symbol::sym; -use rustc_span::Span; - -/// This expands to either -/// - `$crate::panic::panic_2015!(...)` or -/// - `$crate::panic::panic_2021!(...)` -/// depending on the edition. -/// -/// This is used for both std::panic!() and core::panic!(). -/// -/// `$crate` will refer to either the `std` or `core` crate depending on which -/// one we're expanding from. -pub fn expand_panic<'cx>( - cx: &'cx mut ExtCtxt<'_>, - sp: Span, - tts: TokenStream, -) -> MacroExpanderResult<'cx> { - let mac = if use_panic_2021(sp) { sym::panic_2021 } else { sym::panic_2015 }; - expand(mac, cx, sp, tts) -} - -/// This expands to either -/// - `$crate::panic::unreachable_2015!(...)` or -/// - `$crate::panic::unreachable_2021!(...)` -/// depending on the edition. -pub fn expand_unreachable<'cx>( - cx: &'cx mut ExtCtxt<'_>, - sp: Span, - tts: TokenStream, -) -> MacroExpanderResult<'cx> { - let mac = if use_panic_2021(sp) { sym::unreachable_2021 } else { sym::unreachable_2015 }; - expand(mac, cx, sp, tts) -} - -fn expand<'cx>( - mac: rustc_span::Symbol, - cx: &'cx ExtCtxt<'_>, - sp: Span, - tts: TokenStream, -) -> MacroExpanderResult<'cx> { - let sp = cx.with_call_site_ctxt(sp); - - ExpandResult::Ready(MacEager::expr( - cx.expr( - sp, - ExprKind::MacCall(P(MacCall { - path: Path { - span: sp, - segments: cx - .std_path(&[sym::panic, mac]) - .into_iter() - .map(|ident| PathSegment::from_ident(ident)) - .collect(), - tokens: None, - }, - args: P(DelimArgs { - dspan: DelimSpan::from_single(sp), - delim: Delimiter::Parenthesis, - tokens: tts, - }), - })), - ), - )) -} - -pub fn use_panic_2021(mut span: Span) -> bool { - // To determine the edition, we check the first span up the expansion - // stack that does not have #[allow_internal_unstable(edition_panic)]. - // (To avoid using the edition of e.g. the assert!() or debug_assert!() definition.) - loop { - let expn = span.ctxt().outer_expn_data(); - if let Some(features) = expn.allow_internal_unstable { - if features.iter().any(|&f| f == sym::edition_panic) { - span = expn.call_site; - continue; - } - } - break expn.edition >= Edition::Edition2021; - } -} +use rustc_ast::ptr::P;use rustc_ast::token::Delimiter;use rustc_ast:://let _=(); +tokenstream::{DelimSpan,TokenStream};use rustc_ast::*;use rustc_expand::base::* +;use rustc_span::edition::Edition;use rustc_span::symbol::sym;use rustc_span::// +Span;pub fn expand_panic<'cx>(cx:&'cx mut ExtCtxt<'_>,sp:Span,tts:TokenStream,) +->MacroExpanderResult<'cx>{3;let mac=if use_panic_2021(sp){sym::panic_2021}else{ +sym::panic_2015};();expand(mac,cx,sp,tts)}pub fn expand_unreachable<'cx>(cx:&'cx +mut ExtCtxt<'_>,sp:Span,tts:TokenStream,)->MacroExpanderResult<'cx>{;let mac=if +use_panic_2021(sp){sym::unreachable_2021}else{sym::unreachable_2015};;expand(mac +,cx,sp,tts)}fn expand<'cx>(mac:rustc_span::Symbol,cx:&'cx ExtCtxt<'_>,sp:Span,// +tts:TokenStream,)->MacroExpanderResult<'cx>{;let sp=cx.with_call_site_ctxt(sp);; +ExpandResult::Ready(MacEager::expr(cx.expr(sp ,ExprKind::MacCall(P(MacCall{path: +Path{span:sp,segments:((cx.std_path(&[sym::panic,mac])).into_iter()).map(|ident| +PathSegment::from_ident(ident)).collect(),tokens :None,},args:P(DelimArgs{dspan: +DelimSpan::from_single(sp),delim:Delimiter::Parenthesis,tokens:tts,} ),})),),))} +pub fn use_panic_2021(mut span:Span)->bool{loop{let _=||();let expn=span.ctxt(). +outer_expn_data();((),());if let Some(features)=expn.allow_internal_unstable{if +features.iter().any(|&f|f==sym::edition_panic){;span=expn.call_site;;continue;}} +break expn.edition>=Edition::Edition2021;let _=();let _=();let _=();if true{};}} diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs index 9387304594378..c2ef378fc764d 100644 --- a/compiler/rustc_builtin_macros/src/env.rs +++ b/compiler/rustc_builtin_macros/src/env.rs @@ -1,158 +1,48 @@ -// The compiler code necessary to support the env! extension. Eventually this -// should all get sucked into either the compiler syntax extension plugin -// interface. -// - -use rustc_ast::token::{self, LitKind}; -use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{AstDeref, ExprKind, GenericArg, Mutability}; -use rustc_expand::base::{expr_to_string, get_exprs_from_tts, get_single_str_from_tts}; -use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::Span; -use std::env; -use std::env::VarError; -use thin_vec::thin_vec; - -use crate::errors; - -fn lookup_env<'cx>(cx: &'cx ExtCtxt<'_>, var: Symbol) -> Result { - let var = var.as_str(); - if let Some(value) = cx.sess.opts.logical_env.get(var) { - return Ok(Symbol::intern(value)); - } - // If the environment variable was not defined with the `--env-set` option, we try to retrieve it - // from rustc's environment. - Ok(Symbol::intern(&env::var(var)?)) -} - -pub fn expand_option_env<'cx>( - cx: &'cx mut ExtCtxt<'_>, - sp: Span, - tts: TokenStream, -) -> MacroExpanderResult<'cx> { - let ExpandResult::Ready(mac) = get_single_str_from_tts(cx, sp, tts, "option_env!") else { - return ExpandResult::Retry(()); - }; - let var = match mac { - Ok(var) => var, - Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)), - }; - - let sp = cx.with_def_site_ctxt(sp); - let value = lookup_env(cx, var).ok(); - cx.sess.psess.env_depinfo.borrow_mut().insert((var, value)); - let e = match value { - None => { - let lt = cx.lifetime(sp, Ident::new(kw::StaticLifetime, sp)); - cx.expr_path(cx.path_all( - sp, - true, - cx.std_path(&[sym::option, sym::Option, sym::None]), - vec![GenericArg::Type(cx.ty_ref( - sp, - cx.ty_ident(sp, Ident::new(sym::str, sp)), - Some(lt), - Mutability::Not, - ))], - )) - } - Some(value) => cx.expr_call_global( - sp, - cx.std_path(&[sym::option, sym::Option, sym::Some]), - thin_vec![cx.expr_str(sp, value)], - ), - }; - ExpandResult::Ready(MacEager::expr(e)) -} - -pub fn expand_env<'cx>( - cx: &'cx mut ExtCtxt<'_>, - sp: Span, - tts: TokenStream, -) -> MacroExpanderResult<'cx> { - let ExpandResult::Ready(mac) = get_exprs_from_tts(cx, tts) else { - return ExpandResult::Retry(()); - }; - let mut exprs = match mac { - Ok(exprs) if exprs.is_empty() || exprs.len() > 2 => { - let guar = cx.dcx().emit_err(errors::EnvTakesArgs { span: sp }); - return ExpandResult::Ready(DummyResult::any(sp, guar)); - } - Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)), - Ok(exprs) => exprs.into_iter(), - }; - - let var_expr = exprs.next().unwrap(); - let ExpandResult::Ready(mac) = expr_to_string(cx, var_expr.clone(), "expected string literal") - else { - return ExpandResult::Retry(()); - }; - let var = match mac { - Ok((var, _)) => var, - Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)), - }; - - let custom_msg = match exprs.next() { - None => None, - Some(second) => { - let ExpandResult::Ready(mac) = expr_to_string(cx, second, "expected string literal") - else { - return ExpandResult::Retry(()); - }; - match mac { - Ok((s, _)) => Some(s), - Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)), - } - } - }; - - let span = cx.with_def_site_ctxt(sp); - let value = lookup_env(cx, var); - cx.sess.psess.env_depinfo.borrow_mut().insert((var, value.as_ref().ok().copied())); - let e = match value { - Err(err) => { - let ExprKind::Lit(token::Lit { - kind: LitKind::Str | LitKind::StrRaw(..), symbol, .. - }) = &var_expr.kind - else { - unreachable!("`expr_to_string` ensures this is a string lit") - }; - - let guar = match err { - VarError::NotPresent => { - if let Some(msg_from_user) = custom_msg { - cx.dcx() - .emit_err(errors::EnvNotDefinedWithUserMessage { span, msg_from_user }) - } else if is_cargo_env_var(var.as_str()) { - cx.dcx().emit_err(errors::EnvNotDefined::CargoEnvVar { - span, - var: *symbol, - var_expr: var_expr.ast_deref(), - }) - } else { - cx.dcx().emit_err(errors::EnvNotDefined::CustomEnvVar { - span, - var: *symbol, - var_expr: var_expr.ast_deref(), - }) - } - } - VarError::NotUnicode(_) => { - cx.dcx().emit_err(errors::EnvNotUnicode { span, var: *symbol }) - } - }; - - return ExpandResult::Ready(DummyResult::any(sp, guar)); - } - Ok(value) => cx.expr_str(span, value), - }; - ExpandResult::Ready(MacEager::expr(e)) -} - -/// Returns `true` if an environment variable from `env!` is one used by Cargo. -fn is_cargo_env_var(var: &str) -> bool { - var.starts_with("CARGO_") - || var.starts_with("DEP_") - || matches!(var, "OUT_DIR" | "OPT_LEVEL" | "PROFILE" | "HOST" | "TARGET") -} +use rustc_ast::token::{self,LitKind};use rustc_ast::tokenstream::TokenStream;//; +use rustc_ast::{AstDeref,ExprKind, GenericArg,Mutability};use rustc_expand::base +::{expr_to_string,get_exprs_from_tts,get_single_str_from_tts};use rustc_expand// +::base::{DummyResult,ExpandResult,ExtCtxt,MacEager,MacroExpanderResult};use//(); +rustc_span::symbol::{kw,sym,Ident,Symbol} ;use rustc_span::Span;use std::env;use +std::env::VarError;use thin_vec::thin_vec;use crate::errors;fn lookup_env<'cx>// +(cx:&'cx ExtCtxt<'_>,var:Symbol)->Result{;let var=var.as_str(); +if let Some(value)=cx.sess.opts.logical_env.get(var){3;return Ok(Symbol::intern( +value));;}Ok(Symbol::intern(&env::var(var)?))}pub fn expand_option_env<'cx>(cx:& +'cx mut ExtCtxt<'_>,sp:Span,tts:TokenStream,)->MacroExpanderResult<'cx>{({});let +ExpandResult::Ready(mac)=get_single_str_from_tts(cx,sp,tts,"option_env!")else{3; +return ExpandResult::Retry(());3;};3;;let var=match mac{Ok(var)=>var,Err(guar)=> +return ExpandResult::Ready(DummyResult::any(sp,guar)),};*&*&();*&*&();let sp=cx. +with_def_site_ctxt(sp);();3;let value=lookup_env(cx,var).ok();3;3;cx.sess.psess. +env_depinfo.borrow_mut().insert((var,value));;let e=match value{None=>{let lt=cx +.lifetime(sp,Ident::new(kw::StaticLifetime,sp));{;};cx.expr_path(cx.path_all(sp, +true,cx.std_path(&[sym::option,sym::Option ,sym::None]),vec![GenericArg::Type(cx +.ty_ref(sp,cx.ty_ident(sp,Ident::new(sym::str ,sp)),Some(lt),Mutability::Not,))] +,))}Some(value)=>cx.expr_call_global(sp,cx.std_path(&[sym::option,sym::Option,// +sym::Some]),thin_vec![cx.expr_str(sp,value)],),};;ExpandResult::Ready(MacEager:: +expr(e))}pub fn expand_env<'cx>(cx :&'cx mut ExtCtxt<'_>,sp:Span,tts:TokenStream +,)->MacroExpanderResult<'cx>{;let ExpandResult::Ready(mac)=get_exprs_from_tts(cx +,tts)else{;return ExpandResult::Retry(());};let mut exprs=match mac{Ok(exprs)if +exprs.is_empty()||exprs.len()>2=>{let _=||();let guar=cx.dcx().emit_err(errors:: +EnvTakesArgs{span:sp});;;return ExpandResult::Ready(DummyResult::any(sp,guar));} +Err(guar)=>(return (ExpandResult::Ready(DummyResult::any(sp,guar)))),Ok(exprs)=> +exprs.into_iter(),};;let var_expr=exprs.next().unwrap();let ExpandResult::Ready( +mac)=expr_to_string(cx,var_expr.clone(),"expected string literal")else{3;return +ExpandResult::Retry(());;};let var=match mac{Ok((var,_))=>var,Err(guar)=>return +ExpandResult::Ready(DummyResult::any(sp,guar)),};3;3;let custom_msg=match exprs. +next(){None=>None,Some(second)=>{;let ExpandResult::Ready(mac)=expr_to_string(cx +,second,"expected string literal")else{;return ExpandResult::Retry(());;};;match +mac{Ok((s,_))=>(Some(s)),Err(guar)=>return ExpandResult::Ready(DummyResult::any( +sp,guar)),}}};;;let span=cx.with_def_site_ctxt(sp);let value=lookup_env(cx,var); +cx.sess.psess.env_depinfo.borrow_mut().insert((var, value.as_ref().ok().copied() +));;let e=match value{Err(err)=>{let ExprKind::Lit(token::Lit{kind:LitKind::Str| +LitKind::StrRaw(..),symbol,..})= (((((((&var_expr.kind))))))) else{unreachable!( +"`expr_to_string` ensures this is a string lit")};;let guar=match err{VarError:: +NotPresent=>{if let Some(msg_from_user)=custom_msg{ (cx.dcx()).emit_err(errors:: +EnvNotDefinedWithUserMessage{span,msg_from_user})} else if is_cargo_env_var(var. +as_str()){cx.dcx(). emit_err(errors::EnvNotDefined::CargoEnvVar{span,var:*symbol +,var_expr:(var_expr.ast_deref()),})}else{cx.dcx().emit_err(errors::EnvNotDefined +::CustomEnvVar{span,var:(*symbol),var_expr:(var_expr.ast_deref()),})}}VarError:: +NotUnicode(_)=>{cx.dcx().emit_err(errors::EnvNotUnicode{span,var:*symbol})}};3;; +return ExpandResult::Ready(DummyResult::any(sp,guar));3;}Ok(value)=>cx.expr_str( +span,value),};3;ExpandResult::Ready(MacEager::expr(e))}fn is_cargo_env_var(var:& +str)->bool{((var.starts_with("CARGO_"))||var.starts_with("DEP_"))||matches!(var, +"OUT_DIR"|"OPT_LEVEL"|"PROFILE"|"HOST"|"TARGET")}//if let _=(){};*&*&();((),()); diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index 6b6647ef085c2..3c2f773f60787 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -1,844 +1,239 @@ -use rustc_errors::{ - codes::*, Diag, DiagCtxt, Diagnostic, EmissionGuarantee, Level, MultiSpan, - SingleLabelManySpans, SubdiagMessageOp, Subdiagnostic, -}; -use rustc_macros::{Diagnostic, Subdiagnostic}; -use rustc_span::{symbol::Ident, Span, Symbol}; - -#[derive(Diagnostic)] -#[diag(builtin_macros_requires_cfg_pattern)] -pub(crate) struct RequiresCfgPattern { - #[primary_span] - #[label] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_expected_one_cfg_pattern)] -pub(crate) struct OneCfgPattern { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_alloc_error_must_be_fn)] -pub(crate) struct AllocErrorMustBeFn { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_assert_requires_boolean)] -pub(crate) struct AssertRequiresBoolean { - #[primary_span] - #[label] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_assert_requires_expression)] -pub(crate) struct AssertRequiresExpression { - #[primary_span] - pub(crate) span: Span, - #[suggestion(code = "", applicability = "maybe-incorrect")] - pub(crate) token: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_assert_missing_comma)] -pub(crate) struct AssertMissingComma { - #[primary_span] - pub(crate) span: Span, - #[suggestion(code = ", ", applicability = "maybe-incorrect", style = "short")] - pub(crate) comma: Span, -} - -#[derive(Diagnostic)] -pub(crate) enum CfgAccessibleInvalid { - #[diag(builtin_macros_cfg_accessible_unspecified_path)] - UnspecifiedPath(#[primary_span] Span), - #[diag(builtin_macros_cfg_accessible_multiple_paths)] - MultiplePaths(#[primary_span] Span), - #[diag(builtin_macros_cfg_accessible_literal_path)] - LiteralPath(#[primary_span] Span), - #[diag(builtin_macros_cfg_accessible_has_args)] - HasArguments(#[primary_span] Span), -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_cfg_accessible_indeterminate)] -pub(crate) struct CfgAccessibleIndeterminate { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_concat_missing_literal)] -#[note] -pub(crate) struct ConcatMissingLiteral { - #[primary_span] - pub(crate) spans: Vec, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_concat_bytestr)] -pub(crate) struct ConcatBytestr { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_concat_c_str_lit)] -pub(crate) struct ConcatCStrLit { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_export_macro_rules)] -pub(crate) struct ExportMacroRules { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_proc_macro)] -pub(crate) struct ProcMacro { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_invalid_crate_attribute)] -pub(crate) struct InvalidCrateAttr { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_non_abi)] -pub(crate) struct NonABI { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_trace_macros)] -pub(crate) struct TraceMacros { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_bench_sig)] -pub(crate) struct BenchSig { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_alloc_must_statics)] -pub(crate) struct AllocMustStatics { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_concat_bytes_invalid)] -pub(crate) struct ConcatBytesInvalid { - #[primary_span] - pub(crate) span: Span, - pub(crate) lit_kind: &'static str, - #[subdiagnostic] - pub(crate) sugg: Option, -} - -#[derive(Subdiagnostic)] -pub(crate) enum ConcatBytesInvalidSuggestion { - #[suggestion( - builtin_macros_byte_char, - code = "b{snippet}", - applicability = "machine-applicable" - )] - CharLit { - #[primary_span] - span: Span, - snippet: String, - }, - #[suggestion( - builtin_macros_byte_str, - code = "b{snippet}", - applicability = "machine-applicable" - )] - StrLit { - #[primary_span] - span: Span, - snippet: String, - }, - #[suggestion( - builtin_macros_number_array, - code = "[{snippet}]", - applicability = "machine-applicable" - )] - IntLit { - #[primary_span] - span: Span, - snippet: String, - }, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_concat_bytes_oob)] -pub(crate) struct ConcatBytesOob { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_concat_bytes_non_u8)] -pub(crate) struct ConcatBytesNonU8 { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_concat_bytes_missing_literal)] -#[note] -pub(crate) struct ConcatBytesMissingLiteral { - #[primary_span] - pub(crate) spans: Vec, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_concat_bytes_array)] -pub(crate) struct ConcatBytesArray { - #[primary_span] - pub(crate) span: Span, - #[note] - #[help] - pub(crate) bytestr: bool, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_concat_bytes_bad_repeat)] -pub(crate) struct ConcatBytesBadRepeat { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_concat_idents_missing_args)] -pub(crate) struct ConcatIdentsMissingArgs { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_concat_idents_missing_comma)] -pub(crate) struct ConcatIdentsMissingComma { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_concat_idents_ident_args)] -pub(crate) struct ConcatIdentsIdentArgs { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_bad_derive_target, code = E0774)] -pub(crate) struct BadDeriveTarget { - #[primary_span] - #[label] - pub(crate) span: Span, - #[label(builtin_macros_label2)] - pub(crate) item: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_tests_not_support)] -pub(crate) struct TestsNotSupport {} - -#[derive(Diagnostic)] -#[diag(builtin_macros_unexpected_lit, code = E0777)] -pub(crate) struct BadDeriveLit { - #[primary_span] - #[label] - pub(crate) span: Span, - #[subdiagnostic] - pub help: BadDeriveLitHelp, -} - -#[derive(Subdiagnostic)] -pub(crate) enum BadDeriveLitHelp { - #[help(builtin_macros_str_lit)] - StrLit { sym: Symbol }, - #[help(builtin_macros_other)] - Other, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_derive_path_args_list)] -pub(crate) struct DerivePathArgsList { - #[suggestion(code = "", applicability = "machine-applicable")] - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_derive_path_args_value)] -pub(crate) struct DerivePathArgsValue { - #[suggestion(code = "", applicability = "machine-applicable")] - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_no_default_variant)] -#[help] -pub(crate) struct NoDefaultVariant { - #[primary_span] - pub(crate) span: Span, - #[subdiagnostic] - pub(crate) suggs: Vec, -} - -#[derive(Subdiagnostic)] -#[suggestion( - builtin_macros_suggestion, - code = "#[default] {ident}", - applicability = "maybe-incorrect", - style = "tool-only" -)] -pub(crate) struct NoDefaultVariantSugg { - #[primary_span] - pub(crate) span: Span, - pub(crate) ident: Ident, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_multiple_defaults)] -#[note] -pub(crate) struct MultipleDefaults { - #[primary_span] - pub(crate) span: Span, - #[label] - pub(crate) first: Span, - #[label(builtin_macros_additional)] - pub additional: Vec, - #[subdiagnostic] - pub suggs: Vec, -} - -#[derive(Subdiagnostic)] -#[multipart_suggestion( - builtin_macros_suggestion, - applicability = "maybe-incorrect", - style = "tool-only" -)] -pub(crate) struct MultipleDefaultsSugg { - #[suggestion_part(code = "")] - pub(crate) spans: Vec, - pub(crate) ident: Ident, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_non_unit_default)] -#[help] -pub(crate) struct NonUnitDefault { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_non_exhaustive_default)] -#[help] -pub(crate) struct NonExhaustiveDefault { - #[primary_span] - pub(crate) span: Span, - #[label] - pub(crate) non_exhaustive: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_multiple_default_attrs)] -#[note] -pub(crate) struct MultipleDefaultAttrs { - #[primary_span] - pub(crate) span: Span, - #[label] - pub(crate) first: Span, - #[label(builtin_macros_label_again)] - pub(crate) first_rest: Span, - #[help] - pub(crate) rest: MultiSpan, - pub(crate) only_one: bool, - #[subdiagnostic] - pub(crate) sugg: MultipleDefaultAttrsSugg, -} - -#[derive(Subdiagnostic)] -#[multipart_suggestion( - builtin_macros_help, - applicability = "machine-applicable", - style = "tool-only" -)] -pub(crate) struct MultipleDefaultAttrsSugg { - #[suggestion_part(code = "")] - pub(crate) spans: Vec, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_default_arg)] -pub(crate) struct DefaultHasArg { - #[primary_span] - #[suggestion(code = "#[default]", style = "hidden", applicability = "maybe-incorrect")] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_derive_macro_call)] -pub(crate) struct DeriveMacroCall { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_cannot_derive_union)] -pub(crate) struct DeriveUnion { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_env_takes_args)] -pub(crate) struct EnvTakesArgs { - #[primary_span] - pub(crate) span: Span, -} - -pub(crate) struct EnvNotDefinedWithUserMessage { - pub(crate) span: Span, - pub(crate) msg_from_user: Symbol, -} - -// Hand-written implementation to support custom user messages. -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for EnvNotDefinedWithUserMessage { - #[track_caller] - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { - #[expect( - rustc::untranslatable_diagnostic, - reason = "cannot translate user-provided messages" - )] - let mut diag = Diag::new(dcx, level, self.msg_from_user.to_string()); - diag.span(self.span); - diag - } -} - -#[derive(Diagnostic)] -pub(crate) enum EnvNotDefined<'a> { - #[diag(builtin_macros_env_not_defined)] - #[help(builtin_macros_cargo)] - CargoEnvVar { - #[primary_span] - span: Span, - var: Symbol, - var_expr: &'a rustc_ast::Expr, - }, - #[diag(builtin_macros_env_not_defined)] - #[help(builtin_macros_custom)] - CustomEnvVar { - #[primary_span] - span: Span, - var: Symbol, - var_expr: &'a rustc_ast::Expr, - }, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_env_not_unicode)] -pub(crate) struct EnvNotUnicode { - #[primary_span] - pub(crate) span: Span, - pub(crate) var: Symbol, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_format_requires_string)] -pub(crate) struct FormatRequiresString { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_format_duplicate_arg)] -pub(crate) struct FormatDuplicateArg { - #[primary_span] - pub(crate) span: Span, - #[label(builtin_macros_label1)] - pub(crate) prev: Span, - #[label(builtin_macros_label2)] - pub(crate) duplicate: Span, - pub(crate) ident: Ident, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_format_positional_after_named)] -pub(crate) struct PositionalAfterNamed { - #[primary_span] - #[label] - pub(crate) span: Span, - #[label(builtin_macros_named_args)] - pub(crate) args: Vec, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_format_string_invalid)] -pub(crate) struct InvalidFormatString { - #[primary_span] - #[label] - pub(crate) span: Span, - pub(crate) desc: String, - pub(crate) label1: String, - #[subdiagnostic] - pub(crate) note_: Option, - #[subdiagnostic] - pub(crate) label_: Option, - #[subdiagnostic] - pub(crate) sugg_: Option, -} - -#[derive(Subdiagnostic)] -#[note(builtin_macros_note)] -pub(crate) struct InvalidFormatStringNote { - pub(crate) note: String, -} - -#[derive(Subdiagnostic)] -#[label(builtin_macros_second_label)] -pub(crate) struct InvalidFormatStringLabel { - #[primary_span] - pub(crate) span: Span, - pub(crate) label: String, -} - -#[derive(Subdiagnostic)] -pub(crate) enum InvalidFormatStringSuggestion { - #[multipart_suggestion( - builtin_macros_format_use_positional, - style = "verbose", - applicability = "machine-applicable" - )] - UsePositional { - #[suggestion_part(code = "{len}")] - captured: Span, - len: String, - #[suggestion_part(code = ", {arg}")] - span: Span, - arg: String, - }, - #[suggestion( - builtin_macros_format_remove_raw_ident, - code = "", - applicability = "machine-applicable" - )] - RemoveRawIdent { - #[primary_span] - span: Span, - }, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_format_no_arg_named)] -#[note] -#[note(builtin_macros_note2)] -pub(crate) struct FormatNoArgNamed { - #[primary_span] - pub(crate) span: Span, - pub(crate) name: Symbol, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_format_unknown_trait)] -#[note] -pub(crate) struct FormatUnknownTrait<'a> { - #[primary_span] - pub(crate) span: Span, - pub(crate) ty: &'a str, - #[subdiagnostic] - pub(crate) suggs: Vec, -} - -#[derive(Subdiagnostic)] -#[suggestion( - builtin_macros_suggestion, - code = "{fmt}", - style = "tool-only", - applicability = "maybe-incorrect" -)] -pub struct FormatUnknownTraitSugg { - #[primary_span] - pub span: Span, - pub fmt: &'static str, - pub trait_name: &'static str, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_format_unused_arg)] -pub(crate) struct FormatUnusedArg { - #[primary_span] - #[label(builtin_macros_format_unused_arg)] - pub(crate) span: Span, - pub(crate) named: bool, -} - -// Allow the singular form to be a subdiagnostic of the multiple-unused -// form of diagnostic. -impl Subdiagnostic for FormatUnusedArg { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - f: F, - ) { - diag.arg("named", self.named); - let msg = f(diag, crate::fluent_generated::builtin_macros_format_unused_arg.into()); - diag.span_label(self.span, msg); - } -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_format_unused_args)] -pub(crate) struct FormatUnusedArgs { - #[primary_span] - pub(crate) unused: Vec, - #[label] - pub(crate) fmt: Span, - #[subdiagnostic] - pub(crate) unused_labels: Vec, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_format_pos_mismatch)] -pub(crate) struct FormatPositionalMismatch { - #[primary_span] - pub(crate) span: MultiSpan, - pub(crate) n: usize, - pub(crate) desc: String, - #[subdiagnostic] - pub(crate) highlight: SingleLabelManySpans, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_format_redundant_args)] -pub(crate) struct FormatRedundantArgs { - #[primary_span] - pub(crate) span: MultiSpan, - pub(crate) n: usize, - - #[note] - pub(crate) note: MultiSpan, - - #[subdiagnostic] - pub(crate) sugg: Option, -} - -#[derive(Subdiagnostic)] -#[multipart_suggestion(builtin_macros_suggestion, applicability = "machine-applicable")] -pub(crate) struct FormatRedundantArgsSugg { - #[suggestion_part(code = "")] - pub(crate) spans: Vec, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_test_case_non_item)] -pub(crate) struct TestCaseNonItem { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_test_bad_fn)] -pub(crate) struct TestBadFn { - #[primary_span] - pub(crate) span: Span, - #[label] - pub(crate) cause: Span, - pub(crate) kind: &'static str, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_asm_explicit_register_name)] -pub(crate) struct AsmExplicitRegisterName { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_asm_mutually_exclusive)] -pub(crate) struct AsmMutuallyExclusive { - #[primary_span] - pub(crate) spans: Vec, - pub(crate) opt1: &'static str, - pub(crate) opt2: &'static str, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_asm_pure_combine)] -pub(crate) struct AsmPureCombine { - #[primary_span] - pub(crate) spans: Vec, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_asm_pure_no_output)] -pub(crate) struct AsmPureNoOutput { - #[primary_span] - pub(crate) spans: Vec, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_asm_modifier_invalid)] -pub(crate) struct AsmModifierInvalid { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_asm_requires_template)] -pub(crate) struct AsmRequiresTemplate { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_asm_expected_comma)] -pub(crate) struct AsmExpectedComma { - #[primary_span] - #[label] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_asm_underscore_input)] -pub(crate) struct AsmUnderscoreInput { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_asm_sym_no_path)] -pub(crate) struct AsmSymNoPath { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_asm_expected_other)] -pub(crate) struct AsmExpectedOther { - #[primary_span] - #[label(builtin_macros_asm_expected_other)] - pub(crate) span: Span, - pub(crate) is_global_asm: bool, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_asm_duplicate_arg)] -pub(crate) struct AsmDuplicateArg { - #[primary_span] - #[label(builtin_macros_arg)] - pub(crate) span: Span, - #[label] - pub(crate) prev: Span, - pub(crate) name: Symbol, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_asm_pos_after)] -pub(crate) struct AsmPositionalAfter { - #[primary_span] - #[label(builtin_macros_pos)] - pub(crate) span: Span, - #[label(builtin_macros_named)] - pub(crate) named: Vec, - #[label(builtin_macros_explicit)] - pub(crate) explicit: Vec, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_asm_noreturn)] -pub(crate) struct AsmNoReturn { - #[primary_span] - pub(crate) outputs_sp: Vec, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_asm_mayunwind)] -pub(crate) struct AsmMayUnwind { - #[primary_span] - pub(crate) labels_sp: Vec, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_global_asm_clobber_abi)] -pub(crate) struct GlobalAsmClobberAbi { - #[primary_span] - pub(crate) spans: Vec, -} - -pub(crate) struct AsmClobberNoReg { - pub(crate) spans: Vec, - pub(crate) clobbers: Vec, -} - -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AsmClobberNoReg { - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { - // eager translation as `span_labels` takes `AsRef` - let lbl1 = dcx.eagerly_translate_to_string( - crate::fluent_generated::builtin_macros_asm_clobber_abi, - [].into_iter(), - ); - let lbl2 = dcx.eagerly_translate_to_string( - crate::fluent_generated::builtin_macros_asm_clobber_outputs, - [].into_iter(), - ); - Diag::new(dcx, level, crate::fluent_generated::builtin_macros_asm_clobber_no_reg) - .with_span(self.spans.clone()) - .with_span_labels(self.clobbers, &lbl1) - .with_span_labels(self.spans, &lbl2) - } -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_asm_opt_already_provided)] -pub(crate) struct AsmOptAlreadyprovided { - #[primary_span] - #[label] - pub(crate) span: Span, - pub(crate) symbol: Symbol, - #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")] - pub(crate) full_span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_test_runner_invalid)] -pub(crate) struct TestRunnerInvalid { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_test_runner_nargs)] -pub(crate) struct TestRunnerNargs { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_expected_register_class_or_explicit_register)] -pub(crate) struct ExpectedRegisterClassOrExplicitRegister { - #[primary_span] - pub(crate) span: Span, -} +use rustc_errors::{codes::*,Diag,DiagCtxt,Diagnostic,EmissionGuarantee,Level,//; +MultiSpan,SingleLabelManySpans,SubdiagMessageOp,Subdiagnostic,};use//let _=||(); +rustc_macros::{Diagnostic,Subdiagnostic};use rustc_span::{symbol::Ident,Span,//; +Symbol};#[derive(Diagnostic)]#[diag(builtin_macros_requires_cfg_pattern)]pub(//; +crate)struct RequiresCfgPattern{#[primary_span]#[label]pub(crate)span:Span,}#[// +derive(Diagnostic)]#[diag(builtin_macros_expected_one_cfg_pattern)]pub(crate)//; +struct OneCfgPattern{#[primary_span]pub(crate) span:Span,}#[derive(Diagnostic)]# +[diag(builtin_macros_alloc_error_must_be_fn)]pub(crate)struct//((),());let _=(); +AllocErrorMustBeFn{#[primary_span]pub(crate)span:Span,}#[derive(Diagnostic)]#[// +diag(builtin_macros_assert_requires_boolean)]pub(crate)struct//((),());let _=(); +AssertRequiresBoolean{#[primary_span]#[label]pub(crate)span:Span,}#[derive(//(); +Diagnostic)]#[diag(builtin_macros_assert_requires_expression)]pub(crate)struct// +AssertRequiresExpression{#[primary_span]pub(crate)span:Span,#[suggestion(code=// +"",applicability="maybe-incorrect")]pub(crate) token:Span,}#[derive(Diagnostic)] +#[diag(builtin_macros_assert_missing_comma)] pub(crate)struct AssertMissingComma +{#[primary_span]pub(crate)span:Span,#[suggestion(code=", ",applicability=//({}); +"maybe-incorrect",style="short")]pub(crate)comma :Span,}#[derive(Diagnostic)]pub +(crate)enum CfgAccessibleInvalid{#[diag(//let _=();if true{};let _=();if true{}; +builtin_macros_cfg_accessible_unspecified_path)]UnspecifiedPath (#[primary_span] +Span),#[diag(builtin_macros_cfg_accessible_multiple_paths)]MultiplePaths(#[//(); +primary_span]Span),#[diag(builtin_macros_cfg_accessible_literal_path)]//((),()); +LiteralPath(#[primary_span]Span ),#[diag(builtin_macros_cfg_accessible_has_args) +]HasArguments(#[primary_span]Span),}#[derive(Diagnostic)]#[diag(//if let _=(){}; +builtin_macros_cfg_accessible_indeterminate)]pub(crate)struct//((),());let _=(); +CfgAccessibleIndeterminate{#[primary_span]pub(crate)span:Span,}#[derive(//{();}; +Diagnostic)]#[diag(builtin_macros_concat_missing_literal)]#[note]pub(crate)//(); +struct ConcatMissingLiteral{#[primary_span]pub(crate) spans:Vec,}#[derive( +Diagnostic)]#[diag(builtin_macros_concat_bytestr)]pub(crate)struct//loop{break}; +ConcatBytestr{#[primary_span]pub(crate)span:Span,}#[derive(Diagnostic)]#[diag(// +builtin_macros_concat_c_str_lit)]pub(crate) struct ConcatCStrLit{#[primary_span] +pub(crate)span:Span,}#[derive(Diagnostic)]#[diag(//if let _=(){};*&*&();((),()); +builtin_macros_export_macro_rules)]pub(crate)struct ExportMacroRules{#[//*&*&(); +primary_span]pub(crate)span:Span,}#[derive(Diagnostic)]#[diag(//((),());((),()); +builtin_macros_proc_macro)]pub(crate)struct ProcMacro{#[primary_span]pub(crate) +span:Span,}#[derive( Diagnostic)]#[diag(builtin_macros_invalid_crate_attribute)] +pub(crate)struct InvalidCrateAttr{#[primary_span] pub(crate)span:Span,}#[derive( +Diagnostic)]#[diag(builtin_macros_non_abi)]pub(crate)struct NonABI{#[//let _=(); +primary_span]pub(crate)span:Span,}#[derive(Diagnostic)]#[diag(//((),());((),()); +builtin_macros_trace_macros)]pub(crate)struct TraceMacros{#[primary_span]pub(//; +crate)span:Span,}#[derive(Diagnostic)]#[diag(builtin_macros_bench_sig)]pub(//(); +crate)struct BenchSig{#[primary_span]pub(crate )span:Span,}#[derive(Diagnostic)] +#[diag(builtin_macros_alloc_must_statics)]pub(crate)struct AllocMustStatics{#[// +primary_span]pub(crate)span:Span,}#[derive(Diagnostic)]#[diag(//((),());((),()); +builtin_macros_concat_bytes_invalid)]pub(crate)struct ConcatBytesInvalid{#[//(); +primary_span]pub(crate)span:Span,pub(crate)lit_kind:&'static str,#[//let _=||(); +subdiagnostic]pub(crate)sugg:Option,}#[derive(//3; +Subdiagnostic)]pub(crate)enum ConcatBytesInvalidSuggestion{#[suggestion(//{();}; +builtin_macros_byte_char,code="b{snippet}" ,applicability="machine-applicable")] +CharLit{#[primary_span]span:Span,snippet:String,},#[suggestion(//*&*&();((),()); +builtin_macros_byte_str,code="b{snippet}",applicability="machine-applicable")]// +StrLit{#[primary_span]span:Span,snippet:String,},#[suggestion(//((),());((),()); +builtin_macros_number_array,code="[{snippet}]",applicability=//((),());let _=(); +"machine-applicable")]IntLit{#[primary_span]span:Span,snippet:String,},}#[//{;}; +derive(Diagnostic)]#[diag(builtin_macros_concat_bytes_oob)]pub(crate)struct//(); +ConcatBytesOob{#[primary_span]pub(crate)span:Span ,}#[derive(Diagnostic)]#[diag( +builtin_macros_concat_bytes_non_u8)]pub(crate)struct ConcatBytesNonU8{#[//{();}; +primary_span]pub(crate)span:Span,}#[derive(Diagnostic)]#[diag(//((),());((),()); +builtin_macros_concat_bytes_missing_literal)]#[note]pub(crate)struct//if true{}; +ConcatBytesMissingLiteral{#[primary_span]pub(crate)spans:Vec,}#[derive(//; +Diagnostic)]#[diag(builtin_macros_concat_bytes_array)]pub(crate)struct//((),()); +ConcatBytesArray{#[primary_span]pub(crate)span:Span,#[note]#[help]pub(crate)//3; +bytestr:bool,}#[derive(Diagnostic)]#[diag(//let _=();let _=();let _=();let _=(); +builtin_macros_concat_bytes_bad_repeat)]pub(crate )struct ConcatBytesBadRepeat{# +[primary_span]pub(crate)span:Span,}#[derive(Diagnostic)]#[diag(//*&*&();((),()); +builtin_macros_concat_idents_missing_args)]pub(crate)struct//let _=();if true{}; +ConcatIdentsMissingArgs{#[primary_span]pub(crate) span:Span,}#[derive(Diagnostic +)]#[diag(builtin_macros_concat_idents_missing_comma)]pub(crate)struct//let _=(); +ConcatIdentsMissingComma{#[primary_span]pub(crate)span:Span,}#[derive(//((),()); +Diagnostic)]#[diag(builtin_macros_concat_idents_ident_args)]pub(crate)struct//3; +ConcatIdentsIdentArgs{#[primary_span]pub(crate)span :Span,}#[derive(Diagnostic)] +#[diag(builtin_macros_bad_derive_target,code=E0774)]pub(crate)struct//if true{}; +BadDeriveTarget{#[primary_span]#[label]pub(crate)span:Span,#[label(//let _=||(); +builtin_macros_label2)]pub(crate)item:Span,}#[derive(Diagnostic)]#[diag(//{();}; +builtin_macros_tests_not_support)]pub(crate)struct TestsNotSupport{}#[derive(//; +Diagnostic)]#[diag(builtin_macros_unexpected_lit,code=E0777)]pub(crate)struct//; +BadDeriveLit{#[primary_span]#[label]pub(crate)span:Span,#[subdiagnostic]pub//(); +help:BadDeriveLitHelp,}#[derive(Subdiagnostic )]pub(crate)enum BadDeriveLitHelp{ +#[help(builtin_macros_str_lit)]StrLit{sym :Symbol},#[help(builtin_macros_other)] +Other,}#[derive(Diagnostic)]#[diag(builtin_macros_derive_path_args_list)]pub(//; +crate)struct DerivePathArgsList{#[suggestion(code="",applicability=//let _=||(); +"machine-applicable")]#[primary_span]pub(crate) span:Span,}#[derive(Diagnostic)] +#[diag(builtin_macros_derive_path_args_value)]pub(crate)struct//((),());((),()); +DerivePathArgsValue{#[suggestion(code= "",applicability="machine-applicable")]#[ +primary_span]pub(crate)span:Span,}#[derive(Diagnostic)]#[diag(//((),());((),()); +builtin_macros_no_default_variant)]#[help]pub(crate)struct NoDefaultVariant{#[// +primary_span]pub(crate)span:Span,#[subdiagnostic]pub(crate)suggs:Vec,}#[derive(Subdiagnostic)]#[suggestion(//let _=();let _=(); +builtin_macros_suggestion,code="#[default] {ident}",applicability=//loop{break}; +"maybe-incorrect",style="tool-only")]pub(crate)struct NoDefaultVariantSugg{#[//; +primary_span]pub(crate)span:Span,pub(crate) ident:Ident,}#[derive(Diagnostic)]#[ +diag(builtin_macros_multiple_defaults)]#[note ]pub(crate)struct MultipleDefaults +{#[primary_span]pub(crate)span:Span,#[label]pub(crate)first:Span,#[label(//({}); +builtin_macros_additional)]pub additional:Vec,#[subdiagnostic]pub suggs:// +Vec,}#[derive(Subdiagnostic)]#[multipart_suggestion(//{;}; +builtin_macros_suggestion,applicability="maybe-incorrect",style="tool-only")]//; +pub(crate)struct MultipleDefaultsSugg{#[suggestion_part(code="")]pub(crate)//(); +spans:Vec,pub(crate)ident:Ident,}#[derive(Diagnostic)]#[diag(//let _=||(); +builtin_macros_non_unit_default)]#[help]pub(crate)struct NonUnitDefault{#[//{;}; +primary_span]pub(crate)span:Span,}#[derive(Diagnostic)]#[diag(//((),());((),()); +builtin_macros_non_exhaustive_default)]#[help]pub(crate)struct//((),());((),()); +NonExhaustiveDefault{#[primary_span]pub(crate)span:Span,#[label]pub(crate)//{;}; +non_exhaustive:Span,}#[derive(Diagnostic)]#[diag(//if let _=(){};*&*&();((),()); +builtin_macros_multiple_default_attrs)]#[note]pub(crate)struct//((),());((),()); +MultipleDefaultAttrs{#[primary_span]pub(crate)span :Span,#[label]pub(crate)first +:Span,#[label(builtin_macros_label_again)]pub( crate)first_rest:Span,#[help]pub( +crate)rest:MultiSpan,pub(crate)only_one:bool,#[subdiagnostic]pub(crate)sugg://3; +MultipleDefaultAttrsSugg,}#[derive(Subdiagnostic)]#[multipart_suggestion(//({}); +builtin_macros_help,applicability="machine-applicable",style="tool-only")]pub(// +crate)struct MultipleDefaultAttrsSugg{#[suggestion_part(code="")]pub(crate)//(); +spans:Vec,}#[derive(Diagnostic)]#[diag(builtin_macros_default_arg)]pub(//; +crate)struct DefaultHasArg{#[primary_span] #[suggestion(code="#[default]",style= +"hidden",applicability="maybe-incorrect")]pub(crate)span:Span,}#[derive(//{();}; +Diagnostic)]#[diag(builtin_macros_derive_macro_call)]pub(crate)struct//let _=(); +DeriveMacroCall{#[primary_span]pub(crate)span: Span,}#[derive(Diagnostic)]#[diag +(builtin_macros_cannot_derive_union)]pub(crate)struct DeriveUnion{#[//if true{}; +primary_span]pub(crate)span:Span,}#[derive(Diagnostic)]#[diag(//((),());((),()); +builtin_macros_env_takes_args)]pub(crate)struct EnvTakesArgs{#[primary_span]pub +(crate)span:Span,}pub(crate )struct EnvNotDefinedWithUserMessage{pub(crate)span: +Span,pub(crate)msg_from_user:Symbol,} impl<'a,G:EmissionGuarantee>Diagnostic<'a, +G>for EnvNotDefinedWithUserMessage{#[track_caller]fn into_diag(self,dcx:&'a//(); +DiagCtxt,level:Level)->Diag<'a,G>{{;};#[expect(rustc::untranslatable_diagnostic, +reason="cannot translate user-provided messages")]let mut diag=Diag::new(dcx,//; +level,self.msg_from_user.to_string());3;3;diag.span(self.span);3;diag}}#[derive( +Diagnostic)]pub(crate)enum EnvNotDefined<'a>{#[diag(//loop{break;};loop{break;}; +builtin_macros_env_not_defined)]#[help(builtin_macros_cargo)]CargoEnvVar{#[//(); +primary_span]span:Span,var:Symbol,var_expr:&'a rustc_ast::Expr,},#[diag(//{();}; +builtin_macros_env_not_defined)]#[help(builtin_macros_custom)]CustomEnvVar{#[//; +primary_span]span:Span,var:Symbol,var_expr:&'a rustc_ast::Expr,},}#[derive(//(); +Diagnostic)]#[diag(builtin_macros_env_not_unicode)]pub(crate)struct//let _=||(); +EnvNotUnicode{#[primary_span]pub(crate)span:Span ,pub(crate)var:Symbol,}#[derive +(Diagnostic)]#[diag(builtin_macros_format_requires_string)]pub(crate)struct//(); +FormatRequiresString{#[primary_span]pub(crate)span :Span,}#[derive(Diagnostic)]# +[diag(builtin_macros_format_duplicate_arg)]pub (crate)struct FormatDuplicateArg{ +#[primary_span]pub(crate)span:Span,#[label(builtin_macros_label1)]pub(crate)//3; +prev:Span,#[label(builtin_macros_label2)]pub(crate)duplicate:Span,pub(crate)//3; +ident:Ident,}#[derive(Diagnostic)]#[diag(//let _=();let _=();let _=();if true{}; +builtin_macros_format_positional_after_named)]pub(crate)struct//((),());((),()); +PositionalAfterNamed{#[primary_span]#[label]pub(crate)span:Span,#[label(//{();}; +builtin_macros_named_args)]pub(crate)args:Vec,}#[derive(Diagnostic)]#[//3; +diag(builtin_macros_format_string_invalid)]pub (crate)struct InvalidFormatString +{#[primary_span]#[label]pub(crate)span:Span,pub(crate)desc:String,pub(crate)//3; +label1:String,#[subdiagnostic]pub( crate)note_:Option,# +[subdiagnostic]pub(crate)label_:Option,#[//let _=||(); +subdiagnostic]pub(crate)sugg_:Option,}#[derive(// +Subdiagnostic)]#[note(builtin_macros_note)]pub(crate)struct//let _=();if true{}; +InvalidFormatStringNote{pub(crate)note:String,} #[derive(Subdiagnostic)]#[label( +builtin_macros_second_label)]pub(crate)struct InvalidFormatStringLabel{#[//({}); +primary_span]pub(crate)span:Span,pub( crate)label:String,}#[derive(Subdiagnostic +)]pub(crate)enum InvalidFormatStringSuggestion{#[multipart_suggestion(//((),()); +builtin_macros_format_use_positional,style="verbose",applicability=//let _=||(); +"machine-applicable")]UsePositional{#[suggestion_part(code="{len}")]captured://; +Span,len:String,#[suggestion_part(code=", {arg}")]span:Span,arg:String,},#[//(); +suggestion(builtin_macros_format_remove_raw_ident,code="",applicability=//{();}; +"machine-applicable")]RemoveRawIdent{#[primary_span]span:Span,},}#[derive(//{;}; +Diagnostic)]#[diag(builtin_macros_format_no_arg_named)]#[note]#[note(//let _=(); +builtin_macros_note2)]pub(crate)struct FormatNoArgNamed{#[primary_span]pub(//(); +crate)span:Span,pub(crate)name:Symbol,}#[derive(Diagnostic)]#[diag(//let _=||(); +builtin_macros_format_unknown_trait)]#[note] pub(crate)struct FormatUnknownTrait +<'a>{#[primary_span]pub(crate)span:Span,pub(crate)ty:&'a str,#[subdiagnostic]//; +pub(crate)suggs:Vec,}#[derive(Subdiagnostic)]#[//*&*&(); +suggestion(builtin_macros_suggestion,code="{fmt}",style="tool-only",//if true{}; +applicability="maybe-incorrect")]pub struct FormatUnknownTraitSugg{#[//let _=(); +primary_span]pub span:Span,pub fmt:&'static str,pub trait_name:&'static str,}#[ +derive(Diagnostic)]#[diag(builtin_macros_format_unused_arg)]pub(crate)struct//3; +FormatUnusedArg{#[primary_span]#[label(builtin_macros_format_unused_arg)]pub(//; +crate)span:Span,pub(crate)named: bool,}impl Subdiagnostic for FormatUnusedArg{fn +add_to_diag_with>(self,diag:&mut//{;}; +Diag<'_,G>,f:F,){{;};diag.arg("named",self.named);{;};{;};let msg=f(diag,crate:: +fluent_generated::builtin_macros_format_unused_arg.into());;diag.span_label(self +.span,msg);;}}#[derive(Diagnostic)]#[diag(builtin_macros_format_unused_args)]pub +(crate)struct FormatUnusedArgs{#[primary_span]pub(crate)unused:Vec,#[//(); +label]pub(crate)fmt:Span,#[subdiagnostic]pub(crate)unused_labels:Vec,}#[derive(Diagnostic)]#[diag(//((),());((),());((),());((),()); +builtin_macros_format_pos_mismatch)]pub(crate )struct FormatPositionalMismatch{# +[primary_span]pub(crate)span:MultiSpan,pub( crate)n:usize,pub(crate)desc:String, +#[subdiagnostic]pub(crate)highlight: SingleLabelManySpans,}#[derive(Diagnostic)] +#[diag(builtin_macros_format_redundant_args)]pub(crate)struct//((),());let _=(); +FormatRedundantArgs{#[primary_span]pub(crate)span :MultiSpan,pub(crate)n:usize,# +[note]pub(crate)note:MultiSpan,#[subdiagnostic]pub(crate)sugg:Option,}#[derive(Subdiagnostic)]#[multipart_suggestion(//({}); +builtin_macros_suggestion,applicability="machine-applicable")]pub(crate)struct// +FormatRedundantArgsSugg{#[suggestion_part(code="")]pub (crate)spans:Vec,}# +[derive(Diagnostic)]#[diag(builtin_macros_test_case_non_item)]pub(crate)struct// +TestCaseNonItem{#[primary_span]pub(crate)span: Span,}#[derive(Diagnostic)]#[diag +(builtin_macros_test_bad_fn)]pub(crate)struct TestBadFn{#[primary_span]pub(//(); +crate)span:Span,#[label]pub(crate)cause:Span,pub(crate)kind:&'static str,}#[//3; +derive(Diagnostic)]#[diag (builtin_macros_asm_explicit_register_name)]pub(crate) +struct AsmExplicitRegisterName{#[primary_span]pub(crate)span:Span,}#[derive(//3; +Diagnostic)]#[diag(builtin_macros_asm_mutually_exclusive)]pub(crate)struct//{;}; +AsmMutuallyExclusive{#[primary_span]pub(crate)spans:Vec,pub(crate)opt1:&// +'static str,pub(crate)opt2:&'static str,}#[derive(Diagnostic)]#[diag(//let _=(); +builtin_macros_asm_pure_combine)]pub(crate) struct AsmPureCombine{#[primary_span +]pub(crate)spans:Vec,}#[derive(Diagnostic)]#[diag(//let _=||();let _=||(); +builtin_macros_asm_pure_no_output)]pub(crate)struct AsmPureNoOutput{#[//((),()); +primary_span]pub(crate)spans:Vec,}#[derive(Diagnostic)]#[diag(//if true{}; +builtin_macros_asm_modifier_invalid)]pub(crate)struct AsmModifierInvalid{#[//(); +primary_span]pub(crate)span:Span,}#[derive(Diagnostic)]#[diag(//((),());((),()); +builtin_macros_asm_requires_template)]pub(crate)struct AsmRequiresTemplate{#[//; +primary_span]pub(crate)span:Span,}#[derive(Diagnostic)]#[diag(//((),());((),()); +builtin_macros_asm_expected_comma)]pub(crate)struct AsmExpectedComma{#[//*&*&(); +primary_span]#[label]pub(crate)span:Span,}#[derive(Diagnostic)]#[diag(//((),()); +builtin_macros_asm_underscore_input)]pub(crate)struct AsmUnderscoreInput{#[//(); +primary_span]pub(crate)span:Span,}#[derive(Diagnostic)]#[diag(//((),());((),()); +builtin_macros_asm_sym_no_path)]pub(crate)struct AsmSymNoPath{#[primary_span]//; +pub(crate)span:Span,}#[derive(Diagnostic)]#[diag(//if let _=(){};*&*&();((),()); +builtin_macros_asm_expected_other)]pub(crate)struct AsmExpectedOther{#[//*&*&(); +primary_span]#[label(builtin_macros_asm_expected_other)] pub(crate)span:Span,pub +(crate)is_global_asm:bool,}#[derive(Diagnostic)]#[diag(//let _=||();loop{break}; +builtin_macros_asm_duplicate_arg)]pub(crate)struct AsmDuplicateArg{#[//let _=(); +primary_span]#[label(builtin_macros_arg)]pub(crate )span:Span,#[label]pub(crate) +prev:Span,pub(crate)name:Symbol,}#[derive(Diagnostic)]#[diag(//((),());let _=(); +builtin_macros_asm_pos_after)]pub(crate)struct AsmPositionalAfter{#[//if true{}; +primary_span]#[label(builtin_macros_pos)]pub(crate)span:Span,#[label(//let _=(); +builtin_macros_named)]pub(crate)named: Vec,#[label(builtin_macros_explicit +)]pub(crate)explicit:Vec,}#[derive(Diagnostic)]#[diag(//let _=();let _=(); +builtin_macros_asm_noreturn)]pub(crate)struct AsmNoReturn{#[primary_span]pub(//; +crate)outputs_sp:Vec,}#[derive(Diagnostic)]#[diag(//let _=||();let _=||(); +builtin_macros_asm_mayunwind)]pub(crate)struct AsmMayUnwind{#[primary_span]pub( +crate)labels_sp:Vec,}#[derive(Diagnostic)]#[diag(//let _=||();loop{break}; +builtin_macros_global_asm_clobber_abi)]pub(crate)struct GlobalAsmClobberAbi{#[// +primary_span]pub(crate)spans:Vec,}pub(crate)struct AsmClobberNoReg{pub(//; +crate)spans:Vec,pub(crate)clobbers :Vec,}impl<'a,G:EmissionGuarantee +>Diagnostic<'a,G>for AsmClobberNoReg{fn into_diag(self,dcx:&'a DiagCtxt,level:// +Level)->Diag<'a,G>{loop{break;};let lbl1=dcx.eagerly_translate_to_string(crate:: +fluent_generated::builtin_macros_asm_clobber_abi,[].into_iter(),);;let lbl2=dcx. +eagerly_translate_to_string(crate::fluent_generated:://loop{break};loop{break;}; +builtin_macros_asm_clobber_outputs,[].into_iter(),);;Diag::new(dcx,level,crate:: +fluent_generated::builtin_macros_asm_clobber_no_reg).with_span (self.spans.clone +()).with_span_labels(self.clobbers,&lbl1) .with_span_labels(self.spans,&lbl2)}}# +[derive(Diagnostic)]#[diag(builtin_macros_asm_opt_already_provided)]pub(crate)// +struct AsmOptAlreadyprovided{#[primary_span]#[label]pub(crate)span:Span,pub(//3; +crate)symbol:Symbol,#[suggestion(code="",applicability="machine-applicable",//3; +style="tool-only")]pub(crate)full_span:Span,}#[derive(Diagnostic)]#[diag(//({}); +builtin_macros_test_runner_invalid)]pub(crate)struct TestRunnerInvalid{#[//({}); +primary_span]pub(crate)span:Span,}#[derive(Diagnostic)]#[diag(//((),());((),()); +builtin_macros_test_runner_nargs)]pub(crate)struct TestRunnerNargs{#[//let _=(); +primary_span]pub(crate)span:Span,}#[derive(Diagnostic)]#[diag(//((),());((),()); +builtin_macros_expected_register_class_or_explicit_register)]pub(crate)struct//; +ExpectedRegisterClassOrExplicitRegister{#[primary_span]pub(crate)span:Span,}//3; diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 51d6058a744fc..0403be13d0431 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -1,1018 +1,272 @@ -use parse::Position::ArgumentNamed; -use rustc_ast::ptr::P; -use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{token, StmtKind}; -use rustc_ast::{ - Expr, ExprKind, FormatAlignment, FormatArgPosition, FormatArgPositionKind, FormatArgs, - FormatArgsPiece, FormatArgument, FormatArgumentKind, FormatArguments, FormatCount, - FormatDebugHex, FormatOptions, FormatPlaceholder, FormatSign, FormatTrait, -}; -use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{Applicability, Diag, MultiSpan, PResult, SingleLabelManySpans}; -use rustc_expand::base::*; -use rustc_parse::parser::Recovered; -use rustc_parse_format as parse; -use rustc_span::symbol::{Ident, Symbol}; -use rustc_span::{BytePos, ErrorGuaranteed, InnerSpan, Span}; - -use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY; -use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiag, LintId}; - -// 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` AST node. -// 3. Much later, in AST lowering (rustc_ast_lowering), that `FormatArgs` structure will be turned -// into the expression of type `core::fmt::Arguments`. - -// See rustc_ast/src/format.rs for the FormatArgs structure and glossary. - -// 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), - Precision, - Width, -} -use PositionUsedAs::*; - -use crate::errors; - -#[derive(Debug)] -struct MacroInput { - fmtstr: P, - args: FormatArguments, - /// Whether the first argument was a string literal or a result from eager macro expansion. - /// If it's not a string literal, we disallow implicit argument capturing. - /// - /// This does not correspond to whether we can treat spans to the literal normally, as the whole - /// invocation might be the result of another macro expansion, in which case this flag may still be true. - /// - /// See [RFC 2795] for more information. - /// - /// [RFC 2795]: https://rust-lang.github.io/rfcs/2795-format-args-implicit-identifiers.html#macro-hygiene - is_direct_literal: bool, -} - -/// Parses the arguments from the given list of tokens, returning the diagnostic -/// if there's a parse error so we can continue parsing other format! -/// expressions. -/// -/// If parsing succeeds, the return value is: -/// -/// ```text -/// Ok((fmtstr, parsed arguments)) -/// ``` -fn parse_args<'a>(ecx: &ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<'a, MacroInput> { - let mut args = FormatArguments::new(); - - let mut p = ecx.new_parser_from_tts(tts); - - if p.token == token::Eof { - return Err(ecx.dcx().create_err(errors::FormatRequiresString { span: sp })); - } - - let first_token = &p.token; - - let fmtstr = if let token::Literal(lit) = first_token.kind - && matches!(lit.kind, token::Str | token::StrRaw(_)) - { - // This allows us to properly handle cases when the first comma - // after the format string is mistakenly replaced with any operator, - // which cause the expression parser to eat too much tokens. - p.parse_literal_maybe_minus()? - } else { - // Otherwise, we fall back to the expression parser. - p.parse_expr()? - }; - - // Only allow implicit captures to be used when the argument is a direct literal - // instead of a macro expanding to one. - let is_direct_literal = matches!(fmtstr.kind, ExprKind::Lit(_)); - - let mut first = true; - - while p.token != token::Eof { - if !p.eat(&token::Comma) { - if first { - p.clear_expected_tokens(); - } - - match p.expect(&token::Comma) { - Err(err) => { - match token::TokenKind::Comma.similar_tokens() { - Some(tks) if tks.contains(&p.token.kind) => { - // If a similar token is found, then it may be a typo. We - // consider it as a comma, and continue parsing. - err.emit(); - p.bump(); - } - // Otherwise stop the parsing and return the error. - _ => return Err(err), - } - } - Ok(Recovered::Yes) => (), - Ok(Recovered::No) => unreachable!(), - } - } - first = false; - if p.token == token::Eof { - break; - } // accept trailing commas - match p.token.ident() { - Some((ident, _)) if p.look_ahead(1, |t| *t == token::Eq) => { - p.bump(); - p.expect(&token::Eq)?; - let expr = p.parse_expr()?; - if let Some((_, prev)) = args.by_name(ident.name) { - ecx.dcx().emit_err(errors::FormatDuplicateArg { - span: ident.span, - prev: prev.kind.ident().unwrap().span, - duplicate: ident.span, - ident, - }); - continue; - } - args.add(FormatArgument { kind: FormatArgumentKind::Named(ident), expr }); - } - _ => { - let expr = p.parse_expr()?; - if !args.named_args().is_empty() { - return Err(ecx.dcx().create_err(errors::PositionalAfterNamed { - span: expr.span, - args: args - .named_args() - .iter() - .filter_map(|a| a.kind.ident().map(|ident| (a, ident))) - .map(|(arg, n)| n.span.to(arg.expr.span)) - .collect(), - })); - } - args.add(FormatArgument { kind: FormatArgumentKind::Normal, expr }); - } - } - } - Ok(MacroInput { fmtstr, args, is_direct_literal }) -} - -fn make_format_args( - ecx: &mut ExtCtxt<'_>, - input: MacroInput, - append_newline: bool, -) -> ExpandResult, ()> { - let msg = "format argument must be a string literal"; - let unexpanded_fmt_span = input.fmtstr.span; - - let MacroInput { fmtstr: efmt, mut args, is_direct_literal } = input; - - let (fmt_str, fmt_style, fmt_span) = { - let ExpandResult::Ready(mac) = expr_to_spanned_string(ecx, efmt.clone(), msg) else { - return ExpandResult::Retry(()); - }; - match mac { - Ok(mut fmt) if append_newline => { - fmt.0 = Symbol::intern(&format!("{}\n", fmt.0)); - fmt - } - Ok(fmt) => fmt, - Err(err) => { - let guar = match err { - Ok((mut err, suggested)) => { - if !suggested { - if let ExprKind::Block(block, None) = &efmt.kind - && block.stmts.len() == 1 - && let StmtKind::Expr(expr) = &block.stmts[0].kind - && let ExprKind::Path(None, path) = &expr.kind - && path.is_potential_trivial_const_arg() - { - err.multipart_suggestion( - "quote your inlined format argument to use as string literal", - vec![ - (unexpanded_fmt_span.shrink_to_hi(), "\"".to_string()), - (unexpanded_fmt_span.shrink_to_lo(), "\"".to_string()), - ], - Applicability::MaybeIncorrect, - ); - } else { - let sugg_fmt = match args.explicit_args().len() { - 0 => "{}".to_string(), - _ => { - format!("{}{{}}", "{} ".repeat(args.explicit_args().len())) - } - }; - err.span_suggestion( - unexpanded_fmt_span.shrink_to_lo(), - "you might be missing a string literal to format with", - format!("\"{sugg_fmt}\", "), - Applicability::MaybeIncorrect, - ); - } - } - err.emit() - } - Err(guar) => guar, - }; - return ExpandResult::Ready(Err(guar)); - } - } - }; - - let str_style = match fmt_style { - 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(unexpanded_fmt_span).ok(); - let mut parser = parse::Parser::new( - fmt_str, - str_style, - fmt_snippet, - append_newline, - parse::ParseMode::Format, - ); - - let mut pieces = Vec::new(); - while let Some(piece) = parser.next() { - if !parser.errors.is_empty() { - break; - } else { - pieces.push(piece); - } - } - - let is_source_literal = parser.is_source_literal; - - if !parser.errors.is_empty() { - let err = parser.errors.remove(0); - let sp = if is_source_literal { - fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end)) - } else { - // The format string could be another macro invocation, e.g.: - // format!(concat!("abc", "{}"), 4); - // However, `err.span` is an inner span relative to the *result* of - // the macro invocation, which is why we would get a nonsensical - // result calling `fmt_span.from_inner(err.span)` as above, and - // might even end up inside a multibyte character (issue #86085). - // Therefore, we conservatively report the error for the entire - // argument span here. - fmt_span - }; - let mut e = errors::InvalidFormatString { - span: sp, - note_: None, - label_: None, - sugg_: None, - desc: err.description, - label1: err.label, - }; - if let Some(note) = err.note { - e.note_ = Some(errors::InvalidFormatStringNote { note }); - } - if let Some((label, span)) = err.secondary_label - && is_source_literal - { - e.label_ = Some(errors::InvalidFormatStringLabel { - span: fmt_span.from_inner(InnerSpan::new(span.start, span.end)), - label, - }); - } - match err.suggestion { - parse::Suggestion::None => {} - parse::Suggestion::UsePositional => { - let captured_arg_span = - fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end)); - if let Ok(arg) = ecx.source_map().span_to_snippet(captured_arg_span) { - let span = match args.unnamed_args().last() { - Some(arg) => arg.expr.span, - None => fmt_span, - }; - e.sugg_ = Some(errors::InvalidFormatStringSuggestion::UsePositional { - captured: captured_arg_span, - len: args.unnamed_args().len().to_string(), - span: span.shrink_to_hi(), - arg, - }); - } - } - parse::Suggestion::RemoveRawIdent(span) => { - if is_source_literal { - let span = fmt_span.from_inner(InnerSpan::new(span.start, span.end)); - e.sugg_ = Some(errors::InvalidFormatStringSuggestion::RemoveRawIdent { span }) - } - } - } - let guar = ecx.dcx().emit_err(e); - return ExpandResult::Ready(Err(guar)); - } - - let to_span = |inner_span: rustc_parse_format::InnerSpan| { - is_source_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(); - - enum ArgRef<'a> { - Index(usize), - Name(&'a str, Option), - } - use ArgRef::*; - - let mut unnamed_arg_after_named_arg = false; - - let mut lookup_arg = |arg: ArgRef<'_>, - span: Option, - 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_direct_literal { - ecx.expr_ident(span, ident) - } else { - // For the moment capturing variables from format strings expanded from macros is - // disabled (see RFC #2795) - let guar = ecx.dcx().emit_err(errors::FormatNoArgNamed { span, name }); - unnamed_arg_after_named_arg = true; - DummyResult::raw_expr(span, Some(guar)) - }; - Ok(args.add(FormatArgument { kind: FormatArgumentKind::Captured(ident), expr })) - } - } - }; - FormatArgPosition { index, kind, span } - }; - - let mut template = Vec::new(); - let mut unfinished_literal = String::new(); - let mut placeholder_index = 0; - - for piece in &pieces { - match *piece { - parse::Piece::String(s) => { - unfinished_literal.push_str(s); - } - parse::Piece::NextArgument(box parse::Argument { position, position_span, format }) => { - if !unfinished_literal.is_empty() { - template.push(FormatArgsPiece::Literal(Symbol::intern(&unfinished_literal))); - unfinished_literal.clear(); - } - - 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 alignment = match format.align { - parse::AlignUnknown => None, - parse::AlignLeft => Some(FormatAlignment::Left), - parse::AlignRight => Some(FormatAlignment::Right), - parse::AlignCenter => Some(FormatAlignment::Center), - }; - - 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, - sign: format.sign.map(|s| match s { - parse::Sign::Plus => FormatSign::Plus, - parse::Sign::Minus => FormatSign::Minus, - }), - alternate: format.alternate, - zero_pad: format.zero_pad, - debug_hex: format.debug_hex.map(|s| match s { - parse::DebugHex::Lower => FormatDebugHex::Lower, - parse::DebugHex::Upper => FormatDebugHex::Upper, - }), - precision, - width, - }, - })); - } - } - } - - if !unfinished_literal.is_empty() { - template.push(FormatArgsPiece::Literal(Symbol::intern(&unfinished_literal))); - } - - if !invalid_refs.is_empty() { - report_invalid_references(ecx, &invalid_refs, &template, fmt_span, &args, parser); - } - - let unused = used - .iter() - .enumerate() - .filter(|&(_, used)| !used) - .map(|(i, _)| { - let named = matches!(args.explicit_args()[i].kind, FormatArgumentKind::Named(_)); - (args.explicit_args()[i].expr.span, named) - }) - .collect::>(); - - let has_unused = !unused.is_empty(); - if has_unused { - // 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, - &used, - &args, - &pieces, - detect_foreign_fmt, - str_style, - fmt_str, - fmt_span, - ); - } - - // 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() && !has_unused && !unnamed_arg_after_named_arg { - 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) - } - 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: BuiltinLintDiag::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), - }, - }); - } - } - - ExpandResult::Ready(Ok(FormatArgs { span: fmt_span, template, arguments: args })) -} - -fn invalid_placeholder_type_error( - ecx: &ExtCtxt<'_>, - ty: &str, - ty_span: Option, - fmt_span: Span, -) { - let sp = ty_span.map(|sp| fmt_span.from_inner(InnerSpan::new(sp.start, sp.end))); - let suggs = if let Some(sp) = sp { - [ - ("", "Display"), - ("?", "Debug"), - ("e", "LowerExp"), - ("E", "UpperExp"), - ("o", "Octal"), - ("p", "Pointer"), - ("b", "Binary"), - ("x", "LowerHex"), - ("X", "UpperHex"), - ] - .into_iter() - .map(|(fmt, trait_name)| errors::FormatUnknownTraitSugg { span: sp, fmt, trait_name }) - .collect() - } else { - vec![] - }; - ecx.dcx().emit_err(errors::FormatUnknownTrait { span: sp.unwrap_or(fmt_span), ty, suggs }); -} - -fn report_missing_placeholders( - ecx: &ExtCtxt<'_>, - unused: Vec<(Span, bool)>, - used: &[bool], - args: &FormatArguments, - pieces: &[parse::Piece<'_>], - detect_foreign_fmt: bool, - str_style: Option, - fmt_str: &str, - fmt_span: Span, -) { - let mut diag = if let &[(span, named)] = &unused[..] { - ecx.dcx().create_err(errors::FormatUnusedArg { span, named }) - } else { - let unused_labels = - unused.iter().map(|&(span, named)| errors::FormatUnusedArg { span, named }).collect(); - let unused_spans = unused.iter().map(|&(span, _)| span).collect(); - ecx.dcx().create_err(errors::FormatUnusedArgs { - fmt: fmt_span, - unused: unused_spans, - unused_labels, - }) - }; - - let placeholders = pieces - .iter() - .filter_map(|piece| { - if let parse::Piece::NextArgument(argument) = piece - && let ArgumentNamed(binding) = argument.position - { - let span = fmt_span.from_inner(InnerSpan::new( - argument.position_span.start, - argument.position_span.end, - )); - Some((span, binding)) - } else { - None - } - }) - .collect::>(); - - if !placeholders.is_empty() { - if let Some(new_diag) = report_redundant_format_arguments(ecx, args, used, placeholders) { - diag.cancel(); - new_diag.emit(); - return; - } - } - - // 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); - - if !found_foreign { - found_foreign = true; - show_doc_note = true; - } - - let sp = fmt_span.from_inner(pos); - - if success { - suggestions.push((sp, trn)); - } else { - diag.span_note( - sp, - format!("format specifiers use curly braces, and {}", trn), - ); - } - } - - if show_doc_note { - diag.note(concat!( - stringify!($kind), - " formatting is 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 && unused.len() == 1 { - diag.span_label(fmt_span, "formatting specifier missing"); - } - - diag.emit(); -} - -/// This function detects and reports unused format!() arguments that are -/// redundant due to implicit captures (e.g. `format!("{x}", x)`). -fn report_redundant_format_arguments<'a>( - ecx: &ExtCtxt<'a>, - args: &FormatArguments, - used: &[bool], - placeholders: Vec<(Span, &str)>, -) -> Option> { - let mut fmt_arg_indices = vec![]; - let mut args_spans = vec![]; - let mut fmt_spans = vec![]; - - for (i, unnamed_arg) in args.unnamed_args().iter().enumerate().rev() { - let Some(ty) = unnamed_arg.expr.to_ty() else { continue }; - let Some(argument_binding) = ty.kind.is_simple_path() else { continue }; - let argument_binding = argument_binding.as_str(); - - if used[i] { - continue; - } - - let matching_placeholders = placeholders - .iter() - .filter(|(_, inline_binding)| argument_binding == *inline_binding) - .map(|(span, _)| span) - .collect::>(); - - if !matching_placeholders.is_empty() { - fmt_arg_indices.push(i); - args_spans.push(unnamed_arg.expr.span); - for span in &matching_placeholders { - if fmt_spans.contains(*span) { - continue; - } - fmt_spans.push(**span); - } - } - } - - if !args_spans.is_empty() { - let multispan = MultiSpan::from(fmt_spans); - let mut suggestion_spans = vec![]; - - for (arg_span, fmt_arg_idx) in args_spans.iter().zip(fmt_arg_indices.iter()) { - let span = if fmt_arg_idx + 1 == args.explicit_args().len() { - *arg_span - } else { - arg_span.until(args.explicit_args()[*fmt_arg_idx + 1].expr.span) - }; - - suggestion_spans.push(span); - } - - let sugg = if args.named_args().len() == 0 { - Some(errors::FormatRedundantArgsSugg { spans: suggestion_spans }) - } else { - None - }; - - return Some(ecx.dcx().create_err(errors::FormatRedundantArgs { - n: args_spans.len(), - span: MultiSpan::from(args_spans), - note: multispan, - sugg, - })); - } - - None -} - -/// 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: &ExtCtxt<'_>, - invalid_refs: &[(usize, Option, 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 {n} arguments"), - }; - - let mut 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); - } - let span = if spans.is_empty() { - MultiSpan::from_span(fmt_span) - } else { - MultiSpan::from_spans(spans) - }; - e = ecx.dcx().create_err(errors::FormatPositionalMismatch { - span, - n: num_placeholders, - desc: num_args_desc, - highlight: SingleLabelManySpans { - spans: args.explicit_args().iter().map(|arg| arg.expr.span).collect(), - label: "", - }, - }); - // 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 {num_placeholders} arguments") - }, - ), - ); - } - } - 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_source_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::>().join(", ") - ) - }; - e = ecx.dcx().struct_span_err( - span, - format!("invalid reference to positional {arg_list} ({num_args_desc})"), - ); - e.note("positional arguments are zero-based"); - } - - 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 expand_format_args_impl<'cx>( - ecx: &'cx mut ExtCtxt<'_>, - mut sp: Span, - tts: TokenStream, - nl: bool, -) -> MacroExpanderResult<'cx> { - sp = ecx.with_def_site_ctxt(sp); - ExpandResult::Ready(match parse_args(ecx, sp, tts) { - Ok(input) => { - let ExpandResult::Ready(mac) = make_format_args(ecx, input, nl) else { - return ExpandResult::Retry(()); - }; - match mac { - Ok(format_args) => { - MacEager::expr(ecx.expr(sp, ExprKind::FormatArgs(P(format_args)))) - } - Err(guar) => MacEager::expr(DummyResult::raw_expr(sp, Some(guar))), - } - } - Err(err) => { - let guar = err.emit(); - DummyResult::any(sp, guar) - } - }) -} - -pub fn expand_format_args<'cx>( - ecx: &'cx mut ExtCtxt<'_>, - sp: Span, - tts: TokenStream, -) -> MacroExpanderResult<'cx> { - expand_format_args_impl(ecx, sp, tts, false) -} - -pub fn expand_format_args_nl<'cx>( - ecx: &'cx mut ExtCtxt<'_>, - sp: Span, - tts: TokenStream, -) -> MacroExpanderResult<'cx> { - expand_format_args_impl(ecx, sp, tts, true) -} +use parse::Position::ArgumentNamed;use rustc_ast::ptr::P;use rustc_ast:://{();}; +tokenstream::TokenStream;use rustc_ast::{token,StmtKind};use rustc_ast::{Expr,// +ExprKind,FormatAlignment,FormatArgPosition,FormatArgPositionKind,FormatArgs,//3; +FormatArgsPiece,FormatArgument,FormatArgumentKind,FormatArguments,FormatCount,// +FormatDebugHex,FormatOptions,FormatPlaceholder,FormatSign,FormatTrait,};use//(); +rustc_data_structures::fx::FxHashSet;use rustc_errors::{Applicability,Diag,//(); +MultiSpan,PResult,SingleLabelManySpans};use rustc_expand::base::*;use//let _=(); +rustc_parse::parser::Recovered;use rustc_parse_format as parse;use rustc_span:: +symbol::{Ident,Symbol};use rustc_span::{BytePos,ErrorGuaranteed,InnerSpan,Span} +;use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY;use//if true{}; +rustc_lint_defs::{BufferedEarlyLint,BuiltinLintDiag,LintId };#[derive(Clone,Copy +,Debug,PartialEq,Eq)]enum PositionUsedAs{Placeholder(Option),Precision,//; +Width,}use PositionUsedAs::*;use crate::errors;#[derive(Debug)]struct//let _=(); +MacroInput{fmtstr:P,args:FormatArguments,is_direct_literal:bool,}fn//({}); +parse_args<'a>(ecx:&ExtCtxt<'a>, sp:Span,tts:TokenStream)->PResult<'a,MacroInput +>{;let mut args=FormatArguments::new();let mut p=ecx.new_parser_from_tts(tts);if +p.token==token::Eof{if true{};if true{};return Err(ecx.dcx().create_err(errors:: +FormatRequiresString{span:sp}));3;};let first_token=&p.token;;;let fmtstr=if let +token::Literal(lit)=first_token.kind&&matches!(lit.kind,token::Str|token:://{;}; +StrRaw(_)){p.parse_literal_maybe_minus()?}else{p.parse_expr()?};*&*&();{();};let +is_direct_literal=matches!(fmtstr.kind,ExprKind::Lit(_));3;;let mut first=true;; +while p.token!=token::Eof{if!p.eat(&token::Comma){if first{let _=();if true{};p. +clear_expected_tokens();;}match p.expect(&token::Comma){Err(err)=>{match token:: +TokenKind::Comma.similar_tokens(){Some(tks)if tks.contains(&p.token.kind)=>{;err +.emit();;p.bump();}_=>return Err(err),}}Ok(Recovered::Yes)=>(),Ok(Recovered::No) +=>unreachable!(),}}3;first=false;;if p.token==token::Eof{;break;;}match p.token. +ident(){Some((ident,_))if p.look_ahead(1,|t|*t==token::Eq)=>{;p.bump();p.expect( +&token::Eq)?;;let expr=p.parse_expr()?;if let Some((_,prev))=args.by_name(ident. +name){3;ecx.dcx().emit_err(errors::FormatDuplicateArg{span:ident.span,prev:prev. +kind.ident().unwrap().span,duplicate:ident.span,ident,});;;continue;;};args.add( +FormatArgument{kind:FormatArgumentKind::Named(ident),expr});3;}_=>{3;let expr=p. +parse_expr()?;;if!args.named_args().is_empty(){;return Err(ecx.dcx().create_err( +errors::PositionalAfterNamed{span:expr.span,args:(((args.named_args()).iter())). +filter_map(|a|a.kind.ident().map(|ident|(a,ident ))).map(|(arg,n)|n.span.to(arg. +expr.span)).collect(),}));3;}3;args.add(FormatArgument{kind:FormatArgumentKind:: +Normal,expr});*&*&();((),());}}}Ok(MacroInput{fmtstr,args,is_direct_literal})}fn +make_format_args(ecx:&mut ExtCtxt<'_>,input:MacroInput,append_newline:bool,)->// +ExpandResult,()>{if true{};if true{};let msg= +"format argument must be a string literal";;let unexpanded_fmt_span=input.fmtstr +.span;;let MacroInput{fmtstr:efmt,mut args,is_direct_literal}=input;let(fmt_str, +fmt_style,fmt_span)={();let ExpandResult::Ready(mac)=expr_to_spanned_string(ecx, +efmt.clone(),msg)else{;return ExpandResult::Retry(());;};match mac{Ok(mut fmt)if +append_newline=>{;fmt.0=Symbol::intern(&format!("{}\n",fmt.0));fmt}Ok(fmt)=>fmt, +Err(err)=>{({});let guar=match err{Ok((mut err,suggested))=>{if!suggested{if let +ExprKind::Block(block,None)=(&efmt.kind)&&(block.stmts.len()==1)&&let StmtKind:: +Expr(expr)=&block.stmts[0].kind &&let ExprKind::Path(None,path)=&expr.kind&&path +.is_potential_trivial_const_arg(){if true{};let _=||();err.multipart_suggestion( +"quote your inlined format argument to use as string literal",vec![(//if true{}; +unexpanded_fmt_span.shrink_to_hi(),"\"".to_string()),(unexpanded_fmt_span.//{;}; +shrink_to_lo(),"\"".to_string()),],Applicability::MaybeIncorrect,);3;}else{3;let +sugg_fmt=match ((args.explicit_args()).len()){0=>("{}".to_string()),_=>{format!( +"{}{{}}","{} ".repeat(args.explicit_args().len()))}};{;};();err.span_suggestion( +unexpanded_fmt_span.shrink_to_lo(),//if true{};let _=||();let _=||();let _=||(); +"you might be missing a string literal to format with",format!(//*&*&();((),()); +"\"{sugg_fmt}\", "),Applicability::MaybeIncorrect,);{;};}}err.emit()}Err(guar)=> +guar,};;return ExpandResult::Ready(Err(guar));}}};let str_style=match fmt_style{ +rustc_ast::StrStyle::Cooked=>None,rustc_ast::StrStyle::Raw(raw)=>Some(raw as//3; +usize),};();3;let fmt_str=fmt_str.as_str();3;3;let fmt_snippet=ecx.source_map(). +span_to_snippet(unexpanded_fmt_span).ok();3;3;let mut parser=parse::Parser::new( +fmt_str,str_style,fmt_snippet,append_newline,parse::ParseMode::Format,);;let mut +pieces=Vec::new();let _=();while let Some(piece)=parser.next(){if!parser.errors. +is_empty(){3;break;3;}else{;pieces.push(piece);;}};let is_source_literal=parser. +is_source_literal;;if!parser.errors.is_empty(){;let err=parser.errors.remove(0); +let sp=if is_source_literal{fmt_span.from_inner(InnerSpan::new(err.span.start,// +err.span.end))}else{fmt_span};3;3;let mut e=errors::InvalidFormatString{span:sp, +note_:None,label_:None,sugg_:None,desc:err.description,label1:err.label,};{;};if +let Some(note)=err.note{;e.note_=Some(errors::InvalidFormatStringNote{note});}if +let Some((label,span))=err.secondary_label&&is_source_literal{{;};e.label_=Some( +errors::InvalidFormatStringLabel{span:fmt_span.from_inner(InnerSpan::new(span.// +start,span.end)),label,});({});}match err.suggestion{parse::Suggestion::None=>{} +parse::Suggestion::UsePositional=>{();let captured_arg_span=fmt_span.from_inner( +InnerSpan::new(err.span.start,err.span.end));();if let Ok(arg)=ecx.source_map(). +span_to_snippet(captured_arg_span){();let span=match args.unnamed_args().last(){ +Some(arg)=>arg.expr.span,None=>fmt_span,};let _=();((),());e.sugg_=Some(errors:: +InvalidFormatStringSuggestion::UsePositional{captured:captured_arg_span,len://3; +args.unnamed_args().len().to_string(),span:span.shrink_to_hi(),arg,});;}}parse:: +Suggestion::RemoveRawIdent(span)=>{if is_source_literal{{();};let span=fmt_span. +from_inner(InnerSpan::new(span.start,span.end));let _=||();e.sugg_=Some(errors:: +InvalidFormatStringSuggestion::RemoveRawIdent{span})}}}{();};let guar=ecx.dcx(). +emit_err(e);3;;return ExpandResult::Ready(Err(guar));;};let to_span=|inner_span: +rustc_parse_format::InnerSpan|{is_source_literal.then(||{fmt_span.from_inner(//; +InnerSpan{start:inner_span.start,end:inner_span.end})})};();3;let mut used=vec![ +false;args.explicit_args().len()];3;3;let mut invalid_refs=Vec::new();3;;let mut +numeric_refences_to_named_arg=Vec::new();;;enum ArgRef<'a>{Index(usize),Name(&'a +str,Option),};;use ArgRef::*;let mut unnamed_arg_after_named_arg=false;let +mut lookup_arg=|arg:ArgRef<'_>,span:Option,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(){;numeric_refences_to_named_arg.push((index,span,used_as));;}Ok(index)} +else{;invalid_refs.push((index,span,used_as,kind));Err(index)}}Name(name,span)=> +{3;let name=Symbol::intern(name);3;if let Some((index,_))=args.by_name(name){if +index{();unfinished_literal.push_str(s);();}parse::Piece::NextArgument(box parse:: +Argument{position,position_span,format})=>{if!unfinished_literal.is_empty(){{;}; +template.push(FormatArgsPiece::Literal(Symbol::intern(&unfinished_literal)));3;; +unfinished_literal.clear();;};let span=parser.arg_places.get(placeholder_index). +and_then(|&s|to_span(s));3;3;placeholder_index+=1;3;3;let position_span=to_span( +position_span);();3;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 alignment=match format.align{parse::AlignUnknown=>None,parse:: +AlignLeft=>(Some(FormatAlignment::Left)),parse::AlignRight=>Some(FormatAlignment +::Right),parse::AlignCenter=>Some(FormatAlignment::Center),};;;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,_=>{3;invalid_placeholder_type_error(ecx,format.ty,format. +ty_span,fmt_span);({});FormatTrait::Display}};{;};{;};let precision_span=format. +precision_span.and_then(to_span);3;;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,};3;3;template. +push(FormatArgsPiece::Placeholder( FormatPlaceholder{argument,span,format_trait, +format_options:FormatOptions{fill:format.fill,alignment ,sign:format.sign.map(|s +|match s{parse::Sign::Plus=>FormatSign::Plus,parse::Sign::Minus=>FormatSign:://; +Minus,}),alternate:format.alternate,zero_pad:format.zero_pad,debug_hex:format.// +debug_hex.map(|s|match s{parse::DebugHex::Lower=>FormatDebugHex::Lower,parse::// +DebugHex::Upper=>FormatDebugHex::Upper,}),precision,width,},}));if true{};}}}if! +unfinished_literal.is_empty(){();template.push(FormatArgsPiece::Literal(Symbol:: +intern(&unfinished_literal)));let _=||();}if!invalid_refs.is_empty(){let _=||(); +report_invalid_references(ecx,&invalid_refs,&template,fmt_span,&args,parser);;}; +let unused=used.iter().enumerate().filter(|&(_,used)|!used).map(|(i,_)|{({});let +named=matches!(args.explicit_args()[i].kind,FormatArgumentKind::Named(_));;(args +.explicit_args()[i].expr.span,named)}).collect::>();();3;let has_unused=! +unused.is_empty();{;};if has_unused{();let detect_foreign_fmt=unused.len()>args. +explicit_args().len()/2;3;3;report_missing_placeholders(ecx,unused,&used,&args,& +pieces,detect_foreign_fmt,str_style,fmt_str,fmt_span,);((),());}if invalid_refs. +is_empty()&&(!has_unused)&&!unnamed_arg_after_named_arg{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=>{;let span=span.map( +|span|span.with_lo(span.lo()+BytePos(1)));;(span,span)}Width=>(span,span),};;let +arg_name=args.explicit_args()[index].kind.ident().unwrap();let _=();((),());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:BuiltinLintDiag::NamedArgumentUsedPositionally{//if true{};if true{}; +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),},});((),());}}ExpandResult::Ready(Ok(FormatArgs{span:fmt_span, +template,arguments:args}))}fn invalid_placeholder_type_error(ecx:&ExtCtxt<'_>,// +ty:&str,ty_span:Option,fmt_span:Span,){();let sp= +ty_span.map(|sp|fmt_span.from_inner(InnerSpan::new(sp.start,sp.end)));;let suggs +=if let Some(sp)=sp{[(((""),("Display"))),(("?","Debug")),("e","LowerExp"),("E", +"UpperExp"),("o","Octal"),("p","Pointer"), ("b","Binary"),("x","LowerHex"),("X", +"UpperHex"),].into_iter().map (|(fmt,trait_name)|errors::FormatUnknownTraitSugg{ +span:sp,fmt,trait_name}).collect()}else{vec![]};();3;ecx.dcx().emit_err(errors:: +FormatUnknownTrait{span:sp.unwrap_or(fmt_span),ty,suggs});let _=();if true{};}fn +report_missing_placeholders(ecx:&ExtCtxt<'_>,unused:Vec<(Span,bool)>,used:&[//3; +bool],args:&FormatArguments,pieces:&[ parse::Piece<'_>],detect_foreign_fmt:bool, +str_style:Option,fmt_str:&str,fmt_span:Span,){;let mut diag=if let&[(span +,named)]=&unused[..]{ecx. dcx().create_err(errors::FormatUnusedArg{span,named})} +else{;let unused_labels=unused.iter().map(|&(span,named)|errors::FormatUnusedArg +{span,named}).collect();3;3;let unused_spans=unused.iter().map(|&(span,_)|span). +collect();{;};ecx.dcx().create_err(errors::FormatUnusedArgs{fmt:fmt_span,unused: +unused_spans,unused_labels,})};;let placeholders=pieces.iter().filter_map(|piece +|{if let parse::Piece::NextArgument (argument)=piece&&let ArgumentNamed(binding) +=argument.position{((),());let span=fmt_span.from_inner(InnerSpan::new(argument. +position_span.start,argument.position_span.end,));{;};Some((span,binding))}else{ +None}}).collect::>();();if!placeholders.is_empty(){if let Some(new_diag)= +report_redundant_format_arguments(ecx,args,used,placeholders){3;diag.cancel();;; +new_diag.emit();;;return;}}let mut found_foreign=false;if detect_foreign_fmt{use +super::format_foreign as foreign;3;3;let mut explained=FxHashSet::default();3;3; +macro_rules!check_foreign{($kind:ident)=>{{let mut show_doc_note=false;let mut// +suggestions=vec![];let padding=str_style.map(|i|i+2).unwrap_or(1);for sub in//3; +foreign::$kind::iter_subs(fmt_str,padding){ let(trn,success)=match sub.translate +(){Ok(trn)=>(trn,true),Err(Some(msg))=>(msg,false),_=>continue,};let pos=sub.//; +position();let sub=String::from(sub.as_str());if explained.contains(&sub){//{;}; +continue;}explained.insert(sub);if!found_foreign{found_foreign=true;//if true{}; +show_doc_note=true;}let sp=fmt_span. from_inner(pos);if success{suggestions.push +((sp,trn));}else{diag.span_note(sp,format!(//((),());let _=();let _=();let _=(); +"format specifiers use curly braces, and {}",trn),);}}if show_doc_note{diag.//3; +note(concat!(stringify!($kind),//let _=||();loop{break};loop{break};loop{break}; +" formatting is not supported; see the documentation for `std::fmt`",));}if//(); +suggestions.len()>0{diag.multipart_suggestion(//((),());((),());((),());((),()); +"format specifiers use curly braces",suggestions,Applicability:://if let _=(){}; +MachineApplicable,);}}};};check_foreign!(printf);if!found_foreign{check_foreign! +(shell);{();};}}if!found_foreign&&unused.len()==1{({});diag.span_label(fmt_span, +"formatting specifier missing");let _=||();}let _=||();diag.emit();if true{};}fn +report_redundant_format_arguments<'a>(ecx:&ExtCtxt<'a>,args:&FormatArguments,//; +used:&[bool],placeholders:Vec<(Span,&str)>,)->Option>{if true{};let mut +fmt_arg_indices=vec![];;let mut args_spans=vec![];let mut fmt_spans=vec![];for(i +,unnamed_arg)in args.unnamed_args().iter().enumerate().rev(){{();};let Some(ty)= +unnamed_arg.expr.to_ty()else{continue};();();let Some(argument_binding)=ty.kind. +is_simple_path()else{continue};;;let argument_binding=argument_binding.as_str(); +if used[i]{;continue;;}let matching_placeholders=placeholders.iter().filter(|(_, +inline_binding)|(argument_binding==*inline_binding)).map(|(span,_)|span).collect +::>();3;if!matching_placeholders.is_empty(){3;fmt_arg_indices.push(i);3;; +args_spans.push(unnamed_arg.expr.span);{;};for span in&matching_placeholders{if +fmt_spans.contains(*span){;continue;;};fmt_spans.push(**span);;}}}if!args_spans. +is_empty(){;let multispan=MultiSpan::from(fmt_spans);;;let mut suggestion_spans= +vec![];;for(arg_span,fmt_arg_idx)in args_spans.iter().zip(fmt_arg_indices.iter() +){;let span=if fmt_arg_idx+1==args.explicit_args().len(){*arg_span}else{arg_span +.until(args.explicit_args()[*fmt_arg_idx+1].expr.span)};;;suggestion_spans.push( +span);let _=||();}if true{};let sugg=if args.named_args().len()==0{Some(errors:: +FormatRedundantArgsSugg{spans:suggestion_spans})}else{None};;return Some(ecx.dcx +().create_err(errors::FormatRedundantArgs{n: (args_spans.len()),span:MultiSpan:: +from(args_spans),note:multispan,sugg,}));;}None}fn report_invalid_references(ecx +:&ExtCtxt<'_>,invalid_refs:&[(usize,Option,PositionUsedAs,//if let _=(){}; +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 {n} arguments"),};3;;let +mut 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,}){;let mut spans=Vec::new();;let mut num_placeholders=0;for piece +in template{{;};let mut placeholder=None;();if let FormatArgsPiece::Placeholder( +FormatPlaceholder{format_options:FormatOptions{precision:Some(FormatCount:://(); +Argument(FormatArgPosition{span,kind:FormatArgPositionKind:: Implicit,..})),..}, +..})=piece{3;placeholder=*span;3;;num_placeholders+=1;;}if let FormatArgsPiece:: +Placeholder(FormatPlaceholder{argument:FormatArgPosition{kind://((),());((),()); +FormatArgPositionKind::Implicit,..},span,..})=piece{{;};placeholder=*span;();(); +num_placeholders+=1;;};spans.extend(placeholder);;}let span=if spans.is_empty(){ +MultiSpan::from_span(fmt_span)}else{MultiSpan::from_spans(spans)};;;e=ecx.dcx(). +create_err(errors::FormatPositionalMismatch{span,n:num_placeholders,desc://({}); +num_args_desc,highlight:SingleLabelManySpans{spans: args.explicit_args().iter(). +map(|arg|arg.expr.span).collect(),label:"",},});();3;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;*&*&();((),());if let _=(){};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 {num_placeholders} arguments")},),);{;};}}if has_precision_star{{;};e.note( +"positional arguments are zero-based");{();};}}else{({});let mut indexes:Vec<_>= +invalid_refs.iter().map(|&(index,_,_,_)|index).collect();;indexes.sort();indexes +.dedup();();3;let span:MultiSpan=if!parser.is_source_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{3;let tail=indexes.pop +().unwrap();;format!("arguments {head} and {tail}",head=indexes.into_iter().map( +|i|i.to_string()).collect::>().join(", "))};;e=ecx.dcx().struct_span_err( +span,format!("invalid reference to positional {arg_list} ({num_args_desc})"),);; +e.note("positional arguments are zero-based");();}if template.iter().any(|piece| +match piece{FormatArgsPiece::Placeholder( FormatPlaceholder{format_options:f,..} +)=>{*f!=FormatOptions::default()}_=>false,}){if let _=(){};if let _=(){};e.note( +"for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html" +);;};e.emit();;}fn expand_format_args_impl<'cx>(ecx:&'cx mut ExtCtxt<'_>,mut sp: +Span,tts:TokenStream,nl:bool,)->MacroExpanderResult<'cx>{((),());((),());sp=ecx. +with_def_site_ctxt(sp);({});ExpandResult::Ready(match parse_args(ecx,sp,tts){Ok( +input)=>{;let ExpandResult::Ready(mac)=make_format_args(ecx,input,nl)else{return +ExpandResult::Retry(());;};;match mac{Ok(format_args)=>{MacEager::expr(ecx.expr( +sp,ExprKind::FormatArgs(P(format_args))) )}Err(guar)=>MacEager::expr(DummyResult +::raw_expr(sp,Some(guar))),}}Err(err)=>{;let guar=err.emit();DummyResult::any(sp +,guar)}})}pub fn expand_format_args<'cx>(ecx:&'cx mut ExtCtxt<'_>,sp:Span,tts:// +TokenStream,)->MacroExpanderResult<'cx>{expand_format_args_impl(ecx,sp,tts,//(); +false)}pub fn expand_format_args_nl<'cx>(ecx:&'cx mut ExtCtxt<'_>,sp:Span,tts:// +TokenStream,)->MacroExpanderResult<'cx>{ expand_format_args_impl(ecx,sp,tts,true +)}//let _=();if true{};let _=();if true{};let _=();if true{};let _=();if true{}; diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs index 307e582d65ef6..4a93f409ee2e4 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign.rs @@ -1,816 +1,158 @@ -pub(crate) mod printf { - use super::strcursor::StrCursor as Cur; - use rustc_span::InnerSpan; - - /// Represents a single `printf`-style substitution. - #[derive(Clone, PartialEq, Debug)] - pub enum Substitution<'a> { - /// A formatted output substitution with its internal byte offset. - Format(Format<'a>), - /// A literal `%%` escape, with its start and end indices. - Escape((usize, usize)), - } - - impl<'a> Substitution<'a> { - pub fn as_str(&self) -> &str { - match self { - Substitution::Format(fmt) => fmt.span, - Substitution::Escape(_) => "%%", - } - } - - pub fn position(&self) -> InnerSpan { - match self { - Substitution::Format(fmt) => fmt.position, - &Substitution::Escape((start, end)) => InnerSpan::new(start, end), - } - } - - pub fn set_position(&mut self, start: usize, end: usize) { - match self { - Substitution::Format(fmt) => fmt.position = InnerSpan::new(start, end), - Substitution::Escape(pos) => *pos = (start, end), - } - } - - /// Translate this substitution into an equivalent Rust formatting directive. - /// - /// This ignores cases where the substitution does not have an exact equivalent, or where - /// the substitution would be unnecessary. - pub fn translate(&self) -> Result> { - match self { - Substitution::Format(fmt) => fmt.translate(), - Substitution::Escape(_) => Err(None), - } - } - } - - #[derive(Clone, PartialEq, Debug)] - /// A single `printf`-style formatting directive. - pub struct Format<'a> { - /// The entire original formatting directive. - pub span: &'a str, - /// The (1-based) parameter to be converted. - pub parameter: Option, - /// Formatting flags. - pub flags: &'a str, - /// Minimum width of the output. - pub width: Option, - /// Precision of the conversion. - pub precision: Option, - /// Length modifier for the conversion. - pub length: Option<&'a str>, - /// Type of parameter being converted. - pub type_: &'a str, - /// Byte offset for the start and end of this formatting directive. - pub position: InnerSpan, - } - - impl Format<'_> { - /// Translate this directive into an equivalent Rust formatting directive. - /// - /// Returns `Err` in cases where the `printf` directive does not have an exact Rust - /// equivalent, rather than guessing. - pub fn translate(&self) -> Result> { - use std::fmt::Write; - - let (c_alt, c_zero, c_left, c_plus) = { - let mut c_alt = false; - let mut c_zero = false; - let mut c_left = false; - let mut c_plus = false; - for c in self.flags.chars() { - match c { - '#' => c_alt = true, - '0' => c_zero = true, - '-' => c_left = true, - '+' => c_plus = true, - _ => { - return Err(Some(format!("the flag `{c}` is unknown or unsupported"))); - } - } - } - (c_alt, c_zero, c_left, c_plus) - }; - - // Has a special form in Rust for numbers. - let fill = c_zero.then_some("0"); - - let align = c_left.then_some("<"); - - // Rust doesn't have an equivalent to the `' '` flag. - let sign = c_plus.then_some("+"); - - // Not *quite* the same, depending on the type... - let alt = c_alt; - - let width = match self.width { - Some(Num::Next) => { - // NOTE: Rust doesn't support this. - return Err(Some( - "you have to use a positional or named parameter for the width".to_string(), - )); - } - w @ Some(Num::Arg(_)) => w, - w @ Some(Num::Num(_)) => w, - None => None, - }; - - let precision = self.precision; - - // NOTE: although length *can* have an effect, we can't duplicate the effect in Rust, so - // we just ignore it. - - let (type_, use_zero_fill, is_int) = match self.type_ { - "d" | "i" | "u" => (None, true, true), - "f" | "F" => (None, false, false), - "s" | "c" => (None, false, false), - "e" | "E" => (Some(self.type_), true, false), - "x" | "X" | "o" => (Some(self.type_), true, true), - "p" => (Some(self.type_), false, true), - "g" => (Some("e"), true, false), - "G" => (Some("E"), true, false), - _ => { - return Err(Some(format!( - "the conversion specifier `{}` is unknown or unsupported", - self.type_ - ))); - } - }; - - let (fill, width, precision) = match (is_int, width, precision) { - (true, Some(_), Some(_)) => { - // Rust can't duplicate this insanity. - return Err(Some( - "width and precision cannot both be specified for integer conversions" - .to_string(), - )); - } - (true, None, Some(p)) => (Some("0"), Some(p), None), - (true, w, None) => (fill, w, None), - (false, w, p) => (fill, w, p), - }; - - let align = match (self.type_, width.is_some(), align.is_some()) { - ("s", true, false) => Some(">"), - _ => align, - }; - - let (fill, zero_fill) = match (fill, use_zero_fill) { - (Some("0"), true) => (None, true), - (fill, _) => (fill, false), - }; - - let alt = match type_ { - Some("x" | "X") => alt, - _ => false, - }; - - let has_options = fill.is_some() - || align.is_some() - || sign.is_some() - || alt - || zero_fill - || width.is_some() - || precision.is_some() - || type_.is_some(); - - // Initialise with a rough guess. - let cap = self.span.len() + if has_options { 2 } else { 0 }; - let mut s = String::with_capacity(cap); - - s.push('{'); - - if let Some(arg) = self.parameter { - match write!( - s, - "{}", - match arg.checked_sub(1) { - Some(a) => a, - None => return Err(None), - } - ) { - Err(_) => return Err(None), - _ => {} - } - } - - if has_options { - s.push(':'); - - let align = if let Some(fill) = fill { - s.push_str(fill); - align.or(Some(">")) - } else { - align - }; - - if let Some(align) = align { - s.push_str(align); - } - - if let Some(sign) = sign { - s.push_str(sign); - } - - if alt { - s.push('#'); - } - - if zero_fill { - s.push('0'); - } - - if let Some(width) = width { - match width.translate(&mut s) { - Err(_) => return Err(None), - _ => {} - } - } - - if let Some(precision) = precision { - s.push('.'); - match precision.translate(&mut s) { - Err(_) => return Err(None), - _ => {} - } - } - - if let Some(type_) = type_ { - s.push_str(type_); - } - } - - s.push('}'); - Ok(s) - } - } - - /// A general number used in a `printf` formatting directive. - #[derive(Copy, Clone, PartialEq, Debug)] - pub enum Num { - // The range of these values is technically bounded by `NL_ARGMAX`... but, at least for GNU - // libc, it apparently has no real fixed limit. A `u16` is used here on the basis that it - // is *vanishingly* unlikely that *anyone* is going to try formatting something wider, or - // with more precision, than 32 thousand positions which is so wide it couldn't possibly fit - // on a screen. - /// A specific, fixed value. - Num(u16), - /// The value is derived from a positional argument. - Arg(u16), - /// The value is derived from the "next" unconverted argument. - Next, - } - - impl Num { - fn from_str(s: &str, arg: Option<&str>) -> Self { - if let Some(arg) = arg { - Num::Arg(arg.parse().unwrap_or_else(|_| panic!("invalid format arg `{arg:?}`"))) - } else if s == "*" { - Num::Next - } else { - Num::Num(s.parse().unwrap_or_else(|_| panic!("invalid format num `{s:?}`"))) - } - } - - fn translate(&self, s: &mut String) -> std::fmt::Result { - use std::fmt::Write; - match *self { - Num::Num(n) => write!(s, "{n}"), - Num::Arg(n) => { - let n = n.checked_sub(1).ok_or(std::fmt::Error)?; - write!(s, "{n}$") - } - Num::Next => write!(s, "*"), - } - } - } - - /// Returns an iterator over all substitutions in a given string. - pub fn iter_subs(s: &str, start_pos: usize) -> Substitutions<'_> { - Substitutions { s, pos: start_pos } - } - - /// Iterator over substitutions in a string. - pub struct Substitutions<'a> { - s: &'a str, - pos: usize, - } - - impl<'a> Iterator for Substitutions<'a> { - type Item = Substitution<'a>; - fn next(&mut self) -> Option { - let (mut sub, tail) = parse_next_substitution(self.s)?; - self.s = tail; - let InnerSpan { start, end } = sub.position(); - sub.set_position(start + self.pos, end + self.pos); - self.pos += end; - Some(sub) - } - - fn size_hint(&self) -> (usize, Option) { - // Substitutions are at least 2 characters long. - (0, Some(self.s.len() / 2)) - } - } - - enum State { - Start, - Flags, - Width, - WidthArg, - Prec, - PrecInner, - Length, - Type, - } - - /// Parse the next substitution from the input string. - pub fn parse_next_substitution(s: &str) -> Option<(Substitution<'_>, &str)> { - use self::State::*; - - let at = { - let start = s.find('%')?; - if let '%' = s[start + 1..].chars().next()? { - return Some((Substitution::Escape((start, start + 2)), &s[start + 2..])); - } - - Cur::new_at(s, start) - }; - - // This is meant to be a translation of the following regex: - // - // ```regex - // (?x) - // ^ % - // (?: (?P \d+) \$ )? - // (?P [-+ 0\#']* ) - // (?P \d+ | \* (?: (?P \d+) \$ )? )? - // (?: \. (?P \d+ | \* (?: (?P \d+) \$ )? ) )? - // (?P - // # Standard - // hh | h | ll | l | L | z | j | t - // - // # Other - // | I32 | I64 | I | q - // )? - // (?P . ) - // ``` - - // Used to establish the full span at the end. - let start = at; - // The current position within the string. - let mut at = at.at_next_cp()?; - // `c` is the next codepoint, `next` is a cursor after it. - let (mut c, mut next) = at.next_cp()?; - - // Update `at`, `c`, and `next`, exiting if we're out of input. - macro_rules! move_to { - ($cur:expr) => {{ - at = $cur; - let (c_, next_) = at.next_cp()?; - c = c_; - next = next_; - }}; - } - - // Constructs a result when parsing fails. - // - // Note: `move` used to capture copies of the cursors as they are *now*. - let fallback = move || { - Some(( - Substitution::Format(Format { - span: start.slice_between(next).unwrap(), - parameter: None, - flags: "", - width: None, - precision: None, - length: None, - type_: at.slice_between(next).unwrap(), - position: InnerSpan::new(start.at, next.at), - }), - next.slice_after(), - )) - }; - - // Next parsing state. - let mut state = Start; - - // Sadly, Rust isn't *quite* smart enough to know these *must* be initialised by the end. - let mut parameter: Option = None; - let mut flags: &str = ""; - let mut width: Option = None; - let mut precision: Option = None; - let mut length: Option<&str> = None; - let mut type_: &str = ""; - let end: Cur<'_>; - - if let Start = state { - match c { - '1'..='9' => { - let end = at_next_cp_while(next, char::is_ascii_digit); - match end.next_cp() { - // Yes, this *is* the parameter. - Some(('$', end2)) => { - state = Flags; - parameter = Some(at.slice_between(end).unwrap().parse().unwrap()); - move_to!(end2); - } - // Wait, no, actually, it's the width. - Some(_) => { - state = Prec; - parameter = None; - flags = ""; - width = Some(Num::from_str(at.slice_between(end).unwrap(), None)); - move_to!(end); - } - // It's invalid, is what it is. - None => return fallback(), - } - } - _ => { - state = Flags; - parameter = None; - move_to!(at); - } - } - } - - if let Flags = state { - let end = at_next_cp_while(at, is_flag); - state = Width; - flags = at.slice_between(end).unwrap(); - move_to!(end); - } - - if let Width = state { - match c { - '*' => { - state = WidthArg; - move_to!(next); - } - '1'..='9' => { - let end = at_next_cp_while(next, char::is_ascii_digit); - state = Prec; - width = Some(Num::from_str(at.slice_between(end).unwrap(), None)); - move_to!(end); - } - _ => { - state = Prec; - width = None; - move_to!(at); - } - } - } - - if let WidthArg = state { - let end = at_next_cp_while(at, char::is_ascii_digit); - match end.next_cp() { - Some(('$', end2)) => { - state = Prec; - width = Some(Num::from_str("", Some(at.slice_between(end).unwrap()))); - move_to!(end2); - } - _ => { - state = Prec; - width = Some(Num::Next); - move_to!(end); - } - } - } - - if let Prec = state { - match c { - '.' => { - state = PrecInner; - move_to!(next); - } - _ => { - state = Length; - precision = None; - move_to!(at); - } - } - } - - if let PrecInner = state { - match c { - '*' => { - let end = at_next_cp_while(next, char::is_ascii_digit); - match end.next_cp() { - Some(('$', end2)) => { - state = Length; - precision = Some(Num::from_str("*", next.slice_between(end))); - move_to!(end2); - } - _ => { - state = Length; - precision = Some(Num::Next); - move_to!(end); - } - } - } - '0'..='9' => { - let end = at_next_cp_while(next, char::is_ascii_digit); - state = Length; - precision = Some(Num::from_str(at.slice_between(end).unwrap(), None)); - move_to!(end); - } - _ => return fallback(), - } - } - - if let Length = state { - let c1_next1 = next.next_cp(); - match (c, c1_next1) { - ('h', Some(('h', next1))) | ('l', Some(('l', next1))) => { - state = Type; - length = Some(at.slice_between(next1).unwrap()); - move_to!(next1); - } - - ('h' | 'l' | 'L' | 'z' | 'j' | 't' | 'q', _) => { - state = Type; - length = Some(at.slice_between(next).unwrap()); - move_to!(next); - } - - ('I', _) => { - let end = next - .at_next_cp() - .and_then(|end| end.at_next_cp()) - .map(|end| (next.slice_between(end).unwrap(), end)); - let end = match end { - Some(("32" | "64", end)) => end, - _ => next, - }; - state = Type; - length = Some(at.slice_between(end).unwrap()); - move_to!(end); - } - - _ => { - state = Type; - length = None; - move_to!(at); - } - } - } - - if let Type = state { - type_ = at.slice_between(next).unwrap(); - - // Don't use `move_to!` here, as we *can* be at the end of the input. - at = next; - } - - let _ = c; // to avoid never used value - - end = at; - let position = InnerSpan::new(start.at, end.at); - - let f = Format { - span: start.slice_between(end).unwrap(), - parameter, - flags, - width, - precision, - length, - type_, - position, - }; - Some((Substitution::Format(f), end.slice_after())) - } - - fn at_next_cp_while(mut cur: Cur<'_>, mut pred: F) -> Cur<'_> - where - F: FnMut(&char) -> bool, - { - loop { - match cur.next_cp() { - Some((c, next)) => { - if pred(&c) { - cur = next; - } else { - return cur; - } - } - None => return cur, - } - } - } - - fn is_flag(c: &char) -> bool { - matches!(c, '0' | '-' | '+' | ' ' | '#' | '\'') - } - - #[cfg(test)] - mod tests; -} - -pub mod shell { - use super::strcursor::StrCursor as Cur; - use rustc_span::InnerSpan; - - #[derive(Clone, PartialEq, Debug)] - pub enum Substitution<'a> { - Ordinal(u8, (usize, usize)), - Name(&'a str, (usize, usize)), - Escape((usize, usize)), - } - - impl Substitution<'_> { - pub fn as_str(&self) -> String { - match self { - Substitution::Ordinal(n, _) => format!("${n}"), - Substitution::Name(n, _) => format!("${n}"), - Substitution::Escape(_) => "$$".into(), - } - } - - pub fn position(&self) -> InnerSpan { - let (Self::Ordinal(_, pos) | Self::Name(_, pos) | Self::Escape(pos)) = self; - InnerSpan::new(pos.0, pos.1) - } - - pub fn set_position(&mut self, start: usize, end: usize) { - let (Self::Ordinal(_, pos) | Self::Name(_, pos) | Self::Escape(pos)) = self; - *pos = (start, end); - } - - pub fn translate(&self) -> Result> { - match self { - Substitution::Ordinal(n, _) => Ok(format!("{{{}}}", n)), - Substitution::Name(n, _) => Ok(format!("{{{}}}", n)), - Substitution::Escape(_) => Err(None), - } - } - } - - /// Returns an iterator over all substitutions in a given string. - pub fn iter_subs(s: &str, start_pos: usize) -> Substitutions<'_> { - Substitutions { s, pos: start_pos } - } - - /// Iterator over substitutions in a string. - pub struct Substitutions<'a> { - s: &'a str, - pos: usize, - } - - impl<'a> Iterator for Substitutions<'a> { - type Item = Substitution<'a>; - fn next(&mut self) -> Option { - let (mut sub, tail) = parse_next_substitution(self.s)?; - self.s = tail; - let InnerSpan { start, end } = sub.position(); - sub.set_position(start + self.pos, end + self.pos); - self.pos += end; - Some(sub) - } - - fn size_hint(&self) -> (usize, Option) { - (0, Some(self.s.len())) - } - } - - /// Parse the next substitution from the input string. - pub fn parse_next_substitution(s: &str) -> Option<(Substitution<'_>, &str)> { - let at = { - let start = s.find('$')?; - match s[start + 1..].chars().next()? { - '$' => return Some((Substitution::Escape((start, start + 2)), &s[start + 2..])), - c @ '0'..='9' => { - let n = (c as u8) - b'0'; - return Some((Substitution::Ordinal(n, (start, start + 2)), &s[start + 2..])); - } - _ => { /* fall-through */ } - } - - Cur::new_at(s, start) - }; - - let at = at.at_next_cp()?; - let (c, inner) = at.next_cp()?; - - if !is_ident_head(c) { - None - } else { - let end = at_next_cp_while(inner, is_ident_tail); - let slice = at.slice_between(end).unwrap(); - let start = at.at - 1; - let end_pos = at.at + slice.len(); - Some((Substitution::Name(slice, (start, end_pos)), end.slice_after())) - } - } - - fn at_next_cp_while(mut cur: Cur<'_>, mut pred: F) -> Cur<'_> - where - F: FnMut(char) -> bool, - { - loop { - match cur.next_cp() { - Some((c, next)) => { - if pred(c) { - cur = next; - } else { - return cur; - } - } - None => return cur, - } - } - } - - fn is_ident_head(c: char) -> bool { - c.is_ascii_alphabetic() || c == '_' - } - - fn is_ident_tail(c: char) -> bool { - c.is_ascii_alphanumeric() || c == '_' - } - - #[cfg(test)] - mod tests; -} - -mod strcursor { - pub struct StrCursor<'a> { - s: &'a str, - pub at: usize, - } - - impl<'a> StrCursor<'a> { - pub fn new_at(s: &'a str, at: usize) -> StrCursor<'a> { - StrCursor { s, at } - } - - pub fn at_next_cp(mut self) -> Option> { - match self.try_seek_right_cp() { - true => Some(self), - false => None, - } - } - - pub fn next_cp(mut self) -> Option<(char, StrCursor<'a>)> { - let cp = self.cp_after()?; - self.seek_right(cp.len_utf8()); - Some((cp, self)) - } - - fn slice_before(&self) -> &'a str { - &self.s[0..self.at] - } - - pub fn slice_after(&self) -> &'a str { - &self.s[self.at..] - } - - pub fn slice_between(&self, until: StrCursor<'a>) -> Option<&'a str> { - if !str_eq_literal(self.s, until.s) { - None - } else { - use std::cmp::{max, min}; - let beg = min(self.at, until.at); - let end = max(self.at, until.at); - Some(&self.s[beg..end]) - } - } - - fn cp_after(&self) -> Option { - self.slice_after().chars().next() - } - - fn try_seek_right_cp(&mut self) -> bool { - match self.slice_after().chars().next() { - Some(c) => { - self.at += c.len_utf8(); - true - } - None => false, - } - } - - fn seek_right(&mut self, bytes: usize) { - self.at += bytes; - } - } - - impl Copy for StrCursor<'_> {} - - impl<'a> Clone for StrCursor<'a> { - fn clone(&self) -> StrCursor<'a> { - *self - } - } - - impl std::fmt::Debug for StrCursor<'_> { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(fmt, "StrCursor({:?} | {:?})", self.slice_before(), self.slice_after()) - } - } - - fn str_eq_literal(a: &str, b: &str) -> bool { - a.as_bytes().as_ptr() == b.as_bytes().as_ptr() && a.len() == b.len() - } -} +pub(crate)mod printf{use super::strcursor::StrCursor as Cur;use rustc_span:://3; +InnerSpan;#[derive(Clone,PartialEq,Debug)]pub enum Substitution<'a>{Format(//(); +Format<'a>),Escape((usize,usize)),} impl<'a>Substitution<'a>{pub fn as_str(&self +)->&str{match self{Substitution::Format(fmt)=>fmt.span,Substitution::Escape(_)// +=>"%%",}}pub fn position(& self)->InnerSpan{match self{Substitution::Format(fmt) +=>fmt.position,&Substitution::Escape((start,end) )=>InnerSpan::new(start,end),}} +pub fn set_position(&mut self,start:usize,end:usize){match self{Substitution::// +Format(fmt)=>fmt.position=InnerSpan::new( start,end),Substitution::Escape(pos)=> +*pos=(start,end),}}pub fn translate(&self)->Result>{match +self{Substitution::Format(fmt)=>(fmt.translate ()),Substitution::Escape(_)=>Err( +None),}}}#[derive(Clone,PartialEq,Debug) ]pub struct Format<'a>{pub span:&'a str +,pub parameter:Option,pub flags:&'a str,pub width:Option,pub//((),()); +precision:Option,pub length:Option<&'a str>,pub type_:&'a str,pub position +:InnerSpan,}impl Format<'_>{pub fn translate(&self)->Result>{;use std::fmt::Write;;;let(c_alt,c_zero,c_left,c_plus)={;let mut c_alt= +false;;;let mut c_zero=false;let mut c_left=false;let mut c_plus=false;for c in +self.flags.chars(){match c{'#'=>(c_alt=true ),'0'=>c_zero=true,'-'=>c_left=true, +'+'=>c_plus=true,_=>{((),());let _=();let _=();let _=();return Err(Some(format!( +"the flag `{c}` is unknown or unsupported")));;}}}(c_alt,c_zero,c_left,c_plus)}; +let fill=c_zero.then_some("0");;let align=c_left.then_some("<");let sign=c_plus. +then_some("+");3;;let alt=c_alt;;;let width=match self.width{Some(Num::Next)=>{; +return Err( Some("you have to use a positional or named parameter for the width" +.to_string(),));;}w@Some(Num::Arg(_))=>w,w@Some(Num::Num(_))=>w,None=>None,};let +precision=self.precision;;;let(type_,use_zero_fill,is_int)=match self.type_{"d"| +"i"|"u"=>((None,(true),true)),"f"|"F"=>( None,false,false),"s"|"c"=>(None,false, +false),"e"|"E"=>((Some(self.type_),true, false)),"x"|"X"|"o"=>(Some(self.type_), +true,true),"p"=>(Some(self.type_),false,true ),"g"=>(Some("e"),true,false),"G"=> +(Some("E"),true,false),_=>{if let _=(){};*&*&();((),());return Err(Some(format!( +"the conversion specifier `{}` is unknown or unsupported",self.type_)));;}};let( +fill,width,precision)=match(is_int,width,precision){(true,Some(_),Some(_))=>{(); +return Err(Some(//*&*&();((),());((),());((),());*&*&();((),());((),());((),()); +"width and precision cannot both be specified for integer conversions".//*&*&(); +to_string(),));3;}(true,None,Some(p))=>(Some("0"),Some(p),None),(true,w,None)=>( +fill,w,None),(false,w,p)=>(fill,w,p),};;let align=match(self.type_,width.is_some +(),align.is_some()){("s",true,false)=>Some(">"),_=>align,};;let(fill,zero_fill)= +match(fill,use_zero_fill){(Some("0"),true)=>(None, true),(fill,_)=>(fill,false), +};3;3;let alt=match type_{Some("x"|"X")=>alt,_=>false,};3;;let has_options=fill. +is_some()||(align.is_some())||sign.is_some( )||alt||zero_fill||width.is_some()|| +precision.is_some()||type_.is_some();;;let cap=self.span.len()+if has_options{2} +else{0};;let mut s=String::with_capacity(cap);s.push('{');if let Some(arg)=self. +parameter{match write!(s,"{}",match arg.checked_sub(1){Some(a)=>a,None=>return// +Err(None),}){Err(_)=>return Err(None),_=>{}}}if has_options{3;s.push(':');3;;let +align=if let Some(fill)=fill{;s.push_str(fill);;align.or(Some(">"))}else{align}; +if let Some(align)=align{;s.push_str(align);;}if let Some(sign)=sign{s.push_str( +sign);;}if alt{;s.push('#');}if zero_fill{s.push('0');}if let Some(width)=width{ +match (width.translate((&mut s))){Err(_)=>(return Err(None)),_=>{}}}if let Some( +precision)=precision{();s.push('.');3;match precision.translate(&mut s){Err(_)=> +return Err(None),_=>{}}}if let Some(type_)=type_{;s.push_str(type_);}}s.push('}' +);();Ok(s)}}#[derive(Copy,Clone,PartialEq,Debug)]pub enum Num{Num(u16),Arg(u16), +Next,}impl Num{fn from_str(s:&str,arg:Option <&str>)->Self{if let Some(arg)=arg{ +Num::Arg(arg.parse().unwrap_or_else( |_|panic!("invalid format arg `{arg:?}`"))) +}else if (s==("*")){Num::Next}else{Num ::Num(s.parse().unwrap_or_else(|_|panic!( +"invalid format num `{s:?}`")))}}fn translate(&self,s:&mut String)->std::fmt::// +Result{;use std::fmt::Write;;match*self{Num::Num(n)=>write!(s,"{n}"),Num::Arg(n) +=>{;let n=n.checked_sub(1).ok_or(std::fmt::Error)?;;write!(s,"{n}$")}Num::Next=> +write!(s,"*"),}}}pub fn iter_subs(s:&str,start_pos:usize)->Substitutions<'_>{//; +Substitutions{s,pos:start_pos}}pub struct Substitutions<'a>{s:&'a str,pos:usize +,}impl<'a>Iterator for Substitutions<'a>{type Item=Substitution<'a>;fn next(&//; +mut self)->Option{;let(mut sub,tail)=parse_next_substitution(self.s) +?;;;self.s=tail;;let InnerSpan{start,end}=sub.position();sub.set_position(start+ +self.pos,end+self.pos);3;3;self.pos+=end;;Some(sub)}fn size_hint(&self)->(usize, +Option){(0,Some(self.s.len() /2))}}enum State{Start,Flags,Width,WidthArg, +Prec,PrecInner,Length,Type,}pub fn parse_next_substitution(s:&str)->Option<(//3; +Substitution<'_>,&str)>{;use self::State::*;;;let at={;let start=s.find('%')?;if +let '%'=s[start+1..].chars().next()?{3;return Some((Substitution::Escape((start, +start+2)),&s[start+2..]));;}Cur::new_at(s,start)};;;let start=at;;let mut at=at. +at_next_cp()?;;let(mut c,mut next)=at.next_cp()?;macro_rules!move_to{($cur:expr) +=>{{at=$cur;let(c_,next_)=at.next_cp()?;c=c_;next=next_;}};};let fallback=move|| +{Some((Substitution::Format(Format{span :((start.slice_between(next)).unwrap()), +parameter:None,flags:(((("")))),width:None, precision:None,length:None,type_:at. +slice_between(next).unwrap(),position:InnerSpan::new( start.at,next.at),}),next. +slice_after(),))};;;let mut state=Start;;;let mut parameter:Option=None;let +mut flags:&str="";;let mut width:Option=None;let mut precision:Option= +None;;;let mut length:Option<&str>=None;let mut type_:&str="";let end:Cur<'_>;if +let Start=state{match c{'1'..='9'=>{((),());let end=at_next_cp_while(next,char:: +is_ascii_digit);;match end.next_cp(){Some(('$',end2))=>{;state=Flags;;parameter= +Some(at.slice_between(end).unwrap().parse().unwrap());;move_to!(end2);}Some(_)=> +{;state=Prec;;parameter=None;flags="";width=Some(Num::from_str(at.slice_between( +end).unwrap(),None));;;move_to!(end);}None=>return fallback(),}}_=>{state=Flags; +parameter=None;;;move_to!(at);}}}if let Flags=state{let end=at_next_cp_while(at, +is_flag);;state=Width;flags=at.slice_between(end).unwrap();move_to!(end);}if let +Width=state{match c{'*'=>{;state=WidthArg;;;move_to!(next);}'1'..='9'=>{let end= +at_next_cp_while(next,char::is_ascii_digit);;state=Prec;width=Some(Num::from_str +(at.slice_between(end).unwrap(),None));;move_to!(end);}_=>{state=Prec;width=None +;3;3;move_to!(at);3;}}}if let WidthArg=state{;let end=at_next_cp_while(at,char:: +is_ascii_digit);;match end.next_cp(){Some(('$',end2))=>{;state=Prec;;width=Some( +Num::from_str("",Some(at.slice_between(end).unwrap())));;;move_to!(end2);;}_=>{; +state=Prec;;width=Some(Num::Next);move_to!(end);}}}if let Prec=state{match c{'.' +=>{;state=PrecInner;move_to!(next);}_=>{state=Length;precision=None;move_to!(at) +;3;}}}if let PrecInner=state{match c{'*'=>{;let end=at_next_cp_while(next,char:: +is_ascii_digit);;match end.next_cp(){Some(('$',end2))=>{;state=Length;precision= +Some(Num::from_str("*",next.slice_between(end)));3;;move_to!(end2);;}_=>{;state= +Length;3;3;precision=Some(Num::Next);3;3;move_to!(end);;}}}'0'..='9'=>{;let end= +at_next_cp_while(next,char::is_ascii_digit);;;state=Length;;precision=Some(Num:: +from_str(at.slice_between(end).unwrap(),None));();();move_to!(end);3;}_=>return +fallback(),}}if let Length=state{;let c1_next1=next.next_cp();match(c,c1_next1){ +('h',Some(('h',next1)))|('l',Some(('l',next1)))=>{3;state=Type;;;length=Some(at. +slice_between(next1).unwrap());;move_to!(next1);}('h'|'l'|'L'|'z'|'j'|'t'|'q',_) +=>{;state=Type;length=Some(at.slice_between(next).unwrap());move_to!(next);}('I' +,_)=>{;let end=next.at_next_cp().and_then(|end|end.at_next_cp()).map(|end|(next. +slice_between(end).unwrap(),end));;let end=match end{Some(("32"|"64",end))=>end, +_=>next,};;state=Type;length=Some(at.slice_between(end).unwrap());move_to!(end); +}_=>{3;state=Type;3;;length=None;;;move_to!(at);;}}}if let Type=state{;type_=at. +slice_between(next).unwrap();;;at=next;;}let _=c;end=at;let position=InnerSpan:: +new(start.at,end.at);{;};();let f=Format{span:start.slice_between(end).unwrap(), +parameter,flags,width,precision,length,type_,position,};{;};Some((Substitution:: +Format(f),end.slice_after()))}fn at_next_cp_while(mut cur:Cur<'_>,mut pred:F +)->Cur<'_>where F:FnMut(&char)->bool,{loop {match cur.next_cp(){Some((c,next))=> +{if pred(&c){;cur=next;}else{return cur;}}None=>return cur,}}}fn is_flag(c:&char +)->bool{((matches!(c,'0'|'-'|'+'|' '|'#' |'\'')))}#[cfg(test)]mod tests;}pub mod +shell{use super::strcursor::StrCursor as Cur;use rustc_span::InnerSpan;#[derive +(Clone,PartialEq,Debug)]pub enum Substitution<'a>{Ordinal(u8,(usize,usize)),//3; +Name(&'a str,(usize,usize)),Escape(( usize,usize)),}impl Substitution<'_>{pub fn +as_str(&self)->String{match self{Substitution:: Ordinal(n,_)=>(format!("${n}")), +Substitution::Name(n,_)=>format!("${n}"), Substitution::Escape(_)=>"$$".into(),} +}pub fn position(&self)->InnerSpan{3;let(Self::Ordinal(_,pos)|Self::Name(_,pos)| +Self::Escape(pos))=self;{;};InnerSpan::new(pos.0,pos.1)}pub fn set_position(&mut +self,start:usize,end:usize){();let(Self::Ordinal(_,pos)|Self::Name(_,pos)|Self:: +Escape(pos))=self;3;3;*pos=(start,end);;}pub fn translate(&self)->Result>{match self{Substitution::Ordinal(n,_ )=>Ok(format!("{{{}}}",n)), +Substitution::Name(n,_)=>(Ok(format!("{{{}}}",n))),Substitution::Escape(_)=>Err( +None),}}}pub fn iter_subs(s:&str,start_pos:usize)->Substitutions<'_>{//let _=(); +Substitutions{s,pos:start_pos}}pub struct Substitutions<'a>{s:&'a str,pos:usize +,}impl<'a>Iterator for Substitutions<'a>{type Item=Substitution<'a>;fn next(&//; +mut self)->Option{;let(mut sub,tail)=parse_next_substitution(self.s) +?;;;self.s=tail;;let InnerSpan{start,end}=sub.position();sub.set_position(start+ +self.pos,end+self.pos);3;3;self.pos+=end;;Some(sub)}fn size_hint(&self)->(usize, +Option){(0,Some(self.s.len ()))}}pub fn parse_next_substitution(s:&str)-> +Option<(Substitution<'_>,&str)>{;let at={;let start=s.find('$')?;match s[start+1 +..].chars().next()?{'$'=>return Some(( Substitution::Escape((start,start+2)),&s[ +start+2..])),c@'0'..='9'=>{3;let n=(c as u8)-b'0';3;;return Some((Substitution:: +Ordinal(n,(start,start+2)),&s[start+2..]));;}_=>{}}Cur::new_at(s,start)};let at= +at.at_next_cp()?;;;let(c,inner)=at.next_cp()?;;if!is_ident_head(c){None}else{let +end=at_next_cp_while(inner,is_ident_tail);();();let slice=at.slice_between(end). +unwrap();;;let start=at.at-1;;let end_pos=at.at+slice.len();Some((Substitution:: +Name(slice,(start,end_pos)),end.slice_after ()))}}fn at_next_cp_while(mut cur +:Cur<'_>,mut pred:F)->Cur<'_>where F:FnMut(char)->bool,{loop{match cur.next_cp( +){Some((c,next))=>{if pred(c){;cur=next;;}else{return cur;}}None=>return cur,}}} +fn is_ident_head(c:char)->bool{c.is_ascii_alphabetic ()||c=='_'}fn is_ident_tail +(c:char)->bool{((c.is_ascii_alphanumeric())||c =='_')}#[cfg(test)]mod tests;}mod +strcursor{pub struct StrCursor<'a>{s:&'a str,pub at:usize,}impl<'a>StrCursor<'a +>{pub fn new_at(s:&'a str,at:usize )->StrCursor<'a>{(((StrCursor{s,at})))}pub fn +at_next_cp(mut self)->Option>{match self.try_seek_right_cp(){true +=>Some(self),false=>None,}}pub fn next_cp(mut self)->Option<(char,StrCursor<'a> +)>{;let cp=self.cp_after()?;;;self.seek_right(cp.len_utf8());;Some((cp,self))}fn +slice_before(&self)->&'a str{&self.s[0 ..self.at]}pub fn slice_after(&self)->&'a +str{(&self.s[self.at..])}pub fn slice_between(&self,until:StrCursor<'a>)->Option +<&'a str>{if!str_eq_literal(self.s,until.s){None}else{;use std::cmp::{max,min};; +let beg=min(self.at,until.at);;;let end=max(self.at,until.at);Some(&self.s[beg.. +end])}}fn cp_after(&self)->Option{((self.slice_after().chars()).next())}fn +try_seek_right_cp(&mut self)->bool{match self .slice_after().chars().next(){Some +(c)=>{3;self.at+=c.len_utf8();;true}None=>false,}}fn seek_right(&mut self,bytes: +usize){({});self.at+=bytes;({});}}impl Copy for StrCursor<'_>{}impl<'a>Clone for +StrCursor<'a>{fn clone(&self)->StrCursor<'a>{((*self))}}impl std::fmt::Debug for +StrCursor<'_>{fn fmt(&self,fmt:&mut std::fmt::Formatter<'_>)->std::fmt::Result{ +write!(fmt,"StrCursor({:?} | {:?})",self.slice_before( ),self.slice_after())}}fn +str_eq_literal(a:&str,b:&str)->bool{(a.as_bytes().as_ptr())==b.as_bytes().as_ptr +()&&((((((((((((((((((((a.len()))))))))))==(((((((((b.len())))))))))))))))))))}} diff --git a/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs b/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs index df773910dbc8f..07c4a109f2b4c 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs @@ -1,145 +1,57 @@ -use super::{iter_subs, parse_next_substitution as pns, Format as F, Num as N, Substitution as S}; - -macro_rules! assert_eq_pnsat { - ($lhs:expr, $rhs:expr) => { - assert_eq!( - pns($lhs).and_then(|(s, _)| s.translate().ok()), - $rhs.map(>::from) - ) - }; -} - -#[test] -fn test_escape() { - assert_eq!(pns("has no escapes"), None); - assert_eq!(pns("has no escapes, either %"), None); - assert_eq!(pns("*so* has a %% escape"), Some((S::Escape((11, 13)), " escape"))); - assert_eq!(pns("%% leading escape"), Some((S::Escape((0, 2)), " leading escape"))); - assert_eq!(pns("trailing escape %%"), Some((S::Escape((16, 18)), ""))); -} - -#[test] -fn test_parse() { - macro_rules! assert_pns_eq_sub { - ($in_:expr, { - $param:expr, $flags:expr, - $width:expr, $prec:expr, $len:expr, $type_:expr, - $pos:expr, - }) => { - assert_eq!( - pns(concat!($in_, "!")), - Some(( - S::Format(F { - span: $in_, - parameter: $param, - flags: $flags, - width: $width, - precision: $prec, - length: $len, - type_: $type_, - position: rustc_span::InnerSpan::new($pos.0, $pos.1), - }), - "!" - )) - ) - }; - } - - assert_pns_eq_sub!("%!", - { None, "", None, None, None, "!", (0, 2), }); - assert_pns_eq_sub!("%c", - { None, "", None, None, None, "c", (0, 2), }); - assert_pns_eq_sub!("%s", - { None, "", None, None, None, "s", (0, 2), }); - assert_pns_eq_sub!("%06d", - { None, "0", Some(N::Num(6)), None, None, "d", (0, 4), }); - assert_pns_eq_sub!("%4.2f", - { None, "", Some(N::Num(4)), Some(N::Num(2)), None, "f", (0, 5), }); - assert_pns_eq_sub!("%#x", - { None, "#", None, None, None, "x", (0, 3), }); - assert_pns_eq_sub!("%-10s", - { None, "-", Some(N::Num(10)), None, None, "s", (0, 5), }); - assert_pns_eq_sub!("%*s", - { None, "", Some(N::Next), None, None, "s", (0, 3), }); - assert_pns_eq_sub!("%-10.*s", - { None, "-", Some(N::Num(10)), Some(N::Next), None, "s", (0, 7), }); - assert_pns_eq_sub!("%-*.*s", - { None, "-", Some(N::Next), Some(N::Next), None, "s", (0, 6), }); - assert_pns_eq_sub!("%.6i", - { None, "", None, Some(N::Num(6)), None, "i", (0, 4), }); - assert_pns_eq_sub!("%+i", - { None, "+", None, None, None, "i", (0, 3), }); - assert_pns_eq_sub!("%08X", - { None, "0", Some(N::Num(8)), None, None, "X", (0, 4), }); - assert_pns_eq_sub!("%lu", - { None, "", None, None, Some("l"), "u", (0, 3), }); - assert_pns_eq_sub!("%Iu", - { None, "", None, None, Some("I"), "u", (0, 3), }); - assert_pns_eq_sub!("%I32u", - { None, "", None, None, Some("I32"), "u", (0, 5), }); - assert_pns_eq_sub!("%I64u", - { None, "", None, None, Some("I64"), "u", (0, 5), }); - assert_pns_eq_sub!("%'d", - { None, "'", None, None, None, "d", (0, 3), }); - assert_pns_eq_sub!("%10s", - { None, "", Some(N::Num(10)), None, None, "s", (0, 4), }); - assert_pns_eq_sub!("%-10.10s", - { None, "-", Some(N::Num(10)), Some(N::Num(10)), None, "s", (0, 8), }); - assert_pns_eq_sub!("%1$d", - { Some(1), "", None, None, None, "d", (0, 4), }); - assert_pns_eq_sub!("%2$.*3$d", - { Some(2), "", None, Some(N::Arg(3)), None, "d", (0, 8), }); - assert_pns_eq_sub!("%1$*2$.*3$d", - { Some(1), "", Some(N::Arg(2)), Some(N::Arg(3)), None, "d", (0, 11), }); - assert_pns_eq_sub!("%-8ld", - { None, "-", Some(N::Num(8)), None, Some("l"), "d", (0, 5), }); -} - -#[test] -fn test_iter() { - let s = "The %d'th word %% is: `%.*s` %!\n"; - let subs: Vec<_> = iter_subs(s, 0).map(|sub| sub.translate().ok()).collect(); - assert_eq!( - subs.iter().map(Option::as_deref).collect::>(), - vec![Some("{}"), None, Some("{:.*}"), None] - ); -} - -/// Checks that the translations are what we expect. -#[test] -fn test_translation() { - assert_eq_pnsat!("%c", Some("{}")); - assert_eq_pnsat!("%d", Some("{}")); - assert_eq_pnsat!("%u", Some("{}")); - assert_eq_pnsat!("%x", Some("{:x}")); - assert_eq_pnsat!("%X", Some("{:X}")); - assert_eq_pnsat!("%e", Some("{:e}")); - assert_eq_pnsat!("%E", Some("{:E}")); - assert_eq_pnsat!("%f", Some("{}")); - assert_eq_pnsat!("%g", Some("{:e}")); - assert_eq_pnsat!("%G", Some("{:E}")); - assert_eq_pnsat!("%s", Some("{}")); - assert_eq_pnsat!("%p", Some("{:p}")); - - assert_eq_pnsat!("%06d", Some("{:06}")); - assert_eq_pnsat!("%4.2f", Some("{:4.2}")); - assert_eq_pnsat!("%#x", Some("{:#x}")); - assert_eq_pnsat!("%-10s", Some("{:<10}")); - assert_eq_pnsat!("%*s", None); - assert_eq_pnsat!("%-10.*s", Some("{:<10.*}")); - assert_eq_pnsat!("%-*.*s", None); - assert_eq_pnsat!("%.6i", Some("{:06}")); - assert_eq_pnsat!("%+i", Some("{:+}")); - assert_eq_pnsat!("%08X", Some("{:08X}")); - assert_eq_pnsat!("%lu", Some("{}")); - assert_eq_pnsat!("%Iu", Some("{}")); - assert_eq_pnsat!("%I32u", Some("{}")); - assert_eq_pnsat!("%I64u", Some("{}")); - assert_eq_pnsat!("%'d", None); - assert_eq_pnsat!("%10s", Some("{:>10}")); - assert_eq_pnsat!("%-10.10s", Some("{:<10.10}")); - assert_eq_pnsat!("%1$d", Some("{0}")); - assert_eq_pnsat!("%2$.*3$d", Some("{1:02$}")); - assert_eq_pnsat!("%1$*2$.*3$s", Some("{0:>1$.2$}")); - assert_eq_pnsat!("%-8ld", Some("{:<8}")); -} +use super::{iter_subs,parse_next_substitution as pns,Format as F,Num as N,//{;}; +Substitution as S};macro_rules!assert_eq_pnsat{($lhs:expr,$rhs:expr)=>{//*&*&(); +assert_eq!(pns($lhs).and_then(|(s,_)|s.translate().ok()),$rhs.map(>::from))};}#[test]fn test_escape(){;assert_eq!(pns("has no escapes"), +None);();();assert_eq!(pns("has no escapes, either %"),None);3;3;assert_eq!(pns( +"*so* has a %% escape"),Some((S::Escape((11,13))," escape")));3;;assert_eq!(pns( +"%% leading escape"),Some((S::Escape((0,2))," leading escape")));;assert_eq!(pns +("trailing escape %%"),Some((S::Escape((16,18)),"")));;}#[test]fn test_parse(){; +macro_rules!assert_pns_eq_sub{($in_:expr,{$param :expr,$flags:expr,$width:expr,$ +prec:expr,$len:expr,$type_:expr,$pos:expr ,})=>{assert_eq!(pns(concat!($in_,"!") +),Some((S::Format(F{span:$in_,parameter:$param,flags:$flags,width:$width,//({}); +precision:$prec,length:$len,type_:$type_,position:rustc_span::InnerSpan::new($// +pos.0,$pos.1),}),"!")))};};assert_pns_eq_sub!("%!",{None,"",None,None,None,"!",( +0,2),});();();assert_pns_eq_sub!("%c",{None,"",None,None,None,"c",(0,2),});();3; +assert_pns_eq_sub!("%s",{None,"",None,None,None,"s",(0,2),});;assert_pns_eq_sub! +("%06d",{None,"0",Some(N::Num(6)),None,None,"d",(0,4),});3;3;assert_pns_eq_sub!( +"%4.2f",{None,"",Some(N::Num(4)),Some(N::Num(2)),None,"f",(0,5),});*&*&();{();}; +assert_pns_eq_sub!("%#x",{None,"#",None,None,None,"x",(0,3),});let _=();((),()); +assert_pns_eq_sub!("%-10s",{None,"-",Some(N::Num(10)),None,None,"s",(0,5),});3;; +assert_pns_eq_sub!("%*s",{None,"",Some(N::Next),None,None,"s",(0,3),});({});{;}; +assert_pns_eq_sub!("%-10.*s",{None,"-",Some(N::Num (10)),Some(N::Next),None,"s", +(0,7),});;assert_pns_eq_sub!("%-*.*s",{None,"-",Some(N::Next),Some(N::Next),None +,"s",(0,6),});;assert_pns_eq_sub!("%.6i",{None,"",None,Some(N::Num(6)),None,"i", +(0,4),});3;3;assert_pns_eq_sub!("%+i",{None,"+",None,None,None,"i",(0,3),});3;3; +assert_pns_eq_sub!("%08X",{None,"0",Some(N::Num(8)),None,None,"X",(0,4),});();3; +assert_pns_eq_sub!("%lu",{None,"",None,None,Some("l"),"u",(0,3),});*&*&();{();}; +assert_pns_eq_sub!("%Iu",{None,"",None,None,Some("I"),"u",(0,3),});*&*&();{();}; +assert_pns_eq_sub!("%I32u",{None,"",None,None,Some("I32"),"u",(0,5),});({});{;}; +assert_pns_eq_sub!("%I64u",{None,"",None,None,Some("I64"),"u",(0,5),});({});{;}; +assert_pns_eq_sub!("%'d",{None,"'",None,None,None,"d",(0,3),});let _=();((),()); +assert_pns_eq_sub!("%10s",{None,"",Some(N::Num(10)),None,None,"s",(0,4),});();3; +assert_pns_eq_sub!("%-10.10s",{None,"-",Some(N::Num( 10)),Some(N::Num(10)),None, +"s",(0,8),});;assert_pns_eq_sub!("%1$d",{Some(1),"",None,None,None,"d",(0,4),}); +assert_pns_eq_sub!("%2$.*3$d",{Some(2),"",None,Some(N ::Arg(3)),None,"d",(0,8),} +);;assert_pns_eq_sub!("%1$*2$.*3$d",{Some(1),"",Some(N::Arg(2)),Some(N::Arg(3)), +None,"d",(0,11),});3;;assert_pns_eq_sub!("%-8ld",{None,"-",Some(N::Num(8)),None, +Some("l"),"d",(0,5),});if let _=(){};}#[test]fn test_iter(){if let _=(){};let s= +"The %d'th word %% is: `%.*s` %!\n";;let subs:Vec<_>=iter_subs(s,0).map(|sub|sub +.translate().ok()).collect();();();assert_eq!(subs.iter().map(Option::as_deref). +collect::>(),vec![Some("{}"),None,Some("{:.*}"),None]);((),());}#[test]fn +test_translation(){;assert_eq_pnsat!("%c",Some("{}"));assert_eq_pnsat!("%d",Some +("{}"));;;assert_eq_pnsat!("%u",Some("{}"));assert_eq_pnsat!("%x",Some("{:x}")); +assert_eq_pnsat!("%X",Some("{:X}"));3;3;assert_eq_pnsat!("%e",Some("{:e}"));3;3; +assert_eq_pnsat!("%E",Some("{:E}"));();();assert_eq_pnsat!("%f",Some("{}"));3;3; +assert_eq_pnsat!("%g",Some("{:e}"));3;3;assert_eq_pnsat!("%G",Some("{:E}"));3;3; +assert_eq_pnsat!("%s",Some("{}"));();();assert_eq_pnsat!("%p",Some("{:p}"));3;3; +assert_eq_pnsat!("%06d",Some("{:06}"));;assert_eq_pnsat!("%4.2f",Some("{:4.2}")) +;;assert_eq_pnsat!("%#x",Some("{:#x}"));assert_eq_pnsat!("%-10s",Some("{:<10}")) +;;;assert_eq_pnsat!("%*s",None);;;assert_eq_pnsat!("%-10.*s",Some("{:<10.*}"));; +assert_eq_pnsat!("%-*.*s",None);();3;assert_eq_pnsat!("%.6i",Some("{:06}"));3;3; +assert_eq_pnsat!("%+i",Some("{:+}"));;;assert_eq_pnsat!("%08X",Some("{:08X}"));; +assert_eq_pnsat!("%lu",Some("{}"));();();assert_eq_pnsat!("%Iu",Some("{}"));3;3; +assert_eq_pnsat!("%I32u",Some("{}"));3;3;assert_eq_pnsat!("%I64u",Some("{}"));;; +assert_eq_pnsat!("%'d",None);();();assert_eq_pnsat!("%10s",Some("{:>10}"));();3; +assert_eq_pnsat!("%-10.10s",Some("{:<10.10}"));3;3;assert_eq_pnsat!("%1$d",Some( +"{0}"));();();assert_eq_pnsat!("%2$.*3$d",Some("{1:02$}"));3;3;assert_eq_pnsat!( +"%1$*2$.*3$s",Some("{0:>1$.2$}"));3;3;assert_eq_pnsat!("%-8ld",Some("{:<8}"));;} diff --git a/compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs b/compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs index 93a7afcd6e8b6..8e95e92a3772d 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs @@ -1,56 +1,20 @@ -use super::{parse_next_substitution as pns, Substitution as S}; - -macro_rules! assert_eq_pnsat { - ($lhs:expr, $rhs:expr) => { - assert_eq!( - pns($lhs).and_then(|(f, _)| f.translate().ok()), - $rhs.map(>::from) - ) - }; -} - -#[test] -fn test_escape() { - assert_eq!(pns("has no escapes"), None); - assert_eq!(pns("has no escapes, either $"), None); - assert_eq!(pns("*so* has a $$ escape"), Some((S::Escape((11, 13)), " escape"))); - assert_eq!(pns("$$ leading escape"), Some((S::Escape((0, 2)), " leading escape"))); - assert_eq!(pns("trailing escape $$"), Some((S::Escape((16, 18)), ""))); -} - -#[test] -fn test_parse() { - macro_rules! assert_pns_eq_sub { - ($in_:expr, $kind:ident($arg:expr, $pos:expr)) => { - assert_eq!(pns(concat!($in_, "!")), Some((S::$kind($arg.into(), $pos), "!"))) - }; - } - - assert_pns_eq_sub!("$0", Ordinal(0, (0, 2))); - assert_pns_eq_sub!("$1", Ordinal(1, (0, 2))); - assert_pns_eq_sub!("$9", Ordinal(9, (0, 2))); - assert_pns_eq_sub!("$N", Name("N", (0, 2))); - assert_pns_eq_sub!("$NAME", Name("NAME", (0, 5))); -} - -#[test] -fn test_iter() { - use super::iter_subs; - let s = "The $0'th word $$ is: `$WORD` $!\n"; - let subs: Vec<_> = iter_subs(s, 0).map(|sub| sub.translate().ok()).collect(); - assert_eq!( - subs.iter().map(Option::as_deref).collect::>(), - vec![Some("{0}"), None, Some("{WORD}")] - ); -} - -#[test] -fn test_translation() { - assert_eq_pnsat!("$0", Some("{0}")); - assert_eq_pnsat!("$9", Some("{9}")); - assert_eq_pnsat!("$1", Some("{1}")); - assert_eq_pnsat!("$10", Some("{1}")); - assert_eq_pnsat!("$stuff", Some("{stuff}")); - assert_eq_pnsat!("$NAME", Some("{NAME}")); - assert_eq_pnsat!("$PREFIX/bin", Some("{PREFIX}")); -} +use super::{parse_next_substitution as pns,Substitution as S};macro_rules!//{;}; +assert_eq_pnsat{($lhs:expr,$rhs:expr)=>{assert_eq! (pns($lhs).and_then(|(f,_)|f. +translate().ok()),$rhs.map(>::from))};}#[test]fn//let _=(); +test_escape(){{;};assert_eq!(pns("has no escapes"),None);{;};{;};assert_eq!(pns( +"has no escapes, either $"),None);;assert_eq!(pns("*so* has a $$ escape"),Some(( +S::Escape((11,13))," escape")));3;;assert_eq!(pns("$$ leading escape"),Some((S:: +Escape((0,2))," leading escape")));;assert_eq!(pns("trailing escape $$"),Some((S +::Escape((16,18)),"")));;}#[test]fn test_parse(){macro_rules!assert_pns_eq_sub{( +$in_:expr,$kind:ident($arg:expr,$pos: expr))=>{assert_eq!(pns(concat!($in_,"!")) +,Some((S::$kind($arg.into(),$pos),"!")))};};assert_pns_eq_sub!("$0",Ordinal(0,(0 +,2)));;assert_pns_eq_sub!("$1",Ordinal(1,(0,2)));assert_pns_eq_sub!("$9",Ordinal +(9,(0,2)));;assert_pns_eq_sub!("$N",Name("N",(0,2)));assert_pns_eq_sub!("$NAME", +Name("NAME",(0,5)));();}#[test]fn test_iter(){();use super::iter_subs;3;3;let s= +"The $0'th word $$ is: `$WORD` $!\n";3;;let subs:Vec<_>=iter_subs(s,0).map(|sub| +sub.translate().ok()).collect();3;;assert_eq!(subs.iter().map(Option::as_deref). +collect::>(),vec![Some("{0}"),None,Some("{WORD}")]);let _=||();}#[test]fn +test_translation(){3;assert_eq_pnsat!("$0",Some("{0}"));;;assert_eq_pnsat!("$9", +Some("{9}"));;;assert_eq_pnsat!("$1",Some("{1}"));;;assert_eq_pnsat!("$10",Some( +"{1}"));;;assert_eq_pnsat!("$stuff",Some("{stuff}"));;;assert_eq_pnsat!("$NAME", +Some("{NAME}"));({});({});assert_eq_pnsat!("$PREFIX/bin",Some("{PREFIX}"));{;};} diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index 099defd511b5b..3f8bd9bdcac99 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -1,174 +1,63 @@ -use crate::util::check_builtin_macro_attribute; - -use crate::errors; -use rustc_ast::expand::allocator::{ - global_fn_name, AllocatorMethod, AllocatorMethodInput, AllocatorTy, ALLOCATOR_METHODS, -}; -use rustc_ast::ptr::P; -use rustc_ast::{self as ast, AttrVec, Expr, FnHeader, FnSig, Generics, Param, StmtKind}; -use rustc_ast::{Fn, ItemKind, Mutability, Stmt, Ty, TyKind, Unsafe}; -use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::Span; -use thin_vec::{thin_vec, ThinVec}; - -pub fn expand( - ecx: &mut ExtCtxt<'_>, - _span: Span, - meta_item: &ast::MetaItem, - item: Annotatable, -) -> Vec { - check_builtin_macro_attribute(ecx, meta_item, sym::global_allocator); - - let orig_item = item.clone(); - - // Allow using `#[global_allocator]` on an item statement - // FIXME - if we get deref patterns, use them to reduce duplication here - let (item, is_stmt, ty_span) = if let Annotatable::Item(item) = &item - && let ItemKind::Static(box ast::StaticItem { ty, .. }) = &item.kind - { - (item, false, ecx.with_def_site_ctxt(ty.span)) - } else if let Annotatable::Stmt(stmt) = &item - && let StmtKind::Item(item) = &stmt.kind - && let ItemKind::Static(box ast::StaticItem { ty, .. }) = &item.kind - { - (item, true, ecx.with_def_site_ctxt(ty.span)) - } else { - ecx.dcx().emit_err(errors::AllocMustStatics { span: item.span() }); - return vec![orig_item]; - }; - - // Generate a bunch of new items using the AllocFnFactory - let span = ecx.with_def_site_ctxt(item.span); - let f = AllocFnFactory { span, ty_span, global: item.ident, cx: ecx }; - - // Generate item statements for the allocator methods. - let stmts = ALLOCATOR_METHODS.iter().map(|method| f.allocator_fn(method)).collect(); - - // Generate anonymous constant serving as container for the allocator methods. - let const_ty = ecx.ty(ty_span, TyKind::Tup(ThinVec::new())); - let const_body = ecx.expr_block(ecx.block(span, stmts)); - let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body); - let const_item = if is_stmt { - Annotatable::Stmt(P(ecx.stmt_item(span, const_item))) - } else { - Annotatable::Item(const_item) - }; - - // Return the original item and the new methods. - vec![orig_item, const_item] -} - -struct AllocFnFactory<'a, 'b> { - span: Span, - ty_span: Span, - global: Ident, - cx: &'b ExtCtxt<'a>, -} - -impl AllocFnFactory<'_, '_> { - fn allocator_fn(&self, method: &AllocatorMethod) -> Stmt { - let mut abi_args = ThinVec::new(); - let args = method.inputs.iter().map(|input| self.arg_ty(input, &mut abi_args)).collect(); - let result = self.call_allocator(method.name, args); - let output_ty = self.ret_ty(&method.output); - let decl = self.cx.fn_decl(abi_args, ast::FnRetTy::Ty(output_ty)); - let header = FnHeader { unsafety: Unsafe::Yes(self.span), ..FnHeader::default() }; - let sig = FnSig { decl, header, span: self.span }; - let body = Some(self.cx.block_expr(result)); - let kind = ItemKind::Fn(Box::new(Fn { - defaultness: ast::Defaultness::Final, - sig, - generics: Generics::default(), - body, - })); - let item = self.cx.item( - self.span, - Ident::from_str_and_span(&global_fn_name(method.name), self.span), - self.attrs(), - kind, - ); - self.cx.stmt_item(self.ty_span, item) - } - - fn call_allocator(&self, method: Symbol, mut args: ThinVec>) -> P { - let method = self.cx.std_path(&[sym::alloc, sym::GlobalAlloc, method]); - let method = self.cx.expr_path(self.cx.path(self.ty_span, method)); - let allocator = self.cx.path_ident(self.ty_span, self.global); - let allocator = self.cx.expr_path(allocator); - let allocator = self.cx.expr_addr_of(self.ty_span, allocator); - args.insert(0, allocator); - - self.cx.expr_call(self.ty_span, method, args) - } - - fn attrs(&self) -> AttrVec { - thin_vec![self.cx.attr_word(sym::rustc_std_internal_symbol, self.span)] - } - - fn arg_ty(&self, input: &AllocatorMethodInput, args: &mut ThinVec) -> P { - match input.ty { - AllocatorTy::Layout => { - // If an allocator method is ever introduced having multiple - // Layout arguments, these argument names need to be - // disambiguated somehow. Currently the generated code would - // fail to compile with "identifier is bound more than once in - // this parameter list". - let size = Ident::from_str_and_span("size", self.span); - let align = Ident::from_str_and_span("align", self.span); - - let usize = self.cx.path_ident(self.span, Ident::new(sym::usize, self.span)); - let ty_usize = self.cx.ty_path(usize); - args.push(self.cx.param(self.span, size, ty_usize.clone())); - args.push(self.cx.param(self.span, align, ty_usize)); - - let layout_new = - self.cx.std_path(&[sym::alloc, sym::Layout, sym::from_size_align_unchecked]); - let layout_new = self.cx.expr_path(self.cx.path(self.span, layout_new)); - let size = self.cx.expr_ident(self.span, size); - let align = self.cx.expr_ident(self.span, align); - let layout = self.cx.expr_call(self.span, layout_new, thin_vec![size, align]); - layout - } - - AllocatorTy::Ptr => { - let ident = Ident::from_str_and_span(input.name, self.span); - args.push(self.cx.param(self.span, ident, self.ptr_u8())); - self.cx.expr_ident(self.span, ident) - } - - AllocatorTy::Usize => { - let ident = Ident::from_str_and_span(input.name, self.span); - args.push(self.cx.param(self.span, ident, self.usize())); - self.cx.expr_ident(self.span, ident) - } - - AllocatorTy::ResultPtr | AllocatorTy::Unit => { - panic!("can't convert AllocatorTy to an argument") - } - } - } - - fn ret_ty(&self, ty: &AllocatorTy) -> P { - match *ty { - AllocatorTy::ResultPtr => self.ptr_u8(), - - AllocatorTy::Unit => self.cx.ty(self.span, TyKind::Tup(ThinVec::new())), - - AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => { - panic!("can't convert `AllocatorTy` to an output") - } - } - } - - fn usize(&self) -> P { - let usize = self.cx.path_ident(self.span, Ident::new(sym::usize, self.span)); - self.cx.ty_path(usize) - } - - fn ptr_u8(&self) -> P { - let u8 = self.cx.path_ident(self.span, Ident::new(sym::u8, self.span)); - let ty_u8 = self.cx.ty_path(u8); - self.cx.ty_ptr(self.span, ty_u8, Mutability::Mut) - } -} +use crate::util::check_builtin_macro_attribute;use crate::errors;use rustc_ast// +::expand::allocator::{global_fn_name,AllocatorMethod,AllocatorMethodInput,//{;}; +AllocatorTy,ALLOCATOR_METHODS,};use rustc_ast::ptr::P;use rustc_ast::{self as//; +ast,AttrVec,Expr,FnHeader,FnSig,Generics,Param,StmtKind};use rustc_ast::{Fn,//3; +ItemKind,Mutability,Stmt,Ty,TyKind, Unsafe};use rustc_expand::base::{Annotatable +,ExtCtxt};use rustc_span::symbol::{kw,sym,Ident,Symbol};use rustc_span::Span;//; +use thin_vec::{thin_vec,ThinVec};pub fn expand (ecx:&mut ExtCtxt<'_>,_span:Span, +meta_item:&ast::MetaItem,item:Annotatable,)->Vec{let _=();let _=(); +check_builtin_macro_attribute(ecx,meta_item,sym::global_allocator);({});({});let +orig_item=item.clone();;let(item,is_stmt,ty_span)=if let Annotatable::Item(item) +=&item&&let ItemKind::Static(box ast::StaticItem{ty ,..})=&item.kind{(item,false +,(ecx.with_def_site_ctxt(ty.span)))}else if let Annotatable::Stmt(stmt)=&item&& +let StmtKind::Item(item)=(&stmt.kind)&&let ItemKind::Static(box ast::StaticItem{ +ty,..})=&item.kind{(item,true,ecx.with_def_site_ctxt(ty.span))}else{3;ecx.dcx(). +emit_err(errors::AllocMustStatics{span:item.span()});;;return vec![orig_item];}; +let span=ecx.with_def_site_ctxt(item.span);3;;let f=AllocFnFactory{span,ty_span, +global:item.ident,cx:ecx};();3;let stmts=ALLOCATOR_METHODS.iter().map(|method|f. +allocator_fn(method)).collect();;let const_ty=ecx.ty(ty_span,TyKind::Tup(ThinVec +::new()));;;let const_body=ecx.expr_block(ecx.block(span,stmts));let const_item= +ecx.item_const(span,Ident::new(kw::Underscore,span),const_ty,const_body);3;3;let +const_item=if is_stmt{Annotatable::Stmt(P( ecx.stmt_item(span,const_item)))}else +{Annotatable::Item(const_item)};*&*&();((),());vec![orig_item,const_item]}struct +AllocFnFactory<'a,'b>{span:Span,ty_span:Span,global:Ident,cx:&'b ExtCtxt<'a>,}// +impl AllocFnFactory<'_,'_>{fn allocator_fn(&self,method:&AllocatorMethod)->Stmt +{;let mut abi_args=ThinVec::new();let args=method.inputs.iter().map(|input|self. +arg_ty(input,&mut abi_args)).collect();3;;let result=self.call_allocator(method. +name,args);;;let output_ty=self.ret_ty(&method.output);let decl=self.cx.fn_decl( +abi_args,ast::FnRetTy::Ty(output_ty));;let header=FnHeader{unsafety:Unsafe::Yes( +self.span),..FnHeader::default()};;let sig=FnSig{decl,header,span:self.span};let +body=Some(self.cx.block_expr(result));{;};{;};let kind=ItemKind::Fn(Box::new(Fn{ +defaultness:ast::Defaultness::Final,sig,generics:Generics::default(),body,}));;; +let item=self.cx.item(self. span,Ident::from_str_and_span(&global_fn_name(method +.name),self.span),self.attrs(),kind,);();self.cx.stmt_item(self.ty_span,item)}fn +call_allocator(&self,method:Symbol,mut args:ThinVec>)->P{{();};let +method=self.cx.std_path(&[sym::alloc,sym::GlobalAlloc,method]);;let method=self. +cx.expr_path(self.cx.path(self.ty_span,method));({});({});let allocator=self.cx. +path_ident(self.ty_span,self.global);;let allocator=self.cx.expr_path(allocator) +;3;3;let allocator=self.cx.expr_addr_of(self.ty_span,allocator);;;args.insert(0, +allocator);;self.cx.expr_call(self.ty_span,method,args)}fn attrs(&self)->AttrVec +{(((thin_vec![self.cx.attr_word(sym::rustc_std_internal_symbol,self.span)])))}fn +arg_ty(&self,input:&AllocatorMethodInput,args:&mut ThinVec)->P{//3; +match input.ty{AllocatorTy::Layout=>{3;let size=Ident::from_str_and_span("size", +self.span);;let align=Ident::from_str_and_span("align",self.span);let usize=self +.cx.path_ident(self.span,Ident::new(sym::usize,self.span));;let ty_usize=self.cx +.ty_path(usize);;args.push(self.cx.param(self.span,size,ty_usize.clone()));args. +push(self.cx.param(self.span,align,ty_usize));;let layout_new=self.cx.std_path(& +[sym::alloc,sym::Layout,sym::from_size_align_unchecked]);;let layout_new=self.cx +.expr_path(self.cx.path(self.span,layout_new));;let size=self.cx.expr_ident(self +.span,size);;;let align=self.cx.expr_ident(self.span,align);;let layout=self.cx. +expr_call(self.span,layout_new,thin_vec![size,align]);;layout}AllocatorTy::Ptr=> +{3;let ident=Ident::from_str_and_span(input.name,self.span);;;args.push(self.cx. +param(self.span,ident,self.ptr_u8()));{();};self.cx.expr_ident(self.span,ident)} +AllocatorTy::Usize=>{;let ident=Ident::from_str_and_span(input.name,self.span);; +args.push(self.cx.param(self.span,ident,self.usize()));;self.cx.expr_ident(self. +span,ident)}AllocatorTy::ResultPtr|AllocatorTy::Unit=>{panic!(//((),());((),()); +"can't convert AllocatorTy to an argument")}}}fn ret_ty(&self,ty:&AllocatorTy)// +->P{match*ty{AllocatorTy::ResultPtr =>self.ptr_u8(),AllocatorTy::Unit=>self. +cx.ty(self.span,(TyKind::Tup(ThinVec::new()))),AllocatorTy::Layout|AllocatorTy:: +Usize|AllocatorTy::Ptr=>{(panic!("can't convert `AllocatorTy` to an output"))}}} +fn usize(&self)->P{3;let usize=self.cx.path_ident(self.span,Ident::new(sym:: +usize,self.span));;self.cx.ty_path(usize)}fn ptr_u8(&self)->P{let u8=self.cx +.path_ident(self.span,Ident::new(sym::u8,self.span));;let ty_u8=self.cx.ty_path( +u8);loop{break;};if let _=(){};self.cx.ty_ptr(self.span,ty_u8,Mutability::Mut)}} diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 554dac0852f2c..f244de038836e 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -1,134 +1,51 @@ -//! This crate contains implementations of built-in macros and other code generating facilities -//! injecting code into the crate before it is lowered to HIR. - -#![allow(internal_features)] -#![allow(rustc::diagnostic_outside_of_impl)] -#![allow(rustc::untranslatable_diagnostic)] -#![feature(rustdoc_internals)] -#![doc(rust_logo)] -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] -#![feature(assert_matches)] -#![feature(box_patterns)] -#![feature(decl_macro)] -#![feature(if_let_guard)] -#![feature(let_chains)] -#![feature(lint_reasons)] -#![feature(proc_macro_internals)] -#![feature(proc_macro_quote)] -#![feature(try_blocks)] - -extern crate proc_macro; - -#[macro_use] -extern crate tracing; - -use crate::deriving::*; - -use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtensionKind}; -use rustc_expand::proc_macro::BangProcMacro; -use rustc_span::symbol::sym; - -mod alloc_error_handler; -mod assert; -mod cfg; -mod cfg_accessible; -mod cfg_eval; -mod compile_error; -mod concat; -mod concat_bytes; -mod concat_idents; -mod derive; -mod deriving; -mod edition_panic; -mod env; -mod errors; -mod format; -mod format_foreign; -mod global_allocator; -mod log_syntax; -mod source_util; -mod test; -mod trace_macros; -mod util; - -pub mod asm; -pub mod cmdline_attrs; -pub mod proc_macro_harness; -pub mod standard_library_imports; -pub mod test_harness; - -rustc_fluent_macro::fluent_messages! { "../messages.ftl" } - -pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { - let mut register = |name, kind| resolver.register_builtin_macro(name, kind); - macro register_bang($($name:ident: $f:expr,)*) { - $(register(sym::$name, SyntaxExtensionKind::LegacyBang(Box::new($f as MacroExpanderFn)));)* - } - macro register_attr($($name:ident: $f:expr,)*) { - $(register(sym::$name, SyntaxExtensionKind::LegacyAttr(Box::new($f)));)* - } - macro register_derive($($name:ident: $f:expr,)*) { - $(register(sym::$name, SyntaxExtensionKind::LegacyDerive(Box::new(BuiltinDerive($f))));)* - } - - register_bang! { - // tidy-alphabetical-start - asm: asm::expand_asm, - assert: assert::expand_assert, - cfg: cfg::expand_cfg, - column: source_util::expand_column, - compile_error: compile_error::expand_compile_error, - concat: concat::expand_concat, - concat_bytes: concat_bytes::expand_concat_bytes, - concat_idents: concat_idents::expand_concat_idents, - const_format_args: format::expand_format_args, - core_panic: edition_panic::expand_panic, - env: env::expand_env, - file: source_util::expand_file, - format_args: format::expand_format_args, - format_args_nl: format::expand_format_args_nl, - global_asm: asm::expand_global_asm, - include: source_util::expand_include, - include_bytes: source_util::expand_include_bytes, - include_str: source_util::expand_include_str, - line: source_util::expand_line, - log_syntax: log_syntax::expand_log_syntax, - module_path: source_util::expand_mod, - option_env: env::expand_option_env, - std_panic: edition_panic::expand_panic, - stringify: source_util::expand_stringify, - trace_macros: trace_macros::expand_trace_macros, - unreachable: edition_panic::expand_unreachable, - // tidy-alphabetical-end - } - - register_attr! { - alloc_error_handler: alloc_error_handler::expand, - bench: test::expand_bench, - cfg_accessible: cfg_accessible::Expander, - cfg_eval: cfg_eval::expand, - derive: derive::Expander(false), - derive_const: derive::Expander(true), - global_allocator: global_allocator::expand, - test: test::expand_test, - test_case: test::expand_test_case, - } - - register_derive! { - Clone: clone::expand_deriving_clone, - Copy: bounds::expand_deriving_copy, - ConstParamTy: bounds::expand_deriving_const_param_ty, - Debug: debug::expand_deriving_debug, - Default: default::expand_deriving_default, - Eq: eq::expand_deriving_eq, - Hash: hash::expand_deriving_hash, - Ord: ord::expand_deriving_ord, - PartialEq: partial_eq::expand_deriving_partial_eq, - PartialOrd: partial_ord::expand_deriving_partial_ord, - RustcDecodable: decodable::expand_deriving_rustc_decodable, - RustcEncodable: encodable::expand_deriving_rustc_encodable, - } - - let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote); - register(sym::quote, SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client }))); -} +#![allow(internal_features)]#![allow(rustc::diagnostic_outside_of_impl)]#![//(); +allow(rustc::untranslatable_diagnostic)]#![feature(rustdoc_internals)]#![doc(//; +rust_logo)]#![doc(html_root_url=//let _=||();loop{break};let _=||();loop{break}; +"https://doc.rust-lang.org/nightly/nightly-rustc/")]#! [feature(assert_matches)] +#![feature(box_patterns)]#![feature(decl_macro)]#![feature(if_let_guard)]#![//3; +feature(let_chains)]#![feature(lint_reasons )]#![feature(proc_macro_internals)]# +![feature(proc_macro_quote)]#![feature(try_blocks)]extern crate proc_macro;#[//; +macro_use]extern crate tracing;use crate ::deriving::*;use rustc_expand::base::{ +MacroExpanderFn,ResolverExpand,SyntaxExtensionKind};use rustc_expand:://((),()); +proc_macro::BangProcMacro;use rustc_span::symbol::sym;mod alloc_error_handler;// +mod assert;mod cfg;mod cfg_accessible ;mod cfg_eval;mod compile_error;mod concat +;mod concat_bytes;mod concat_idents;mod derive;mod deriving;mod edition_panic;// +mod env;mod errors;mod format;mod format_foreign;mod global_allocator;mod//({}); +log_syntax;mod source_util;mod test;mod trace_macros;mod util;pub mod asm;pub//; +mod cmdline_attrs;pub mod proc_macro_harness;pub mod standard_library_imports;// +pub mod test_harness;rustc_fluent_macro ::fluent_messages!{"../messages.ftl"}pub +fn register_builtin_macros(resolver:&mut dyn ResolverExpand){3;let mut register= +|name,kind|resolver.register_builtin_macro(name,kind);3;;macro register_bang($($ +name:ident:$f:expr,)*){$(register(sym::$name,SyntaxExtensionKind::LegacyBang(//; +Box::new($f as MacroExpanderFn)));)*};macro register_attr($($name:ident:$f:expr, +)*){$(register(sym::$name,SyntaxExtensionKind::LegacyAttr(Box::new($f)));)*}3;3; +macro register_derive($($name:ident:$f:expr,)*){$(register(sym::$name,//((),()); +SyntaxExtensionKind::LegacyDerive(Box::new(BuiltinDerive($f))));)*}loop{break;}; +register_bang!{asm:asm::expand_asm,assert:assert::expand_assert,cfg:cfg:://({}); +expand_cfg,column:source_util::expand_column,compile_error:compile_error:://{;}; +expand_compile_error,concat:concat::expand_concat,concat_bytes:concat_bytes:://; +expand_concat_bytes,concat_idents:concat_idents::expand_concat_idents,//((),()); +const_format_args:format::expand_format_args,core_panic:edition_panic:://*&*&(); +expand_panic,env:env::expand_env,file:source_util::expand_file,format_args://(); +format::expand_format_args,format_args_nl:format::expand_format_args_nl,//{();}; +global_asm:asm::expand_global_asm,include:source_util::expand_include,//((),()); +include_bytes:source_util::expand_include_bytes,include_str:source_util:://({}); +expand_include_str,line:source_util::expand_line,log_syntax:log_syntax:://{();}; +expand_log_syntax,module_path:source_util::expand_mod,option_env:env:://((),()); +expand_option_env,std_panic:edition_panic:: expand_panic,stringify:source_util:: +expand_stringify,trace_macros:trace_macros::expand_trace_macros,unreachable://3; +edition_panic::expand_unreachable,}register_attr!{alloc_error_handler://((),()); +alloc_error_handler::expand,bench:test::expand_bench,cfg_accessible://if true{}; +cfg_accessible::Expander,cfg_eval:cfg_eval::expand,derive:derive::Expander(//(); +false),derive_const:derive::Expander(true),global_allocator:global_allocator::// +expand,test:test::expand_test, test_case:test::expand_test_case,}register_derive +!{Clone:clone::expand_deriving_clone,Copy:bounds::expand_deriving_copy,//*&*&(); +ConstParamTy:bounds::expand_deriving_const_param_ty,Debug:debug:://loop{break;}; +expand_deriving_debug,Default:default::expand_deriving_default,Eq:eq:://((),()); +expand_deriving_eq,Hash:hash:: expand_deriving_hash,Ord:ord::expand_deriving_ord +,PartialEq:partial_eq::expand_deriving_partial_eq,PartialOrd:partial_ord:://{;}; +expand_deriving_partial_ord,RustcDecodable:decodable:://loop{break};loop{break}; +expand_deriving_rustc_decodable,RustcEncodable:encodable:://if true{};if true{}; +expand_deriving_rustc_encodable,}3;let client=proc_macro::bridge::client::Client +::expand1(proc_macro::quote);;;register(sym::quote,SyntaxExtensionKind::Bang(Box +::new(BangProcMacro{client})));loop{break};loop{break};loop{break};loop{break};} diff --git a/compiler/rustc_builtin_macros/src/log_syntax.rs b/compiler/rustc_builtin_macros/src/log_syntax.rs index 288a475ac241c..ce8997af97aac 100644 --- a/compiler/rustc_builtin_macros/src/log_syntax.rs +++ b/compiler/rustc_builtin_macros/src/log_syntax.rs @@ -1,14 +1,5 @@ -use rustc_ast::tokenstream::TokenStream; -use rustc_ast_pretty::pprust; -use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; - -pub fn expand_log_syntax<'cx>( - _cx: &'cx mut ExtCtxt<'_>, - sp: rustc_span::Span, - tts: TokenStream, -) -> MacroExpanderResult<'cx> { - println!("{}", pprust::tts_to_string(&tts)); - - // any so that `log_syntax` can be invoked as an expression and item. - ExpandResult::Ready(DummyResult::any_valid(sp)) -} +use rustc_ast::tokenstream::TokenStream;use rustc_ast_pretty::pprust;use//{();}; +rustc_expand::base::{DummyResult,ExpandResult,ExtCtxt,MacroExpanderResult};pub// +fn expand_log_syntax<'cx>(_cx:&'cx mut ExtCtxt<'_>,sp:rustc_span::Span,tts://(); +TokenStream,)->MacroExpanderResult<'cx>{();println!("{}",pprust::tts_to_string(& +tts));loop{break;};loop{break;};ExpandResult::Ready(DummyResult::any_valid(sp))} diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index 477e5c8bec531..ee6486a6e7907 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -1,386 +1,111 @@ -use crate::errors; -use rustc_ast::ptr::P; -use rustc_ast::visit::{self, Visitor}; -use rustc_ast::{self as ast, attr, NodeId}; -use rustc_ast_pretty::pprust; -use rustc_expand::base::{parse_macro_name_and_helper_attrs, ExtCtxt, ResolverExpand}; -use rustc_expand::expand::{AstFragment, ExpansionConfig}; -use rustc_feature::Features; -use rustc_session::Session; -use rustc_span::hygiene::AstPass; -use rustc_span::source_map::SourceMap; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{Span, DUMMY_SP}; -use smallvec::smallvec; -use std::mem; -use thin_vec::{thin_vec, ThinVec}; - -struct ProcMacroDerive { - id: NodeId, - trait_name: Symbol, - function_name: Ident, - span: Span, - attrs: Vec, -} - -struct ProcMacroDef { - id: NodeId, - function_name: Ident, - span: Span, -} - -enum ProcMacro { - Derive(ProcMacroDerive), - Attr(ProcMacroDef), - Bang(ProcMacroDef), -} - -struct CollectProcMacros<'a> { - macros: Vec, - in_root: bool, - dcx: &'a rustc_errors::DiagCtxt, - source_map: &'a SourceMap, - is_proc_macro_crate: bool, - is_test_crate: bool, -} - -pub fn inject( - krate: &mut ast::Crate, - sess: &Session, - features: &Features, - resolver: &mut dyn ResolverExpand, - is_proc_macro_crate: bool, - has_proc_macro_decls: bool, - is_test_crate: bool, - dcx: &rustc_errors::DiagCtxt, -) { - let ecfg = ExpansionConfig::default("proc_macro".to_string(), features); - let mut cx = ExtCtxt::new(sess, ecfg, resolver, None); - - let mut collect = CollectProcMacros { - macros: Vec::new(), - in_root: true, - dcx, - source_map: sess.source_map(), - is_proc_macro_crate, - is_test_crate, - }; - - if has_proc_macro_decls || is_proc_macro_crate { - visit::walk_crate(&mut collect, krate); - } - let macros = collect.macros; - - if !is_proc_macro_crate { - return; - } - - if is_test_crate { - return; - } - - let decls = mk_decls(&mut cx, ¯os); - krate.items.push(decls); -} - -impl<'a> CollectProcMacros<'a> { - fn check_not_pub_in_root(&self, vis: &ast::Visibility, sp: Span) { - if self.is_proc_macro_crate && self.in_root && vis.kind.is_pub() { - self.dcx.emit_err(errors::ProcMacro { span: sp }); - } - } - - fn collect_custom_derive(&mut self, item: &'a ast::Item, attr: &'a ast::Attribute) { - let Some((trait_name, proc_attrs)) = - parse_macro_name_and_helper_attrs(self.dcx, attr, "derive") - else { - return; - }; - - if self.in_root && item.vis.kind.is_pub() { - self.macros.push(ProcMacro::Derive(ProcMacroDerive { - id: item.id, - span: item.span, - trait_name, - function_name: item.ident, - attrs: proc_attrs, - })); - } else { - let msg = if !self.in_root { - "functions tagged with `#[proc_macro_derive]` must \ +use crate::errors;use rustc_ast::ptr::P;use rustc_ast::visit::{self,Visitor};//; +use rustc_ast::{self as ast,attr,NodeId};use rustc_ast_pretty::pprust;use//({}); +rustc_expand::base::{parse_macro_name_and_helper_attrs ,ExtCtxt,ResolverExpand}; +use rustc_expand::expand::{AstFragment,ExpansionConfig};use rustc_feature:://(); +Features;use rustc_session::Session;use rustc_span::hygiene::AstPass;use//{();}; +rustc_span::source_map::SourceMap;use rustc_span:: symbol::{kw,sym,Ident,Symbol} +;use rustc_span::{Span,DUMMY_SP};use smallvec::smallvec;use std::mem;use//{();}; +thin_vec::{thin_vec,ThinVec};struct ProcMacroDerive{id:NodeId,trait_name:Symbol +,function_name:Ident,span:Span,attrs:Vec ,}struct ProcMacroDef{id:NodeId +,function_name:Ident,span:Span,}enum ProcMacro{Derive(ProcMacroDerive),Attr(//3; +ProcMacroDef),Bang(ProcMacroDef),}struct CollectProcMacros<'a>{macros:Vec,in_root:bool,dcx:&'a rustc_errors::DiagCtxt,source_map:&'a SourceMap +,is_proc_macro_crate:bool,is_test_crate:bool,}pub fn inject(krate:&mut ast:://3; +Crate,sess:&Session,features:&Features,resolver:&mut dyn ResolverExpand,//{();}; +is_proc_macro_crate:bool,has_proc_macro_decls:bool,is_test_crate:bool,dcx:&//(); +rustc_errors::DiagCtxt,){((),());let ecfg=ExpansionConfig::default("proc_macro". +to_string(),features);;;let mut cx=ExtCtxt::new(sess,ecfg,resolver,None);let mut +collect=CollectProcMacros{macros:(Vec::new()) ,in_root:true,dcx,source_map:sess. +source_map(),is_proc_macro_crate,is_test_crate,};{();};if has_proc_macro_decls|| +is_proc_macro_crate{;visit::walk_crate(&mut collect,krate);;}let macros=collect. +macros;3;if!is_proc_macro_crate{;return;;}if is_test_crate{;return;;};let decls= +mk_decls(&mut cx,¯os);;krate.items.push(decls);}impl<'a>CollectProcMacros<'a +>{fn check_not_pub_in_root(&self,vis:&ast::Visibility,sp:Span){if self.//*&*&(); +is_proc_macro_crate&&self.in_root&&vis.kind.is_pub(){;self.dcx.emit_err(errors:: +ProcMacro{span:sp});{;};}}fn collect_custom_derive(&mut self,item:&'a ast::Item, +attr:&'a ast::Attribute){if true{};let _=||();let Some((trait_name,proc_attrs))= +parse_macro_name_and_helper_attrs(self.dcx,attr,"derive")else{;return;};if self. +in_root&&item.vis.kind.is_pub(){loop{break;};self.macros.push(ProcMacro::Derive( +ProcMacroDerive{id:item.id,span:item.span,trait_name,function_name:item.ident,// +attrs:proc_attrs,}));*&*&();((),());}else{if let _=(){};let msg=if!self.in_root{ +"functions tagged with `#[proc_macro_derive]` must \ currently reside in the root of the crate" - } else { - "functions tagged with `#[proc_macro_derive]` must be `pub`" - }; - self.dcx.span_err(self.source_map.guess_head_span(item.span), msg); - } - } - - fn collect_attr_proc_macro(&mut self, item: &'a ast::Item) { - if self.in_root && item.vis.kind.is_pub() { - self.macros.push(ProcMacro::Attr(ProcMacroDef { - id: item.id, - span: item.span, - function_name: item.ident, - })); - } else { - let msg = if !self.in_root { - "functions tagged with `#[proc_macro_attribute]` must \ +}else{"functions tagged with `#[proc_macro_derive]` must be `pub`"};3;;self.dcx. +span_err(self.source_map.guess_head_span(item.span),msg);let _=();if true{};}}fn +collect_attr_proc_macro(&mut self,item:&'a ast:: Item){if self.in_root&&item.vis +.kind.is_pub(){();self.macros.push(ProcMacro::Attr(ProcMacroDef{id:item.id,span: +item.span,function_name:item.ident,}));{();};}else{({});let msg=if!self.in_root{ +"functions tagged with `#[proc_macro_attribute]` must \ currently reside in the root of the crate" - } else { - "functions tagged with `#[proc_macro_attribute]` must be `pub`" - }; - self.dcx.span_err(self.source_map.guess_head_span(item.span), msg); - } - } - - fn collect_bang_proc_macro(&mut self, item: &'a ast::Item) { - if self.in_root && item.vis.kind.is_pub() { - self.macros.push(ProcMacro::Bang(ProcMacroDef { - id: item.id, - span: item.span, - function_name: item.ident, - })); - } else { - let msg = if !self.in_root { - "functions tagged with `#[proc_macro]` must \ +}else{"functions tagged with `#[proc_macro_attribute]` must be `pub`"};;self.dcx +.span_err(self.source_map.guess_head_span(item.span),msg);let _=();let _=();}}fn +collect_bang_proc_macro(&mut self,item:&'a ast:: Item){if self.in_root&&item.vis +.kind.is_pub(){();self.macros.push(ProcMacro::Bang(ProcMacroDef{id:item.id,span: +item.span,function_name:item.ident,}));{();};}else{({});let msg=if!self.in_root{ +"functions tagged with `#[proc_macro]` must \ currently reside in the root of the crate" - } else { - "functions tagged with `#[proc_macro]` must be `pub`" - }; - self.dcx.span_err(self.source_map.guess_head_span(item.span), msg); - } - } -} - -impl<'a> Visitor<'a> for CollectProcMacros<'a> { - fn visit_item(&mut self, item: &'a ast::Item) { - if let ast::ItemKind::MacroDef(..) = item.kind { - if self.is_proc_macro_crate && attr::contains_name(&item.attrs, sym::macro_export) { - self.dcx.emit_err(errors::ExportMacroRules { - span: self.source_map.guess_head_span(item.span), - }); - } - } - - // First up, make sure we're checking a bare function. If we're not then - // we're just not interested in this item. - // - // If we find one, try to locate a `#[proc_macro_derive]` attribute on it. - let is_fn = matches!(item.kind, ast::ItemKind::Fn(..)); - - let mut found_attr: Option<&'a ast::Attribute> = None; - - for attr in &item.attrs { - if attr.is_proc_macro_attr() { - if let Some(prev_attr) = found_attr { - let prev_item = prev_attr.get_normal_item(); - let item = attr.get_normal_item(); - let path_str = pprust::path_to_string(&item.path); - let msg = if item.path.segments[0].ident.name - == prev_item.path.segments[0].ident.name - { - format!( - "only one `#[{path_str}]` attribute is allowed on any given function", - ) - } else { - format!( - "`#[{}]` and `#[{}]` attributes cannot both be applied - to the same function", - path_str, - pprust::path_to_string(&prev_item.path), - ) - }; - - self.dcx - .struct_span_err(attr.span, msg) - .with_span_label(prev_attr.span, "previous attribute here") - .emit(); - - return; - } - - found_attr = Some(attr); - } - } - - let Some(attr) = found_attr else { - self.check_not_pub_in_root(&item.vis, self.source_map.guess_head_span(item.span)); - let prev_in_root = mem::replace(&mut self.in_root, false); - visit::walk_item(self, item); - self.in_root = prev_in_root; - return; - }; - - if !is_fn { - let msg = format!( - "the `#[{}]` attribute may only be used on bare functions", - pprust::path_to_string(&attr.get_normal_item().path), - ); - - self.dcx.span_err(attr.span, msg); - return; - } - - if self.is_test_crate { - return; - } - - if !self.is_proc_macro_crate { - let msg = format!( - "the `#[{}]` attribute is only usable with crates of the `proc-macro` crate type", - pprust::path_to_string(&attr.get_normal_item().path), - ); - - self.dcx.span_err(attr.span, msg); - return; - } - - if attr.has_name(sym::proc_macro_derive) { - self.collect_custom_derive(item, attr); - } else if attr.has_name(sym::proc_macro_attribute) { - self.collect_attr_proc_macro(item); - } else if attr.has_name(sym::proc_macro) { - self.collect_bang_proc_macro(item); - }; - - let prev_in_root = mem::replace(&mut self.in_root, false); - visit::walk_item(self, item); - self.in_root = prev_in_root; - } -} - -// Creates a new module which looks like: -// -// const _: () = { -// extern crate proc_macro; -// -// use proc_macro::bridge::client::ProcMacro; -// -// #[rustc_proc_macro_decls] -// #[used] -// #[allow(deprecated)] -// static DECLS: &[ProcMacro] = &[ -// ProcMacro::custom_derive($name_trait1, &[], ::$name1); -// ProcMacro::custom_derive($name_trait2, &["attribute_name"], ::$name2); -// // ... -// ]; -// } -fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P { - let expn_id = cx.resolver.expansion_for_ast_pass( - DUMMY_SP, - AstPass::ProcMacroHarness, - &[sym::rustc_attrs, sym::proc_macro_internals], - None, - ); - let span = DUMMY_SP.with_def_site_ctxt(expn_id.to_expn_id()); - - let proc_macro = Ident::new(sym::proc_macro, span); - let krate = cx.item(span, proc_macro, ast::AttrVec::new(), ast::ItemKind::ExternCrate(None)); - - let bridge = Ident::new(sym::bridge, span); - let client = Ident::new(sym::client, span); - let proc_macro_ty = Ident::new(sym::ProcMacro, span); - let custom_derive = Ident::new(sym::custom_derive, span); - let attr = Ident::new(sym::attr, span); - let bang = Ident::new(sym::bang, span); - - // We add NodeIds to 'resolver.proc_macros' in the order - // that we generate expressions. The position of each NodeId - // in the 'proc_macros' Vec corresponds to its position - // in the static array that will be generated - let decls = macros - .iter() - .map(|m| { - let harness_span = span; - let span = match m { - ProcMacro::Derive(m) => m.span, - ProcMacro::Attr(m) | ProcMacro::Bang(m) => m.span, - }; - let local_path = |cx: &ExtCtxt<'_>, name| cx.expr_path(cx.path(span, vec![name])); - let proc_macro_ty_method_path = |cx: &ExtCtxt<'_>, method| { - cx.expr_path(cx.path( - span.with_ctxt(harness_span.ctxt()), - vec![proc_macro, bridge, client, proc_macro_ty, method], - )) - }; - match m { - ProcMacro::Derive(cd) => { - cx.resolver.declare_proc_macro(cd.id); - cx.expr_call( - span, - proc_macro_ty_method_path(cx, custom_derive), - thin_vec![ - cx.expr_str(span, cd.trait_name), - cx.expr_array_ref( - span, - cd.attrs - .iter() - .map(|&s| cx.expr_str(span, s)) - .collect::>(), - ), - local_path(cx, cd.function_name), - ], - ) - } - ProcMacro::Attr(ca) | ProcMacro::Bang(ca) => { - cx.resolver.declare_proc_macro(ca.id); - let ident = match m { - ProcMacro::Attr(_) => attr, - ProcMacro::Bang(_) => bang, - ProcMacro::Derive(_) => unreachable!(), - }; - - cx.expr_call( - span, - proc_macro_ty_method_path(cx, ident), - thin_vec![ - cx.expr_str(span, ca.function_name.name), - local_path(cx, ca.function_name), - ], - ) - } - } - }) - .collect(); - - let decls_static = cx - .item_static( - span, - Ident::new(sym::_DECLS, span), - cx.ty_ref( - span, - cx.ty( - span, - ast::TyKind::Slice( - cx.ty_path(cx.path(span, vec![proc_macro, bridge, client, proc_macro_ty])), - ), - ), - None, - ast::Mutability::Not, - ), - ast::Mutability::Not, - cx.expr_array_ref(span, decls), - ) - .map(|mut i| { - i.attrs.push(cx.attr_word(sym::rustc_proc_macro_decls, span)); - i.attrs.push(cx.attr_word(sym::used, span)); - i.attrs.push(cx.attr_nested_word(sym::allow, sym::deprecated, span)); - i - }); - - let block = cx.expr_block( - cx.block(span, thin_vec![cx.stmt_item(span, krate), cx.stmt_item(span, decls_static)]), - ); - - let anon_constant = cx.item_const( - span, - Ident::new(kw::Underscore, span), - cx.ty(span, ast::TyKind::Tup(ThinVec::new())), - block, - ); - - // Integrate the new item into existing module structures. - let items = AstFragment::Items(smallvec![anon_constant]); - cx.monotonic_expander().fully_expand_fragment(items).make_items().pop().unwrap() -} +}else{"functions tagged with `#[proc_macro]` must be `pub`"};;self.dcx.span_err( +self.source_map.guess_head_span(item.span),msg);*&*&();}}}impl<'a>Visitor<'a>for +CollectProcMacros<'a>{fn visit_item(&mut self,item:&'a ast::Item){if let ast::// +ItemKind::MacroDef(..)=item.kind{if self.is_proc_macro_crate&&attr:://if true{}; +contains_name(&item.attrs,sym::macro_export){let _=();self.dcx.emit_err(errors:: +ExportMacroRules{span:self.source_map.guess_head_span(item.span),});;}}let is_fn +=matches!(item.kind,ast::ItemKind::Fn(..));;;let mut found_attr:Option<&'a ast:: +Attribute>=None;;for attr in&item.attrs{if attr.is_proc_macro_attr(){if let Some +(prev_attr)=found_attr{;let prev_item=prev_attr.get_normal_item();let item=attr. +get_normal_item();;;let path_str=pprust::path_to_string(&item.path);;let msg=if +item.path.segments[0].ident.name==prev_item .path.segments[0].ident.name{format! +("only one `#[{path_str}]` attribute is allowed on any given function",)}else{// +format!(//((),());let _=();let _=();let _=();((),());let _=();let _=();let _=(); +"`#[{}]` and `#[{}]` attributes cannot both be applied + to the same function" +,path_str,pprust::path_to_string(&prev_item.path),)};;;self.dcx.struct_span_err( +attr.span,msg).with_span_label(prev_attr. span,"previous attribute here").emit() +;3;3;return;3;}3;found_attr=Some(attr);;}};let Some(attr)=found_attr else{;self. +check_not_pub_in_root(&item.vis,self.source_map.guess_head_span(item.span));;let +prev_in_root=mem::replace(&mut self.in_root,false);;;visit::walk_item(self,item) +;();();self.in_root=prev_in_root;();();return;();};3;if!is_fn{3;let msg=format!( +"the `#[{}]` attribute may only be used on bare functions",pprust:://let _=||(); +path_to_string(&attr.get_normal_item().path),);;self.dcx.span_err(attr.span,msg) +;;;return;;}if self.is_test_crate{;return;;}if!self.is_proc_macro_crate{let msg= +format!(//((),());let _=();let _=();let _=();((),());let _=();let _=();let _=(); +"the `#[{}]` attribute is only usable with crates of the `proc-macro` crate type" +,pprust::path_to_string(&attr.get_normal_item().path),);;self.dcx.span_err(attr. +span,msg);{;};();return;();}();if attr.has_name(sym::proc_macro_derive){();self. +collect_custom_derive(item,attr);let _=();if true{};}else if attr.has_name(sym:: +proc_macro_attribute){;self.collect_attr_proc_macro(item);}else if attr.has_name +(sym::proc_macro){;self.collect_bang_proc_macro(item);;};;let prev_in_root=mem:: +replace(&mut self.in_root,false);3;3;visit::walk_item(self,item);;;self.in_root= +prev_in_root;{;};}}fn mk_decls(cx:&mut ExtCtxt<'_>,macros:&[ProcMacro])->P{let _=();let expn_id=cx.resolver.expansion_for_ast_pass(DUMMY_SP,AstPass:: +ProcMacroHarness,&[sym::rustc_attrs,sym::proc_macro_internals],None,);;let span= +DUMMY_SP.with_def_site_ctxt(expn_id.to_expn_id());;let proc_macro=Ident::new(sym +::proc_macro,span);;;let krate=cx.item(span,proc_macro,ast::AttrVec::new(),ast:: +ItemKind::ExternCrate(None));;let bridge=Ident::new(sym::bridge,span);let client +=Ident::new(sym::client,span);;let proc_macro_ty=Ident::new(sym::ProcMacro,span) +;;;let custom_derive=Ident::new(sym::custom_derive,span);let attr=Ident::new(sym +::attr,span);;let bang=Ident::new(sym::bang,span);let decls=macros.iter().map(|m +|{;let harness_span=span;let span=match m{ProcMacro::Derive(m)=>m.span,ProcMacro +::Attr(m)|ProcMacro::Bang(m)=>m.span,};;let local_path=|cx:&ExtCtxt<'_>,name|cx. +expr_path(cx.path(span,vec![name]));;let proc_macro_ty_method_path=|cx:&ExtCtxt< +'_>,method|{cx.expr_path(cx.path(((span.with_ctxt((harness_span.ctxt())))),vec![ +proc_macro,bridge,client,proc_macro_ty,method],))};;match m{ProcMacro::Derive(cd +)=>{if true{};cx.resolver.declare_proc_macro(cd.id);if true{};cx.expr_call(span, +proc_macro_ty_method_path(cx,custom_derive),thin_vec![cx.expr_str(span,cd.//{;}; +trait_name),cx.expr_array_ref(span,cd.attrs.iter() .map(|&s|cx.expr_str(span,s)) +.collect::>(),),local_path(cx ,cd.function_name),],)}ProcMacro::Attr( +ca)|ProcMacro::Bang(ca)=>{;cx.resolver.declare_proc_macro(ca.id);let ident=match +m{ProcMacro::Attr(_)=>attr,ProcMacro::Bang(_)=>bang,ProcMacro::Derive(_)=>//{;}; +unreachable!(),};;cx.expr_call(span,proc_macro_ty_method_path(cx,ident),thin_vec +![cx.expr_str(span,ca.function_name.name), local_path(cx,ca.function_name),],)}} +}).collect();;let decls_static=cx.item_static(span,Ident::new(sym::_DECLS,span), +cx.ty_ref(span,cx.ty(span,ast::TyKind::Slice(cx.ty_path(cx.path(span,vec![//{;}; +proc_macro,bridge,client,proc_macro_ty])),) ,),None,ast::Mutability::Not,),ast:: +Mutability::Not,cx.expr_array_ref(span,decls),).map(|mut i|{{;};i.attrs.push(cx. +attr_word(sym::rustc_proc_macro_decls,span));3;3;i.attrs.push(cx.attr_word(sym:: +used,span));;i.attrs.push(cx.attr_nested_word(sym::allow,sym::deprecated,span)); +i});;let block=cx.expr_block(cx.block(span,thin_vec![cx.stmt_item(span,krate),cx +.stmt_item(span,decls_static)]),);;;let anon_constant=cx.item_const(span,Ident:: +new(kw::Underscore,span),cx.ty(span,ast::TyKind::Tup(ThinVec::new())),block,);;; +let items=AstFragment::Items(smallvec![anon_constant]);;cx.monotonic_expander(). +fully_expand_fragment(items).make_items().pop().unwrap()}//if true{};let _=||(); diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index 61a6361ae8dcf..54981fd820ed4 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -1,342 +1,104 @@ -use rustc_ast as ast; -use rustc_ast::ptr::P; -use rustc_ast::token; -use rustc_ast::tokenstream::TokenStream; -use rustc_ast_pretty::pprust; -use rustc_data_structures::sync::Lrc; -use rustc_expand::base::{ - check_zero_tts, get_single_str_from_tts, get_single_str_spanned_from_tts, parse_expr, - resolve_path, -}; -use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt}; -use rustc_expand::base::{MacEager, MacResult, MacroExpanderResult}; -use rustc_expand::module::DirOwnership; -use rustc_parse::new_parser_from_file; -use rustc_parse::parser::{ForceCollect, Parser}; -use rustc_session::lint::builtin::INCOMPLETE_INCLUDE; -use rustc_span::source_map::SourceMap; -use rustc_span::symbol::Symbol; -use rustc_span::{Pos, Span}; -use smallvec::SmallVec; -use std::path::{Path, PathBuf}; -use std::rc::Rc; - -// These macros all relate to the file system; they either return -// the column/row/filename of the expression, or they include -// a given file into the current one. - -/// line!(): expands to the current line number -pub fn expand_line( - cx: &mut ExtCtxt<'_>, - sp: Span, - tts: TokenStream, -) -> MacroExpanderResult<'static> { - let sp = cx.with_def_site_ctxt(sp); - check_zero_tts(cx, sp, tts, "line!"); - - let topmost = cx.expansion_cause().unwrap_or(sp); - let loc = cx.source_map().lookup_char_pos(topmost.lo()); - - ExpandResult::Ready(MacEager::expr(cx.expr_u32(topmost, loc.line as u32))) -} - -/* column!(): expands to the current column number */ -pub fn expand_column( - cx: &mut ExtCtxt<'_>, - sp: Span, - tts: TokenStream, -) -> MacroExpanderResult<'static> { - let sp = cx.with_def_site_ctxt(sp); - check_zero_tts(cx, sp, tts, "column!"); - - let topmost = cx.expansion_cause().unwrap_or(sp); - let loc = cx.source_map().lookup_char_pos(topmost.lo()); - - ExpandResult::Ready(MacEager::expr(cx.expr_u32(topmost, loc.col.to_usize() as u32 + 1))) -} - -/// file!(): expands to the current filename */ -/// The source_file (`loc.file`) contains a bunch more information we could spit -/// out if we wanted. -pub fn expand_file( - cx: &mut ExtCtxt<'_>, - sp: Span, - tts: TokenStream, -) -> MacroExpanderResult<'static> { - let sp = cx.with_def_site_ctxt(sp); - check_zero_tts(cx, sp, tts, "file!"); - - let topmost = cx.expansion_cause().unwrap_or(sp); - let loc = cx.source_map().lookup_char_pos(topmost.lo()); - - use rustc_session::{config::RemapPathScopeComponents, RemapFileNameExt}; - ExpandResult::Ready(MacEager::expr(cx.expr_str( - topmost, - Symbol::intern( - &loc.file.name.for_scope(cx.sess, RemapPathScopeComponents::MACRO).to_string_lossy(), - ), - ))) -} - -pub fn expand_stringify( - cx: &mut ExtCtxt<'_>, - sp: Span, - tts: TokenStream, -) -> MacroExpanderResult<'static> { - let sp = cx.with_def_site_ctxt(sp); - let s = pprust::tts_to_string(&tts); - ExpandResult::Ready(MacEager::expr(cx.expr_str(sp, Symbol::intern(&s)))) -} - -pub fn expand_mod( - cx: &mut ExtCtxt<'_>, - sp: Span, - tts: TokenStream, -) -> MacroExpanderResult<'static> { - let sp = cx.with_def_site_ctxt(sp); - check_zero_tts(cx, sp, tts, "module_path!"); - let mod_path = &cx.current_expansion.module.mod_path; - let string = mod_path.iter().map(|x| x.to_string()).collect::>().join("::"); - - ExpandResult::Ready(MacEager::expr(cx.expr_str(sp, Symbol::intern(&string)))) -} - -/// include! : parse the given file as an expr -/// This is generally a bad idea because it's going to behave -/// unhygienically. -pub fn expand_include<'cx>( - cx: &'cx mut ExtCtxt<'_>, - sp: Span, - tts: TokenStream, -) -> MacroExpanderResult<'cx> { - let sp = cx.with_def_site_ctxt(sp); - let ExpandResult::Ready(mac) = get_single_str_from_tts(cx, sp, tts, "include!") else { - return ExpandResult::Retry(()); - }; - let file = match mac { - Ok(file) => file, - Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)), - }; - // The file will be added to the code map by the parser - let file = match resolve_path(&cx.sess, file.as_str(), sp) { - Ok(f) => f, - Err(err) => { - let guar = err.emit(); - return ExpandResult::Ready(DummyResult::any(sp, guar)); - } - }; - let p = new_parser_from_file(cx.psess(), &file, Some(sp)); - - // If in the included file we have e.g., `mod bar;`, - // then the path of `bar.rs` should be relative to the directory of `file`. - // See https://github.com/rust-lang/rust/pull/69838/files#r395217057 for a discussion. - // `MacroExpander::fully_expand_fragment` later restores, so "stack discipline" is maintained. - let dir_path = file.parent().unwrap_or(&file).to_owned(); - cx.current_expansion.module = Rc::new(cx.current_expansion.module.with_dir_path(dir_path)); - cx.current_expansion.dir_ownership = DirOwnership::Owned { relative: None }; - - struct ExpandInclude<'a> { - p: Parser<'a>, - node_id: ast::NodeId, - } - impl<'a> MacResult for ExpandInclude<'a> { - fn make_expr(mut self: Box>) -> Option> { - let expr = parse_expr(&mut self.p).ok()?; - if self.p.token != token::Eof { - self.p.psess.buffer_lint( - INCOMPLETE_INCLUDE, - self.p.token.span, - self.node_id, - "include macro expected single expression in source", - ); - } - Some(expr) - } - - fn make_items(mut self: Box>) -> Option; 1]>> { - let mut ret = SmallVec::new(); - loop { - match self.p.parse_item(ForceCollect::No) { - Err(err) => { - err.emit(); - break; - } - Ok(Some(item)) => ret.push(item), - Ok(None) => { - if self.p.token != token::Eof { - let token = pprust::token_to_string(&self.p.token); - let msg = format!("expected item, found `{token}`"); - self.p.dcx().span_err(self.p.token.span, msg); - } - - break; - } - } - } - Some(ret) - } - } - - ExpandResult::Ready(Box::new(ExpandInclude { p, node_id: cx.current_expansion.lint_node_id })) -} - -/// `include_str!`: read the given file, insert it as a literal string expr -pub fn expand_include_str( - cx: &mut ExtCtxt<'_>, - sp: Span, - tts: TokenStream, -) -> MacroExpanderResult<'static> { - let sp = cx.with_def_site_ctxt(sp); - let ExpandResult::Ready(mac) = get_single_str_spanned_from_tts(cx, sp, tts, "include_str!") - else { - return ExpandResult::Retry(()); - }; - let (path, path_span) = match mac { - Ok(res) => res, - Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)), - }; - ExpandResult::Ready(match load_binary_file(cx, path.as_str().as_ref(), sp, path_span) { - Ok(bytes) => match std::str::from_utf8(&bytes) { - Ok(src) => { - let interned_src = Symbol::intern(src); - MacEager::expr(cx.expr_str(sp, interned_src)) - } - Err(_) => { - let guar = cx.dcx().span_err(sp, format!("`{path}` wasn't a utf-8 file")); - DummyResult::any(sp, guar) - } - }, - Err(dummy) => dummy, - }) -} - -pub fn expand_include_bytes( - cx: &mut ExtCtxt<'_>, - sp: Span, - tts: TokenStream, -) -> MacroExpanderResult<'static> { - let sp = cx.with_def_site_ctxt(sp); - let ExpandResult::Ready(mac) = get_single_str_spanned_from_tts(cx, sp, tts, "include_bytes!") - else { - return ExpandResult::Retry(()); - }; - let (path, path_span) = match mac { - Ok(res) => res, - Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)), - }; - ExpandResult::Ready(match load_binary_file(cx, path.as_str().as_ref(), sp, path_span) { - Ok(bytes) => { - let expr = cx.expr(sp, ast::ExprKind::IncludedBytes(bytes)); - MacEager::expr(expr) - } - Err(dummy) => dummy, - }) -} - -fn load_binary_file( - cx: &ExtCtxt<'_>, - original_path: &Path, - macro_span: Span, - path_span: Span, -) -> Result, Box> { - let resolved_path = match resolve_path(&cx.sess, original_path, macro_span) { - Ok(path) => path, - Err(err) => { - let guar = err.emit(); - return Err(DummyResult::any(macro_span, guar)); - } - }; - match cx.source_map().load_binary_file(&resolved_path) { - Ok(data) => Ok(data), - Err(io_err) => { - let mut err = cx.dcx().struct_span_err( - macro_span, - format!("couldn't read `{}`: {io_err}", resolved_path.display()), - ); - - if original_path.is_relative() { - let source_map = cx.sess.source_map(); - let new_path = source_map - .span_to_filename(macro_span.source_callsite()) - .into_local_path() - .and_then(|src| find_path_suggestion(source_map, src.parent()?, original_path)) - .and_then(|path| path.into_os_string().into_string().ok()); - - if let Some(new_path) = new_path { - err.span_suggestion( - path_span, - "there is a file with the same name in a different directory", - format!("\"{}\"", new_path.replace('\\', "/").escape_debug()), - rustc_lint_defs::Applicability::MachineApplicable, - ); - } - } - let guar = err.emit(); - Err(DummyResult::any(macro_span, guar)) - } - } -} - -fn find_path_suggestion( - source_map: &SourceMap, - base_dir: &Path, - wanted_path: &Path, -) -> Option { - // Fix paths that assume they're relative to cargo manifest dir - let mut base_c = base_dir.components(); - let mut wanted_c = wanted_path.components(); - let mut without_base = None; - while let Some(wanted_next) = wanted_c.next() { - if wanted_c.as_path().file_name().is_none() { - break; - } - // base_dir may be absolute - while let Some(base_next) = base_c.next() { - if base_next == wanted_next { - without_base = Some(wanted_c.as_path()); - break; - } - } - } - let root_absolute = without_base.into_iter().map(PathBuf::from); - - let base_dir_components = base_dir.components().count(); - // Avoid going all the way to the root dir - let max_parent_components = if base_dir.is_relative() { - base_dir_components + 1 - } else { - base_dir_components.saturating_sub(1) - }; - - // Try with additional leading ../ - let mut prefix = PathBuf::new(); - let add = std::iter::from_fn(|| { - prefix.push(".."); - Some(prefix.join(wanted_path)) - }) - .take(max_parent_components.min(3)); - - // Try without leading directories - let mut trimmed_path = wanted_path; - let remove = std::iter::from_fn(|| { - let mut components = trimmed_path.components(); - let removed = components.next()?; - trimmed_path = components.as_path(); - let _ = trimmed_path.file_name()?; // ensure there is a file name left - Some([ - Some(trimmed_path.to_path_buf()), - (removed != std::path::Component::ParentDir) - .then(|| Path::new("..").join(trimmed_path)), - ]) - }) - .flatten() - .flatten() - .take(4); - - for new_path in root_absolute.chain(add).chain(remove) { - if source_map.file_exists(&base_dir.join(&new_path)) { - return Some(new_path); - } - } - None -} +use rustc_ast as ast;use rustc_ast::ptr ::P;use rustc_ast::token;use rustc_ast:: +tokenstream::TokenStream;use rustc_ast_pretty::pprust;use rustc_data_structures +::sync::Lrc;use rustc_expand::base::{check_zero_tts,get_single_str_from_tts,//3; +get_single_str_spanned_from_tts,parse_expr,resolve_path,};use rustc_expand:://3; +base::{DummyResult,ExpandResult,ExtCtxt};use rustc_expand::base::{MacEager,//(); +MacResult,MacroExpanderResult};use rustc_expand::module::DirOwnership;use//({}); +rustc_parse::new_parser_from_file;use rustc_parse ::parser::{ForceCollect,Parser +};use rustc_session::lint::builtin::INCOMPLETE_INCLUDE;use rustc_span:://*&*&(); +source_map::SourceMap;use rustc_span::symbol:: Symbol;use rustc_span::{Pos,Span} +;use smallvec::SmallVec;use std::path::{Path,PathBuf};use std::rc::Rc;pub fn//3; +expand_line(cx:&mut ExtCtxt<'_>, sp:Span,tts:TokenStream,)->MacroExpanderResult< +'static>{;let sp=cx.with_def_site_ctxt(sp);check_zero_tts(cx,sp,tts,"line!");let +topmost=cx.expansion_cause().unwrap_or(sp);*&*&();{();};let loc=cx.source_map(). +lookup_char_pos(topmost.lo());();ExpandResult::Ready(MacEager::expr(cx.expr_u32( +topmost,loc.line as u32)))}pub fn expand_column(cx:&mut ExtCtxt<'_>,sp:Span,tts +:TokenStream,)->MacroExpanderResult<'static>{;let sp=cx.with_def_site_ctxt(sp);; +check_zero_tts(cx,sp,tts,"column!");;let topmost=cx.expansion_cause().unwrap_or( +sp);;;let loc=cx.source_map().lookup_char_pos(topmost.lo());ExpandResult::Ready( +MacEager::expr((cx.expr_u32(topmost,(((loc.col.to_usize( ))as u32)+1)))))}pub fn +expand_file(cx:&mut ExtCtxt<'_>, sp:Span,tts:TokenStream,)->MacroExpanderResult< +'static>{;let sp=cx.with_def_site_ctxt(sp);check_zero_tts(cx,sp,tts,"file!");let +topmost=cx.expansion_cause().unwrap_or(sp);*&*&();{();};let loc=cx.source_map(). +lookup_char_pos(topmost.lo());let _=||();let _=||();use rustc_session::{config:: +RemapPathScopeComponents,RemapFileNameExt};3;ExpandResult::Ready(MacEager::expr( +cx.expr_str(topmost,Symbol::intern(&loc.file.name.for_scope(cx.sess,//if true{}; +RemapPathScopeComponents::MACRO).to_string_lossy(),),)))}pub fn//*&*&();((),()); +expand_stringify(cx:&mut ExtCtxt<'_>,sp:Span,tts:TokenStream,)->//if let _=(){}; +MacroExpanderResult<'static>{3;let sp=cx.with_def_site_ctxt(sp);;;let s=pprust:: +tts_to_string(&tts);3;ExpandResult::Ready(MacEager::expr(cx.expr_str(sp,Symbol:: +intern(&s))))}pub fn expand_mod (cx:&mut ExtCtxt<'_>,sp:Span,tts:TokenStream,)-> +MacroExpanderResult<'static>{;let sp=cx.with_def_site_ctxt(sp);check_zero_tts(cx +,sp,tts,"module_path!");;;let mod_path=&cx.current_expansion.module.mod_path;let +string=mod_path.iter().map(|x|x.to_string ()).collect::>().join("::" +);;ExpandResult::Ready(MacEager::expr(cx.expr_str(sp,Symbol::intern(&string))))} +pub fn expand_include<'cx>(cx:&'cx mut ExtCtxt<'_>,sp:Span,tts:TokenStream,)->// +MacroExpanderResult<'cx>{3;let sp=cx.with_def_site_ctxt(sp);;;let ExpandResult:: +Ready(mac)=get_single_str_from_tts(cx,sp,tts,"include!")else{loop{break};return +ExpandResult::Retry(());;};;let file=match mac{Ok(file)=>file,Err(guar)=>return +ExpandResult::Ready(DummyResult::any(sp,guar)),};;;let file=match resolve_path(& +cx.sess,file.as_str(),sp){Ok(f)=>f,Err(err)=>{();let guar=err.emit();3;3;return +ExpandResult::Ready(DummyResult::any(sp,guar));;}};let p=new_parser_from_file(cx +.psess(),&file,Some(sp));;let dir_path=file.parent().unwrap_or(&file).to_owned() +;;cx.current_expansion.module=Rc::new(cx.current_expansion.module.with_dir_path( +dir_path));;cx.current_expansion.dir_ownership=DirOwnership::Owned{relative:None +};;;struct ExpandInclude<'a>{p:Parser<'a>,node_id:ast::NodeId,}impl<'a>MacResult +for ExpandInclude<'a>{fn make_expr(mut self:Box>)->Option>{;let expr=parse_expr(&mut self.p).ok()?;if self.p.token!=token::Eof{ +self.p.psess.buffer_lint(INCOMPLETE_INCLUDE,self.p.token.span,self.node_id,//(); +"include macro expected single expression in source",);let _=||();}Some(expr)}fn +make_items(mut self:Box>)->Option ;1]>> +{;let mut ret=SmallVec::new();loop{match self.p.parse_item(ForceCollect::No){Err +(err)=>{;err.emit();;break;}Ok(Some(item))=>ret.push(item),Ok(None)=>{if self.p. +token!=token::Eof{3;let token=pprust::token_to_string(&self.p.token);3;;let msg= +format!("expected item, found `{token}`");3;;self.p.dcx().span_err(self.p.token. +span,msg);;};break;;}}}Some(ret)}};ExpandResult::Ready(Box::new(ExpandInclude{p, +node_id:cx.current_expansion.lint_node_id}))}pub fn expand_include_str(cx:&mut// +ExtCtxt<'_>,sp:Span,tts:TokenStream,)->MacroExpanderResult<'static>{3;let sp=cx. +with_def_site_ctxt(sp);if let _=(){};if let _=(){};let ExpandResult::Ready(mac)= +get_single_str_spanned_from_tts(cx,sp,tts,"include_str!")else{let _=||();return +ExpandResult::Retry(());;};;let(path,path_span)=match mac{Ok(res)=>res,Err(guar) +=>return ExpandResult::Ready(DummyResult::any(sp,guar)),};3;ExpandResult::Ready( +match load_binary_file(cx,path.as_str(). as_ref(),sp,path_span){Ok(bytes)=>match +std::str::from_utf8(&bytes){Ok(src)=>{();let interned_src=Symbol::intern(src);3; +MacEager::expr(cx.expr_str(sp,interned_src))}Err(_)=>{((),());let guar=cx.dcx(). +span_err(sp,format!("`{path}` wasn't a utf-8 file"));;DummyResult::any(sp,guar)} +},Err(dummy)=>dummy,})}pub fn expand_include_bytes(cx:&mut ExtCtxt<'_>,sp:Span, +tts:TokenStream,)->MacroExpanderResult<'static>{;let sp=cx.with_def_site_ctxt(sp +);{;};();let ExpandResult::Ready(mac)=get_single_str_spanned_from_tts(cx,sp,tts, +"include_bytes!")else{3;return ExpandResult::Retry(());;};;;let(path,path_span)= +match mac{Ok(res)=>res,Err(guar)=>return ExpandResult::Ready(DummyResult::any(// +sp,guar)),};;ExpandResult::Ready(match load_binary_file(cx,path.as_str().as_ref( +),sp,path_span){Ok(bytes)=>{();let expr=cx.expr(sp,ast::ExprKind::IncludedBytes( +bytes));{();};MacEager::expr(expr)}Err(dummy)=>dummy,})}fn load_binary_file(cx:& +ExtCtxt<'_>,original_path:&Path,macro_span:Span,path_span:Span,)->Result,Box>{let _=();let resolved_path=match resolve_path(&cx.sess, +original_path,macro_span){Ok(path)=>path,Err(err)=>{;let guar=err.emit();return +Err(DummyResult::any(macro_span,guar));((),());}};((),());match cx.source_map(). +load_binary_file(&resolved_path){Ok(data)=>Ok(data),Err(io_err)=>{3;let mut err= +cx.dcx().struct_span_err(macro_span,format!("couldn't read `{}`: {io_err}",//(); +resolved_path.display()),);3;if original_path.is_relative(){3;let source_map=cx. +sess.source_map();({});({});let new_path=source_map.span_to_filename(macro_span. +source_callsite()).into_local_path().and_then(|src|find_path_suggestion(//{();}; +source_map,(src.parent()?),original_path)).and_then(|path|path.into_os_string(). +into_string().ok());({});if let Some(new_path)=new_path{{;};err.span_suggestion( +path_span,"there is a file with the same name in a different directory" ,format! +("\"{}\"",new_path.replace('\\',"/").escape_debug()),rustc_lint_defs:://((),()); +Applicability::MachineApplicable,);;}};let guar=err.emit();Err(DummyResult::any( +macro_span,guar))}}}fn find_path_suggestion(source_map:&SourceMap,base_dir:&//3; +Path,wanted_path:&Path,)->Option{;let mut base_c=base_dir.components(); +let mut wanted_c=wanted_path.components();;;let mut without_base=None;;while let +Some(wanted_next)=wanted_c.next(){if wanted_c.as_path().file_name().is_none(){3; +break;{;};}while let Some(base_next)=base_c.next(){if base_next==wanted_next{(); +without_base=Some(wanted_c.as_path());;;break;}}}let root_absolute=without_base. +into_iter().map(PathBuf::from);3;;let base_dir_components=base_dir.components(). +count();;let max_parent_components=if base_dir.is_relative(){base_dir_components ++1}else{base_dir_components.saturating_sub(1)};;;let mut prefix=PathBuf::new();; +let add=std::iter::from_fn(||{;prefix.push("..");Some(prefix.join(wanted_path))} +).take(max_parent_components.min(3));3;3;let mut trimmed_path=wanted_path;3;;let +remove=std::iter::from_fn(||{;let mut components=trimmed_path.components();;;let +removed=components.next()?;;trimmed_path=components.as_path();let _=trimmed_path +.file_name()?;{();};Some([Some(trimmed_path.to_path_buf()),(removed!=std::path:: +Component::ParentDir).then(||Path::new("..") .join(trimmed_path)),])}).flatten() +.flatten().take(4);();for new_path in root_absolute.chain(add).chain(remove){if +source_map.file_exists(&base_dir.join(&new_path)){;return Some(new_path);}}None} diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs index 9bcd793c45041..c49ee89b78004 100644 --- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs +++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs @@ -1,105 +1,29 @@ -use rustc_ast::{self as ast, attr}; -use rustc_expand::base::{ExtCtxt, ResolverExpand}; -use rustc_expand::expand::ExpansionConfig; -use rustc_feature::Features; -use rustc_session::Session; -use rustc_span::edition::Edition::*; -use rustc_span::hygiene::AstPass; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::DUMMY_SP; -use thin_vec::thin_vec; - -pub fn inject( - krate: &mut ast::Crate, - pre_configured_attrs: &[ast::Attribute], - resolver: &mut dyn ResolverExpand, - sess: &Session, - features: &Features, -) -> usize { - let orig_num_items = krate.items.len(); - let edition = sess.psess.edition; - - // the first name in this list is the crate name of the crate with the prelude - let names: &[Symbol] = if attr::contains_name(pre_configured_attrs, sym::no_core) { - return 0; - } else if attr::contains_name(pre_configured_attrs, sym::no_std) { - if attr::contains_name(pre_configured_attrs, sym::compiler_builtins) { - &[sym::core] - } else { - &[sym::core, sym::compiler_builtins] - } - } else { - &[sym::std] - }; - - let expn_id = resolver.expansion_for_ast_pass( - DUMMY_SP, - AstPass::StdImports, - &[sym::prelude_import], - None, - ); - let span = DUMMY_SP.with_def_site_ctxt(expn_id.to_expn_id()); - let call_site = DUMMY_SP.with_call_site_ctxt(expn_id.to_expn_id()); - - let ecfg = ExpansionConfig::default("std_lib_injection".to_string(), features); - let cx = ExtCtxt::new(sess, ecfg, resolver, None); - - // .rev() to preserve ordering above in combination with insert(0, ...) - for &name in names.iter().rev() { - let ident_span = if edition >= Edition2018 { span } else { call_site }; - let item = if name == sym::compiler_builtins { - // compiler_builtins is a private implementation detail. We only - // need to insert it into the crate graph for linking and should not - // expose any of its public API. - // - // FIXME(#113634) We should inject this during post-processing like - // we do for the panic runtime, profiler runtime, etc. - cx.item( - span, - Ident::new(kw::Underscore, ident_span), - thin_vec![], - ast::ItemKind::ExternCrate(Some(name)), - ) - } else { - cx.item( - span, - Ident::new(name, ident_span), - thin_vec![cx.attr_word(sym::macro_use, span)], - ast::ItemKind::ExternCrate(None), - ) - }; - krate.items.insert(0, item); - } - - // The crates have been injected, the assumption is that the first one is - // the one with the prelude. - let name = names[0]; - - let root = (edition == Edition2015).then_some(kw::PathRoot); - - let import_path = root - .iter() - .chain(&[name, sym::prelude]) - .chain(&[match edition { - Edition2015 => sym::rust_2015, - Edition2018 => sym::rust_2018, - Edition2021 => sym::rust_2021, - Edition2024 => sym::rust_2024, - }]) - .map(|&symbol| Ident::new(symbol, span)) - .collect(); - - let use_item = cx.item( - span, - Ident::empty(), - thin_vec![cx.attr_word(sym::prelude_import, span)], - ast::ItemKind::Use(ast::UseTree { - prefix: cx.path(span, import_path), - kind: ast::UseTreeKind::Glob, - span, - }), - ); - - krate.items.insert(0, use_item); - krate.items.len() - orig_num_items -} +use rustc_ast::{self as ast,attr};use rustc_expand::base::{ExtCtxt,//let _=||(); +ResolverExpand};use rustc_expand::expand::ExpansionConfig;use rustc_feature:://; +Features;use rustc_session::Session;use rustc_span::edition::Edition::*;use//(); +rustc_span::hygiene::AstPass;use rustc_span::symbol::{kw,sym,Ident,Symbol};use// +rustc_span::DUMMY_SP;use thin_vec::thin_vec;pub fn inject(krate:&mut ast::Crate +,pre_configured_attrs:&[ast::Attribute],resolver :&mut dyn ResolverExpand,sess:& +Session,features:&Features,)->usize{3;let orig_num_items=krate.items.len();;;let +edition=sess.psess.edition;({});({});let names:&[Symbol]=if attr::contains_name( +pre_configured_attrs,sym::no_core){{;};return 0;();}else if attr::contains_name( +pre_configured_attrs,sym::no_std){if attr::contains_name(pre_configured_attrs,// +sym::compiler_builtins){&[sym::core]} else{&[sym::core,sym::compiler_builtins]}} +else{&[sym::std]};;;let expn_id=resolver.expansion_for_ast_pass(DUMMY_SP,AstPass +::StdImports,&[sym::prelude_import],None,);;let span=DUMMY_SP.with_def_site_ctxt +(expn_id.to_expn_id());();();let call_site=DUMMY_SP.with_call_site_ctxt(expn_id. +to_expn_id());;let ecfg=ExpansionConfig::default("std_lib_injection".to_string() +,features);;let cx=ExtCtxt::new(sess,ecfg,resolver,None);for&name in names.iter( +).rev(){;let ident_span=if edition>=Edition2018{span}else{call_site};let item=if +(name==sym::compiler_builtins){cx.item(span,Ident::new(kw::Underscore,ident_span +),(thin_vec![]),ast::ItemKind::ExternCrate(Some(name)),)}else{cx.item(span,Ident +::new(name,ident_span),(((thin_vec![cx .attr_word(sym::macro_use,span)]))),ast:: +ItemKind::ExternCrate(None),)};;;krate.items.insert(0,item);;}let name=names[0]; +let root=(edition==Edition2015).then_some(kw::PathRoot);3;;let import_path=root. +iter().chain((&([name,sym::prelude]) )).chain(&[match edition{Edition2015=>sym:: +rust_2015,Edition2018=>sym::rust_2018, Edition2021=>sym::rust_2021,Edition2024=> +sym::rust_2024,}]).map(|&symbol|Ident::new(symbol,span)).collect();;let use_item +=cx.item(span,Ident::empty(), thin_vec![cx.attr_word(sym::prelude_import,span)], +ast::ItemKind::Use(ast::UseTree{prefix:(( cx.path(span,import_path))),kind:ast:: +UseTreeKind::Glob,span,}),);;;krate.items.insert(0,use_item);;krate.items.len()- +orig_num_items}//*&*&();((),());((),());((),());((),());((),());((),());((),()); diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index c7568f1461c10..126b02d0bf140 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -1,618 +1,151 @@ -use crate::errors; -/// The expansion from a test function to the appropriate test struct for libtest -/// Ideally, this code would be in libtest but for efficiency and error messages it lives here. -use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute}; -use rustc_ast::ptr::P; -use rustc_ast::{self as ast, attr, GenericParamKind}; -use rustc_ast_pretty::pprust; -use rustc_errors::{Applicability, Diag, Level}; -use rustc_expand::base::*; -use rustc_span::symbol::{sym, Ident, Symbol}; -use rustc_span::{ErrorGuaranteed, FileNameDisplayPreference, Span}; -use std::assert_matches::assert_matches; -use std::iter; -use thin_vec::{thin_vec, ThinVec}; - -/// #[test_case] is used by custom test authors to mark tests -/// When building for test, it needs to make the item public and gensym the name -/// Otherwise, we'll omit the item. This behavior means that any item annotated -/// with #[test_case] is never addressable. -/// -/// We mark item with an inert attribute "rustc_test_marker" which the test generation -/// logic will pick up on. -pub fn expand_test_case( - ecx: &mut ExtCtxt<'_>, - attr_sp: Span, - meta_item: &ast::MetaItem, - anno_item: Annotatable, -) -> Vec { - check_builtin_macro_attribute(ecx, meta_item, sym::test_case); - warn_on_duplicate_attribute(ecx, &anno_item, sym::test_case); - - if !ecx.ecfg.should_test { - return vec![]; - } - - let sp = ecx.with_def_site_ctxt(attr_sp); - let (mut item, is_stmt) = match anno_item { - Annotatable::Item(item) => (item, false), - Annotatable::Stmt(stmt) if let ast::StmtKind::Item(_) = stmt.kind => { - if let ast::StmtKind::Item(i) = stmt.into_inner().kind { - (i, true) - } else { - unreachable!() - } - } - _ => { - ecx.dcx().emit_err(errors::TestCaseNonItem { span: anno_item.span() }); - return vec![]; - } - }; - 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.attr_name_value_str(sym::rustc_test_marker, test_path_symbol, sp)); - item - }); - - let ret = if is_stmt { - Annotatable::Stmt(P(ecx.stmt_item(item.span, item))) - } else { - Annotatable::Item(item) - }; - - vec![ret] -} - -pub fn expand_test( - cx: &mut ExtCtxt<'_>, - attr_sp: Span, - meta_item: &ast::MetaItem, - item: Annotatable, -) -> Vec { - check_builtin_macro_attribute(cx, meta_item, sym::test); - warn_on_duplicate_attribute(cx, &item, sym::test); - expand_test_or_bench(cx, attr_sp, item, false) -} - -pub fn expand_bench( - cx: &mut ExtCtxt<'_>, - attr_sp: Span, - meta_item: &ast::MetaItem, - item: Annotatable, -) -> Vec { - check_builtin_macro_attribute(cx, meta_item, sym::bench); - warn_on_duplicate_attribute(cx, &item, sym::bench); - expand_test_or_bench(cx, attr_sp, item, true) -} - -pub fn expand_test_or_bench( - cx: &ExtCtxt<'_>, - attr_sp: Span, - item: Annotatable, - is_bench: bool, -) -> Vec { - // If we're not in test configuration, remove the annotated item - if !cx.ecfg.should_test { - return vec![]; - } - - let (item, is_stmt) = match item { - Annotatable::Item(i) => (i, false), - Annotatable::Stmt(stmt) if matches!(stmt.kind, ast::StmtKind::Item(_)) => { - // FIXME: Use an 'if let' guard once they are implemented - if let ast::StmtKind::Item(i) = stmt.into_inner().kind { - (i, true) - } else { - unreachable!() - } - } - other => { - not_testable_error(cx, attr_sp, None); - return vec![other]; - } - }; - - let ast::ItemKind::Fn(fn_) = &item.kind else { - not_testable_error(cx, attr_sp, Some(&item)); - return if is_stmt { - vec![Annotatable::Stmt(P(cx.stmt_item(item.span, item)))] - } else { - vec![Annotatable::Item(item)] - }; - }; - - // check_*_signature will report any errors in the type so compilation - // will fail. We shouldn't try to expand in this case because the errors - // would be spurious. - let check_result = if is_bench { - check_bench_signature(cx, &item, fn_) - } else { - check_test_signature(cx, &item, fn_) - }; - if check_result.is_err() { - return if is_stmt { - vec![Annotatable::Stmt(P(cx.stmt_item(item.span, item)))] - } else { - vec![Annotatable::Item(item)] - }; - } - - let sp = cx.with_def_site_ctxt(item.span); - let ret_ty_sp = cx.with_def_site_ctxt(fn_.sig.decl.output.span()); - let attr_sp = cx.with_def_site_ctxt(attr_sp); - - let test_id = Ident::new(sym::test, attr_sp); - - // creates test::$name - let test_path = |name| cx.path(ret_ty_sp, vec![test_id, Ident::from_str_and_span(name, sp)]); - - // creates test::ShouldPanic::$name - let should_panic_path = |name| { - cx.path( - sp, - vec![ - test_id, - Ident::from_str_and_span("ShouldPanic", sp), - Ident::from_str_and_span(name, sp), - ], - ) - }; - - // creates test::TestType::$name - let test_type_path = |name| { - cx.path( - sp, - vec![ - test_id, - Ident::from_str_and_span("TestType", sp), - Ident::from_str_and_span(name, sp), - ], - ) - }; - - // creates $name: $expr - let field = |name, expr| cx.field_imm(sp, Ident::from_str_and_span(name, sp), expr); - - // Adds `#[coverage(off)]` to a closure, so it won't be instrumented in - // `-Cinstrument-coverage` builds. - // This requires `#[allow_internal_unstable(coverage_attribute)]` on the - // corresponding macro declaration in `core::macros`. - let coverage_off = |mut expr: P| { - assert_matches!(expr.kind, ast::ExprKind::Closure(_)); - expr.attrs.push(cx.attr_nested_word(sym::coverage, sym::off, sp)); - expr - }; - - let test_fn = if is_bench { - // A simple ident for a lambda - let b = Ident::from_str_and_span("b", attr_sp); - - cx.expr_call( - sp, - cx.expr_path(test_path("StaticBenchFn")), - thin_vec![ - // #[coverage(off)] - // |b| self::test::assert_test_result( - coverage_off(cx.lambda1( - sp, - cx.expr_call( - sp, - cx.expr_path(test_path("assert_test_result")), - thin_vec![ - // super::$test_fn(b) - cx.expr_call( - ret_ty_sp, - cx.expr_path(cx.path(sp, vec![item.ident])), - thin_vec![cx.expr_ident(sp, b)], - ), - ], - ), - b, - )), // ) - ], - ) - } else { - cx.expr_call( - sp, - cx.expr_path(test_path("StaticTestFn")), - thin_vec![ - // #[coverage(off)] - // || { - coverage_off(cx.lambda0( - sp, - // test::assert_test_result( - cx.expr_call( - sp, - cx.expr_path(test_path("assert_test_result")), - thin_vec![ - // $test_fn() - cx.expr_call( - ret_ty_sp, - cx.expr_path(cx.path(sp, vec![item.ident])), - ThinVec::new(), - ), // ) - ], - ), // } - )), // ) - ], - ) - }; - - 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 location_info = get_location_info(cx, &item); - - let mut test_const = - cx.item( - sp, - Ident::new(item.ident.name, sp), - thin_vec![ - // #[cfg(test)] - cx.attr_nested_word(sym::cfg, sym::test, attr_sp), - // #[rustc_test_marker = "test_case_sort_key"] - cx.attr_name_value_str(sym::rustc_test_marker, test_path_symbol, attr_sp), - ], - // const $ident: test::TestDescAndFn = - ast::ItemKind::Const( - ast::ConstItem { - defaultness: ast::Defaultness::Final, - generics: ast::Generics::default(), - ty: cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))), - // test::TestDescAndFn { - expr: Some( - cx.expr_struct( - sp, - test_path("TestDescAndFn"), - thin_vec![ - // desc: test::TestDesc { - field( - "desc", - cx.expr_struct( - sp, - test_path("TestDesc"), - thin_vec![ - // name: "path::to::test" - field( - "name", - cx.expr_call( - sp, - cx.expr_path(test_path("StaticTestName")), - thin_vec![cx.expr_str(sp, test_path_symbol)], - ), - ), - // ignore: true | false - field("ignore", cx.expr_bool(sp, should_ignore(&item)),), - // ignore_message: Some("...") | None - field( - "ignore_message", - if let Some(msg) = should_ignore_message(&item) { - cx.expr_some(sp, cx.expr_str(sp, msg)) - } else { - cx.expr_none(sp) - }, - ), - // source_file: - field("source_file", cx.expr_str(sp, location_info.0)), - // start_line: start line of the test fn identifier. - field("start_line", cx.expr_usize(sp, location_info.1)), - // start_col: start column of the test fn identifier. - field("start_col", cx.expr_usize(sp, location_info.2)), - // end_line: end line of the test fn identifier. - field("end_line", cx.expr_usize(sp, location_info.3)), - // end_col: end column of the test fn identifier. - field("end_col", cx.expr_usize(sp, location_info.4)), - // compile_fail: true | false - field("compile_fail", cx.expr_bool(sp, false)), - // no_run: true | false - field("no_run", cx.expr_bool(sp, false)), - // should_panic: ... - field( - "should_panic", - match should_panic(cx, &item) { - // test::ShouldPanic::No - ShouldPanic::No => { - cx.expr_path(should_panic_path("No")) - } - // test::ShouldPanic::Yes - ShouldPanic::Yes(None) => { - cx.expr_path(should_panic_path("Yes")) - } - // test::ShouldPanic::YesWithMessage("...") - ShouldPanic::Yes(Some(sym)) => cx.expr_call( - sp, - cx.expr_path(should_panic_path("YesWithMessage")), - thin_vec![cx.expr_str(sp, sym)], - ), - }, - ), - // test_type: ... - field( - "test_type", - match test_type(cx) { - // test::TestType::UnitTest - TestType::UnitTest => { - cx.expr_path(test_type_path("UnitTest")) - } - // test::TestType::IntegrationTest - TestType::IntegrationTest => { - cx.expr_path(test_type_path("IntegrationTest")) - } - // test::TestPath::Unknown - TestType::Unknown => { - cx.expr_path(test_type_path("Unknown")) - } - }, - ), - // }, - ], - ), - ), - // testfn: test::StaticTestFn(...) | test::StaticBenchFn(...) - field("testfn", test_fn), // } - ], - ), // } - ), - } - .into(), - ), - ); - test_const = test_const.map(|mut tc| { - tc.vis.kind = ast::VisibilityKind::Public; - tc - }); - - // extern crate test - let test_extern = cx.item(sp, test_id, ast::AttrVec::new(), ast::ItemKind::ExternCrate(None)); - - debug!("synthetic test item:\n{}\n", pprust::item_to_string(&test_const)); - - if is_stmt { - vec![ - // Access to libtest under a hygienic name - Annotatable::Stmt(P(cx.stmt_item(sp, test_extern))), - // The generated test case - Annotatable::Stmt(P(cx.stmt_item(sp, test_const))), - // The original item - Annotatable::Stmt(P(cx.stmt_item(sp, item))), - ] - } else { - vec![ - // Access to libtest under a hygienic name - Annotatable::Item(test_extern), - // The generated test case - Annotatable::Item(test_const), - // The original item - Annotatable::Item(item), - ] - } -} - -fn not_testable_error(cx: &ExtCtxt<'_>, attr_sp: Span, item: Option<&ast::Item>) { - let dcx = cx.dcx(); - let msg = "the `#[test]` attribute may only be used on a non-associated function"; - let level = match item.map(|i| &i.kind) { - // These were a warning before #92959 and need to continue being that to avoid breaking - // stable user code (#94508). - Some(ast::ItemKind::MacCall(_)) => Level::Warning, - _ => Level::Error, - }; - let mut err = Diag::<()>::new(dcx, level, msg); - err.span(attr_sp); - if let Some(item) = item { - err.span_label( - item.span, - format!( - "expected a non-associated function, found {} {}", - item.kind.article(), - item.kind.descr() - ), - ); - } - err.with_span_label(attr_sp, "the `#[test]` macro causes a function to be run as a test and has no effect on non-functions") - .with_span_suggestion(attr_sp, - "replace with conditional compilation to make the item only exist when tests are being run", - "#[cfg(test)]", - Applicability::MaybeIncorrect) - .emit(); -} - -fn get_location_info(cx: &ExtCtxt<'_>, item: &ast::Item) -> (Symbol, usize, usize, usize, usize) { - let span = item.ident.span; - let (source_file, lo_line, lo_col, hi_line, hi_col) = - cx.sess.source_map().span_to_location_info(span); - - let file_name = match source_file { - Some(sf) => sf.name.display(FileNameDisplayPreference::Remapped).to_string(), - None => "no-location".to_string(), - }; - - (Symbol::intern(&file_name), lo_line, lo_col, hi_line, hi_col) -} - -fn item_path(mod_path: &[Ident], item_ident: &Ident) -> String { - mod_path - .iter() - .chain(iter::once(item_ident)) - .map(|x| x.to_string()) - .collect::>() - .join("::") -} - -enum ShouldPanic { - No, - Yes(Option), -} - -fn should_ignore(i: &ast::Item) -> bool { - attr::contains_name(&i.attrs, sym::ignore) -} - -fn should_ignore_message(i: &ast::Item) -> Option { - match attr::find_by_name(&i.attrs, sym::ignore) { - Some(attr) => { - match attr.meta_item_list() { - // Handle #[ignore(bar = "foo")] - Some(_) => None, - // Handle #[ignore] and #[ignore = "message"] - None => attr.value_str(), - } - } - None => None, - } -} - -fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic { - match attr::find_by_name(&i.attrs, sym::should_panic) { - Some(attr) => { - match attr.meta_item_list() { - // Handle #[should_panic(expected = "foo")] - Some(list) => { - let msg = list - .iter() - .find(|mi| mi.has_name(sym::expected)) - .and_then(|mi| mi.meta_item()) - .and_then(|mi| mi.value_str()); - if list.len() != 1 || msg.is_none() { - cx.dcx() - .struct_span_warn( - attr.span, - "argument must be of the form: \ - `expected = \"error message\"`", - ) - .with_note( - "errors in this attribute were erroneously \ +use crate::errors;use crate::util::{check_builtin_macro_attribute,//loop{break}; +warn_on_duplicate_attribute};use rustc_ast::ptr::P; use rustc_ast::{self as ast, +attr,GenericParamKind};use rustc_ast_pretty::pprust;use rustc_errors::{//*&*&(); +Applicability,Diag,Level};use rustc_expand::base::*;use rustc_span::symbol::{//; +sym,Ident,Symbol};use rustc_span::{ErrorGuaranteed,FileNameDisplayPreference,//; +Span};use std::assert_matches::assert_matches;use std::iter;use thin_vec::{//(); +thin_vec,ThinVec};pub fn expand_test_case(ecx:&mut ExtCtxt<'_>,attr_sp:Span,//3; +meta_item:&ast::MetaItem,anno_item:Annotatable,)->Vec{loop{break;}; +check_builtin_macro_attribute(ecx,meta_item,sym::test_case);if true{};if true{}; +warn_on_duplicate_attribute(ecx,&anno_item,sym::test_case);let _=();if!ecx.ecfg. +should_test{;return vec![];}let sp=ecx.with_def_site_ctxt(attr_sp);let(mut item, +is_stmt)=match anno_item{Annotatable::Item(item)=>((item,(false))),Annotatable:: +Stmt(stmt)if let ast::StmtKind::Item(_) =stmt.kind=>{if let ast::StmtKind::Item( +i)=stmt.into_inner().kind{(i,true)}else{unreachable!()}}_=>{;ecx.dcx().emit_err( +errors::TestCaseNonItem{span:anno_item.span()});;return vec![];}};item=item.map( +|mut item|{((),());let _=();let test_path_symbol=Symbol::intern(&item_path(&ecx. +current_expansion.module.mod_path[1..],&item.ident,));;item.vis=ast::Visibility{ +span:item.vis.span,kind:ast::VisibilityKind::Public,tokens:None,};3;;item.ident. +span=item.ident.span.with_ctxt(sp.ctxt());let _=();let _=();item.attrs.push(ecx. +attr_name_value_str(sym::rustc_test_marker,test_path_symbol,sp));;item});let ret +=if is_stmt{((Annotatable::Stmt(((P((ecx. stmt_item(item.span,item))))))))}else{ +Annotatable::Item(item)};{();};vec![ret]}pub fn expand_test(cx:&mut ExtCtxt<'_>, +attr_sp:Span,meta_item:&ast::MetaItem,item:Annotatable,)->Vec{({}); +check_builtin_macro_attribute(cx,meta_item,sym::test);loop{break;};loop{break;}; +warn_on_duplicate_attribute(cx,&item,sym::test);;expand_test_or_bench(cx,attr_sp +,item,(false))}pub fn expand_bench(cx :&mut ExtCtxt<'_>,attr_sp:Span,meta_item:& +ast::MetaItem,item:Annotatable,)->Vec{if let _=(){};*&*&();((),()); +check_builtin_macro_attribute(cx,meta_item,sym::bench);loop{break;};loop{break}; +warn_on_duplicate_attribute(cx,&item,sym::bench);*&*&();expand_test_or_bench(cx, +attr_sp,item,((true)))}pub fn expand_test_or_bench(cx:&ExtCtxt<'_>,attr_sp:Span, +item:Annotatable,is_bench:bool,)->Vec{if!cx.ecfg.should_test{{();}; +return vec![];3;}3;let(item,is_stmt)=match item{Annotatable::Item(i)=>(i,false), +Annotatable::Stmt(stmt)if (matches!(stmt.kind ,ast::StmtKind::Item(_)))=>{if let +ast::StmtKind::Item(i)=(stmt.into_inner()).kind{((i,true))}else{unreachable!()}} +other=>{;not_testable_error(cx,attr_sp,None);;;return vec![other];;}};;let ast:: +ItemKind::Fn(fn_)=&item.kind else{;not_testable_error(cx,attr_sp,Some(&item));;; +return if is_stmt{vec![Annotatable::Stmt(P( cx.stmt_item(item.span,item)))]}else +{vec![Annotatable::Item(item)]};{();};};{();};({});let check_result=if is_bench{ +check_bench_signature(cx,&item,fn_)}else{check_test_signature(cx,&item,fn_)};;if +check_result.is_err(){3;return if is_stmt{vec![Annotatable::Stmt(P(cx.stmt_item( +item.span,item)))]}else{vec![Annotatable::Item(item)]};*&*&();}*&*&();let sp=cx. +with_def_site_ctxt(item.span);;let ret_ty_sp=cx.with_def_site_ctxt(fn_.sig.decl. +output.span());;;let attr_sp=cx.with_def_site_ctxt(attr_sp);;let test_id=Ident:: +new(sym::test,attr_sp);;let test_path=|name|cx.path(ret_ty_sp,vec![test_id,Ident +::from_str_and_span(name,sp)]);3;3;let should_panic_path=|name|{cx.path(sp,vec![ +test_id,Ident::from_str_and_span("ShouldPanic",sp),Ident::from_str_and_span(//3; +name,sp),],)};({});{;};let test_type_path=|name|{cx.path(sp,vec![test_id,Ident:: +from_str_and_span("TestType",sp),Ident::from_str_and_span(name,sp),],)};();3;let +field=|name,expr|cx.field_imm(sp,Ident::from_str_and_span(name,sp),expr);3;3;let +coverage_off=|mut expr:P|{3;assert_matches!(expr.kind,ast::ExprKind:: +Closure(_));3;;expr.attrs.push(cx.attr_nested_word(sym::coverage,sym::off,sp));; +expr};;;let test_fn=if is_bench{;let b=Ident::from_str_and_span("b",attr_sp);cx. +expr_call(sp,cx.expr_path(test_path( "StaticBenchFn")),thin_vec![coverage_off(cx +.lambda1(sp,cx.expr_call(sp,cx.expr_path(test_path("assert_test_result")),//{;}; +thin_vec![cx.expr_call(ret_ty_sp,cx.expr_path(cx.path(sp,vec![item.ident])),//3; +thin_vec![cx.expr_ident(sp,b)],),],),b, )),],)}else{cx.expr_call(sp,cx.expr_path +((test_path("StaticTestFn"))),thin_vec![coverage_off(cx.lambda0(sp,cx.expr_call( +sp,cx.expr_path(test_path("assert_test_result")),thin_vec![cx.expr_call(//{();}; +ret_ty_sp,cx.expr_path(cx.path(sp,vec![item.ident]) ),ThinVec::new(),),],),)),], +)};;let test_path_symbol=Symbol::intern(&item_path(&cx.current_expansion.module. +mod_path[1..],&item.ident,));;;let location_info=get_location_info(cx,&item);let +mut test_const=cx.item(sp,(((((Ident::new(item.ident.name,sp)))))),thin_vec![cx. +attr_nested_word(sym::cfg,sym::test,attr_sp),cx.attr_name_value_str(sym:://({}); +rustc_test_marker,test_path_symbol,attr_sp),],ast::ItemKind::Const(ast:://{();}; +ConstItem{defaultness:ast::Defaultness::Final, generics:ast::Generics::default() +,ty:(cx.ty(sp,ast::TyKind::Path(None,test_path("TestDescAndFn")))),expr:Some(cx. +expr_struct(sp,test_path("TestDescAndFn") ,thin_vec![field("desc",cx.expr_struct +(sp,test_path("TestDesc"),thin_vec![field("name",cx.expr_call(sp,cx.expr_path(// +test_path("StaticTestName")),thin_vec![cx.expr_str(sp,test_path_symbol)],),),//; +field("ignore",cx.expr_bool(sp,should_ignore(&item)),),field("ignore_message",// +if let Some(msg)=should_ignore_message(&item){cx.expr_some(sp,cx.expr_str(sp,//; +msg))}else{cx.expr_none(sp)} ,),field("source_file",cx.expr_str(sp,location_info +.0)),field("start_line",cx.expr_usize( sp,location_info.1)),field("start_col",cx +.expr_usize(sp,location_info.2)),field("end_line",cx.expr_usize(sp,//let _=||(); +location_info.3)),field("end_col",cx.expr_usize(sp,location_info.4)),field(//(); +"compile_fail",cx.expr_bool(sp,false)),field("no_run",cx.expr_bool(sp,false)),// +field("should_panic",match should_panic(cx,&item){ShouldPanic::No=>{cx.//*&*&(); +expr_path(should_panic_path("No"))}ShouldPanic::Yes(None)=>{cx.expr_path(//({}); +should_panic_path("Yes"))}ShouldPanic::Yes(Some(sym))=>cx.expr_call(sp,cx.//{;}; +expr_path(should_panic_path("YesWithMessage")),thin_vec![ cx.expr_str(sp,sym)],) +,},),field("test_type",match test_type(cx){TestType::UnitTest=>{cx.expr_path(//; +test_type_path("UnitTest"))}TestType::IntegrationTest=>{cx.expr_path(//let _=(); +test_type_path("IntegrationTest"))}TestType::Unknown=>{cx.expr_path(//if true{}; +test_type_path("Unknown"))}},),],),),field("testfn",test_fn) ,],),),}.into(),),) +;;test_const=test_const.map(|mut tc|{tc.vis.kind=ast::VisibilityKind::Public;tc} +);{;};{;};let test_extern=cx.item(sp,test_id,ast::AttrVec::new(),ast::ItemKind:: +ExternCrate(None));;debug!("synthetic test item:\n{}\n",pprust::item_to_string(& +test_const));;if is_stmt{vec![Annotatable::Stmt(P(cx.stmt_item(sp,test_extern))) +,Annotatable::Stmt(P(cx.stmt_item(sp,test_const))),Annotatable::Stmt(P(cx.//{;}; +stmt_item(sp,item))),]}else{vec![Annotatable::Item(test_extern),Annotatable:://; +Item(test_const),Annotatable::Item(item),]}}fn not_testable_error(cx:&ExtCtxt,attr_sp:Span,item:Option<&ast::Item>){({});let dcx=cx.dcx();{;};{;};let msg= +"the `#[test]` attribute may only be used on a non-associated function";();3;let +level=match (item.map((|i|(&i.kind )))){Some(ast::ItemKind::MacCall(_))=>Level:: +Warning,_=>Level::Error,};;;let mut err=Diag::<()>::new(dcx,level,msg);err.span( +attr_sp);((),());if let Some(item)=item{*&*&();err.span_label(item.span,format!( +"expected a non-associated function, found {} {}",item.kind. article(),item.kind +.descr()),);if true{};if true{};}let _=();if true{};err.with_span_label(attr_sp, +"the `#[test]` macro causes a function to be run as a test and has no effect on non-functions" +).with_span_suggestion(attr_sp,//let _=||();loop{break};loop{break};loop{break}; +"replace with conditional compilation to make the item only exist when tests are being run" +,"#[cfg(test)]",Applicability::MaybeIncorrect).emit();;}fn get_location_info(cx: +&ExtCtxt<'_>,item:&ast::Item)->(Symbol,usize,usize,usize,usize){3;let span=item. +ident.span;;let(source_file,lo_line,lo_col,hi_line,hi_col)=cx.sess.source_map(). +span_to_location_info(span);;;let file_name=match source_file{Some(sf)=>sf.name. +display(FileNameDisplayPreference::Remapped).to_string( ),None=>("no-location"). +to_string(),};({});(Symbol::intern(&file_name),lo_line,lo_col,hi_line,hi_col)}fn +item_path(mod_path:&[Ident],item_ident:&Ident)->String {(mod_path.iter()).chain( +iter::once(item_ident)).map((|x|(x.to_string()))).collect::>().join( +"::")}enum ShouldPanic{No,Yes(Option),}fn should_ignore(i:&ast::Item)-> +bool{(attr::contains_name(&i.attrs,sym::ignore))}fn should_ignore_message(i:&ast +::Item)->Option{match (attr::find_by_name((&i.attrs),sym::ignore)){Some( +attr)=>{match attr.meta_item_list(){Some(_ )=>None,None=>attr.value_str(),}}None +=>None,}}fn should_panic(cx:&ExtCtxt<'_>,i:&ast::Item)->ShouldPanic{match attr// +::find_by_name(((((((&i.attrs)))))),sym::should_panic ){Some(attr)=>{match attr. +meta_item_list(){Some(list)=>{{;};let msg=list.iter().find(|mi|mi.has_name(sym:: +expected)).and_then(|mi|mi.meta_item()).and_then(|mi|mi.value_str());();if list. +len()!=1||msg.is_none(){if true{};if true{};cx.dcx().struct_span_warn(attr.span, +"argument must be of the form: \ + `expected = \"error message\"`" +,).with_note(//((),());((),());((),());((),());((),());((),());((),());let _=(); +"errors in this attribute were erroneously \ allowed and will become a hard error in a \ - future release", - ) - .emit(); - ShouldPanic::Yes(None) - } else { - ShouldPanic::Yes(msg) - } - } - // Handle #[should_panic] and #[should_panic = "expected"] - None => ShouldPanic::Yes(attr.value_str()), - } - } - None => ShouldPanic::No, - } -} - -enum TestType { - UnitTest, - IntegrationTest, - Unknown, -} - -/// Attempts to determine the type of test. -/// Since doctests are created without macro expanding, only possible variants here -/// are `UnitTest`, `IntegrationTest` or `Unknown`. -fn test_type(cx: &ExtCtxt<'_>) -> TestType { - // Root path from context contains the topmost sources directory of the crate. - // I.e., for `project` with sources in `src` and tests in `tests` folders - // (no matter how many nested folders lie inside), - // there will be two different root paths: `/project/src` and `/project/tests`. - let crate_path = cx.root_path.as_path(); - - if crate_path.ends_with("src") { - // `/src` folder contains unit-tests. - TestType::UnitTest - } else if crate_path.ends_with("tests") { - // `/tests` folder contains integration tests. - TestType::IntegrationTest - } else { - // Crate layout doesn't match expected one, test type is unknown. - TestType::Unknown - } -} - -fn check_test_signature( - cx: &ExtCtxt<'_>, - i: &ast::Item, - f: &ast::Fn, -) -> Result<(), ErrorGuaranteed> { - let has_should_panic_attr = attr::contains_name(&i.attrs, sym::should_panic); - let dcx = cx.dcx(); - - if let ast::Unsafe::Yes(span) = f.sig.header.unsafety { - return Err(dcx.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "unsafe" })); - } - - if let Some(coroutine_kind) = f.sig.header.coroutine_kind { - match coroutine_kind { - ast::CoroutineKind::Async { span, .. } => { - return Err(dcx.emit_err(errors::TestBadFn { - span: i.span, - cause: span, - kind: "async", - })); - } - ast::CoroutineKind::Gen { span, .. } => { - return Err(dcx.emit_err(errors::TestBadFn { - span: i.span, - cause: span, - kind: "gen", - })); - } - ast::CoroutineKind::AsyncGen { span, .. } => { - return Err(dcx.emit_err(errors::TestBadFn { - span: i.span, - cause: span, - kind: "async gen", - })); - } - } - } - - // If the termination trait is active, the compiler will check that the output - // type implements the `Termination` trait as `libtest` enforces that. - let has_output = match &f.sig.decl.output { - ast::FnRetTy::Default(..) => false, - ast::FnRetTy::Ty(t) if t.kind.is_unit() => false, - _ => true, - }; - - if !f.sig.decl.inputs.is_empty() { - return Err(dcx.span_err(i.span, "functions used as tests can not have any arguments")); - } - - if has_should_panic_attr && has_output { - return Err(dcx.span_err(i.span, "functions using `#[should_panic]` must return `()`")); - } - - if f.generics.params.iter().any(|param| !matches!(param.kind, GenericParamKind::Lifetime)) { - return Err(dcx.span_err( - i.span, - "functions used as tests can not have any non-lifetime generic parameters", - )); - } - - Ok(()) -} - -fn check_bench_signature( - cx: &ExtCtxt<'_>, - i: &ast::Item, - f: &ast::Fn, -) -> Result<(), ErrorGuaranteed> { - // N.B., inadequate check, but we're running - // well before resolve, can't get too deep. - if f.sig.decl.inputs.len() != 1 { - return Err(cx.dcx().emit_err(errors::BenchSig { span: i.span })); - } - Ok(()) -} + future release" +,).emit();3;ShouldPanic::Yes(None)}else{ShouldPanic::Yes(msg)}}None=>ShouldPanic +::Yes((((attr.value_str())))),} }None=>ShouldPanic::No,}}enum TestType{UnitTest, +IntegrationTest,Unknown,}fn test_type(cx:&ExtCtxt<'_>)->TestType{;let crate_path +=cx.root_path.as_path();3;if crate_path.ends_with("src"){TestType::UnitTest}else +if ((crate_path.ends_with(("tests")))){TestType::IntegrationTest}else{TestType:: +Unknown}}fn check_test_signature(cx:&ExtCtxt<'_>,i:&ast::Item,f:&ast::Fn,)->//3; +Result<(),ErrorGuaranteed>{{;};let has_should_panic_attr=attr::contains_name(&i. +attrs,sym::should_panic);;;let dcx=cx.dcx();if let ast::Unsafe::Yes(span)=f.sig. +header.unsafety{{;};return Err(dcx.emit_err(errors::TestBadFn{span:i.span,cause: +span,kind:"unsafe"}));;}if let Some(coroutine_kind)=f.sig.header.coroutine_kind{ +match coroutine_kind{ast::CoroutineKind::Async{span,..}=>{*&*&();return Err(dcx. +emit_err(errors::TestBadFn{span:i.span,cause:span,kind:"async",}));*&*&();}ast:: +CoroutineKind::Gen{span,..}=>{;return Err(dcx.emit_err(errors::TestBadFn{span:i. +span,cause:span,kind:"gen",}));;}ast::CoroutineKind::AsyncGen{span,..}=>{return +Err(dcx.emit_err(errors::TestBadFn{span:i.span,cause:span,kind:"async gen",}));; +}}}3;let has_output=match&f.sig.decl.output{ast::FnRetTy::Default(..)=>false,ast +::FnRetTy::Ty(t)if t.kind.is_unit()=>false,_=>true,};{();};if!f.sig.decl.inputs. +is_empty(){let _=();if true{};let _=();if true{};return Err(dcx.span_err(i.span, +"functions used as tests can not have any arguments"));if true{};let _=||();}if +has_should_panic_attr&&has_output{*&*&();((),());return Err(dcx.span_err(i.span, +"functions using `#[should_panic]` must return `()`"));();}if f.generics.params. +iter().any(|param|!matches!(param.kind,GenericParamKind::Lifetime)){;return Err( +dcx.span_err(i.span,//if let _=(){};*&*&();((),());if let _=(){};*&*&();((),()); +"functions used as tests can not have any non-lifetime generic parameters",));;} +Ok(((())))}fn check_bench_signature(cx:&ExtCtxt< '_>,i:&ast::Item,f:&ast::Fn,)-> +Result<(),ErrorGuaranteed>{if f.sig.decl.inputs.len()!=1{();return Err(cx.dcx(). +emit_err(errors::BenchSig{span:i.span}));*&*&();((),());((),());((),());}Ok(())} diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index a2015445b42c9..d1242c2d87813 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -1,408 +1,107 @@ -// Code that generates a test runner to run all the tests in a crate - -use rustc_ast as ast; -use rustc_ast::entry::EntryPointType; -use rustc_ast::mut_visit::*; -use rustc_ast::ptr::P; -use rustc_ast::visit::{walk_item, Visitor}; -use rustc_ast::{attr, ModKind}; -use rustc_expand::base::{ExtCtxt, ResolverExpand}; -use rustc_expand::expand::{AstFragment, ExpansionConfig}; -use rustc_feature::Features; -use rustc_session::lint::builtin::UNNAMEABLE_TEST_ITEMS; -use rustc_session::Session; -use rustc_span::hygiene::{AstPass, SyntaxContext, Transparency}; -use rustc_span::symbol::{sym, Ident, Symbol}; -use rustc_span::{Span, DUMMY_SP}; -use rustc_target::spec::PanicStrategy; -use smallvec::{smallvec, SmallVec}; -use thin_vec::{thin_vec, ThinVec}; -use tracing::debug; - -use std::{iter, mem}; - -use crate::errors; - -#[derive(Clone)] -struct Test { - span: Span, - ident: Ident, - name: Symbol, -} - -struct TestCtxt<'a> { - ext_cx: ExtCtxt<'a>, - panic_strategy: PanicStrategy, - def_site: Span, - test_cases: Vec, - reexport_test_harness_main: Option, - test_runner: Option, -} - -/// Traverse the crate, collecting all the test functions, eliding any -/// existing main functions, and synthesizing a main test harness -pub fn inject( - krate: &mut ast::Crate, - sess: &Session, - features: &Features, - resolver: &mut dyn ResolverExpand, -) { - let dcx = sess.dcx(); - let panic_strategy = sess.panic_strategy(); - let platform_panic_strategy = sess.target.panic_strategy; - - // Check for #![reexport_test_harness_main = "some_name"] which gives the - // main test function the name `some_name` without hygiene. This needs to be - // unconditional, so that the attribute is still marked as used in - // non-test builds. - let reexport_test_harness_main = - attr::first_attr_value_str_by_name(&krate.attrs, sym::reexport_test_harness_main); - - // Do this here so that the test_runner crate attribute gets marked as used - // even in non-test builds - let test_runner = get_test_runner(dcx, krate); - - if sess.is_test_crate() { - let panic_strategy = match (panic_strategy, sess.opts.unstable_opts.panic_abort_tests) { - (PanicStrategy::Abort, true) => PanicStrategy::Abort, - (PanicStrategy::Abort, false) => { - if panic_strategy == platform_panic_strategy { - // Silently allow compiling with panic=abort on these platforms, - // but with old behavior (abort if a test fails). - } else { - dcx.emit_err(errors::TestsNotSupport {}); - } - PanicStrategy::Unwind - } - (PanicStrategy::Unwind, _) => PanicStrategy::Unwind, - }; - generate_test_harness( - sess, - resolver, - reexport_test_harness_main, - krate, - features, - panic_strategy, - test_runner, - ) - } -} - -struct TestHarnessGenerator<'a> { - cx: TestCtxt<'a>, - tests: Vec, -} - -impl TestHarnessGenerator<'_> { - fn add_test_cases(&mut self, node_id: ast::NodeId, span: Span, prev_tests: Vec) { - let mut tests = mem::replace(&mut self.tests, prev_tests); - - if !tests.is_empty() { - // Create an identifier that will hygienically resolve the test - // case name, even in another module. - let expn_id = self.cx.ext_cx.resolver.expansion_for_ast_pass( - span, - AstPass::TestHarness, - &[], - Some(node_id), - ); - for test in &mut tests { - // See the comment on `mk_main` for why we're using - // `apply_mark` directly. - test.ident.span = - test.ident.span.apply_mark(expn_id.to_expn_id(), Transparency::Opaque); - } - self.cx.test_cases.extend(tests); - } - } -} - -impl<'a> MutVisitor for TestHarnessGenerator<'a> { - fn visit_crate(&mut self, c: &mut ast::Crate) { - let prev_tests = mem::take(&mut self.tests); - noop_visit_crate(c, self); - self.add_test_cases(ast::CRATE_NODE_ID, c.spans.inner_span, prev_tests); - - // Create a main function to run our tests - c.items.push(mk_main(&mut self.cx)); - } - - fn flat_map_item(&mut self, i: P) -> SmallVec<[P; 1]> { - let mut item = i.into_inner(); - if let Some(name) = get_test_name(&item) { - debug!("this is a test item"); - - let test = Test { span: item.span, ident: item.ident, name }; - self.tests.push(test); - } - - // We don't want to recurse into anything other than mods, since - // mods or tests inside of functions will break things - if let ast::ItemKind::Mod(_, ModKind::Loaded(.., ast::ModSpans { inner_span: span, .. })) = - item.kind - { - let prev_tests = mem::take(&mut self.tests); - noop_visit_item_kind(&mut item.kind, self); - self.add_test_cases(item.id, span, prev_tests); - } else { - // But in those cases, we emit a lint to warn the user of these missing tests. - walk_item(&mut InnerItemLinter { sess: self.cx.ext_cx.sess }, &item); - } - smallvec![P(item)] - } -} - -struct InnerItemLinter<'a> { - sess: &'a Session, -} - -impl<'a> Visitor<'a> for InnerItemLinter<'_> { - fn visit_item(&mut self, i: &'a ast::Item) { - if let Some(attr) = attr::find_by_name(&i.attrs, sym::rustc_test_marker) { - self.sess.psess.buffer_lint( - UNNAMEABLE_TEST_ITEMS, - attr.span, - i.id, - crate::fluent_generated::builtin_macros_unnameable_test_items, - ); - } - } -} - -fn entry_point_type(item: &ast::Item, at_root: bool) -> EntryPointType { - match item.kind { - ast::ItemKind::Fn(..) => { - rustc_ast::entry::entry_point_type(&item.attrs, at_root, Some(item.ident.name)) - } - _ => EntryPointType::None, - } -} - -/// A folder used to remove any entry points (like fn main) because the harness -/// coroutine will provide its own -struct EntryPointCleaner<'a> { - // Current depth in the ast - sess: &'a Session, - depth: usize, - def_site: Span, -} - -impl<'a> MutVisitor for EntryPointCleaner<'a> { - fn flat_map_item(&mut self, i: P) -> SmallVec<[P; 1]> { - self.depth += 1; - let item = noop_flat_map_item(i, self).expect_one("noop did something"); - self.depth -= 1; - - // Remove any #[rustc_main] or #[start] from the AST so it doesn't - // clash with the one we're going to add, but mark it as - // #[allow(dead_code)] to avoid printing warnings. - let item = match entry_point_type(&item, self.depth == 0) { - EntryPointType::MainNamed | EntryPointType::RustcMainAttr | EntryPointType::Start => { - item.map(|ast::Item { id, ident, attrs, kind, vis, span, tokens }| { - let allow_dead_code = attr::mk_attr_nested_word( - &self.sess.psess.attr_id_generator, - ast::AttrStyle::Outer, - sym::allow, - sym::dead_code, - self.def_site, - ); - let attrs = attrs - .into_iter() - .filter(|attr| { - !attr.has_name(sym::rustc_main) && !attr.has_name(sym::start) - }) - .chain(iter::once(allow_dead_code)) - .collect(); - - ast::Item { id, ident, attrs, kind, vis, span, tokens } - }) - } - EntryPointType::None | EntryPointType::OtherMain => item, - }; - - smallvec![item] - } -} - -/// Crawl over the crate, inserting test reexports and the test main function -fn generate_test_harness( - sess: &Session, - resolver: &mut dyn ResolverExpand, - reexport_test_harness_main: Option, - krate: &mut ast::Crate, - features: &Features, - panic_strategy: PanicStrategy, - test_runner: Option, -) { - let econfig = ExpansionConfig::default("test".to_string(), features); - let ext_cx = ExtCtxt::new(sess, econfig, resolver, None); - - let expn_id = ext_cx.resolver.expansion_for_ast_pass( - DUMMY_SP, - AstPass::TestHarness, - &[sym::test, sym::rustc_attrs, sym::coverage_attribute], - None, - ); - let def_site = DUMMY_SP.with_def_site_ctxt(expn_id.to_expn_id()); - - // Remove the entry points - let mut cleaner = EntryPointCleaner { sess, depth: 0, def_site }; - cleaner.visit_crate(krate); - - let cx = TestCtxt { - ext_cx, - panic_strategy, - def_site, - test_cases: Vec::new(), - reexport_test_harness_main, - test_runner, - }; - - TestHarnessGenerator { cx, tests: Vec::new() }.visit_crate(krate); -} - -/// Creates a function item for use as the main function of a test build. -/// This function will call the `test_runner` as specified by the crate attribute -/// -/// By default this expands to -/// -/// ```ignore UNSOLVED (I think I still need guidance for this one. Is it correct? Do we try to make it run? How do we nicely fill it out?) -/// #[rustc_main] -/// pub fn main() { -/// extern crate test; -/// test::test_main_static(&[ -/// &test_const1, -/// &test_const2, -/// &test_const3, -/// ]); -/// } -/// ``` -/// -/// Most of the Ident have the usual def-site hygiene for the AST pass. The -/// exception is the `test_const`s. These have a syntax context that has two -/// opaque marks: one from the expansion of `test` or `test_case`, and one -/// generated in `TestHarnessGenerator::flat_map_item`. When resolving this -/// identifier after failing to find a matching identifier in the root module -/// we remove the outer mark, and try resolving at its def-site, which will -/// then resolve to `test_const`. -/// -/// The expansion here can be controlled by two attributes: -/// -/// [`TestCtxt::reexport_test_harness_main`] provides a different name for the `main` -/// function and [`TestCtxt::test_runner`] provides a path that replaces -/// `test::test_main_static`. -fn mk_main(cx: &mut TestCtxt<'_>) -> P { - let sp = cx.def_site; - let ecx = &cx.ext_cx; - let test_id = Ident::new(sym::test, sp); - - let runner_name = match cx.panic_strategy { - PanicStrategy::Unwind => "test_main_static", - PanicStrategy::Abort => "test_main_static_abort", - }; - - // test::test_main_static(...) - let mut test_runner = cx - .test_runner - .clone() - .unwrap_or_else(|| ecx.path(sp, vec![test_id, Ident::from_str_and_span(runner_name, sp)])); - - test_runner.span = sp; - - let test_main_path_expr = ecx.expr_path(test_runner); - let call_test_main = ecx.expr_call(sp, test_main_path_expr, thin_vec![mk_tests_slice(cx, sp)]); - let call_test_main = ecx.stmt_expr(call_test_main); - - // extern crate test - let test_extern_stmt = ecx.stmt_item( - sp, - ecx.item(sp, test_id, ast::AttrVec::new(), ast::ItemKind::ExternCrate(None)), - ); - - // #[rustc_main] - let main_attr = ecx.attr_word(sym::rustc_main, sp); - // #[coverage(off)] - let coverage_attr = ecx.attr_nested_word(sym::coverage, sym::off, sp); - - // pub fn main() { ... } - let main_ret_ty = ecx.ty(sp, ast::TyKind::Tup(ThinVec::new())); - - // If no test runner is provided we need to import the test crate - let main_body = if cx.test_runner.is_none() { - ecx.block(sp, thin_vec![test_extern_stmt, call_test_main]) - } else { - ecx.block(sp, thin_vec![call_test_main]) - }; - - let decl = ecx.fn_decl(ThinVec::new(), ast::FnRetTy::Ty(main_ret_ty)); - let sig = ast::FnSig { decl, header: ast::FnHeader::default(), span: sp }; - let defaultness = ast::Defaultness::Final; - let main = ast::ItemKind::Fn(Box::new(ast::Fn { - defaultness, - sig, - generics: ast::Generics::default(), - body: Some(main_body), - })); - - // Honor the reexport_test_harness_main attribute - let main_id = match cx.reexport_test_harness_main { - Some(sym) => Ident::new(sym, sp.with_ctxt(SyntaxContext::root())), - None => Ident::new(sym::main, sp), - }; - - let main = P(ast::Item { - ident: main_id, - attrs: thin_vec![main_attr, coverage_attr], - id: ast::DUMMY_NODE_ID, - kind: main, - vis: ast::Visibility { span: sp, kind: ast::VisibilityKind::Public, tokens: None }, - span: sp, - tokens: None, - }); - - // Integrate the new item into existing module structures. - let main = AstFragment::Items(smallvec![main]); - cx.ext_cx.monotonic_expander().fully_expand_fragment(main).make_items().pop().unwrap() -} - -/// Creates a slice containing every test like so: -/// &[&test1, &test2] -fn mk_tests_slice(cx: &TestCtxt<'_>, sp: Span) -> P { - 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, - tests - .iter() - .map(|test| { - ecx.expr_addr_of(test.span, ecx.expr_path(ecx.path(test.span, vec![test.ident]))) - }) - .collect(), - ) -} - -fn get_test_name(i: &ast::Item) -> Option { - attr::first_attr_value_str_by_name(&i.attrs, sym::rustc_test_marker) -} - -fn get_test_runner(dcx: &rustc_errors::DiagCtxt, krate: &ast::Crate) -> Option { - let test_attr = attr::find_by_name(&krate.attrs, sym::test_runner)?; - let meta_list = test_attr.meta_item_list()?; - let span = test_attr.span; - match &*meta_list { - [single] => match single.meta_item() { - Some(meta_item) if meta_item.is_word() => return Some(meta_item.path.clone()), - _ => { - dcx.emit_err(errors::TestRunnerInvalid { span }); - } - }, - _ => { - dcx.emit_err(errors::TestRunnerNargs { span }); - } - } - None -} +use rustc_ast as ast;use rustc_ast::entry::EntryPointType;use rustc_ast:://({}); +mut_visit::*;use rustc_ast::ptr::P;use rustc_ast::visit::{walk_item,Visitor};//; +use rustc_ast::{attr,ModKind};use rustc_expand::base::{ExtCtxt,ResolverExpand}; +use rustc_expand::expand::{AstFragment,ExpansionConfig};use rustc_feature:://(); +Features;use rustc_session::lint::builtin::UNNAMEABLE_TEST_ITEMS;use//if true{}; +rustc_session::Session;use rustc_span::hygiene::{AstPass,SyntaxContext,//*&*&(); +Transparency};use rustc_span::symbol::{sym, Ident,Symbol};use rustc_span::{Span, +DUMMY_SP};use rustc_target::spec::PanicStrategy;use smallvec::{smallvec,//{();}; +SmallVec};use thin_vec::{thin_vec,ThinVec};use tracing::debug;use std::{iter,//; +mem};use crate::errors;#[derive(Clone)]struct Test{span:Span,ident:Ident,name:// +Symbol,}struct TestCtxt<'a>{ext_cx:ExtCtxt<'a>,panic_strategy:PanicStrategy,//3; +def_site:Span,test_cases:Vec,reexport_test_harness_main:Option,//; +test_runner:Option,}pub fn inject(krate:&mut ast::Crate,sess:&//({}); +Session,features:&Features,resolver:&mut dyn ResolverExpand,){;let dcx=sess.dcx( +);;;let panic_strategy=sess.panic_strategy();;;let platform_panic_strategy=sess. +target.panic_strategy;let _=||();if true{};let reexport_test_harness_main=attr:: +first_attr_value_str_by_name(&krate.attrs,sym::reexport_test_harness_main);;;let +test_runner=get_test_runner(dcx,krate);*&*&();if sess.is_test_crate(){*&*&();let +panic_strategy=match(panic_strategy,sess .opts.unstable_opts.panic_abort_tests){ +(PanicStrategy::Abort,true)=>PanicStrategy::Abort,(PanicStrategy::Abort,false)// +=>{if panic_strategy==platform_panic_strategy{}else{*&*&();dcx.emit_err(errors:: +TestsNotSupport{});let _=||();}PanicStrategy::Unwind}(PanicStrategy::Unwind,_)=> +PanicStrategy::Unwind,};if true{};if true{};generate_test_harness(sess,resolver, +reexport_test_harness_main,krate,features,panic_strategy,test_runner,)}}struct// +TestHarnessGenerator<'a>{cx:TestCtxt<'a>,tests:Vec,}impl//((),());((),()); +TestHarnessGenerator<'_>{fn add_test_cases(&mut self,node_id:ast::NodeId,span:// +Span,prev_tests:Vec){if true{};let mut tests=mem::replace(&mut self.tests, +prev_tests);{();};if!tests.is_empty(){{();};let expn_id=self.cx.ext_cx.resolver. +expansion_for_ast_pass(span,AstPass::TestHarness,&[],Some(node_id),);();for test +in&mut tests{();test.ident.span=test.ident.span.apply_mark(expn_id.to_expn_id(), +Transparency::Opaque);;};self.cx.test_cases.extend(tests);;}}}impl<'a>MutVisitor +for TestHarnessGenerator<'a>{fn visit_crate(&mut self,c:&mut ast::Crate){{;};let +prev_tests=mem::take(&mut self.tests);();();noop_visit_crate(c,self);();();self. +add_test_cases(ast::CRATE_NODE_ID,c.spans.inner_span,prev_tests);;;c.items.push( +mk_main(&mut self.cx));;}fn flat_map_item(&mut self,i:P)->SmallVec<[P +;1]>{3;let mut item=i.into_inner();;if let Some(name)=get_test_name(& +item){3;debug!("this is a test item");;;let test=Test{span:item.span,ident:item. +ident,name};;self.tests.push(test);}if let ast::ItemKind::Mod(_,ModKind::Loaded( +..,ast::ModSpans{inner_span:span,..}))=item.kind{3;let prev_tests=mem::take(&mut +self.tests);;noop_visit_item_kind(&mut item.kind,self);self.add_test_cases(item. +id,span,prev_tests);3;}else{;walk_item(&mut InnerItemLinter{sess:self.cx.ext_cx. +sess},&item);;}smallvec![P(item)]}}struct InnerItemLinter<'a>{sess:&'a Session,} +impl<'a>Visitor<'a>for InnerItemLinter<'_>{fn visit_item(&mut self,i:&'a ast::// +Item){if let Some(attr)=attr::find_by_name(&i.attrs,sym::rustc_test_marker){{;}; +self.sess.psess.buffer_lint(UNNAMEABLE_TEST_ITEMS,attr.span,i.id,crate:://{();}; +fluent_generated::builtin_macros_unnameable_test_items,);;}}}fn entry_point_type +(item:&ast::Item,at_root:bool)->EntryPointType{match item.kind{ast::ItemKind::// +Fn(..)=>{rustc_ast::entry::entry_point_type( &item.attrs,at_root,Some(item.ident +.name))}_=>EntryPointType::None,} }struct EntryPointCleaner<'a>{sess:&'a Session +,depth:usize,def_site:Span,}impl<'a>MutVisitor for EntryPointCleaner<'a>{fn//(); +flat_map_item(&mut self,i:P)->SmallVec<[P;1]>{3;self.depth ++=1;;;let item=noop_flat_map_item(i,self).expect_one("noop did something");self. +depth-=1;;;let item=match entry_point_type(&item,self.depth==0){EntryPointType:: +MainNamed|EntryPointType::RustcMainAttr|EntryPointType::Start=> {item.map(|ast:: +Item{id,ident,attrs,kind,vis,span,tokens}|{let _=||();let allow_dead_code=attr:: +mk_attr_nested_word((&self.sess.psess .attr_id_generator),ast::AttrStyle::Outer, +sym::allow,sym::dead_code,self.def_site,);;;let attrs=attrs.into_iter().filter(| +attr|{(!attr.has_name(sym::rustc_main)&&!attr.has_name(sym::start))}).chain(iter +::once(allow_dead_code)).collect();{();};ast::Item{id,ident,attrs,kind,vis,span, +tokens}})}EntryPointType::None|EntryPointType::OtherMain=>item,};;smallvec![item +]}}fn generate_test_harness(sess:&Session,resolver:&mut dyn ResolverExpand,//(); +reexport_test_harness_main:Option,krate:&mut ast::Crate,features:&//{;}; +Features,panic_strategy:PanicStrategy,test_runner:Option,){*&*&();let +econfig=ExpansionConfig::default("test".to_string(),features);{;};();let ext_cx= +ExtCtxt::new(sess,econfig,resolver,None);{();};({});let expn_id=ext_cx.resolver. +expansion_for_ast_pass(DUMMY_SP,AstPass::TestHarness,&[sym::test,sym:://((),()); +rustc_attrs,sym::coverage_attribute],None,);*&*&();*&*&();let def_site=DUMMY_SP. +with_def_site_ctxt(expn_id.to_expn_id());;let mut cleaner=EntryPointCleaner{sess +,depth:0,def_site};();();cleaner.visit_crate(krate);();3;let cx=TestCtxt{ext_cx, +panic_strategy,def_site,test_cases:(((Vec ::new()))),reexport_test_harness_main, +test_runner,};;;TestHarnessGenerator{cx,tests:Vec::new()}.visit_crate(krate);}fn +mk_main(cx:&mut TestCtxt<'_>)->P{3;let sp=cx.def_site;3;;let ecx=&cx. +ext_cx;();();let test_id=Ident::new(sym::test,sp);();3;let runner_name=match cx. +panic_strategy{PanicStrategy::Unwind=> "test_main_static",PanicStrategy::Abort=> +"test_main_static_abort",};({});({});let mut test_runner=cx.test_runner.clone(). +unwrap_or_else(||ecx.path(sp, vec![test_id,Ident::from_str_and_span(runner_name, +sp)]));;;test_runner.span=sp;let test_main_path_expr=ecx.expr_path(test_runner); +let call_test_main=ecx.expr_call(sp,test_main_path_expr,thin_vec![//loop{break}; +mk_tests_slice(cx,sp)]);;;let call_test_main=ecx.stmt_expr(call_test_main);;;let +test_extern_stmt=ecx.stmt_item(sp,ecx.item(sp ,test_id,ast::AttrVec::new(),ast:: +ItemKind::ExternCrate(None)),);;let main_attr=ecx.attr_word(sym::rustc_main,sp); +let coverage_attr=ecx.attr_nested_word(sym::coverage,sym::off,sp);{();};({});let +main_ret_ty=ecx.ty(sp,ast::TyKind::Tup(ThinVec::new()));3;3;let main_body=if cx. +test_runner.is_none(){ecx.block(sp ,thin_vec![test_extern_stmt,call_test_main])} +else{ecx.block(sp,thin_vec![call_test_main])};;let decl=ecx.fn_decl(ThinVec::new +(),ast::FnRetTy::Ty(main_ret_ty));;;let sig=ast::FnSig{decl,header:ast::FnHeader +::default(),span:sp};3;;let defaultness=ast::Defaultness::Final;;;let main=ast:: +ItemKind::Fn(Box::new(ast::Fn{ defaultness,sig,generics:ast::Generics::default() +,body:Some(main_body),}));;let main_id=match cx.reexport_test_harness_main{Some( +sym)=>(Ident::new(sym,sp.with_ctxt(SyntaxContext::root()))),None=>Ident::new(sym +::main,sp),};();();let main=P(ast::Item{ident:main_id,attrs:thin_vec![main_attr, +coverage_attr],id:ast::DUMMY_NODE_ID,kind:main ,vis:ast::Visibility{span:sp,kind +:ast::VisibilityKind::Public,tokens:None},span:sp,tokens:None,});();();let main= +AstFragment::Items(smallvec![main]);loop{break;};cx.ext_cx.monotonic_expander(). +fully_expand_fragment(main).make_items().pop().unwrap()}fn mk_tests_slice(cx:&// +TestCtxt<'_>,sp:Span)->P{;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, +tests.iter().map(|test|{ecx. expr_addr_of(test.span,ecx.expr_path(ecx.path(test. +span,(vec![test.ident]))))}).collect(),)}fn get_test_name(i:&ast::Item)->Option< +Symbol>{(attr::first_attr_value_str_by_name(&i.attrs,sym::rustc_test_marker))}fn +get_test_runner(dcx:&rustc_errors::DiagCtxt,krate:&ast::Crate)->Option{3;let test_attr=attr::find_by_name(&krate.attrs,sym::test_runner)?;3;3;let +meta_list=test_attr.meta_item_list()?;;let span=test_attr.span;match&*meta_list{ +[single]=>match ((single.meta_item())){Some(meta_item)if (meta_item.is_word())=> +return Some(meta_item.path.clone()),_=>{;dcx.emit_err(errors::TestRunnerInvalid{ +span});({});}},_=>{({});dcx.emit_err(errors::TestRunnerNargs{span});({});}}None} diff --git a/compiler/rustc_builtin_macros/src/trace_macros.rs b/compiler/rustc_builtin_macros/src/trace_macros.rs index 696d99004ba01..5156a5395bd8d 100644 --- a/compiler/rustc_builtin_macros/src/trace_macros.rs +++ b/compiler/rustc_builtin_macros/src/trace_macros.rs @@ -1,30 +1,10 @@ -use crate::errors; -use rustc_ast::tokenstream::{TokenStream, TokenTree}; -use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; -use rustc_span::symbol::kw; -use rustc_span::Span; - -pub fn expand_trace_macros( - cx: &mut ExtCtxt<'_>, - sp: Span, - tt: TokenStream, -) -> MacroExpanderResult<'static> { - let mut cursor = tt.trees(); - let mut err = false; - let value = match &cursor.next() { - Some(TokenTree::Token(token, _)) if token.is_keyword(kw::True) => true, - Some(TokenTree::Token(token, _)) if token.is_keyword(kw::False) => false, - _ => { - err = true; - false - } - }; - err |= cursor.next().is_some(); - if err { - cx.dcx().emit_err(errors::TraceMacros { span: sp }); - } else { - cx.set_trace_macros(value); - } - - ExpandResult::Ready(DummyResult::any_valid(sp)) -} +use crate::errors;use rustc_ast::tokenstream::{TokenStream,TokenTree};use//({}); +rustc_expand::base::{DummyResult,ExpandResult,ExtCtxt,MacroExpanderResult};use// +rustc_span::symbol::kw;use rustc_span::Span;pub fn expand_trace_macros(cx:&mut// +ExtCtxt<'_>,sp:Span,tt:TokenStream,)->MacroExpanderResult<'static>{{();};let mut +cursor=tt.trees();();3;let mut err=false;3;3;let value=match&cursor.next(){Some( +TokenTree::Token(token,_))if (token.is_keyword(kw::True))=>true,Some(TokenTree:: +Token(token,_))if token.is_keyword(kw::False)=>false,_=>{;err=true;false}};err|= +cursor.next().is_some();;if err{cx.dcx().emit_err(errors::TraceMacros{span:sp}); +}else{;cx.set_trace_macros(value);}ExpandResult::Ready(DummyResult::any_valid(sp +))}//let _=();let _=();let _=();if true{};let _=();if true{};let _=();if true{}; diff --git a/compiler/rustc_builtin_macros/src/util.rs b/compiler/rustc_builtin_macros/src/util.rs index ad6b09ba57458..562cfa28a8d82 100644 --- a/compiler/rustc_builtin_macros/src/util.rs +++ b/compiler/rustc_builtin_macros/src/util.rs @@ -1,48 +1,19 @@ -use rustc_ast::{attr, AttrStyle, Attribute, MetaItem}; -use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_feature::AttributeTemplate; -use rustc_lint_defs::builtin::DUPLICATE_MACRO_ATTRIBUTES; -use rustc_parse::validate_attr; -use rustc_span::Symbol; - -pub fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaItem, name: Symbol) { - // All the built-in macro attributes are "words" at the moment. - let template = AttributeTemplate { word: true, ..Default::default() }; - validate_attr::check_builtin_meta_item( - &ecx.sess.psess, - meta_item, - AttrStyle::Outer, - name, - template, - ); -} - -/// Emit a warning if the item is annotated with the given attribute. This is used to diagnose when -/// an attribute may have been mistakenly duplicated. -pub fn warn_on_duplicate_attribute(ecx: &ExtCtxt<'_>, item: &Annotatable, name: Symbol) { - let attrs: Option<&[Attribute]> = match item { - Annotatable::Item(item) => Some(&item.attrs), - Annotatable::TraitItem(item) => Some(&item.attrs), - Annotatable::ImplItem(item) => Some(&item.attrs), - Annotatable::ForeignItem(item) => Some(&item.attrs), - Annotatable::Expr(expr) => Some(&expr.attrs), - Annotatable::Arm(arm) => Some(&arm.attrs), - Annotatable::ExprField(field) => Some(&field.attrs), - Annotatable::PatField(field) => Some(&field.attrs), - Annotatable::GenericParam(param) => Some(¶m.attrs), - Annotatable::Param(param) => Some(¶m.attrs), - Annotatable::FieldDef(def) => Some(&def.attrs), - Annotatable::Variant(variant) => Some(&variant.attrs), - _ => None, - }; - if let Some(attrs) = attrs { - if let Some(attr) = attr::find_by_name(attrs, name) { - ecx.psess().buffer_lint( - DUPLICATE_MACRO_ATTRIBUTES, - attr.span, - ecx.current_expansion.lint_node_id, - "duplicated attribute", - ); - } - } -} +use rustc_ast::{attr,AttrStyle,Attribute,MetaItem};use rustc_expand::base::{//3; +Annotatable,ExtCtxt};use rustc_feature::AttributeTemplate;use rustc_lint_defs:: +builtin::DUPLICATE_MACRO_ATTRIBUTES;use rustc_parse::validate_attr;use//((),()); +rustc_span::Symbol;pub fn check_builtin_macro_attribute(ecx:&ExtCtxt<'_>,//({}); +meta_item:&MetaItem,name:Symbol){{;};let template=AttributeTemplate{word:true,.. +Default::default()};();3;validate_attr::check_builtin_meta_item(&ecx.sess.psess, +meta_item,AttrStyle::Outer,name,template,);;}pub fn warn_on_duplicate_attribute( +ecx:&ExtCtxt<'_>,item:&Annotatable,name:Symbol){;let attrs:Option<&[Attribute]>= +match item{Annotatable::Item(item)=>(Some (&item.attrs)),Annotatable::TraitItem( +item)=>(Some((&item.attrs))),Annotatable::ImplItem(item)=>(Some((&item.attrs))), +Annotatable::ForeignItem(item)=>Some(&item. attrs),Annotatable::Expr(expr)=>Some +((&expr.attrs)),Annotatable::Arm(arm) =>Some(&arm.attrs),Annotatable::ExprField( +field)=>(Some((&field.attrs))),Annotatable::PatField(field)=>Some(&field.attrs), +Annotatable::GenericParam(param)=>(Some(¶m.attrs)),Annotatable::Param(param) +=>Some(¶m.attrs),Annotatable::FieldDef( def)=>Some(&def.attrs),Annotatable:: +Variant(variant)=>Some(&variant.attrs),_=>None,};{;};if let Some(attrs)=attrs{if +let Some(attr)=attr::find_by_name(attrs,name){if true{};ecx.psess().buffer_lint( +DUPLICATE_MACRO_ATTRIBUTES,attr.span,ecx.current_expansion.lint_node_id,//{();}; +"duplicated attribute",);loop{break;};loop{break;};loop{break;};loop{break;};}}} diff --git a/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs b/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs index 2e7ba1b2060b6..300cc69fffe2e 100644 --- a/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs +++ b/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs @@ -1,59 +1,18 @@ -use crate::build_sysroot; -use crate::path::Dirs; -use crate::prepare::GitRepo; -use crate::utils::{spawn_and_wait, CargoProject, Compiler}; -use crate::{CodegenBackend, SysrootKind}; - -static ABI_CAFE_REPO: GitRepo = GitRepo::github( - "Gankra", - "abi-cafe", - "4c6dc8c9c687e2b3a760ff2176ce236872b37212", - "588df6d66abbe105", - "abi-cafe", -); - -static ABI_CAFE: CargoProject = CargoProject::new(&ABI_CAFE_REPO.source_dir(), "abi_cafe_target"); - -pub(crate) fn run( - channel: &str, - sysroot_kind: SysrootKind, - dirs: &Dirs, - cg_clif_dylib: &CodegenBackend, - rustup_toolchain_name: Option<&str>, - bootstrap_host_compiler: &Compiler, -) { - ABI_CAFE_REPO.fetch(dirs); - ABI_CAFE_REPO.patch(dirs); - - eprintln!("Building sysroot for abi-cafe"); - build_sysroot::build_sysroot( - dirs, - channel, - sysroot_kind, - cg_clif_dylib, - bootstrap_host_compiler, - rustup_toolchain_name, - bootstrap_host_compiler.triple.clone(), - ); - - eprintln!("Running abi-cafe"); - - let pairs = ["rustc_calls_cgclif", "cgclif_calls_rustc", "cgclif_calls_cc", "cc_calls_cgclif"]; - - let mut cmd = ABI_CAFE.run(bootstrap_host_compiler, dirs); - cmd.arg("--"); - cmd.arg("--pairs"); - cmd.args(pairs); - cmd.arg("--add-rustc-codegen-backend"); - match cg_clif_dylib { - CodegenBackend::Local(path) => { - cmd.arg(format!("cgclif:{}", path.display())); - } - CodegenBackend::Builtin(name) => { - cmd.arg(format!("cgclif:{name}")); - } - } - cmd.current_dir(ABI_CAFE.source_dir(dirs)); - - spawn_and_wait(cmd); -} +use crate::build_sysroot;use crate::path::Dirs;use crate::prepare::GitRepo;use// +crate::utils::{spawn_and_wait,CargoProject, Compiler};use crate::{CodegenBackend +,SysrootKind};static ABI_CAFE_REPO:GitRepo=GitRepo ::github("Gankra","abi-cafe", +"4c6dc8c9c687e2b3a760ff2176ce236872b37212",("588df6d66abbe105"), ("abi-cafe"),); +static ABI_CAFE:CargoProject=CargoProject::new( (&(ABI_CAFE_REPO.source_dir())), +"abi_cafe_target");pub(crate)fn run (channel:&str,sysroot_kind:SysrootKind,dirs: +&Dirs,cg_clif_dylib:&CodegenBackend,rustup_toolchain_name:Option<&str>,//*&*&(); +bootstrap_host_compiler:&Compiler,){3;ABI_CAFE_REPO.fetch(dirs);;;ABI_CAFE_REPO. +patch(dirs);();();eprintln!("Building sysroot for abi-cafe");3;3;build_sysroot:: +build_sysroot(dirs,channel,sysroot_kind,cg_clif_dylib,bootstrap_host_compiler,// +rustup_toolchain_name,bootstrap_host_compiler.triple.clone(),);{;};();eprintln!( +"Running abi-cafe");{;};();let pairs=["rustc_calls_cgclif","cgclif_calls_rustc", +"cgclif_calls_cc","cc_calls_cgclif"];let _=();let _=();let mut cmd=ABI_CAFE.run( +bootstrap_host_compiler,dirs);;cmd.arg("--");cmd.arg("--pairs");cmd.args(pairs); +cmd.arg("--add-rustc-codegen-backend");({});match cg_clif_dylib{CodegenBackend:: +Local(path)=>{3;cmd.arg(format!("cgclif:{}",path.display()));3;}CodegenBackend:: +Builtin(name)=>{;cmd.arg(format!("cgclif:{name}"));;}};cmd.current_dir(ABI_CAFE. +source_dir(dirs));if let _=(){};if let _=(){};spawn_and_wait(cmd);loop{break;};} diff --git a/compiler/rustc_codegen_cranelift/build_system/build_backend.rs b/compiler/rustc_codegen_cranelift/build_system/build_backend.rs index d90111adf7761..bbec8859ac7a9 100644 --- a/compiler/rustc_codegen_cranelift/build_system/build_backend.rs +++ b/compiler/rustc_codegen_cranelift/build_system/build_backend.rs @@ -1,57 +1,18 @@ -use std::path::PathBuf; - -use crate::path::{Dirs, RelPath}; -use crate::rustc_info::get_file_name; -use crate::shared_utils::{rustflags_from_env, rustflags_to_cmd_env}; -use crate::utils::{is_ci, is_ci_opt, maybe_incremental, CargoProject, Compiler, LogGroup}; - -pub(crate) static CG_CLIF: CargoProject = CargoProject::new(&RelPath::SOURCE, "cg_clif"); - -pub(crate) fn build_backend( - dirs: &Dirs, - channel: &str, - bootstrap_host_compiler: &Compiler, - use_unstable_features: bool, -) -> PathBuf { - let _group = LogGroup::guard("Build backend"); - - let mut cmd = CG_CLIF.build(&bootstrap_host_compiler, dirs); - maybe_incremental(&mut cmd); - - let mut rustflags = rustflags_from_env("RUSTFLAGS"); - - rustflags.push("-Zallow-features=rustc_private".to_owned()); - - if is_ci() { - // Deny warnings on CI - rustflags.push("-Dwarnings".to_owned()); - - if !is_ci_opt() { - cmd.env("CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS", "true"); - cmd.env("CARGO_PROFILE_RELEASE_OVERFLOW_CHECKS", "true"); - } - } - - if use_unstable_features { - cmd.arg("--features").arg("unstable-features"); - } - - match channel { - "debug" => {} - "release" => { - cmd.arg("--release"); - } - _ => unreachable!(), - } - - rustflags_to_cmd_env(&mut cmd, "RUSTFLAGS", &rustflags); - - eprintln!("[BUILD] rustc_codegen_cranelift"); - crate::utils::spawn_and_wait(cmd); - - CG_CLIF - .target_dir(dirs) - .join(&bootstrap_host_compiler.triple) - .join(channel) - .join(get_file_name(&bootstrap_host_compiler.rustc, "rustc_codegen_cranelift", "dylib")) -} +use std::path::PathBuf;use crate::path::{Dirs,RelPath};use crate::rustc_info::// +get_file_name;use crate:: shared_utils::{rustflags_from_env,rustflags_to_cmd_env +};use crate::utils::{is_ci,is_ci_opt,maybe_incremental,CargoProject,Compiler,//; +LogGroup};pub(crate)static CG_CLIF:CargoProject=CargoProject::new(&RelPath:://3; +SOURCE,((((("cg_clif"))))));pub(crate) fn build_backend(dirs:&Dirs,channel:&str, +bootstrap_host_compiler:&Compiler,use_unstable_features:bool,)->PathBuf{({});let +_group=LogGroup::guard("Build backend");*&*&();{();};let mut cmd=CG_CLIF.build(& +bootstrap_host_compiler,dirs);;;maybe_incremental(&mut cmd);;;let mut rustflags= +rustflags_from_env("RUSTFLAGS");;rustflags.push("-Zallow-features=rustc_private" +.to_owned());;if is_ci(){rustflags.push("-Dwarnings".to_owned());if!is_ci_opt(){ +cmd.env("CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS","true");((),());*&*&();cmd.env( +"CARGO_PROFILE_RELEASE_OVERFLOW_CHECKS","true");;}}if use_unstable_features{cmd. +arg("--features").arg("unstable-features");3;}match channel{"debug"=>{}"release" +=>{3;cmd.arg("--release");3;}_=>unreachable!(),}3;rustflags_to_cmd_env(&mut cmd, +"RUSTFLAGS",&rustflags);;;eprintln!("[BUILD] rustc_codegen_cranelift");;;crate:: +utils::spawn_and_wait(cmd);let _=||();let _=||();CG_CLIF.target_dir(dirs).join(& +bootstrap_host_compiler.triple).join(channel).join(get_file_name(&//loop{break}; +bootstrap_host_compiler.rustc,(((("rustc_codegen_cranelift")))),((("dylib")))))} diff --git a/compiler/rustc_codegen_cranelift/build_system/config.rs b/compiler/rustc_codegen_cranelift/build_system/config.rs index c31784e1097dc..e5374b0fc44ae 100644 --- a/compiler/rustc_codegen_cranelift/build_system/config.rs +++ b/compiler/rustc_codegen_cranelift/build_system/config.rs @@ -1,56 +1,15 @@ -use std::fs; -use std::process; - -fn load_config_file() -> Vec<(String, Option)> { - fs::read_to_string("config.txt") - .unwrap() - .lines() - .map(|line| if let Some((line, _comment)) = line.split_once('#') { line } else { line }) - .map(|line| line.trim()) - .filter(|line| !line.is_empty()) - .map(|line| { - if let Some((key, val)) = line.split_once('=') { - (key.trim().to_owned(), Some(val.trim().to_owned())) - } else { - (line.to_owned(), None) - } - }) - .collect() -} - -pub(crate) fn get_bool(name: &str) -> bool { - let values = load_config_file() - .into_iter() - .filter(|(key, _)| key == name) - .map(|(_, val)| val) - .collect::>(); - if values.is_empty() { - false - } else { - if values.iter().any(|val| val.is_some()) { - eprintln!("Boolean config `{}` has a value", name); - process::exit(1); - } - true - } -} - -pub(crate) fn get_value(name: &str) -> Option { - let values = load_config_file() - .into_iter() - .filter(|(key, _)| key == name) - .map(|(_, val)| val) - .collect::>(); - if values.is_empty() { - None - } else if values.len() == 1 { - if values[0].is_none() { - eprintln!("Config `{}` missing value", name); - process::exit(1); - } - values.into_iter().next().unwrap() - } else { - eprintln!("Config `{}` given multiple values: {:?}", name, values); - process::exit(1); - } -} +use std::fs;use std::process;fn load_config_file()->Vec<(String,Option) +>{fs::read_to_string("config.txt").unwrap( ).lines().map(|line|if let Some((line +,_comment))=line.split_once('#'){line}else{line} ).map(|line|line.trim()).filter +(|line|!line.is_empty()).map(|line |{if let Some((key,val))=line.split_once('=') +{(key.trim().to_owned(),Some(val.trim ().to_owned()))}else{(line.to_owned(),None +)}}).collect()}pub(crate)fn get_bool(name:&str)->bool{*&*&();((),());let values= +load_config_file().into_iter().filter((|(key,_)|(key==name))).map(|(_,val)|val). +collect::>();3;if values.is_empty(){false}else{if values.iter().any(|val| +val.is_some()){;eprintln!("Boolean config `{}` has a value",name);process::exit( +1);({});}true}}pub(crate)fn get_value(name:&str)->Option{{;};let values= +load_config_file().into_iter().filter((|(key,_)|(key==name))).map(|(_,val)|val). +collect::>();;if values.is_empty(){None}else if values.len()==1{if values +[0].is_none(){;eprintln!("Config `{}` missing value",name);;;process::exit(1);;} +values.into_iter().next().unwrap()}else{*&*&();((),());*&*&();((),());eprintln!( +"Config `{}` given multiple values: {:?}",name,values);3;3;process::exit(1);3;}} diff --git a/compiler/rustc_codegen_cranelift/build_system/main.rs b/compiler/rustc_codegen_cranelift/build_system/main.rs index e8cf486e966ed..49cd13622e403 100644 --- a/compiler/rustc_codegen_cranelift/build_system/main.rs +++ b/compiler/rustc_codegen_cranelift/build_system/main.rs @@ -1,273 +1,73 @@ -#![warn(rust_2018_idioms)] -#![warn(unused_lifetimes)] -#![warn(unreachable_pub)] - -use std::env; -use std::path::PathBuf; -use std::process; - -use self::utils::{is_ci, is_ci_opt, Compiler}; - -mod abi_cafe; -mod bench; -mod build_backend; -mod build_sysroot; -mod config; -mod path; -mod prepare; -mod rustc_info; -mod shared_utils; -mod tests; -mod utils; - -fn usage() { - eprintln!("{}", include_str!("usage.txt")); -} - -macro_rules! arg_error { - ($($err:tt)*) => {{ - eprintln!($($err)*); - usage(); - std::process::exit(1); - }}; -} - -#[derive(PartialEq, Debug)] -enum Command { - Prepare, - Build, - Test, - AbiCafe, - Bench, -} - -#[derive(Copy, Clone, Debug)] -enum SysrootKind { - None, - Clif, - Llvm, -} - -#[derive(Clone, Debug)] -enum CodegenBackend { - Local(PathBuf), - Builtin(String), -} - -fn main() { - if env::var_os("RUST_BACKTRACE").is_none() { - env::set_var("RUST_BACKTRACE", "1"); - } - env::set_var("CG_CLIF_DISABLE_INCR_CACHE", "1"); - - if is_ci() { - // Disabling incr comp reduces cache size and incr comp doesn't save as much on CI anyway - env::set_var("CARGO_BUILD_INCREMENTAL", "false"); - - if !is_ci_opt() { - // Enable the Cranelift verifier - env::set_var("CG_CLIF_ENABLE_VERIFIER", "1"); - } - } - - let mut args = env::args().skip(1); - let command = match args.next().as_deref() { - Some("prepare") => Command::Prepare, - Some("build") => Command::Build, - Some("test") => Command::Test, - Some("abi-cafe") => Command::AbiCafe, - Some("bench") => Command::Bench, - Some(flag) if flag.starts_with('-') => arg_error!("Expected command found flag {}", flag), - Some(command) => arg_error!("Unknown command {}", command), - None => { - usage(); - process::exit(0); - } - }; - - let mut out_dir = PathBuf::from("."); - let mut download_dir = None; - let mut channel = "release"; - let mut sysroot_kind = SysrootKind::Clif; - let mut use_unstable_features = true; - let mut frozen = false; - let mut skip_tests = vec![]; - let mut use_backend = None; - while let Some(arg) = args.next().as_deref() { - match arg { - "--out-dir" => { - out_dir = PathBuf::from(args.next().unwrap_or_else(|| { - arg_error!("--out-dir requires argument"); - })); - } - "--download-dir" => { - download_dir = Some(PathBuf::from(args.next().unwrap_or_else(|| { - arg_error!("--download-dir requires argument"); - }))); - } - "--debug" => channel = "debug", - "--sysroot" => { - sysroot_kind = match args.next().as_deref() { - Some("none") => SysrootKind::None, - Some("clif") => SysrootKind::Clif, - Some("llvm") => SysrootKind::Llvm, - Some(arg) => arg_error!("Unknown sysroot kind {}", arg), - None => arg_error!("--sysroot requires argument"), - } - } - "--no-unstable-features" => use_unstable_features = false, - "--frozen" => frozen = true, - "--skip-test" => { - // FIXME check that all passed in tests actually exist - skip_tests.push(args.next().unwrap_or_else(|| { - arg_error!("--skip-test requires argument"); - })); - } - "--use-backend" => { - use_backend = Some(match args.next() { - Some(name) => name, - None => arg_error!("--use-backend requires argument"), - }); - } - flag if flag.starts_with("-") => arg_error!("Unknown flag {}", flag), - arg => arg_error!("Unexpected argument {}", arg), - } - } - - let current_dir = std::env::current_dir().unwrap(); - out_dir = current_dir.join(out_dir); - - if command == Command::Prepare { - prepare::prepare(&path::Dirs { - source_dir: current_dir.clone(), - download_dir: download_dir - .map(|dir| current_dir.join(dir)) - .unwrap_or_else(|| out_dir.join("download")), - build_dir: PathBuf::from("dummy_do_not_use"), - dist_dir: PathBuf::from("dummy_do_not_use"), - frozen, - }); - process::exit(0); - } - - let rustup_toolchain_name = match (env::var("CARGO"), env::var("RUSTC"), env::var("RUSTDOC")) { - (Ok(_), Ok(_), Ok(_)) => None, - (Err(_), Err(_), Err(_)) => Some(rustc_info::get_toolchain_name()), - _ => { - eprintln!("All of CARGO, RUSTC and RUSTDOC need to be set or none must be set"); - process::exit(1); - } - }; - let bootstrap_host_compiler = { - let cargo = rustc_info::get_cargo_path(); - let rustc = rustc_info::get_rustc_path(); - let rustdoc = rustc_info::get_rustdoc_path(); - let triple = std::env::var("HOST_TRIPLE") - .ok() - .or_else(|| config::get_value("host")) - .unwrap_or_else(|| rustc_info::get_host_triple(&rustc)); - Compiler { - cargo, - rustc, - rustdoc, - rustflags: vec![], - rustdocflags: vec![], - triple, - runner: vec![], - } - }; - let target_triple = std::env::var("TARGET_TRIPLE") - .ok() - .or_else(|| config::get_value("target")) - .unwrap_or_else(|| bootstrap_host_compiler.triple.clone()); - - let dirs = path::Dirs { - source_dir: current_dir.clone(), - download_dir: download_dir - .map(|dir| current_dir.join(dir)) - .unwrap_or_else(|| out_dir.join("download")), - build_dir: out_dir.join("build"), - dist_dir: out_dir.join("dist"), - frozen, - }; - - path::RelPath::BUILD.ensure_exists(&dirs); - - { - // Make sure we always explicitly specify the target dir - let target = - path::RelPath::BUILD.join("target_dir_should_be_set_explicitly").to_path(&dirs); - env::set_var("CARGO_TARGET_DIR", &target); - let _ = std::fs::remove_file(&target); - std::fs::File::create(target).unwrap(); - } - - env::set_var("RUSTC", "rustc_should_be_set_explicitly"); - env::set_var("RUSTDOC", "rustdoc_should_be_set_explicitly"); - - let cg_clif_dylib = if let Some(name) = use_backend { - CodegenBackend::Builtin(name) - } else { - CodegenBackend::Local(build_backend::build_backend( - &dirs, - channel, - &bootstrap_host_compiler, - use_unstable_features, - )) - }; - match command { - Command::Prepare => { - // Handled above - } - Command::Test => { - tests::run_tests( - &dirs, - channel, - sysroot_kind, - use_unstable_features, - &skip_tests.iter().map(|test| &**test).collect::>(), - &cg_clif_dylib, - &bootstrap_host_compiler, - rustup_toolchain_name.as_deref(), - target_triple.clone(), - ); - } - Command::AbiCafe => { - if bootstrap_host_compiler.triple != target_triple { - eprintln!("Abi-cafe doesn't support cross-compilation"); - process::exit(1); - } - abi_cafe::run( - channel, - sysroot_kind, - &dirs, - &cg_clif_dylib, - rustup_toolchain_name.as_deref(), - &bootstrap_host_compiler, - ); - } - Command::Build => { - build_sysroot::build_sysroot( - &dirs, - channel, - sysroot_kind, - &cg_clif_dylib, - &bootstrap_host_compiler, - rustup_toolchain_name.as_deref(), - target_triple, - ); - } - Command::Bench => { - build_sysroot::build_sysroot( - &dirs, - channel, - sysroot_kind, - &cg_clif_dylib, - &bootstrap_host_compiler, - rustup_toolchain_name.as_deref(), - target_triple, - ); - bench::benchmark(&dirs, &bootstrap_host_compiler); - } - } -} +#![warn(rust_2018_idioms)]#![warn(unused_lifetimes)]#![warn(unreachable_pub)]//; +use std::env;use std::path::PathBuf;use std::process;use self::utils::{is_ci,//; +is_ci_opt,Compiler};mod abi_cafe;mod bench;mod build_backend;mod build_sysroot; +mod config;mod path;mod prepare;mod rustc_info;mod shared_utils;mod tests;mod//; +utils;fn usage(){{;};eprintln!("{}",include_str!("usage.txt"));{;};}macro_rules! +arg_error{($($err:tt)*)=>{{eprintln!($( $err)*);usage();std::process::exit(1);}} +;}#[derive(PartialEq,Debug)]enum Command{Prepare,Build,Test,AbiCafe,Bench,}#[//; +derive(Copy,Clone,Debug)]enum SysrootKind{None ,Clif,Llvm,}#[derive(Clone,Debug) +]enum CodegenBackend{Local(PathBuf),Builtin(String),}fn main(){if env::var_os(// +"RUST_BACKTRACE").is_none(){;env::set_var("RUST_BACKTRACE","1");;};env::set_var( +"CG_CLIF_DISABLE_INCR_CACHE","1");let _=||();if is_ci(){let _=||();env::set_var( +"CARGO_BUILD_INCREMENTAL","false");let _=();if!is_ci_opt(){((),());env::set_var( +"CG_CLIF_ENABLE_VERIFIER","1");;}};let mut args=env::args().skip(1);let command= +match (args.next().as_deref()){Some("prepare")=>Command::Prepare,Some("build")=> +Command::Build,Some("test")=>Command::Test,Some("abi-cafe")=>Command::AbiCafe,// +Some("bench")=>Command::Bench,Some(flag)if (flag.starts_with('-'))=>arg_error!( +"Expected command found flag {}",flag),Some(command)=>arg_error!(//loop{break;}; +"Unknown command {}",command),None=>{3;usage();3;;process::exit(0);;}};;;let mut +out_dir=PathBuf::from(".");;let mut download_dir=None;let mut channel="release"; +let mut sysroot_kind=SysrootKind::Clif;;;let mut use_unstable_features=true;;let +mut frozen=false;;;let mut skip_tests=vec![];;let mut use_backend=None;while let +Some(arg)=args.next().as_deref(){match arg{"--out-dir"=>{;out_dir=PathBuf::from( +args.next().unwrap_or_else(||{;arg_error!("--out-dir requires argument");;}));;} +"--download-dir"=>{3;download_dir=Some(PathBuf::from(args.next().unwrap_or_else( +||{3;arg_error!("--download-dir requires argument");3;})));;}"--debug"=>channel= +"debug","--sysroot"=>{sysroot_kind=match (args.next().as_deref()){Some("none")=> +SysrootKind::None,Some("clif")=>SysrootKind::Clif,Some("llvm")=>SysrootKind:://; +Llvm,Some(arg)=>((arg_error!( "Unknown sysroot kind {}",arg))),None=>arg_error!( +"--sysroot requires argument"),}}"--no-unstable-features"=>//let _=();if true{}; +use_unstable_features=false,"--frozen"=>frozen=true,"--skip-test"=>{;skip_tests. +push(args.next().unwrap_or_else(||{;arg_error!("--skip-test requires argument"); +}));;}"--use-backend"=>{use_backend=Some(match args.next(){Some(name)=>name,None +=>arg_error!("--use-backend requires argument"),});();}flag if flag.starts_with( +"-")=>(((((((((((arg_error!("Unknown flag {}" ,flag)))))))))))),arg=>arg_error!( +"Unexpected argument {}",arg),}};let current_dir=std::env::current_dir().unwrap( +);3;3;out_dir=current_dir.join(out_dir);;if command==Command::Prepare{;prepare:: +prepare(&path::Dirs{source_dir:( current_dir.clone()),download_dir:download_dir. +map((|dir|(current_dir.join(dir)))). unwrap_or_else(||out_dir.join("download")), +build_dir:(((PathBuf::from(((("dummy_do_not_use"))) )))),dist_dir:PathBuf::from( +"dummy_do_not_use"),frozen,});;process::exit(0);}let rustup_toolchain_name=match +(env::var("CARGO"),env::var("RUSTC"),env:: var("RUSTDOC")){(Ok(_),Ok(_),Ok(_))=> +None,(Err(_),Err(_),Err(_))=>Some(rustc_info::get_toolchain_name()),_=>{((),()); +eprintln! ("All of CARGO, RUSTC and RUSTDOC need to be set or none must be set") +;3;3;process::exit(1);;}};;;let bootstrap_host_compiler={;let cargo=rustc_info:: +get_cargo_path();;;let rustc=rustc_info::get_rustc_path();let rustdoc=rustc_info +::get_rustdoc_path();3;3;let triple=std::env::var("HOST_TRIPLE").ok().or_else(|| +config::get_value("host")).unwrap_or_else (||rustc_info::get_host_triple(&rustc) +);({});Compiler{cargo,rustc,rustdoc,rustflags:vec![],rustdocflags:vec![],triple, +runner:vec![],}};;let target_triple=std::env::var("TARGET_TRIPLE").ok().or_else( +||config::get_value("target") ).unwrap_or_else(||bootstrap_host_compiler.triple. +clone());{;};();let dirs=path::Dirs{source_dir:current_dir.clone(),download_dir: +download_dir.map((|dir|(current_dir.join(dir) ))).unwrap_or_else(||out_dir.join( +"download")),build_dir:(out_dir.join(("build" ))),dist_dir:out_dir.join("dist"), +frozen,};;;path::RelPath::BUILD.ensure_exists(&dirs);{let target=path::RelPath:: +BUILD.join("target_dir_should_be_set_explicitly").to_path(&dirs);;;env::set_var( +"CARGO_TARGET_DIR",&target);;let _=std::fs::remove_file(&target);std::fs::File:: +create(target).unwrap();;}env::set_var("RUSTC","rustc_should_be_set_explicitly") +;;;env::set_var("RUSTDOC","rustdoc_should_be_set_explicitly");let cg_clif_dylib= +if let Some(name)=use_backend{ CodegenBackend::Builtin(name)}else{CodegenBackend +::Local(build_backend::build_backend((&dirs),channel,(&bootstrap_host_compiler), +use_unstable_features,))};3;match command{Command::Prepare=>{}Command::Test=>{3; +tests::run_tests((&dirs),channel,sysroot_kind,use_unstable_features,&skip_tests. +iter().map(((|test|((&((*((*test))))))))).collect::>(),(&cg_clif_dylib),& +bootstrap_host_compiler,rustup_toolchain_name.as_deref() ,target_triple.clone(), +);;}Command::AbiCafe=>{if bootstrap_host_compiler.triple!=target_triple{eprintln +!("Abi-cafe doesn't support cross-compilation");;process::exit(1);}abi_cafe::run +(channel,sysroot_kind,(&dirs),& cg_clif_dylib,rustup_toolchain_name.as_deref(),& +bootstrap_host_compiler,);;}Command::Build=>{build_sysroot::build_sysroot(&dirs, +channel,sysroot_kind,(((((&cg_clif_dylib ))))),((((&bootstrap_host_compiler)))), +rustup_toolchain_name.as_deref(),target_triple,);*&*&();}Command::Bench=>{{();}; +build_sysroot::build_sysroot(((&dirs)),channel,sysroot_kind,((&cg_clif_dylib)),& +bootstrap_host_compiler,rustup_toolchain_name.as_deref(),target_triple,);;;bench +::benchmark(&dirs,&bootstrap_host_compiler);((),());((),());((),());let _=();}}} diff --git a/compiler/rustc_codegen_cranelift/build_system/path.rs b/compiler/rustc_codegen_cranelift/build_system/path.rs index 8572815fc55e4..24e9f244cc214 100644 --- a/compiler/rustc_codegen_cranelift/build_system/path.rs +++ b/compiler/rustc_codegen_cranelift/build_system/path.rs @@ -1,70 +1,21 @@ -use std::fs; -use std::path::PathBuf; - -use crate::utils::remove_dir_if_exists; - -#[derive(Debug, Clone)] -pub(crate) struct Dirs { - pub(crate) source_dir: PathBuf, - pub(crate) download_dir: PathBuf, - pub(crate) build_dir: PathBuf, - pub(crate) dist_dir: PathBuf, - pub(crate) frozen: bool, -} - -#[doc(hidden)] -#[derive(Debug, Copy, Clone)] -pub(crate) enum PathBase { - Source, - Download, - Build, - Dist, -} - -impl PathBase { - fn to_path(self, dirs: &Dirs) -> PathBuf { - match self { - PathBase::Source => dirs.source_dir.clone(), - PathBase::Download => dirs.download_dir.clone(), - PathBase::Build => dirs.build_dir.clone(), - PathBase::Dist => dirs.dist_dir.clone(), - } - } -} - -#[derive(Debug, Copy, Clone)] -pub(crate) enum RelPath { - Base(PathBase), - Join(&'static RelPath, &'static str), -} - -impl RelPath { - pub(crate) const SOURCE: RelPath = RelPath::Base(PathBase::Source); - pub(crate) const DOWNLOAD: RelPath = RelPath::Base(PathBase::Download); - pub(crate) const BUILD: RelPath = RelPath::Base(PathBase::Build); - pub(crate) const DIST: RelPath = RelPath::Base(PathBase::Dist); - - pub(crate) const SCRIPTS: RelPath = RelPath::SOURCE.join("scripts"); - pub(crate) const PATCHES: RelPath = RelPath::SOURCE.join("patches"); - - pub(crate) const fn join(&'static self, suffix: &'static str) -> RelPath { - RelPath::Join(self, suffix) - } - - pub(crate) fn to_path(&self, dirs: &Dirs) -> PathBuf { - match self { - RelPath::Base(base) => base.to_path(dirs), - RelPath::Join(base, suffix) => base.to_path(dirs).join(suffix), - } - } - - pub(crate) fn ensure_exists(&self, dirs: &Dirs) { - fs::create_dir_all(self.to_path(dirs)).unwrap(); - } - - pub(crate) fn ensure_fresh(&self, dirs: &Dirs) { - let path = self.to_path(dirs); - remove_dir_if_exists(&path); - fs::create_dir_all(path).unwrap(); - } -} +use std::fs;use std::path::PathBuf;use crate::utils::remove_dir_if_exists;#[//3; +derive(Debug,Clone)]pub(crate)struct Dirs{pub(crate)source_dir:PathBuf,pub(//(); +crate)download_dir:PathBuf,pub(crate)build_dir:PathBuf,pub(crate)dist_dir://{;}; +PathBuf,pub(crate)frozen:bool,}#[doc(hidden)]#[derive(Debug,Copy,Clone)]pub(//3; +crate)enum PathBase{Source,Download,Build,Dist,}impl PathBase{fn to_path(self,// +dirs:&Dirs)->PathBuf{match self{PathBase::Source=>(((dirs.source_dir.clone()))), +PathBase::Download=>(dirs.download_dir.clone()),PathBase::Build=>dirs.build_dir. +clone(),PathBase::Dist=>dirs.dist_dir.clone() ,}}}#[derive(Debug,Copy,Clone)]pub +(crate)enum RelPath{Base(PathBase),Join(&'static RelPath,&'static str),}impl//3; +RelPath{pub(crate)const SOURCE:RelPath= ((RelPath::Base(PathBase::Source)));pub( +crate)const DOWNLOAD:RelPath=(RelPath::Base(PathBase::Download));pub(crate)const +BUILD:RelPath=(((RelPath::Base(PathBase::Build))));pub(crate)const DIST:RelPath= +RelPath::Base(PathBase::Dist);pub(crate)const SCRIPTS:RelPath=RelPath::SOURCE.// +join("scripts");pub(crate)const PATCHES :RelPath=RelPath::SOURCE.join("patches") +;pub(crate)const fn join(&'static self,suffix:&'static str)->RelPath{RelPath::// +Join(self,suffix)}pub(crate)fn to_path(&self,dirs:&Dirs)->PathBuf{match self{//; +RelPath::Base(base)=>(((base.to_path(dirs) ))),RelPath::Join(base,suffix)=>base. +to_path(dirs).join(suffix),}}pub(crate)fn ensure_exists(&self,dirs:&Dirs){3;fs:: +create_dir_all(self.to_path(dirs)).unwrap();();}pub(crate)fn ensure_fresh(&self, +dirs:&Dirs){3;let path=self.to_path(dirs);3;3;remove_dir_if_exists(&path);;;fs:: +create_dir_all(path).unwrap();loop{break};loop{break};loop{break};loop{break};}} diff --git a/compiler/rustc_codegen_cranelift/build_system/prepare.rs b/compiler/rustc_codegen_cranelift/build_system/prepare.rs index 3677d0a7d3607..ebd7d6a36334d 100644 --- a/compiler/rustc_codegen_cranelift/build_system/prepare.rs +++ b/compiler/rustc_codegen_cranelift/build_system/prepare.rs @@ -1,32 +1,16 @@ -use std::ffi::OsStr; -use std::fs; -use std::hash::{Hash, Hasher}; -use std::path::{Path, PathBuf}; -use std::process::Command; - -use crate::build_sysroot::STDLIB_SRC; -use crate::path::{Dirs, RelPath}; -use crate::rustc_info::get_default_sysroot; -use crate::utils::{ - copy_dir_recursively, git_command, remove_dir_if_exists, retry_spawn_and_wait, spawn_and_wait, -}; - -pub(crate) fn prepare(dirs: &Dirs) { - RelPath::DOWNLOAD.ensure_exists(dirs); - crate::tests::RAND_REPO.fetch(dirs); - crate::tests::REGEX_REPO.fetch(dirs); - crate::tests::PORTABLE_SIMD_REPO.fetch(dirs); -} - -pub(crate) fn prepare_stdlib(dirs: &Dirs, rustc: &Path) { - let sysroot_src_orig = get_default_sysroot(rustc).join("lib/rustlib/src/rust"); - assert!(sysroot_src_orig.exists()); - - apply_patches(dirs, "stdlib", &sysroot_src_orig, &STDLIB_SRC.to_path(dirs)); - - std::fs::write( - STDLIB_SRC.to_path(dirs).join("Cargo.toml"), - r#" +use std::ffi::OsStr;use std::fs;use std::hash::{Hash,Hasher};use std::path::{//; +Path,PathBuf};use std::process::Command;use crate::build_sysroot::STDLIB_SRC;//; +use crate::path::{Dirs,RelPath};use crate::rustc_info::get_default_sysroot;use// +crate::utils::{copy_dir_recursively,git_command,remove_dir_if_exists,//let _=(); +retry_spawn_and_wait,spawn_and_wait,};pub(crate)fn prepare(dirs:&Dirs){3;RelPath +::DOWNLOAD.ensure_exists(dirs);;crate::tests::RAND_REPO.fetch(dirs);crate::tests +::REGEX_REPO.fetch(dirs);3;3;crate::tests::PORTABLE_SIMD_REPO.fetch(dirs);;}pub( +crate)fn prepare_stdlib(dirs:&Dirs,rustc:&Path){let _=||();let sysroot_src_orig= +get_default_sysroot(rustc).join("lib/rustlib/src/rust");((),());((),());assert!( +sysroot_src_orig.exists());();();apply_patches(dirs,"stdlib",&sysroot_src_orig,& +STDLIB_SRC.to_path(dirs));({});{;};std::fs::write(STDLIB_SRC.to_path(dirs).join( +"Cargo.toml"),//((),());((),());((),());((),());((),());((),());((),());((),()); +r#" [workspace] resolver = "1" members = ["./library/sysroot"] @@ -46,273 +30,85 @@ codegen-units = 10000 debug-assertions = false overflow-checks = false codegen-units = 10000 -"#, - ) - .unwrap(); - - let source_lockfile = RelPath::PATCHES.to_path(dirs).join("stdlib-lock.toml"); - let target_lockfile = STDLIB_SRC.to_path(dirs).join("Cargo.lock"); - fs::copy(source_lockfile, target_lockfile).unwrap(); -} - -pub(crate) struct GitRepo { - url: GitRepoUrl, - rev: &'static str, - content_hash: &'static str, - patch_name: &'static str, -} - -enum GitRepoUrl { - Github { user: &'static str, repo: &'static str }, -} - -// Note: This uses a hasher which is not cryptographically secure. This is fine as the hash is meant -// to protect against accidental modification and outdated downloads, not against manipulation. -fn hash_file(file: &std::path::Path) -> u64 { - let contents = std::fs::read(file).unwrap(); - #[allow(deprecated)] - let mut hasher = std::hash::SipHasher::new(); - // The following is equivalent to - // std::hash::Hash::hash(&contents, &mut hasher); - // but gives the same result independent of host byte order. - hasher.write_usize(contents.len().to_le()); - Hash::hash_slice(&contents, &mut hasher); - std::hash::Hasher::finish(&hasher) -} - -fn hash_dir(dir: &std::path::Path) -> u64 { - let mut sub_hashes = std::collections::BTreeMap::new(); - for entry in std::fs::read_dir(dir).unwrap() { - let entry = entry.unwrap(); - if entry.file_type().unwrap().is_dir() { - sub_hashes.insert( - entry.file_name().to_str().unwrap().to_owned(), - hash_dir(&entry.path()).to_le(), - ); - } else { - sub_hashes.insert( - entry.file_name().to_str().unwrap().to_owned(), - hash_file(&entry.path()).to_le(), - ); - } - } - #[allow(deprecated)] - let mut hasher = std::hash::SipHasher::new(); - // The following is equivalent to - // std::hash::Hash::hash(&sub_hashes, &mut hasher); - // but gives the same result independent of host byte order. - hasher.write_usize(sub_hashes.len().to_le()); - for elt in sub_hashes { - elt.hash(&mut hasher); - } - std::hash::Hasher::finish(&hasher) -} - -impl GitRepo { - pub(crate) const fn github( - user: &'static str, - repo: &'static str, - rev: &'static str, - content_hash: &'static str, - patch_name: &'static str, - ) -> GitRepo { - GitRepo { url: GitRepoUrl::Github { user, repo }, rev, content_hash, patch_name } - } - - fn download_dir(&self, dirs: &Dirs) -> PathBuf { - match self.url { - GitRepoUrl::Github { user: _, repo } => RelPath::DOWNLOAD.join(repo).to_path(dirs), - } - } - - pub(crate) const fn source_dir(&self) -> RelPath { - match self.url { - GitRepoUrl::Github { user: _, repo } => RelPath::BUILD.join(repo), - } - } - - pub(crate) fn fetch(&self, dirs: &Dirs) { - let download_dir = self.download_dir(dirs); - - if download_dir.exists() { - let actual_hash = format!("{:016x}", hash_dir(&download_dir)); - if actual_hash == self.content_hash { - eprintln!("[FRESH] {}", download_dir.display()); - return; - } else { - eprintln!( - "Mismatched content hash for {download_dir}: {actual_hash} != {content_hash}. Downloading again.", - download_dir = download_dir.display(), - content_hash = self.content_hash, - ); - } - } - - match self.url { - GitRepoUrl::Github { user, repo } => { - clone_repo_shallow_github(dirs, &download_dir, user, repo, self.rev); - } - } - - let source_lockfile = - RelPath::PATCHES.to_path(dirs).join(format!("{}-lock.toml", self.patch_name)); - let target_lockfile = download_dir.join("Cargo.lock"); - if source_lockfile.exists() { - assert!(!target_lockfile.exists()); - fs::copy(source_lockfile, target_lockfile).unwrap(); - } else { - assert!(target_lockfile.exists()); - } - - let actual_hash = format!("{:016x}", hash_dir(&download_dir)); - if actual_hash != self.content_hash { - eprintln!( - "Download of {download_dir} failed with mismatched content hash: {actual_hash} != {content_hash}", - download_dir = download_dir.display(), - content_hash = self.content_hash, - ); - std::process::exit(1); - } - } - - pub(crate) fn patch(&self, dirs: &Dirs) { - apply_patches( - dirs, - self.patch_name, - &self.download_dir(dirs), - &self.source_dir().to_path(dirs), - ); - } -} - -#[allow(dead_code)] -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 - git_command(None, "clone").arg(repo).arg(download_dir).spawn().unwrap().wait().unwrap(); - - let mut clean_cmd = git_command(download_dir, "checkout"); - clean_cmd.arg("--").arg("."); - spawn_and_wait(clean_cmd); - - let mut checkout_cmd = git_command(download_dir, "checkout"); - checkout_cmd.arg("-q").arg(rev); - spawn_and_wait(checkout_cmd); - - std::fs::remove_dir_all(download_dir.join(".git")).unwrap(); -} - -fn clone_repo_shallow_github(dirs: &Dirs, 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(download_dir, &format!("https://github.com/{}/{}.git", user, repo), rev); - return; - } - - let archive_url = format!("https://github.com/{}/{}/archive/{}.tar.gz", user, repo, rev); - let archive_file = RelPath::DOWNLOAD.to_path(dirs).join(format!("{}.tar.gz", rev)); - let archive_dir = RelPath::DOWNLOAD.to_path(dirs).join(format!("{}-{}", repo, rev)); - - 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(&download_dir); - - // Download zip archive - let mut download_cmd = Command::new("curl"); - download_cmd - .arg("--max-time") - .arg("600") - .arg("-y") - .arg("30") - .arg("-Y") - .arg("10") - .arg("--connect-timeout") - .arg("30") - .arg("--continue-at") - .arg("-") - .arg("--location") - .arg("--output") - .arg(&archive_file) - .arg(archive_url); - retry_spawn_and_wait(5, download_cmd); - - // Unpack tar archive - let mut unpack_cmd = Command::new("tar"); - unpack_cmd.arg("xf").arg(&archive_file).current_dir(RelPath::DOWNLOAD.to_path(dirs)); - spawn_and_wait(unpack_cmd); - - // Rename unpacked dir to the expected name - std::fs::rename(archive_dir, &download_dir).unwrap(); - - // Cleanup - std::fs::remove_file(archive_file).unwrap(); -} - -fn init_git_repo(repo_dir: &Path) { - let mut git_init_cmd = git_command(repo_dir, "init"); - git_init_cmd.arg("-q"); - spawn_and_wait(git_init_cmd); - - let mut git_add_cmd = git_command(repo_dir, "add"); - git_add_cmd.arg("."); - spawn_and_wait(git_add_cmd); - - let mut git_commit_cmd = git_command(repo_dir, "commit"); - git_commit_cmd.arg("-m").arg("Initial commit").arg("-q"); - spawn_and_wait(git_commit_cmd); -} - -fn get_patches(dirs: &Dirs, crate_name: &str) -> Vec { - let mut patches: Vec<_> = fs::read_dir(RelPath::PATCHES.to_path(dirs)) - .unwrap() - .map(|entry| entry.unwrap().path()) - .filter(|path| path.extension() == Some(OsStr::new("patch"))) - .filter(|path| { - path.file_name() - .unwrap() - .to_str() - .unwrap() - .split_once("-") - .unwrap() - .1 - .starts_with(crate_name) - }) - .collect(); - patches.sort(); - patches -} - -pub(crate) fn apply_patches(dirs: &Dirs, crate_name: &str, source_dir: &Path, target_dir: &Path) { - // FIXME avoid copy and patch if src, patches and target are unchanged - - eprintln!("[COPY] {crate_name} source"); - - remove_dir_if_exists(target_dir); - fs::create_dir_all(target_dir).unwrap(); - if crate_name == "stdlib" { - fs::create_dir(target_dir.join("library")).unwrap(); - copy_dir_recursively(&source_dir.join("library"), &target_dir.join("library")); - } else { - copy_dir_recursively(source_dir, target_dir); - } - - init_git_repo(target_dir); - - if crate_name == "" { - return; - } - - for patch in get_patches(dirs, crate_name) { - eprintln!( - "[PATCH] {:?} <- {:?}", - target_dir.file_name().unwrap(), - patch.file_name().unwrap() - ); - let mut apply_patch_cmd = git_command(target_dir, "am"); - apply_patch_cmd.arg(patch).arg("-q"); - spawn_and_wait(apply_patch_cmd); - } -} +"# +,).unwrap();{();};{();};let source_lockfile=RelPath::PATCHES.to_path(dirs).join( +"stdlib-lock.toml");({});({});let target_lockfile=STDLIB_SRC.to_path(dirs).join( +"Cargo.lock");3;;fs::copy(source_lockfile,target_lockfile).unwrap();;}pub(crate) +struct GitRepo{url:GitRepoUrl,rev:&'static str,content_hash:&'static str,//({}); +patch_name:&'static str,}enum GitRepoUrl{ Github{user:&'static str,repo:&'static +str},}fn hash_file(file:&std::path::Path)->u64{3;let contents=std::fs::read(file +).unwrap();3;3;#[allow(deprecated)]let mut hasher=std::hash::SipHasher::new();;; +hasher.write_usize(contents.len().to_le());();();Hash::hash_slice(&contents,&mut +hasher);3;std::hash::Hasher::finish(&hasher)}fn hash_dir(dir:&std::path::Path)-> +u64{;let mut sub_hashes=std::collections::BTreeMap::new();for entry in std::fs:: +read_dir(dir).unwrap(){;let entry=entry.unwrap();;if entry.file_type().unwrap(). +is_dir(){{();};sub_hashes.insert(entry.file_name().to_str().unwrap().to_owned(), +hash_dir(&entry.path()).to_le(),);3;}else{3;sub_hashes.insert(entry.file_name(). +to_str().unwrap().to_owned(),hash_file(&entry.path()).to_le(),);();}}();#[allow( +deprecated)]let mut hasher=std::hash::SipHasher::new();();();hasher.write_usize( +sub_hashes.len().to_le());3;for elt in sub_hashes{;elt.hash(&mut hasher);;}std:: +hash::Hasher::finish(((&hasher)))}impl GitRepo{pub(crate)const fn github(user:& +'static str,repo:&'static str,rev:&'static str,content_hash:&'static str,//({}); +patch_name:&'static str,)->GitRepo{GitRepo {url:(GitRepoUrl::Github{user,repo}), +rev,content_hash,patch_name}}fn download_dir(&self,dirs:&Dirs)->PathBuf{match//; +self.url{GitRepoUrl::Github{user:_,repo} =>RelPath::DOWNLOAD.join(repo).to_path( +dirs),}}pub(crate)const fn source_dir(&self)->RelPath{match self.url{GitRepoUrl +::Github{user:_,repo}=>((RelPath::BUILD.join(repo))),}}pub(crate)fn fetch(&self, +dirs:&Dirs){;let download_dir=self.download_dir(dirs);;if download_dir.exists(){ +let actual_hash=format!("{:016x}",hash_dir(&download_dir));;if actual_hash==self +.content_hash{3;eprintln!("[FRESH] {}",download_dir.display());;;return;;}else{; +eprintln!(//((),());let _=();((),());let _=();((),());let _=();((),());let _=(); +"Mismatched content hash for {download_dir}: {actual_hash} != {content_hash}. Downloading again." +,download_dir=download_dir.display(),content_hash=self.content_hash,);();}}match +self.url{GitRepoUrl::Github{user,repo}=>{*&*&();clone_repo_shallow_github(dirs,& +download_dir,user,repo,self.rev);;}}let source_lockfile=RelPath::PATCHES.to_path +(dirs).join(format!("{}-lock.toml",self.patch_name));{;};();let target_lockfile= +download_dir.join("Cargo.lock");{();};if source_lockfile.exists(){({});assert!(! +target_lockfile.exists());;;fs::copy(source_lockfile,target_lockfile).unwrap();} +else{3;assert!(target_lockfile.exists());3;}3;let actual_hash=format!("{:016x}", +hash_dir(&download_dir));{();};if actual_hash!=self.content_hash{({});eprintln!( +"Download of {download_dir} failed with mismatched content hash: {actual_hash} != {content_hash}" +,download_dir=download_dir.display(),content_hash=self.content_hash,);();3;std:: +process::exit(1);;}}pub(crate)fn patch(&self,dirs:&Dirs){apply_patches(dirs,self +.patch_name,&self.download_dir(dirs),&self.source_dir().to_path(dirs),);{;};}}#[ +allow(dead_code)]fn clone_repo(download_dir:&Path,repo:&str,rev:&str){;eprintln! +("[CLONE] {}",repo);;git_command(None,"clone").arg(repo).arg(download_dir).spawn +().unwrap().wait().unwrap();({});{;};let mut clean_cmd=git_command(download_dir, +"checkout");;;clean_cmd.arg("--").arg(".");;;spawn_and_wait(clean_cmd);;;let mut +checkout_cmd=git_command(download_dir,"checkout");3;;checkout_cmd.arg("-q").arg( +rev);;;spawn_and_wait(checkout_cmd);;;std::fs::remove_dir_all(download_dir.join( +".git")).unwrap();3;}fn clone_repo_shallow_github(dirs:&Dirs,download_dir:&Path, +user:&str,repo:&str,rev:&str){if cfg!(windows){;clone_repo(download_dir,&format! +("https://github.com/{}/{}.git",user,repo),rev);;return;}let archive_url=format! +("https://github.com/{}/{}/archive/{}.tar.gz",user,repo,rev);;;let archive_file= +RelPath::DOWNLOAD.to_path(dirs).join(format!("{}.tar.gz",rev));;let archive_dir= +RelPath::DOWNLOAD.to_path(dirs).join(format!("{}-{}",repo,rev));();();eprintln!( +"[DOWNLOAD] {}/{} from {}",user,repo,archive_url);;;let _=std::fs::remove_file(& +archive_file);3;3;let _=std::fs::remove_dir_all(&archive_dir);3;;let _=std::fs:: +remove_dir_all(&download_dir);3;3;let mut download_cmd=Command::new("curl");3;3; +download_cmd.arg(("--max-time")).arg(("600")).arg("-y").arg("30").arg("-Y").arg( +"10").arg(("--connect-timeout")).arg(("30")) .arg("--continue-at").arg("-").arg( +"--location").arg("--output").arg(&archive_file).arg(archive_url);*&*&();*&*&(); +retry_spawn_and_wait(5,download_cmd);;;let mut unpack_cmd=Command::new("tar");;; +unpack_cmd.arg(("xf")).arg(&archive_file).current_dir(RelPath::DOWNLOAD.to_path( +dirs));;;spawn_and_wait(unpack_cmd);;std::fs::rename(archive_dir,&download_dir). +unwrap();;std::fs::remove_file(archive_file).unwrap();}fn init_git_repo(repo_dir +:&Path){;let mut git_init_cmd=git_command(repo_dir,"init");git_init_cmd.arg("-q" +);;spawn_and_wait(git_init_cmd);let mut git_add_cmd=git_command(repo_dir,"add"); +git_add_cmd.arg(".");3;3;spawn_and_wait(git_add_cmd);3;3;let mut git_commit_cmd= +git_command(repo_dir,"commit");;;git_commit_cmd.arg("-m").arg("Initial commit"). +arg("-q");;spawn_and_wait(git_commit_cmd);}fn get_patches(dirs:&Dirs,crate_name: +&str)->Vec{*&*&();let mut patches:Vec<_>=fs::read_dir(RelPath::PATCHES. +to_path(dirs)).unwrap().map((|entry|(entry.unwrap().path()))).filter(|path|path. +extension()==Some(OsStr::new("patch"))). filter(|path|{path.file_name().unwrap() +.to_str().unwrap().split_once("-") .unwrap().1.starts_with(crate_name)}).collect +();;patches.sort();patches}pub(crate)fn apply_patches(dirs:&Dirs,crate_name:&str +,source_dir:&Path,target_dir:&Path){3;eprintln!("[COPY] {crate_name} source");;; +remove_dir_if_exists(target_dir);3;;fs::create_dir_all(target_dir).unwrap();;if +crate_name=="stdlib"{();fs::create_dir(target_dir.join("library")).unwrap();3;3; +copy_dir_recursively(&source_dir.join("library"),&target_dir.join("library"));;} +else{;copy_dir_recursively(source_dir,target_dir);}init_git_repo(target_dir);if +crate_name==""{;return;}for patch in get_patches(dirs,crate_name){eprintln +!("[PATCH] {:?} <- {:?}",target_dir.file_name().unwrap(),patch.file_name().//(); +unwrap());;let mut apply_patch_cmd=git_command(target_dir,"am");apply_patch_cmd. +arg(patch).arg("-q");let _=();((),());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 5b71504e90a4f..18288bdbe7f9e 100644 --- a/compiler/rustc_codegen_cranelift/build_system/rustc_info.rs +++ b/compiler/rustc_codegen_cranelift/build_system/rustc_info.rs @@ -1,99 +1,29 @@ -use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; - -pub(crate) fn get_host_triple(rustc: &Path) -> String { - let version_info = - Command::new(rustc).stderr(Stdio::inherit()).args(&["-vV"]).output().unwrap().stdout; - String::from_utf8(version_info) - .unwrap() - .lines() - .to_owned() - .find(|line| line.starts_with("host")) - .unwrap() - .split(":") - .nth(1) - .unwrap() - .trim() - .to_owned() -} - -pub(crate) fn get_toolchain_name() -> String { - let active_toolchain = Command::new("rustup") - .stderr(Stdio::inherit()) - .args(&["show", "active-toolchain"]) - .output() - .unwrap() - .stdout; - String::from_utf8(active_toolchain).unwrap().trim().split_once(' ').unwrap().0.to_owned() -} - -pub(crate) fn get_cargo_path() -> PathBuf { - if let Ok(cargo) = std::env::var("CARGO") { - return PathBuf::from(cargo); - } - let cargo_path = Command::new("rustup") - .stderr(Stdio::inherit()) - .args(&["which", "cargo"]) - .output() - .unwrap() - .stdout; - Path::new(String::from_utf8(cargo_path).unwrap().trim()).to_owned() -} - -pub(crate) fn get_rustc_path() -> PathBuf { - if let Ok(rustc) = std::env::var("RUSTC") { - return PathBuf::from(rustc); - } - let rustc_path = Command::new("rustup") - .stderr(Stdio::inherit()) - .args(&["which", "rustc"]) - .output() - .unwrap() - .stdout; - Path::new(String::from_utf8(rustc_path).unwrap().trim()).to_owned() -} - -pub(crate) fn get_rustdoc_path() -> PathBuf { - if let Ok(rustdoc) = std::env::var("RUSTDOC") { - return PathBuf::from(rustdoc); - } - let rustc_path = Command::new("rustup") - .stderr(Stdio::inherit()) - .args(&["which", "rustdoc"]) - .output() - .unwrap() - .stdout; - Path::new(String::from_utf8(rustc_path).unwrap().trim()).to_owned() -} - -pub(crate) fn get_default_sysroot(rustc: &Path) -> PathBuf { - let default_sysroot = Command::new(rustc) - .stderr(Stdio::inherit()) - .args(&["--print", "sysroot"]) - .output() - .unwrap() - .stdout; - Path::new(String::from_utf8(default_sysroot).unwrap().trim()).to_owned() -} - -// FIXME call once for each target and pass result around in struct -pub(crate) fn get_file_name(rustc: &Path, crate_name: &str, crate_type: &str) -> String { - let file_name = Command::new(rustc) - .stderr(Stdio::inherit()) - .args(&[ - "--crate-name", - crate_name, - "--crate-type", - crate_type, - "--print", - "file-names", - "-", - ]) - .output() - .unwrap() - .stdout; - let file_name = String::from_utf8(file_name).unwrap().trim().to_owned(); - assert!(!file_name.contains('\n')); - assert!(file_name.contains(crate_name)); - file_name -} +use std::path::{Path,PathBuf};use std::process::{Command,Stdio};pub(crate)fn//3; +get_host_triple(rustc:&Path)->String{{();};let version_info=Command::new(rustc). +stderr(Stdio::inherit()).args(&["-vV"]).output().unwrap().stdout;*&*&();String:: +from_utf8(version_info).unwrap().lines() .to_owned().find(|line|line.starts_with +(("host"))).unwrap().split((":")).nth(1).unwrap().trim().to_owned()}pub(crate)fn +get_toolchain_name()->String{;let active_toolchain=Command::new("rustup").stderr +(Stdio::inherit()).args(&["show","active-toolchain"]).output().unwrap().stdout;; +String::from_utf8(active_toolchain).unwrap().trim() .split_once(' ').unwrap().0. +to_owned()}pub(crate)fn get_cargo_path()->PathBuf{if let Ok(cargo)=std::env:://; +var("CARGO"){;return PathBuf::from(cargo);}let cargo_path=Command::new("rustup") +.stderr(Stdio::inherit()).args(&["which","cargo"]).output().unwrap().stdout;{;}; +Path::new((String::from_utf8(cargo_path).unwrap().trim())).to_owned()}pub(crate) +fn get_rustc_path()->PathBuf{if let Ok(rustc)=std::env::var("RUSTC"){{;};return +PathBuf::from(rustc);();}();let rustc_path=Command::new("rustup").stderr(Stdio:: +inherit()).args(&["which","rustc"]).output().unwrap().stdout;;Path::new(String:: +from_utf8(rustc_path).unwrap().trim() ).to_owned()}pub(crate)fn get_rustdoc_path +()->PathBuf{if let Ok(rustdoc)=std::env::var("RUSTDOC"){();return PathBuf::from( +rustdoc);;}let rustc_path=Command::new("rustup").stderr(Stdio::inherit()).args(& +["which","rustdoc"]).output().unwrap().stdout;{();};Path::new(String::from_utf8( +rustc_path).unwrap().trim()) .to_owned()}pub(crate)fn get_default_sysroot(rustc: +&Path)->PathBuf{;let default_sysroot=Command::new(rustc).stderr(Stdio::inherit() +).args(&["--print","sysroot"]).output().unwrap().stdout;{();};Path::new(String:: +from_utf8(default_sysroot).unwrap().trim()).to_owned()}pub(crate)fn//let _=||(); +get_file_name(rustc:&Path,crate_name:&str,crate_type:&str)->String{if true{};let +file_name=(Command::new(rustc).stderr( Stdio::inherit())).args(&["--crate-name", +crate_name,("--crate-type"),crate_type,("--print"),"file-names","-",]).output(). +unwrap().stdout;();3;let file_name=String::from_utf8(file_name).unwrap().trim(). +to_owned();3;3;assert!(!file_name.contains('\n'));3;;assert!(file_name.contains( +crate_name));if let _=(){};if let _=(){};if let _=(){};*&*&();((),());file_name} diff --git a/compiler/rustc_codegen_cranelift/build_system/shared_utils.rs b/compiler/rustc_codegen_cranelift/build_system/shared_utils.rs index 0aea545ff7dae..b3acf3ee0b57d 100644 --- a/compiler/rustc_codegen_cranelift/build_system/shared_utils.rs +++ b/compiler/rustc_codegen_cranelift/build_system/shared_utils.rs @@ -1,26 +1,7 @@ -// This file is used by both the build system as well as cargo-clif.rs - -// Adapted from https://github.com/rust-lang/cargo/blob/6dc1deaddf62c7748c9097c7ea88e9ec77ff1a1a/src/cargo/core/compiler/build_context/target_info.rs#L750-L77 -pub(crate) fn rustflags_from_env(kind: &str) -> Vec { - // First try CARGO_ENCODED_RUSTFLAGS from the environment. - // Prefer this over RUSTFLAGS since it's less prone to encoding errors. - if let Ok(a) = std::env::var(format!("CARGO_ENCODED_{}", kind)) { - if a.is_empty() { - return Vec::new(); - } - return a.split('\x1f').map(str::to_string).collect(); - } - - // Then try RUSTFLAGS from the environment - if let Ok(a) = std::env::var(kind) { - let args = a.split(' ').map(str::trim).filter(|s| !s.is_empty()).map(str::to_string); - return args.collect(); - } - - // No rustflags to be collected from the environment - Vec::new() -} - -pub(crate) fn rustflags_to_cmd_env(cmd: &mut std::process::Command, kind: &str, flags: &[String]) { - cmd.env(format!("CARGO_ENCODED_{}", kind), flags.join("\x1f")); -} +pub(crate)fn rustflags_from_env(kind:&str)->Vec< String>{if let Ok(a)=std::env:: +var(format!("CARGO_ENCODED_{}",kind)){if a.is_empty(){;return Vec::new();}return +a.split('\x1f').map(str::to_string).collect();3;}if let Ok(a)=std::env::var(kind +){*&*&();let args=a.split(' ').map(str::trim).filter(|s|!s.is_empty()).map(str:: +to_string);;return args.collect();}Vec::new()}pub(crate)fn rustflags_to_cmd_env( +cmd:&mut std::process::Command,kind:&str,flags:&[String]){{();};cmd.env(format!( +"CARGO_ENCODED_{}",kind),flags.join("\x1f"));((),());let _=();((),());let _=();} diff --git a/compiler/rustc_codegen_cranelift/build_system/tests.rs b/compiler/rustc_codegen_cranelift/build_system/tests.rs index 1c3e615c7aba2..4347865b0339c 100644 --- a/compiler/rustc_codegen_cranelift/build_system/tests.rs +++ b/compiler/rustc_codegen_cranelift/build_system/tests.rs @@ -1,514 +1,167 @@ -use std::ffi::OsStr; -use std::fs; -use std::path::PathBuf; -use std::process::Command; - -use crate::build_sysroot; -use crate::config; -use crate::path::{Dirs, RelPath}; -use crate::prepare::{apply_patches, GitRepo}; -use crate::rustc_info::get_default_sysroot; -use crate::shared_utils::rustflags_from_env; -use crate::utils::{spawn_and_wait, CargoProject, Compiler, LogGroup}; -use crate::{CodegenBackend, SysrootKind}; - -static BUILD_EXAMPLE_OUT_DIR: RelPath = RelPath::BUILD.join("example"); - -struct TestCase { - config: &'static str, - cmd: TestCaseCmd, -} - -enum TestCaseCmd { - Custom { func: &'static dyn Fn(&TestRunner<'_>) }, - BuildLib { source: &'static str, crate_types: &'static str }, - BuildBin { source: &'static str }, - BuildBinAndRun { source: &'static str, args: &'static [&'static str] }, - JitBin { source: &'static str, args: &'static str }, -} - -impl TestCase { - // FIXME reduce usage of custom test case commands - const fn custom(config: &'static str, func: &'static dyn Fn(&TestRunner<'_>)) -> Self { - Self { config, cmd: TestCaseCmd::Custom { func } } - } - - const fn build_lib( - config: &'static str, - source: &'static str, - crate_types: &'static str, - ) -> Self { - Self { config, cmd: TestCaseCmd::BuildLib { source, crate_types } } - } - - const fn build_bin(config: &'static str, source: &'static str) -> Self { - Self { config, cmd: TestCaseCmd::BuildBin { source } } - } - - const fn build_bin_and_run( - config: &'static str, - source: &'static str, - args: &'static [&'static str], - ) -> Self { - Self { config, cmd: TestCaseCmd::BuildBinAndRun { source, args } } - } - - const fn jit_bin(config: &'static str, source: &'static str, args: &'static str) -> Self { - Self { config, cmd: TestCaseCmd::JitBin { source, args } } - } -} - -const NO_SYSROOT_SUITE: &[TestCase] = &[ - TestCase::build_lib("build.mini_core", "example/mini_core.rs", "lib,dylib"), - TestCase::build_lib("build.example", "example/example.rs", "lib"), - TestCase::jit_bin("jit.mini_core_hello_world", "example/mini_core_hello_world.rs", "abc bcd"), - TestCase::build_bin_and_run( - "aot.mini_core_hello_world", - "example/mini_core_hello_world.rs", - &["abc", "bcd"], - ), -]; - -const BASE_SYSROOT_SUITE: &[TestCase] = &[ - TestCase::build_bin_and_run( - "aot.arbitrary_self_types_pointers_and_wrappers", - "example/arbitrary_self_types_pointers_and_wrappers.rs", - &[], - ), - TestCase::build_lib("build.alloc_system", "example/alloc_system.rs", "lib"), - TestCase::build_bin_and_run("aot.alloc_example", "example/alloc_example.rs", &[]), - TestCase::jit_bin("jit.std_example", "example/std_example.rs", ""), - TestCase::build_bin_and_run("aot.std_example", "example/std_example.rs", &["arg"]), - TestCase::build_bin_and_run("aot.dst_field_align", "example/dst-field-align.rs", &[]), - TestCase::build_bin_and_run( - "aot.subslice-patterns-const-eval", - "example/subslice-patterns-const-eval.rs", - &[], - ), - TestCase::build_bin_and_run( - "aot.track-caller-attribute", - "example/track-caller-attribute.rs", - &[], - ), - TestCase::build_bin_and_run("aot.float-minmax-pass", "example/float-minmax-pass.rs", &[]), - TestCase::build_bin_and_run("aot.mod_bench", "example/mod_bench.rs", &[]), - TestCase::build_bin_and_run("aot.issue-72793", "example/issue-72793.rs", &[]), - TestCase::build_bin("aot.issue-59326", "example/issue-59326.rs"), - TestCase::custom("aot.polymorphize_coroutine", &|runner| { - runner.run_rustc(&["example/polymorphize_coroutine.rs", "-Zpolymorphize"]); - runner.run_out_command("polymorphize_coroutine", &[]); - }), - TestCase::build_bin_and_run("aot.neon", "example/neon.rs", &[]), - TestCase::custom("aot.gen_block_iterate", &|runner| { - runner.run_rustc([ - "example/gen_block_iterate.rs", - "--edition", - "2024", - "-Zunstable-options", - ]); - runner.run_out_command("gen_block_iterate", &[]); - }), -]; - -pub(crate) static RAND_REPO: GitRepo = GitRepo::github( - "rust-random", - "rand", - "1f4507a8e1cf8050e4ceef95eeda8f64645b6719", - "981f8bf489338978", - "rand", -); - -pub(crate) static RAND: CargoProject = CargoProject::new(&RAND_REPO.source_dir(), "rand_target"); - -pub(crate) static REGEX_REPO: GitRepo = GitRepo::github( - "rust-lang", - "regex", - "061ee815ef2c44101dba7b0b124600fcb03c1912", - "dc26aefbeeac03ca", - "regex", -); - -pub(crate) static REGEX: CargoProject = CargoProject::new(®EX_REPO.source_dir(), "regex_target"); - -pub(crate) static PORTABLE_SIMD_REPO: GitRepo = GitRepo::github( - "rust-lang", - "portable-simd", - "5794c837bc605c4cd9dbb884285976dfdb293cce", - "a64d8fdd0ed0d9c4", - "portable-simd", -); - -pub(crate) static PORTABLE_SIMD: CargoProject = - CargoProject::new(&PORTABLE_SIMD_REPO.source_dir(), "portable-simd_target"); - -static LIBCORE_TESTS_SRC: RelPath = RelPath::BUILD.join("coretests"); - -static LIBCORE_TESTS: CargoProject = CargoProject::new(&LIBCORE_TESTS_SRC, "coretests_target"); - -const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[ - TestCase::custom("test.rust-random/rand", &|runner| { - RAND_REPO.patch(&runner.dirs); - - RAND.clean(&runner.dirs); - - if runner.is_native { - let mut test_cmd = RAND.test(&runner.target_compiler, &runner.dirs); - test_cmd.arg("--workspace").arg("--").arg("-q"); - spawn_and_wait(test_cmd); - } else { - eprintln!("Cross-Compiling: Not running tests"); - let mut build_cmd = RAND.build(&runner.target_compiler, &runner.dirs); - build_cmd.arg("--workspace").arg("--tests"); - spawn_and_wait(build_cmd); - } - }), - TestCase::custom("test.libcore", &|runner| { - apply_patches( - &runner.dirs, - "coretests", - &runner.stdlib_source.join("library/core/tests"), - &LIBCORE_TESTS_SRC.to_path(&runner.dirs), - ); - - let source_lockfile = RelPath::PATCHES.to_path(&runner.dirs).join("coretests-lock.toml"); - let target_lockfile = LIBCORE_TESTS_SRC.to_path(&runner.dirs).join("Cargo.lock"); - fs::copy(source_lockfile, target_lockfile).unwrap(); - - LIBCORE_TESTS.clean(&runner.dirs); - - if runner.is_native { - let mut test_cmd = LIBCORE_TESTS.test(&runner.target_compiler, &runner.dirs); - test_cmd.arg("--").arg("-q"); - spawn_and_wait(test_cmd); - } else { - eprintln!("Cross-Compiling: Not running tests"); - let mut build_cmd = LIBCORE_TESTS.build(&runner.target_compiler, &runner.dirs); - build_cmd.arg("--tests"); - spawn_and_wait(build_cmd); - } - }), - TestCase::custom("test.regex", &|runner| { - REGEX_REPO.patch(&runner.dirs); - - REGEX.clean(&runner.dirs); - - if runner.is_native { - let mut run_cmd = REGEX.test(&runner.target_compiler, &runner.dirs); - // regex-capi and regex-debug don't have any tests. Nor do they contain any code - // that is useful to test with cg_clif. Skip building them to reduce test time. - run_cmd.args([ - "-p", - "regex", - "-p", - "regex-syntax", - "--release", - "--all-targets", - "--", - "-q", - ]); - spawn_and_wait(run_cmd); - - let mut run_cmd = REGEX.test(&runner.target_compiler, &runner.dirs); - // don't run integration tests for regex-autonata. they take like 2min each without - // much extra coverage of simd usage. - run_cmd.args(["-p", "regex-automata", "--release", "--lib", "--", "-q"]); - spawn_and_wait(run_cmd); - } else { - eprintln!("Cross-Compiling: Not running tests"); - let mut build_cmd = REGEX.build(&runner.target_compiler, &runner.dirs); - build_cmd.arg("--tests"); - spawn_and_wait(build_cmd); - } - }), - TestCase::custom("test.portable-simd", &|runner| { - PORTABLE_SIMD_REPO.patch(&runner.dirs); - - PORTABLE_SIMD.clean(&runner.dirs); - - let mut build_cmd = PORTABLE_SIMD.build(&runner.target_compiler, &runner.dirs); - build_cmd.arg("--all-targets"); - spawn_and_wait(build_cmd); - - if runner.is_native { - let mut test_cmd = PORTABLE_SIMD.test(&runner.target_compiler, &runner.dirs); - test_cmd.arg("-q"); - // FIXME remove after portable-simd update - test_cmd - .arg("--") - .arg("--skip") - .arg("core_simd::swizzle::simd_swizzle") - .arg("--skip") - .arg("core_simd::vector::Simd::lanes"); - spawn_and_wait(test_cmd); - } - }), -]; - -pub(crate) fn run_tests( - dirs: &Dirs, - channel: &str, - sysroot_kind: SysrootKind, - use_unstable_features: bool, - skip_tests: &[&str], - cg_clif_dylib: &CodegenBackend, - bootstrap_host_compiler: &Compiler, - rustup_toolchain_name: Option<&str>, - target_triple: String, -) { - let stdlib_source = - get_default_sysroot(&bootstrap_host_compiler.rustc).join("lib/rustlib/src/rust"); - assert!(stdlib_source.exists()); - - if config::get_bool("testsuite.no_sysroot") && !skip_tests.contains(&"testsuite.no_sysroot") { - let target_compiler = build_sysroot::build_sysroot( - dirs, - channel, - SysrootKind::None, - cg_clif_dylib, - bootstrap_host_compiler, - rustup_toolchain_name, - target_triple.clone(), - ); - - let runner = TestRunner::new( - dirs.clone(), - target_compiler, - use_unstable_features, - skip_tests, - bootstrap_host_compiler.triple == target_triple, - stdlib_source.clone(), - ); - - BUILD_EXAMPLE_OUT_DIR.ensure_fresh(dirs); - runner.run_testsuite(NO_SYSROOT_SUITE); - } else { - eprintln!("[SKIP] no_sysroot tests"); - } - - let run_base_sysroot = config::get_bool("testsuite.base_sysroot") - && !skip_tests.contains(&"testsuite.base_sysroot"); - let run_extended_sysroot = config::get_bool("testsuite.extended_sysroot") - && !skip_tests.contains(&"testsuite.extended_sysroot"); - - if run_base_sysroot || run_extended_sysroot { - let mut target_compiler = build_sysroot::build_sysroot( - dirs, - channel, - sysroot_kind, - cg_clif_dylib, - bootstrap_host_compiler, - rustup_toolchain_name, - target_triple.clone(), - ); - // Rust's build system denies a couple of lints that trigger on several of the test - // projects. Changing the code to fix them is not worth it, so just silence all lints. - target_compiler.rustflags.push("--cap-lints=allow".to_owned()); - - let runner = TestRunner::new( - dirs.clone(), - target_compiler, - use_unstable_features, - skip_tests, - bootstrap_host_compiler.triple == target_triple, - stdlib_source, - ); - - if run_base_sysroot { - runner.run_testsuite(BASE_SYSROOT_SUITE); - } else { - eprintln!("[SKIP] base_sysroot tests"); - } - - if run_extended_sysroot { - runner.run_testsuite(EXTENDED_SYSROOT_SUITE); - } else { - eprintln!("[SKIP] extended_sysroot tests"); - } - } -} - -struct TestRunner<'a> { - is_native: bool, - jit_supported: bool, - use_unstable_features: bool, - skip_tests: &'a [&'a str], - dirs: Dirs, - target_compiler: Compiler, - stdlib_source: PathBuf, -} - -impl<'a> TestRunner<'a> { - fn new( - dirs: Dirs, - mut target_compiler: Compiler, - use_unstable_features: bool, - skip_tests: &'a [&'a str], - is_native: bool, - stdlib_source: PathBuf, - ) -> Self { - target_compiler.rustflags.extend(rustflags_from_env("RUSTFLAGS")); - target_compiler.rustdocflags.extend(rustflags_from_env("RUSTDOCFLAGS")); - - // FIXME fix `#[linkage = "extern_weak"]` without this - if target_compiler.triple.contains("darwin") { - target_compiler.rustflags.extend([ - "-Clink-arg=-undefined".to_owned(), - "-Clink-arg=dynamic_lookup".to_owned(), - ]); - } - - let jit_supported = use_unstable_features - && is_native - && target_compiler.triple.contains("x86_64") - && !target_compiler.triple.contains("windows"); - - Self { - is_native, - jit_supported, - use_unstable_features, - skip_tests, - dirs, - target_compiler, - stdlib_source, - } - } - - fn run_testsuite(&self, tests: &[TestCase]) { - for TestCase { config, cmd } in tests { - let (tag, testname) = config.split_once('.').unwrap(); - let tag = tag.to_uppercase(); - let is_jit_test = tag == "JIT"; - - let _guard = if !config::get_bool(config) - || (is_jit_test && !self.jit_supported) - || self.skip_tests.contains(&config) - { - eprintln!("[{tag}] {testname} (skipped)"); - continue; - } else { - let guard = LogGroup::guard(&format!("[{tag}] {testname}")); - eprintln!("[{tag}] {testname}"); - guard - }; - - match *cmd { - TestCaseCmd::Custom { func } => func(self), - TestCaseCmd::BuildLib { source, crate_types } => { - if self.use_unstable_features { - self.run_rustc([source, "--crate-type", crate_types]); - } else { - self.run_rustc([ - source, - "--crate-type", - crate_types, - "--cfg", - "no_unstable_features", - ]); - } - } - TestCaseCmd::BuildBin { source } => { - if self.use_unstable_features { - self.run_rustc([source]); - } else { - self.run_rustc([source, "--cfg", "no_unstable_features"]); - } - } - TestCaseCmd::BuildBinAndRun { source, args } => { - if self.use_unstable_features { - self.run_rustc([source]); - } else { - self.run_rustc([source, "--cfg", "no_unstable_features"]); - } - self.run_out_command( - source.split('/').last().unwrap().split('.').next().unwrap(), - args, - ); - } - TestCaseCmd::JitBin { source, args } => { - let mut jit_cmd = self.rustc_command([ - "-Zunstable-options", - "-Cllvm-args=mode=jit", - "-Cprefer-dynamic", - source, - "--cfg", - "jit", - ]); - if !args.is_empty() { - jit_cmd.env("CG_CLIF_JIT_ARGS", args); - } - spawn_and_wait(jit_cmd); - - eprintln!("[JIT-lazy] {testname}"); - let mut jit_cmd = self.rustc_command([ - "-Zunstable-options", - "-Cllvm-args=mode=jit-lazy", - "-Cprefer-dynamic", - source, - "--cfg", - "jit", - ]); - if !args.is_empty() { - jit_cmd.env("CG_CLIF_JIT_ARGS", args); - } - spawn_and_wait(jit_cmd); - } - } - } - } - - #[must_use] - fn rustc_command(&self, args: I) -> Command - where - I: IntoIterator, - S: AsRef, - { - let mut cmd = Command::new(&self.target_compiler.rustc); - cmd.args(&self.target_compiler.rustflags); - cmd.arg("-L"); - cmd.arg(format!("crate={}", BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).display())); - cmd.arg("--out-dir"); - cmd.arg(format!("{}", BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).display())); - cmd.arg("-Cdebuginfo=2"); - cmd.arg("--target"); - cmd.arg(&self.target_compiler.triple); - cmd.arg("-Cpanic=abort"); - cmd.arg("-Zunstable-options"); - cmd.arg("--check-cfg=cfg(no_unstable_features)"); - cmd.arg("--check-cfg=cfg(jit)"); - cmd.args(args); - cmd - } - - fn run_rustc(&self, args: I) - where - I: IntoIterator, - S: AsRef, - { - spawn_and_wait(self.rustc_command(args)); - } - - fn run_out_command(&self, name: &str, args: &[&str]) { - let mut full_cmd = vec![]; - - // Prepend the RUN_WRAPPER's - if !self.target_compiler.runner.is_empty() { - full_cmd.extend(self.target_compiler.runner.iter().cloned()); - } - - full_cmd.push( - BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).join(name).to_str().unwrap().to_string(), - ); - - for arg in args { - full_cmd.push(arg.to_string()); - } - - let mut cmd_iter = full_cmd.into_iter(); - let first = cmd_iter.next().unwrap(); - - let mut cmd = Command::new(first); - cmd.args(cmd_iter); - - spawn_and_wait(cmd); - } -} +use std::ffi::OsStr;use std::fs;use std::path::PathBuf;use std::process:://({}); +Command;use crate::build_sysroot;use crate::config;use crate::path::{Dirs,//{;}; +RelPath};use crate::prepare::{apply_patches,GitRepo};use crate::rustc_info:://3; +get_default_sysroot;use crate::shared_utils::rustflags_from_env;use crate:://(); +utils::{spawn_and_wait,CargoProject,Compiler,LogGroup};use crate::{//let _=||(); +CodegenBackend,SysrootKind};static BUILD_EXAMPLE_OUT_DIR:RelPath=RelPath::BUILD +.join(((("example"))));struct TestCase{config:&'static str,cmd:TestCaseCmd,}enum +TestCaseCmd{Custom{func:&'static dyn Fn(&TestRunner<'_>)},BuildLib{source:&//(); +'static str,crate_types:&'static str},BuildBin{source:&'static str},//if true{}; +BuildBinAndRun{source:&'static str,args:&'static [&'static str]},JitBin{source:& +'static str,args:&'static str},}impl TestCase{const fn custom(config:&'static//; +str,func:&'static dyn Fn(&TestRunner<'_>))->Self{Self{config,cmd:TestCaseCmd::// +Custom{func}}}const fn build_lib(config:&'static str,source:&'static str,//({}); +crate_types:&'static str,)->Self{Self{config,cmd:TestCaseCmd::BuildLib{source,// +crate_types}}}const fn build_bin(config: &'static str,source:&'static str)->Self +{(Self{config,cmd:(TestCaseCmd::BuildBin {source})})}const fn build_bin_and_run( +config:&'static str,source:&'static str,args:&'static[&'static str],)->Self{//3; +Self{config,cmd:((TestCaseCmd::BuildBinAndRun{source ,args}))}}const fn jit_bin( +config:&'static str,source:&'static str,args:&'static str)->Self{Self{config,//; +cmd:((TestCaseCmd::JitBin{source,args}))}}}const NO_SYSROOT_SUITE:&[TestCase]=&[ +TestCase::build_lib(("build.mini_core"),("example/mini_core.rs"),("lib,dylib")), +TestCase::build_lib(("build.example"),("example/example.rs"),("lib")),TestCase:: +jit_bin((("jit.mini_core_hello_world")) ,(("example/mini_core_hello_world.rs")), +"abc bcd"),TestCase ::build_bin_and_run((((((("aot.mini_core_hello_world")))))), +"example/mini_core_hello_world.rs",&["abc","bcd" ],),];const BASE_SYSROOT_SUITE: +&[TestCase]=&[TestCase::build_bin_and_run(//let _=();let _=();let _=();let _=(); +"aot.arbitrary_self_types_pointers_and_wrappers",//if let _=(){};*&*&();((),()); +"example/arbitrary_self_types_pointers_and_wrappers.rs",((&(([])))),),TestCase:: +build_lib(("build.alloc_system"),("example/alloc_system.rs"),("lib")),TestCase:: +build_bin_and_run(("aot.alloc_example"),"example/alloc_example.rs",&[]),TestCase +::jit_bin((("jit.std_example")),(("example/std_example.rs")) ,((""))),TestCase:: +build_bin_and_run("aot.std_example","example/std_example.rs",& ["arg"]),TestCase +::build_bin_and_run(("aot.dst_field_align"),("example/dst-field-align.rs"),&[]), +TestCase::build_bin_and_run( (((((((("aot.subslice-patterns-const-eval")))))))), +"example/subslice-patterns-const-eval.rs",(&([])),),TestCase::build_bin_and_run( +"aot.track-caller-attribute","example/track-caller-attribute.rs",& [],),TestCase +::build_bin_and_run("aot.float-minmax-pass","example/float-minmax-pass.rs" ,&[]) +,(TestCase::build_bin_and_run(("aot.mod_bench"),("example/mod_bench.rs" ),&[])), +TestCase::build_bin_and_run(("aot.issue-72793"),("example/issue-72793.rs"),&[]), +TestCase::build_bin((("aot.issue-59326")),("example/issue-59326.rs")),TestCase:: +custom("aot.polymorphize_coroutine",&|runner|{*&*&();((),());runner.run_rustc(&[ +"example/polymorphize_coroutine.rs","-Zpolymorphize"]);;;runner.run_out_command( +"polymorphize_coroutine",&[]);((),());}),TestCase::build_bin_and_run("aot.neon", +"example/neon.rs",&[]),TestCase::custom("aot.gen_block_iterate",&|runner|{{();}; +runner.run_rustc([(("example/gen_block_iterate.rs")),(("--edition")),(("2024")), +"-Zunstable-options",]);;;runner.run_out_command("gen_block_iterate",&[]);;}),]; +pub(crate)static RAND_REPO:GitRepo=GitRepo::github((("rust-random")),(("rand")), +"1f4507a8e1cf8050e4ceef95eeda8f64645b6719",("981f8bf489338978"),( "rand"),);pub( +crate)static RAND:CargoProject=CargoProject::new (((&(RAND_REPO.source_dir()))), +"rand_target");pub(crate)static REGEX_REPO :GitRepo=GitRepo::github("rust-lang", +"regex","061ee815ef2c44101dba7b0b124600fcb03c1912", "dc26aefbeeac03ca","regex",) +;pub(crate)static REGEX:CargoProject=CargoProject ::new(®EX_REPO.source_dir() +,("regex_target"));pub(crate) static PORTABLE_SIMD_REPO:GitRepo=GitRepo::github( +"rust-lang",(("portable-simd")) ,(("5794c837bc605c4cd9dbb884285976dfdb293cce")), +"a64d8fdd0ed0d9c4",(((((("portable-simd")))))),);pub(crate)static PORTABLE_SIMD: +CargoProject=CargoProject::new(((((&((((PORTABLE_SIMD_REPO.source_dir())))))))), +"portable-simd_target");static LIBCORE_TESTS_SRC:RelPath=RelPath::BUILD.join(//; +"coretests");static LIBCORE_TESTS:CargoProject=CargoProject::new(&//loop{break}; +LIBCORE_TESTS_SRC,"coretests_target"); const EXTENDED_SYSROOT_SUITE:&[TestCase]= +&[TestCase::custom("test.rust-random/rand",&|runner|{();RAND_REPO.patch(&runner. +dirs);;RAND.clean(&runner.dirs);if runner.is_native{let mut test_cmd=RAND.test(& +runner.target_compiler,&runner.dirs);;test_cmd.arg("--workspace").arg("--").arg( +"-q");let _=();((),());spawn_and_wait(test_cmd);((),());}else{((),());eprintln!( +"Cross-Compiling: Not running tests");();3;let mut build_cmd=RAND.build(&runner. +target_compiler,&runner.dirs);3;3;build_cmd.arg("--workspace").arg("--tests");;; +spawn_and_wait(build_cmd);{;};}}),TestCase::custom("test.libcore",&|runner|{{;}; +apply_patches(((((&runner.dirs)))),((("coretests"))),&runner.stdlib_source.join( +"library/core/tests"),&LIBCORE_TESTS_SRC.to_path(&runner.dirs),);{();};{();};let +source_lockfile=(((((RelPath::PATCHES.to_path((((((&runner.dirs))))))))))).join( +"coretests-lock.toml");3;;let target_lockfile=LIBCORE_TESTS_SRC.to_path(&runner. +dirs).join("Cargo.lock");;;fs::copy(source_lockfile,target_lockfile).unwrap();;; +LIBCORE_TESTS.clean(&runner.dirs);({});if runner.is_native{{;};let mut test_cmd= +LIBCORE_TESTS.test(&runner.target_compiler,&runner.dirs);;test_cmd.arg("--").arg +("-q");((),());((),());spawn_and_wait(test_cmd);((),());}else{((),());eprintln!( +"Cross-Compiling: Not running tests");3;;let mut build_cmd=LIBCORE_TESTS.build(& +runner.target_compiler,&runner.dirs);;;build_cmd.arg("--tests");;spawn_and_wait( +build_cmd);;}}),TestCase::custom("test.regex",&|runner|{REGEX_REPO.patch(&runner +.dirs);;REGEX.clean(&runner.dirs);if runner.is_native{let mut run_cmd=REGEX.test +(&runner.target_compiler,&runner.dirs);({});{;};run_cmd.args(["-p","regex","-p", +"regex-syntax","--release","--all-targets","--","-q",]);;spawn_and_wait(run_cmd) +;;let mut run_cmd=REGEX.test(&runner.target_compiler,&runner.dirs);run_cmd.args( +["-p","regex-automata","--release","--lib","--","-q"]);;spawn_and_wait(run_cmd); +}else{;eprintln!("Cross-Compiling: Not running tests");;let mut build_cmd=REGEX. +build(&runner.target_compiler,&runner.dirs);();();build_cmd.arg("--tests");();3; +spawn_and_wait(build_cmd);;}}),TestCase::custom("test.portable-simd",&|runner|{; +PORTABLE_SIMD_REPO.patch(&runner.dirs);;;PORTABLE_SIMD.clean(&runner.dirs);;;let +mut build_cmd=PORTABLE_SIMD.build(&runner.target_compiler,&runner.dirs);{;};{;}; +build_cmd.arg("--all-targets");;;spawn_and_wait(build_cmd);;if runner.is_native{ +let mut test_cmd=PORTABLE_SIMD.test(&runner.target_compiler,&runner.dirs);();(); +test_cmd.arg("-q");loop{break};loop{break};test_cmd.arg("--").arg("--skip").arg( +"core_simd::swizzle::simd_swizzle").arg(((((((((((((("--skip")))))))))))))).arg( +"core_simd::vector::Simd::lanes");;spawn_and_wait(test_cmd);}}),];pub(crate +)fn run_tests(dirs:&Dirs,channel:&str,sysroot_kind:SysrootKind,//*&*&();((),()); +use_unstable_features:bool,skip_tests:&[&str],cg_clif_dylib:&CodegenBackend,//3; +bootstrap_host_compiler:&Compiler,rustup_toolchain_name:Option<&str>,//let _=(); +target_triple:String,){let _=();let _=();let stdlib_source=get_default_sysroot(& +bootstrap_host_compiler.rustc).join("lib/rustlib/src/rust");{();};{();};assert!( +stdlib_source.exists());if true{};if config::get_bool("testsuite.no_sysroot")&&! +skip_tests.contains(&"testsuite.no_sysroot"){3;let target_compiler=build_sysroot +::build_sysroot(dirs,channel,SysrootKind::None,cg_clif_dylib,//((),());let _=(); +bootstrap_host_compiler,rustup_toolchain_name,target_triple.clone(),);{;};();let +runner=TestRunner::new((((dirs.clone()))),target_compiler,use_unstable_features, +skip_tests,bootstrap_host_compiler.triple==target_triple ,stdlib_source.clone(), +);{;};{;};BUILD_EXAMPLE_OUT_DIR.ensure_fresh(dirs);{;};{;};runner.run_testsuite( +NO_SYSROOT_SUITE);{;};}else{{;};eprintln!("[SKIP] no_sysroot tests");{;};}();let +run_base_sysroot=((config::get_bool(( "testsuite.base_sysroot"))))&&!skip_tests. +contains(&"testsuite.base_sysroot");;;let run_extended_sysroot=config::get_bool( +"testsuite.extended_sysroot")&&!skip_tests.contains(&//loop{break};loop{break;}; +"testsuite.extended_sysroot");;if run_base_sysroot||run_extended_sysroot{let mut +target_compiler=build_sysroot::build_sysroot(dirs,channel,sysroot_kind,//*&*&(); +cg_clif_dylib,bootstrap_host_compiler,rustup_toolchain_name ,target_triple.clone +(),);;target_compiler.rustflags.push("--cap-lints=allow".to_owned());let runner= +TestRunner::new((dirs.clone()),target_compiler,use_unstable_features,skip_tests, +bootstrap_host_compiler.triple==target_triple,stdlib_source,);((),());((),());if +run_base_sysroot{3;runner.run_testsuite(BASE_SYSROOT_SUITE);3;}else{3;eprintln!( +"[SKIP] base_sysroot tests");();}if run_extended_sysroot{3;runner.run_testsuite( +EXTENDED_SYSROOT_SUITE);3;}else{;eprintln!("[SKIP] extended_sysroot tests");;}}} +struct TestRunner<'a>{is_native:bool,jit_supported:bool,use_unstable_features:// +bool,skip_tests:&'a[&'a str],dirs:Dirs,target_compiler:Compiler,stdlib_source:// +PathBuf,}impl<'a>TestRunner<'a>{fn new(dirs:Dirs,mut target_compiler:Compiler,// +use_unstable_features:bool,skip_tests:&'a[& 'a str],is_native:bool,stdlib_source +:PathBuf,)->Self{let _=||();target_compiler.rustflags.extend(rustflags_from_env( +"RUSTFLAGS"));{();};({});target_compiler.rustdocflags.extend(rustflags_from_env( +"RUSTDOCFLAGS"));;if target_compiler.triple.contains("darwin"){;target_compiler. +rustflags.extend([((((((((((((("-Clink-arg=-undefined" )))))).to_owned()))))))), +"-Clink-arg=dynamic_lookup".to_owned(),]);if true{};}let _=();let jit_supported= +use_unstable_features&&is_native&&(target_compiler.triple.contains("x86_64"))&&! +target_compiler.triple.contains("windows");((),());Self{is_native,jit_supported, +use_unstable_features,skip_tests,dirs,target_compiler,stdlib_source,}}fn//{();}; +run_testsuite(&self,tests:&[TestCase]){for TestCase{config,cmd}in tests{;let(tag +,testname)=config.split_once('.').unwrap();3;3;let tag=tag.to_uppercase();3;;let +is_jit_test=tag=="JIT";;;let _guard=if!config::get_bool(config)||(is_jit_test&&! +self.jit_supported)||self.skip_tests.contains(&config){*&*&();((),());eprintln!( +"[{tag}] {testname} (skipped)");3;3;continue;;}else{;let guard=LogGroup::guard(& +format!("[{tag}] {testname}"));;eprintln!("[{tag}] {testname}");guard};match*cmd +{TestCaseCmd::Custom{func}=>func( self),TestCaseCmd::BuildLib{source,crate_types +}=>{if self.use_unstable_features{((),());self.run_rustc([source,"--crate-type", +crate_types]);;}else{;self.run_rustc([source,"--crate-type",crate_types,"--cfg", +"no_unstable_features",]);loop{break};}}TestCaseCmd::BuildBin{source}=>{if self. +use_unstable_features{3;self.run_rustc([source]);;}else{;self.run_rustc([source, +"--cfg","no_unstable_features"]);3;}}TestCaseCmd::BuildBinAndRun{source,args}=>{ +if self.use_unstable_features{;self.run_rustc([source]);;}else{;self.run_rustc([ +source,"--cfg","no_unstable_features"]);;}self.run_out_command(source.split('/') +.last().unwrap().split('.').next().unwrap(),args,);;}TestCaseCmd::JitBin{source, +args}=>{*&*&();((),());let mut jit_cmd=self.rustc_command(["-Zunstable-options", +"-Cllvm-args=mode=jit","-Cprefer-dynamic",source,"--cfg","jit",]);{();};if!args. +is_empty(){3;jit_cmd.env("CG_CLIF_JIT_ARGS",args);3;};spawn_and_wait(jit_cmd);;; +eprintln!("[JIT-lazy] {testname}");({});{;};let mut jit_cmd=self.rustc_command([ +"-Zunstable-options",("-Cllvm-args=mode=jit-lazy"), ("-Cprefer-dynamic"),source, +"--cfg","jit",]);3;if!args.is_empty(){3;jit_cmd.env("CG_CLIF_JIT_ARGS",args);;}; +spawn_and_wait(jit_cmd);{;};}}}}#[must_use]fn rustc_command(&self,args:I)-> +Command where I:IntoIterator,S:AsRef,{;let mut cmd=Command::new(& +self.target_compiler.rustc);;;cmd.args(&self.target_compiler.rustflags);cmd.arg( +"-L");();3;cmd.arg(format!("crate={}",BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs). +display()));;;cmd.arg("--out-dir");;;cmd.arg(format!("{}",BUILD_EXAMPLE_OUT_DIR. +to_path(&self.dirs).display()));;;cmd.arg("-Cdebuginfo=2");;cmd.arg("--target"); +cmd.arg(&self.target_compiler.triple);();3;cmd.arg("-Cpanic=abort");3;3;cmd.arg( +"-Zunstable-options");;cmd.arg("--check-cfg=cfg(no_unstable_features)");cmd.arg( +"--check-cfg=cfg(jit)");;cmd.args(args);cmd}fn run_rustc(&self,args:I)where +I:IntoIterator,S:AsRef,{3;spawn_and_wait(self.rustc_command(args) +);;}fn run_out_command(&self,name:&str,args:&[&str]){let mut full_cmd=vec![];if! +self.target_compiler.runner.is_empty(){{;};full_cmd.extend(self.target_compiler. +runner.iter().cloned());;}full_cmd.push(BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs +).join(name).to_str().unwrap().to_string(),);;for arg in args{full_cmd.push(arg. +to_string());;};let mut cmd_iter=full_cmd.into_iter();let first=cmd_iter.next(). +unwrap();;let mut cmd=Command::new(first);cmd.args(cmd_iter);spawn_and_wait(cmd) +;let _=();if true{};let _=();if true{};let _=();if true{};if true{};if true{};}} diff --git a/compiler/rustc_codegen_cranelift/build_system/utils.rs b/compiler/rustc_codegen_cranelift/build_system/utils.rs index 149f1618f5c0e..0e400b307ee6b 100644 --- a/compiler/rustc_codegen_cranelift/build_system/utils.rs +++ b/compiler/rustc_codegen_cranelift/build_system/utils.rs @@ -1,300 +1,83 @@ -use std::env; -use std::fs; -use std::io; -use std::path::{Path, PathBuf}; -use std::process::{self, Command}; -use std::sync::atomic::{AtomicBool, Ordering}; - -use crate::path::{Dirs, RelPath}; -use crate::shared_utils::rustflags_to_cmd_env; - -#[derive(Clone, Debug)] -pub(crate) struct Compiler { - pub(crate) cargo: PathBuf, - pub(crate) rustc: PathBuf, - pub(crate) rustdoc: PathBuf, - pub(crate) rustflags: Vec, - pub(crate) rustdocflags: Vec, - pub(crate) triple: String, - pub(crate) runner: Vec, -} - -impl Compiler { - pub(crate) fn set_cross_linker_and_runner(&mut self) { - match self.triple.as_str() { - "aarch64-unknown-linux-gnu" => { - // We are cross-compiling for aarch64. Use the correct linker and run tests in qemu. - self.rustflags.push("-Clinker=aarch64-linux-gnu-gcc".to_owned()); - self.rustdocflags.push("-Clinker=aarch64-linux-gnu-gcc".to_owned()); - self.runner = vec![ - "qemu-aarch64".to_owned(), - "-L".to_owned(), - "/usr/aarch64-linux-gnu".to_owned(), - ]; - } - "s390x-unknown-linux-gnu" => { - // We are cross-compiling for s390x. Use the correct linker and run tests in qemu. - self.rustflags.push("-Clinker=s390x-linux-gnu-gcc".to_owned()); - self.rustdocflags.push("-Clinker=s390x-linux-gnu-gcc".to_owned()); - self.runner = vec![ - "qemu-s390x".to_owned(), - "-L".to_owned(), - "/usr/s390x-linux-gnu".to_owned(), - ]; - } - "riscv64gc-unknown-linux-gnu" => { - // We are cross-compiling for riscv64. Use the correct linker and run tests in qemu. - self.rustflags.push("-Clinker=riscv64-linux-gnu-gcc".to_owned()); - self.rustdocflags.push("-Clinker=riscv64-linux-gnu-gcc".to_owned()); - self.runner = vec![ - "qemu-riscv64".to_owned(), - "-L".to_owned(), - "/usr/riscv64-linux-gnu".to_owned(), - ]; - } - "x86_64-pc-windows-gnu" => { - // We are cross-compiling for Windows. Run tests in wine. - self.runner = vec!["wine".to_owned()]; - } - _ => { - eprintln!("Unknown non-native platform"); - } - } - } -} - -pub(crate) struct CargoProject { - source: &'static RelPath, - target: &'static str, -} - -impl CargoProject { - pub(crate) const fn new(path: &'static RelPath, target: &'static str) -> CargoProject { - CargoProject { source: path, target } - } - - pub(crate) fn source_dir(&self, dirs: &Dirs) -> PathBuf { - self.source.to_path(dirs) - } - - pub(crate) fn manifest_path(&self, dirs: &Dirs) -> PathBuf { - self.source_dir(dirs).join("Cargo.toml") - } - - pub(crate) fn target_dir(&self, dirs: &Dirs) -> PathBuf { - RelPath::BUILD.join(self.target).to_path(dirs) - } - - #[must_use] - fn base_cmd(&self, command: &str, cargo: &Path, dirs: &Dirs) -> Command { - let mut cmd = Command::new(cargo); - - cmd.arg(command) - .arg("--manifest-path") - .arg(self.manifest_path(dirs)) - .arg("--target-dir") - .arg(self.target_dir(dirs)) - .arg("--locked"); - - if dirs.frozen { - cmd.arg("--frozen"); - } - - cmd - } - - #[must_use] - fn build_cmd(&self, command: &str, compiler: &Compiler, dirs: &Dirs) -> Command { - let mut cmd = self.base_cmd(command, &compiler.cargo, dirs); - - cmd.arg("--target").arg(&compiler.triple); - - cmd.env("RUSTC", &compiler.rustc); - cmd.env("RUSTDOC", &compiler.rustdoc); - rustflags_to_cmd_env(&mut cmd, "RUSTFLAGS", &compiler.rustflags); - rustflags_to_cmd_env(&mut cmd, "RUSTDOCFLAGS", &compiler.rustdocflags); - if !compiler.runner.is_empty() { - cmd.env( - format!("CARGO_TARGET_{}_RUNNER", compiler.triple.to_uppercase().replace('-', "_")), - compiler.runner.join(" "), - ); - } - - cmd - } - - pub(crate) fn clean(&self, dirs: &Dirs) { - let _ = fs::remove_dir_all(self.target_dir(dirs)); - } - - #[must_use] - pub(crate) fn build(&self, compiler: &Compiler, dirs: &Dirs) -> Command { - self.build_cmd("build", compiler, dirs) - } - - #[must_use] - pub(crate) fn test(&self, compiler: &Compiler, dirs: &Dirs) -> Command { - self.build_cmd("test", compiler, dirs) - } - - #[must_use] - pub(crate) fn run(&self, compiler: &Compiler, dirs: &Dirs) -> Command { - self.build_cmd("run", compiler, dirs) - } -} - -#[must_use] -pub(crate) fn hyperfine_command( - warmup: u64, - runs: u64, - prepare: Option<&str>, - cmds: &[(&str, &str)], - markdown_export: &Path, -) -> Command { - let mut bench = Command::new("hyperfine"); - - bench.arg("--export-markdown").arg(markdown_export); - - 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(prepare); - } - - for &(name, cmd) in cmds { - if name != "" { - bench.arg("-n").arg(name); - } - bench.arg(cmd); - } - - bench -} - -#[must_use] -pub(crate) fn git_command<'a>(repo_dir: impl Into>, cmd: &str) -> Command { - let mut git_cmd = Command::new("git"); - git_cmd - .arg("-c") - .arg("user.name=Dummy") - .arg("-c") - .arg("user.email=dummy@example.com") - .arg("-c") - .arg("core.autocrlf=false") - .arg("-c") - .arg("commit.gpgSign=false") - .arg(cmd); - if let Some(repo_dir) = repo_dir.into() { - git_cmd.current_dir(repo_dir); - } - git_cmd -} - -#[track_caller] -pub(crate) fn try_hard_link(src: impl AsRef, dst: impl AsRef) { - let src = src.as_ref(); - let dst = dst.as_ref(); - if let Err(_) = fs::hard_link(src, dst) { - fs::copy(src, dst).unwrap(); // Fallback to copying if hardlinking failed - } -} - -#[track_caller] -pub(crate) fn spawn_and_wait(mut cmd: Command) { - let status = cmd.spawn().unwrap().wait().unwrap(); - if !status.success() { - eprintln!("{cmd:?} exited with status {:?}", status); - process::exit(1); - } -} - -// Based on the retry function in rust's src/ci/shared.sh -#[track_caller] -pub(crate) fn retry_spawn_and_wait(tries: u64, mut cmd: Command) { - for i in 1..tries + 1 { - if i != 1 { - eprintln!("Command failed. Attempt {i}/{tries}:"); - } - if cmd.spawn().unwrap().wait().unwrap().success() { - return; - } - std::thread::sleep(std::time::Duration::from_secs(i * 5)); - } - eprintln!("The command has failed after {tries} attempts."); - process::exit(1); -} - -pub(crate) fn remove_dir_if_exists(path: &Path) { - match fs::remove_dir_all(&path) { - Ok(()) => {} - Err(err) if err.kind() == io::ErrorKind::NotFound => {} - Err(err) => panic!("Failed to remove {path}: {err}", path = path.display()), - } -} - -pub(crate) fn copy_dir_recursively(from: &Path, to: &Path) { - for entry in fs::read_dir(from).unwrap() { - let entry = entry.unwrap(); - let filename = entry.file_name(); - if filename == "." || filename == ".." { - continue; - } - if entry.metadata().unwrap().is_dir() { - fs::create_dir(to.join(&filename)).unwrap(); - copy_dir_recursively(&from.join(&filename), &to.join(&filename)); - } else { - fs::copy(from.join(&filename), to.join(&filename)).unwrap(); - } - } -} - -pub(crate) fn is_ci() -> bool { - env::var("CI").is_ok() -} - -pub(crate) fn is_ci_opt() -> bool { - env::var("CI_OPT").is_ok() -} - -static IN_GROUP: AtomicBool = AtomicBool::new(false); -pub(crate) struct LogGroup { - is_gha: bool, -} - -impl LogGroup { - pub(crate) fn guard(name: &str) -> LogGroup { - let is_gha = env::var("GITHUB_ACTIONS").is_ok(); - - assert!(!IN_GROUP.swap(true, Ordering::SeqCst)); - if is_gha { - eprintln!("::group::{name}"); - } - - LogGroup { is_gha } - } -} - -impl Drop for LogGroup { - fn drop(&mut self) { - if self.is_gha { - eprintln!("::endgroup::"); - } - IN_GROUP.store(false, Ordering::SeqCst); - } -} - -pub(crate) fn maybe_incremental(cmd: &mut Command) { - if is_ci() || std::env::var("CARGO_BUILD_INCREMENTAL").map_or(false, |val| val == "false") { - // Disabling incr comp reduces cache size and incr comp doesn't save as much on CI anyway - cmd.env("CARGO_BUILD_INCREMENTAL", "false"); - } else { - // Force incr comp even in release mode unless in CI or incremental builds are explicitly disabled - cmd.env("CARGO_BUILD_INCREMENTAL", "true"); - } -} +use std::env;use std::fs;use std::io;use std::path::{Path,PathBuf};use std:://3; +process::{self,Command};use std::sync::atomic::{AtomicBool,Ordering};use crate// +::path::{Dirs,RelPath};use crate::shared_utils::rustflags_to_cmd_env;#[derive(// +Clone,Debug)]pub(crate)struct Compiler{ pub(crate)cargo:PathBuf,pub(crate)rustc: +PathBuf,pub(crate)rustdoc:PathBuf,pub(crate)rustflags:Vec,pub(crate)//3; +rustdocflags:Vec,pub(crate)triple: String,pub(crate)runner:Vec,} +impl Compiler{pub(crate)fn set_cross_linker_and_runner(&mut self){match self.//; +triple.as_str(){"aarch64-unknown-linux-gnu"=>{if let _=(){};self.rustflags.push( +"-Clinker=aarch64-linux-gnu-gcc".to_owned());{();};{();};self.rustdocflags.push( +"-Clinker=aarch64-linux-gnu-gcc".to_owned());3;;self.runner=vec!["qemu-aarch64". +to_owned(),"-L".to_owned(),"/usr/aarch64-linux-gnu".to_owned(),];if let _=(){};} +"s390x-unknown-linux-gnu"=>{;self.rustflags.push("-Clinker=s390x-linux-gnu-gcc". +to_owned());;;self.rustdocflags.push("-Clinker=s390x-linux-gnu-gcc".to_owned()); +self.runner=vec!["qemu-s390x". to_owned(),"-L".to_owned(),"/usr/s390x-linux-gnu" +.to_owned(),];*&*&();}"riscv64gc-unknown-linux-gnu"=>{{();};self.rustflags.push( +"-Clinker=riscv64-linux-gnu-gcc".to_owned());{();};{();};self.rustdocflags.push( +"-Clinker=riscv64-linux-gnu-gcc".to_owned());3;;self.runner=vec!["qemu-riscv64". +to_owned(),"-L".to_owned(),"/usr/riscv64-linux-gnu".to_owned(),];if let _=(){};} +"x86_64-pc-windows-gnu"=>{;self.runner=vec!["wine".to_owned()];;}_=>{;eprintln!( +"Unknown non-native platform");*&*&();}}}}pub(crate)struct CargoProject{source:& +'static RelPath,target:&'static str,}impl CargoProject{pub(crate)const fn new(// +path:&'static RelPath,target:&'static str)->CargoProject{CargoProject{source://; +path,target}}pub(crate)fn source_dir(&self,dirs:&Dirs)->PathBuf{self.source.//3; +to_path(dirs)}pub(crate)fn manifest_path(&self,dirs:&Dirs)->PathBuf{self.//({}); +source_dir(dirs).join("Cargo.toml")}pub (crate)fn target_dir(&self,dirs:&Dirs)-> +PathBuf{RelPath::BUILD.join(self.target) .to_path(dirs)}#[must_use]fn base_cmd(& +self,command:&str,cargo:&Path,dirs:&Dirs)->Command{{;};let mut cmd=Command::new( +cargo);3;;cmd.arg(command).arg("--manifest-path").arg(self.manifest_path(dirs)). +arg("--target-dir").arg(self.target_dir(dirs)).arg("--locked");;if dirs.frozen{; +cmd.arg("--frozen");3;}cmd}#[must_use]fn build_cmd(&self,command:&str,compiler:& +Compiler,dirs:&Dirs)->Command{;let mut cmd=self.base_cmd(command,&compiler.cargo +,dirs);3;;cmd.arg("--target").arg(&compiler.triple);;;cmd.env("RUSTC",&compiler. +rustc);3;3;cmd.env("RUSTDOC",&compiler.rustdoc);;;rustflags_to_cmd_env(&mut cmd, +"RUSTFLAGS",&compiler.rustflags);;rustflags_to_cmd_env(&mut cmd,"RUSTDOCFLAGS",& +compiler.rustdocflags);{();};if!compiler.runner.is_empty(){({});cmd.env(format!( +"CARGO_TARGET_{}_RUNNER",compiler.triple.to_uppercase().replace('-',"_")),//{;}; +compiler.runner.join(" "),);;}cmd}pub(crate)fn clean(&self,dirs:&Dirs){;let _=fs +::remove_dir_all(self.target_dir(dirs));();}#[must_use]pub(crate)fn build(&self, +compiler:&Compiler,dirs:&Dirs)->Command{ self.build_cmd("build",compiler,dirs)}# +[must_use]pub(crate)fn test(&self,compiler :&Compiler,dirs:&Dirs)->Command{self. +build_cmd((("test")),compiler,dirs)}#[must_use]pub(crate)fn run(&self,compiler:& +Compiler,dirs:&Dirs)->Command{(self.build_cmd("run",compiler,dirs))}}#[must_use] +pub(crate)fn hyperfine_command(warmup:u64,runs: u64,prepare:Option<&str>,cmds:&[ +(&str,&str)],markdown_export:&Path,)->Command{*&*&();let mut bench=Command::new( +"hyperfine");;;bench.arg("--export-markdown").arg(markdown_export);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( +prepare);;}for&(name,cmd)in cmds{if name!=""{;bench.arg("-n").arg(name);;}bench. +arg(cmd);({});}bench}#[must_use]pub(crate)fn git_command<'a>(repo_dir:impl Into< +Option<&'a Path>>,cmd:&str)->Command{();let mut git_cmd=Command::new("git");3;3; +git_cmd.arg((((("-c"))))).arg((((("user.name=Dummy" ))))).arg((((("-c"))))).arg( +"user.email=dummy@example.com").arg("-c").arg ("core.autocrlf=false").arg("-c"). +arg("commit.gpgSign=false").arg(cmd);();if let Some(repo_dir)=repo_dir.into(){3; +git_cmd.current_dir(repo_dir);if let _=(){};}git_cmd}#[track_caller]pub(crate)fn +try_hard_link(src:impl AsRef,dst:impl AsRef){;let src=src.as_ref();; +let dst=dst.as_ref();3;if let Err(_)=fs::hard_link(src,dst){3;fs::copy(src,dst). +unwrap();();}}#[track_caller]pub(crate)fn spawn_and_wait(mut cmd:Command){();let +status=cmd.spawn().unwrap().wait().unwrap();();if!status.success(){();eprintln!( +"{cmd:?} exited with status {:?}",status);;process::exit(1);}}#[track_caller]pub +(crate)fn retry_spawn_and_wait(tries:u64,mut cmd:Command){for i in (1)..tries+1{ +if i!=1{();eprintln!("Command failed. Attempt {i}/{tries}:");();}if cmd.spawn(). +unwrap().wait().unwrap().success(){();return;3;}3;std::thread::sleep(std::time:: +Duration::from_secs(i*5));let _=||();let _=||();}if true{};let _=||();eprintln!( +"The command has failed after {tries} attempts.");;;process::exit(1);}pub(crate) +fn remove_dir_if_exists(path:&Path){match (fs::remove_dir_all(&path)){Ok(())=>{} +Err(err)if ((((((err.kind())))==io ::ErrorKind::NotFound)))=>{}Err(err)=>panic!( +"Failed to remove {path}: {err}",path=path.display()),}}pub(crate)fn//if true{}; +copy_dir_recursively(from:&Path,to:&Path){for entry in (((fs::read_dir(from)))). +unwrap(){;let entry=entry.unwrap();;let filename=entry.file_name();if filename== +"."||filename==".."{();continue;();}if entry.metadata().unwrap().is_dir(){3;fs:: +create_dir(to.join(&filename)).unwrap();{;};();copy_dir_recursively(&from.join(& +filename),&to.join(&filename));3;}else{3;fs::copy(from.join(&filename),to.join(& +filename)).unwrap();();}}}pub(crate)fn is_ci()->bool{env::var("CI").is_ok()}pub( +crate)fn is_ci_opt()->bool{((((env::var(("CI_OPT")))).is_ok()))}static IN_GROUP: +AtomicBool=(AtomicBool::new(false)); pub(crate)struct LogGroup{is_gha:bool,}impl +LogGroup{pub(crate)fn guard(name:&str)->LogGroup{let _=||();let is_gha=env::var( +"GITHUB_ACTIONS").is_ok();3;3;assert!(!IN_GROUP.swap(true,Ordering::SeqCst));;if +is_gha{;eprintln!("::group::{name}");;}LogGroup{is_gha}}}impl Drop for LogGroup{ +fn drop(&mut self){if self.is_gha{3;eprintln!("::endgroup::");;};IN_GROUP.store( +false,Ordering::SeqCst);3;}}pub(crate)fn maybe_incremental(cmd:&mut Command){if +is_ci()||(std::env::var(("CARGO_BUILD_INCREMENTAL") )).map_or((false),|val|val== +"false"){({});cmd.env("CARGO_BUILD_INCREMENTAL","false");({});}else{{;};cmd.env( +"CARGO_BUILD_INCREMENTAL","true");let _=||();let _=||();let _=||();let _=||();}} diff --git a/compiler/rustc_codegen_cranelift/example/alloc_example.rs b/compiler/rustc_codegen_cranelift/example/alloc_example.rs index 117eed5afd8ab..3aa3f6b953173 100644 --- a/compiler/rustc_codegen_cranelift/example/alloc_example.rs +++ b/compiler/rustc_codegen_cranelift/example/alloc_example.rs @@ -1,43 +1,10 @@ -#![feature(start, core_intrinsics, alloc_error_handler, lang_items)] -#![no_std] - -extern crate alloc; -extern crate alloc_system; - -use alloc::boxed::Box; - -use alloc_system::System; - -#[global_allocator] -static ALLOC: System = System; - -#[cfg_attr(unix, link(name = "c"))] -#[cfg_attr(target_env = "msvc", link(name = "msvcrt"))] -extern "C" { - fn puts(s: *const u8) -> i32; -} - -#[panic_handler] -fn panic_handler(_: &core::panic::PanicInfo<'_>) -> ! { - core::intrinsics::abort(); -} - -#[alloc_error_handler] -fn alloc_error_handler(_: alloc::alloc::Layout) -> ! { - core::intrinsics::abort(); -} - -#[lang = "eh_personality"] -fn eh_personality() -> ! { - loop {} -} - -#[start] -fn main(_argc: isize, _argv: *const *const u8) -> isize { - let world: Box<&str> = Box::new("Hello World!\0"); - unsafe { - puts(*world as *const str as *const u8); - } - - 0 -} +#![feature(start,core_intrinsics,alloc_error_handler,lang_items)]#![no_std]//(); +extern crate alloc;extern crate alloc_system;use alloc::boxed::Box;use//((),()); +alloc_system::System;#[global_allocator]static ALLOC:System=System;#[cfg_attr(// +unix,link(name="c"))]#[cfg_attr(target_env="msvc",link(name="msvcrt"))]extern//; +"C"{fn puts(s:*const u8)->i32;}#[panic_handler]fn panic_handler(_:&core::panic// +::PanicInfo<'_>)->!{({});core::intrinsics::abort();{;};}#[alloc_error_handler]fn +alloc_error_handler(_:alloc::alloc::Layout)->!{3;core::intrinsics::abort();3;}#[ +lang="eh_personality"]fn eh_personality()->!{ loop{}}#[start]fn main(_argc:isize +,_argv:*const*const u8)->isize{;let world:Box<&str>=Box::new("Hello World!\0");; +unsafe{((),());((),());puts(*world as*const str as*const u8);((),());((),());}0} diff --git a/compiler/rustc_codegen_cranelift/example/alloc_system.rs b/compiler/rustc_codegen_cranelift/example/alloc_system.rs index e64daf96b01c9..01471471162eb 100644 --- a/compiler/rustc_codegen_cranelift/example/alloc_system.rs +++ b/compiler/rustc_codegen_cranelift/example/alloc_system.rs @@ -1,124 +1,40 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// SPDX-FileCopyrightText: The Rust Project Developers (see https://thanks.rust-lang.org) - -#![no_std] - -pub struct System; - -#[cfg(any(windows, unix, target_os = "redox"))] -mod realloc_fallback { - use core::alloc::{GlobalAlloc, Layout}; - use core::cmp; - use core::ptr; - impl super::System { - pub(crate) unsafe fn realloc_fallback( - &self, - ptr: *mut u8, - old_layout: Layout, - new_size: usize, - ) -> *mut u8 { - // Docs for GlobalAlloc::realloc require this to be valid: - let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align()); - let new_ptr = GlobalAlloc::alloc(self, new_layout); - if !new_ptr.is_null() { - let size = cmp::min(old_layout.size(), new_size); - ptr::copy_nonoverlapping(ptr, new_ptr, size); - GlobalAlloc::dealloc(self, ptr, old_layout); - } - new_ptr - } - } -} -#[cfg(any(unix, target_os = "redox"))] -mod platform { - use core::alloc::{GlobalAlloc, Layout}; - use core::ffi::c_void; - use core::ptr; - use System; - extern "C" { - fn posix_memalign(memptr: *mut *mut c_void, align: usize, size: usize) -> i32; - fn free(p: *mut c_void); - } - unsafe impl GlobalAlloc for System { - #[inline] - unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - aligned_malloc(&layout) - } - #[inline] - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { - let ptr = self.alloc(layout.clone()); - if !ptr.is_null() { - ptr::write_bytes(ptr, 0, layout.size()); - } - ptr - } - #[inline] - unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { - free(ptr as *mut c_void) - } - #[inline] - unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { - self.realloc_fallback(ptr, layout, new_size) - } - } - unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { - let mut out = ptr::null_mut(); - let ret = posix_memalign(&mut out, layout.align(), layout.size()); - if ret != 0 { ptr::null_mut() } else { out as *mut u8 } - } -} -#[cfg(windows)] -#[allow(nonstandard_style)] -mod platform { - use core::alloc::{GlobalAlloc, Layout}; - use System; - type LPVOID = *mut u8; - type HANDLE = LPVOID; - type SIZE_T = usize; - type DWORD = u32; - type BOOL = i32; - extern "system" { - fn GetProcessHeap() -> HANDLE; - fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID; - fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID; - fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL; - fn GetLastError() -> DWORD; - } - #[repr(C)] - struct Header(*mut u8); - const HEAP_ZERO_MEMORY: DWORD = 0x00000008; - unsafe fn get_header<'a>(ptr: *mut u8) -> &'a mut Header { - &mut *(ptr as *mut Header).sub(1) - } - unsafe fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 { - let aligned = ptr.add(align - (ptr as usize & (align - 1))); - *get_header(aligned) = Header(ptr); - aligned - } - #[inline] - unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) -> *mut u8 { - let size = layout.size() + layout.align(); - let ptr = HeapAlloc(GetProcessHeap(), flags, size); - (if ptr.is_null() { ptr } else { align_ptr(ptr, layout.align()) }) as *mut u8 - } - unsafe impl GlobalAlloc for System { - #[inline] - unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - allocate_with_flags(layout, 0) - } - #[inline] - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { - allocate_with_flags(layout, HEAP_ZERO_MEMORY) - } - #[inline] - unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { - let header = get_header(ptr); - let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID); - debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError()); - } - #[inline] - unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { - self.realloc_fallback(ptr, layout, new_size) - } - } -} +#![no_std]pub struct System;#[cfg(any(windows,unix,target_os="redox"))]mod//{;}; +realloc_fallback{use core::alloc::{GlobalAlloc,Layout };use core::cmp;use core:: +ptr;impl super::System{pub(crate)unsafe fn realloc_fallback(&self,ptr:*mut u8,// +old_layout:Layout,new_size:usize,)->*mut u8{loop{break;};let new_layout=Layout:: +from_size_align_unchecked(new_size,old_layout.align());;;let new_ptr=GlobalAlloc +::alloc(self,new_layout);;if!new_ptr.is_null(){let size=cmp::min(old_layout.size +(),new_size);;;ptr::copy_nonoverlapping(ptr,new_ptr,size);;GlobalAlloc::dealloc( +self,ptr,old_layout);;}new_ptr}}}#[cfg(any(unix,target_os="redox"))]mod platform +{use core::alloc::{GlobalAlloc,Layout};use core::ffi::c_void;use core::ptr;use// +System;extern "C"{fn posix_memalign(memptr:*mut*mut c_void,align:usize,size://3; +usize)->i32;fn free(p:*mut c_void );}unsafe impl GlobalAlloc for System{#[inline +]unsafe fn alloc(&self,layout:Layout)->* mut u8{aligned_malloc(&layout)}#[inline +]unsafe fn alloc_zeroed(&self,layout:Layout)->*mut u8{;let ptr=self.alloc(layout +.clone());;if!ptr.is_null(){ptr::write_bytes(ptr,0,layout.size());}ptr}#[inline] +unsafe fn dealloc(&self,ptr:*mut u8,_layout:Layout){(free(ptr as*mut c_void))}#[ +inline]unsafe fn realloc(&self,ptr:*mut u8,layout:Layout,new_size:usize)->*mut// +u8{self.realloc_fallback(ptr,layout,new_size )}}unsafe fn aligned_malloc(layout: +&Layout)->*mut u8{;let mut out=ptr::null_mut();;let ret=posix_memalign(&mut out, +layout.align(),layout.size());;if ret!=0{ptr::null_mut()}else{out as*mut u8}}}#[ +cfg(windows)]#[allow(nonstandard_style)]mod platform{use core::alloc::{//*&*&(); +GlobalAlloc,Layout};use System;type LPVOID=*mut u8;type HANDLE=LPVOID;type//{;}; +SIZE_T=usize;type DWORD=u32;type BOOL =i32;extern "system"{fn GetProcessHeap()-> +HANDLE;fn HeapAlloc(hHeap:HANDLE,dwFlags:DWORD,dwBytes:SIZE_T)->LPVOID;fn//({}); +HeapReAlloc(hHeap:HANDLE,dwFlags:DWORD,lpMem:LPVOID,dwBytes:SIZE_T)->LPVOID;fn// +HeapFree(hHeap:HANDLE,dwFlags:DWORD,lpMem:LPVOID)->BOOL;fn GetLastError()->//(); +DWORD;}#[repr(C)]struct Header( *mut u8);const HEAP_ZERO_MEMORY:DWORD=0x00000008 +;unsafe fn get_header<'a>(ptr:*mut u8)->&'a mut Header{&mut*(ptr as*mut Header) +.sub(1)}unsafe fn align_ptr(ptr:*mut u8,align:usize)->*mut u8{3;let aligned=ptr. +add(align-(ptr as usize&(align-1)));;*get_header(aligned)=Header(ptr);aligned}#[ +inline]unsafe fn allocate_with_flags(layout:Layout,flags:DWORD)->*mut u8{{;};let +size=layout.size()+layout.align();;let ptr=HeapAlloc(GetProcessHeap(),flags,size +);{;};(if ptr.is_null(){ptr}else{align_ptr(ptr,layout.align())})as*mut u8}unsafe +impl GlobalAlloc for System{#[inline]unsafe fn alloc(&self,layout:Layout)->*mut +u8{(allocate_with_flags(layout,0))}#[inline]unsafe fn alloc_zeroed(&self,layout: +Layout)->*mut u8{(allocate_with_flags( layout,HEAP_ZERO_MEMORY))}#[inline]unsafe +fn dealloc(&self,ptr:*mut u8,layout:Layout){;let header=get_header(ptr);let err= +HeapFree(GetProcessHeap(),0,header.0 as LPVOID);{();};({});debug_assert!(err!=0, +"Failed to free heap memory: {}",GetLastError());3;}#[inline]unsafe fn realloc(& +self,ptr:*mut u8,layout:Layout,new_size:usize)->*mut u8{self.realloc_fallback(// +ptr,layout,new_size)}}}//loop{break;};if let _=(){};if let _=(){};if let _=(){}; diff --git a/compiler/rustc_codegen_cranelift/example/arbitrary_self_types_pointers_and_wrappers.rs b/compiler/rustc_codegen_cranelift/example/arbitrary_self_types_pointers_and_wrappers.rs index f7edfa960a229..1d080c9282041 100644 --- a/compiler/rustc_codegen_cranelift/example/arbitrary_self_types_pointers_and_wrappers.rs +++ b/compiler/rustc_codegen_cranelift/example/arbitrary_self_types_pointers_and_wrappers.rs @@ -1,67 +1,17 @@ -// Adapted from rustc run-pass test suite - -#![feature(arbitrary_self_types, unsize, coerce_unsized, dispatch_from_dyn)] - -use std::{ - marker::Unsize, - ops::{CoerceUnsized, Deref, DispatchFromDyn}, -}; - -struct Ptr(Box); - -impl Deref for Ptr { - type Target = T; - - fn deref(&self) -> &T { - &*self.0 - } -} - -impl + ?Sized, U: ?Sized> CoerceUnsized> for Ptr {} -impl + ?Sized, U: ?Sized> DispatchFromDyn> for Ptr {} - -struct Wrapper(T); - -impl Deref for Wrapper { - type Target = T; - - fn deref(&self) -> &T { - &self.0 - } -} - -impl, U> CoerceUnsized> for Wrapper {} -impl, U> DispatchFromDyn> for Wrapper {} - -trait Trait { - // This method isn't object-safe yet. Unsized by-value `self` is object-safe (but not callable - // without unsized_locals), but wrappers around `Self` currently are not. - // FIXME (mikeyhew) uncomment this when unsized rvalues object-safety is implemented - // fn wrapper(self: Wrapper) -> i32; - fn ptr_wrapper(self: Ptr>) -> i32; - fn wrapper_ptr(self: Wrapper>) -> i32; - fn wrapper_ptr_wrapper(self: Wrapper>>) -> i32; -} - -impl Trait for i32 { - fn ptr_wrapper(self: Ptr>) -> i32 { - **self - } - fn wrapper_ptr(self: Wrapper>) -> i32 { - **self - } - fn wrapper_ptr_wrapper(self: Wrapper>>) -> i32 { - ***self - } -} - -fn main() { - let pw = Ptr(Box::new(Wrapper(5))) as Ptr>; - assert_eq!(pw.ptr_wrapper(), 5); - - let wp = Wrapper(Ptr(Box::new(6))) as Wrapper>; - assert_eq!(wp.wrapper_ptr(), 6); - - let wpw = Wrapper(Ptr(Box::new(Wrapper(7)))) as Wrapper>>; - assert_eq!(wpw.wrapper_ptr_wrapper(), 7); -} +#![feature(arbitrary_self_types,unsize,coerce_unsized,dispatch_from_dyn)]use//3; +std::{marker::Unsize,ops::{CoerceUnsized, Deref,DispatchFromDyn},};struct Ptr(Box);implDeref for Ptr{type Target=T;fn deref(&self)->& +T{&*self.0}}impl+?Sized,U:?Sized>CoerceUnsized>for Ptr{}// +impl+?Sized,U:?Sized>DispatchFromDyn>for Ptr{}struct//{;}; +Wrapper(T);impl Deref for Wrapper{type Target=T;fn deref( +&self)->&T{&self.0}}impl,U>CoerceUnsized>for//{;}; +Wrapper{}impl,U>DispatchFromDyn>for Wrapper< +T>{}trait Trait{fn ptr_wrapper(self:Ptr>)->i32;fn wrapper_ptr(//3; +self:Wrapper>)->i32;fn wrapper_ptr_wrapper(self:Wrapper>>)->i32;}impl Trait for i32{ fn ptr_wrapper(self:Ptr>)->i32{ +**self}fn wrapper_ptr(self:Wrapper>)->i32{**self}fn//((),());let _=(); +wrapper_ptr_wrapper(self:Wrapper>>)->i32{***self}}fn main(){3; +let pw=Ptr(Box::new(Wrapper(5)))as Ptr>;{;};();assert_eq!(pw. +ptr_wrapper(),5);;;let wp=Wrapper(Ptr(Box::new(6)))as Wrapper>;;; +assert_eq!(wp.wrapper_ptr(),6);();3;let wpw=Wrapper(Ptr(Box::new(Wrapper(7))))as +Wrapper>>;3;3;assert_eq!(wpw.wrapper_ptr_wrapper(),7);3;} diff --git a/compiler/rustc_codegen_cranelift/example/dst-field-align.rs b/compiler/rustc_codegen_cranelift/example/dst-field-align.rs index 22fc6ff33e33f..d8f7876ca9a3e 100644 --- a/compiler/rustc_codegen_cranelift/example/dst-field-align.rs +++ b/compiler/rustc_codegen_cranelift/example/dst-field-align.rs @@ -1,66 +1,12 @@ -// run-pass -#![allow(dead_code)] -struct Foo { - a: u16, - b: T, -} - -trait Bar { - fn get(&self) -> usize; -} - -impl Bar for usize { - fn get(&self) -> usize { - *self - } -} - -struct Baz { - a: T, -} - -struct HasDrop { - ptr: Box, - data: T, -} - -fn main() { - // Test that zero-offset works properly - let b: Baz = Baz { a: 7 }; - assert_eq!(b.a.get(), 7); - let b: &Baz = &b; - assert_eq!(b.a.get(), 7); - - // Test that the field is aligned properly - let f: Foo = Foo { a: 0, b: 11 }; - assert_eq!(f.b.get(), 11); - let ptr1: *const u8 = &f.b as *const _ as *const u8; - - let f: &Foo = &f; - let ptr2: *const u8 = &f.b as *const _ as *const u8; - assert_eq!(f.b.get(), 11); - - // The pointers should be the same - assert_eq!(ptr1, ptr2); - - // Test that nested DSTs work properly - let f: Foo> = Foo { a: 0, b: Foo { a: 1, b: 17 } }; - assert_eq!(f.b.b.get(), 17); - let f: &Foo> = &f; - assert_eq!(f.b.b.get(), 17); - - // Test that get the pointer via destructuring works - - let f: Foo = Foo { a: 0, b: 11 }; - let f: &Foo = &f; - let &Foo { a: _, b: ref bar } = f; - assert_eq!(bar.get(), 11); - - // Make sure that drop flags don't screw things up - - let d: HasDrop> = HasDrop { ptr: Box::new(0), data: Baz { a: [1, 2, 3, 4] } }; - assert_eq!([1, 2, 3, 4], d.data.a); - - let d: &HasDrop> = &d; - assert_eq!(&[1, 2, 3, 4], &d.data.a); -} +#![allow(dead_code)]struct Foo{a:u16,b:T,}trait Bar{fn get(&self)->//; +usize;}impl Bar for usize{fn get(&self)->usize {*self}}struct Baz{a:T, +}struct HasDrop{ptr:Box,data:T,}fn main(){;let b:Baz=Baz +{a:7};;;assert_eq!(b.a.get(),7);;let b:&Baz=&b;assert_eq!(b.a.get(),7); +let f:Foo=Foo{a:0,b:11};;assert_eq!(f.b.get(),11);let ptr1:*const u8=&f.b +as*const _ as*const u8;;;let f:&Foo=&f;let ptr2:*const u8=&f.b as*const +_ as*const u8;;;assert_eq!(f.b.get(),11);;;assert_eq!(ptr1,ptr2);;let f:Foo>=Foo{a:0,b:Foo{a:1,b:17}};;;assert_eq!(f.b.b.get(),17);let f:&Foo>=&f;;;assert_eq!(f.b.b.get(),17);let f:Foo=Foo{a:0,b:11};let f:&Foo< +dyn Bar>=&f;;let&Foo{a:_,b:ref bar}=f;assert_eq!(bar.get(),11);let d:HasDrop>=HasDrop{ptr:Box::new(0),data:Baz{a:[1,2,3,4]}};;assert_eq!([1,2,3,4], +d.data.a);3;;let d:&HasDrop>=&d;;;assert_eq!(&[1,2,3,4],&d.data.a);;} diff --git a/compiler/rustc_codegen_cranelift/example/example.rs b/compiler/rustc_codegen_cranelift/example/example.rs index 885e55bc76423..c914e72f70dff 100644 --- a/compiler/rustc_codegen_cranelift/example/example.rs +++ b/compiler/rustc_codegen_cranelift/example/example.rs @@ -1,204 +1,37 @@ -#![feature(no_core, unboxed_closures)] -#![no_core] -#![allow(dead_code)] - -extern crate mini_core; - -use mini_core::*; - -pub fn abc(a: u8) -> u8 { - a * 2 -} - -pub fn bcd(b: bool, a: u8) -> u8 { - if b { a * 2 } else { a * 3 } -} - -pub fn call() { - abc(42); -} - -pub fn indirect_call() { - let f: fn() = call; - f(); -} - -pub enum BoolOption { - Some(bool), - None, -} - -pub fn option_unwrap_or(o: BoolOption, d: bool) -> bool { - match o { - BoolOption::Some(b) => b, - BoolOption::None => d, - } -} - -pub fn ret_42() -> u8 { - 42 -} - -pub fn return_str() -> &'static str { - "hello world" -} - -pub fn promoted_val() -> &'static u8 { - &(1 * 2) -} - -pub fn cast_ref_to_raw_ptr(abc: &u8) -> *const u8 { - abc as *const u8 -} - -pub fn cmp_raw_ptr(a: *const u8, b: *const u8) -> bool { - a == b -} - -pub fn int_cast(a: u16, b: i16) -> (u8, u16, u32, usize, i8, i16, i32, isize, u8, u32) { - ( - a as u8, a as u16, a as u32, a as usize, a as i8, a as i16, a as i32, a as isize, b as u8, - b as u32, - ) -} - -pub fn char_cast(c: char) -> u8 { - c as u8 -} - -pub struct DebugTuple(()); - -pub fn debug_tuple() -> DebugTuple { - DebugTuple(()) -} - -pub fn size_of() -> usize { - intrinsics::size_of::() -} - -pub fn use_size_of() -> usize { - size_of::() -} - -pub unsafe fn use_copy_intrinsic(src: *const u8, dst: *mut u8) { - intrinsics::copy::(src, dst, 1); -} - -pub unsafe fn use_copy_intrinsic_ref(src: *const u8, dst: *mut u8) { - let copy2 = &intrinsics::copy::; - copy2(src, dst, 1); -} - -pub const ABC: u8 = 6 * 7; - -pub fn use_const() -> u8 { - ABC -} - -pub fn call_closure_3arg() { - (|_, _, _| {})(0u8, 42u16, 0u8) -} - -pub fn call_closure_2arg() { - (|_, _| {})(0u8, 42u16) -} - -pub struct IsNotEmpty; - -impl<'a, 'b> FnOnce<(&'a &'b [u16],)> for IsNotEmpty { - type Output = (u8, u8); - - #[inline] - extern "rust-call" fn call_once(mut self, arg: (&'a &'b [u16],)) -> (u8, u8) { - self.call_mut(arg) - } -} - -impl<'a, 'b> FnMut<(&'a &'b [u16],)> for IsNotEmpty { - #[inline] - extern "rust-call" fn call_mut(&mut self, _arg: (&'a &'b [u16],)) -> (u8, u8) { - (0, 42) - } -} - -pub fn call_is_not_empty() { - IsNotEmpty.call_once((&(&[0u16] as &[_]),)); -} - -pub fn eq_char(a: char, b: char) -> bool { - a == b -} - -pub unsafe fn transmute(c: char) -> u32 { - intrinsics::transmute(c) -} - -pub unsafe fn deref_str_ptr(s: *const str) -> &'static str { - &*s -} - -pub fn use_array(arr: [u8; 3]) -> u8 { - arr[1] -} - -pub fn repeat_array() -> [u8; 3] { - [0; 3] -} - -pub fn array_as_slice(arr: &[u8; 3]) -> &[u8] { - arr -} - -pub unsafe fn use_ctlz_nonzero(a: u16) -> u16 { - intrinsics::ctlz_nonzero(a) -} - -pub fn ptr_as_usize(ptr: *const u8) -> usize { - ptr as usize -} - -pub fn float_cast(a: f32, b: f64) -> (f64, f32) { - (a as f64, b as f32) -} - -pub fn int_to_float(a: u8, b: i32) -> (f64, f32) { - (a as f64, b as f32) -} - -pub fn make_array() -> [u8; 3] { - [42, 0, 5] -} - -pub fn some_promoted_tuple() -> &'static (&'static str, &'static str) { - &("abc", "some") -} - -pub fn index_slice(s: &[u8]) -> u8 { - s[2] -} - -pub struct StrWrapper { - s: str, -} - -pub fn str_wrapper_get(w: &StrWrapper) -> &str { - &w.s -} - -pub fn i16_as_i8(a: i16) -> i8 { - a as i8 -} - -pub struct Unsized(u8, str); - -pub fn get_sized_field_ref_from_unsized_type(u: &Unsized) -> &u8 { - &u.0 -} - -pub fn get_unsized_field_ref_from_unsized_type(u: &Unsized) -> &str { - &u.1 -} - -pub fn reuse_byref_argument_storage(a: (u8, u16, u32)) -> u8 { - a.0 -} +#![feature(no_core,unboxed_closures)]#![no_core]#![allow(dead_code)]extern//{;}; +crate mini_core;use mini_core::*;pub fn abc(a:u8)->u8{(a*2)}pub fn bcd(b:bool,a: +u8)->u8{if b{a*2}else{a*3}}pub fn call(){;abc(42);}pub fn indirect_call(){let f: +fn()=call;;;f();}pub enum BoolOption{Some(bool),None,}pub fn option_unwrap_or(o: +BoolOption,d:bool)->bool{match o{BoolOption::Some(b)=>b,BoolOption::None=>d,}}// +pub fn ret_42()->u8{(42)}pub fn return_str()->&'static str{"hello world"}pub fn +promoted_val()->&'static u8{(&(1*2))}pub fn cast_ref_to_raw_ptr(abc:&u8)->*const +u8{(abc as*const u8)}pub fn cmp_raw_ptr(a:* const u8,b:*const u8)->bool{a==b}pub +fn int_cast(a:u16,b:i16)->(u8,u16,u32,usize,i8 ,i16,i32,isize,u8,u32){(a as u8,a +as u16,(a as u32),(a as usize),a as i8,a as i16,a as i32,a as isize,b as u8,b as +u32,)}pub fn char_cast(c:char)->u8{(( c as u8))}pub struct DebugTuple(());pub fn +debug_tuple()->DebugTuple{(DebugTuple(()))}pub fn size_of()->usize{intrinsics +::size_of::()}pub fn use_size_of() ->usize{((size_of::()))}pub unsafe fn +use_copy_intrinsic(src:*const u8,dst:*mut u8){;intrinsics::copy::(src,dst,1) +;3;}pub unsafe fn use_copy_intrinsic_ref(src:*const u8,dst:*mut u8){;let copy2=& +intrinsics::copy::;;copy2(src,dst,1);}pub const ABC:u8=6*7;pub fn use_const( +)->u8{ABC}pub fn call_closure_3arg(){((((|_,_,_|{})))((0u8),(42u16),0u8))}pub fn +call_closure_2arg(){((((|_,_|{})))(0u8,42u16))}pub struct IsNotEmpty;impl<'a,'b> +FnOnce<(&'a&'b[u16],)>for IsNotEmpty{type Output=(u8,u8);#[inline]extern//{();}; +"rust-call" fn call_once(mut self,arg:(&'a&'b[u16],))->(u8,u8){self.call_mut(//; +arg)}}impl<'a,'b>FnMut<(&'a&'b[u16],)>for IsNotEmpty{#[inline]extern//if true{}; +"rust-call" fn call_mut(&mut self,_arg:(&'a&'b[u16],))->(u8,u8){((0,42))}}pub fn +call_is_not_empty(){;IsNotEmpty.call_once((&(&[0u16]as&[_]),));}pub fn eq_char(a +:char,b:char)->bool{(((a==b)))}pub unsafe fn transmute(c:char)->u32{intrinsics:: +transmute(c)}pub unsafe fn deref_str_ptr(s:*const str)->&'static str{&*s}pub fn +use_array(arr:[u8;(3)])->u8{(arr[1])}pub fn repeat_array()->[u8;3]{[0;3]}pub fn +array_as_slice(arr:&[u8;(3)])->&[u8]{arr}pub unsafe fn use_ctlz_nonzero(a:u16)-> +u16{(intrinsics::ctlz_nonzero(a))}pub fn ptr_as_usize(ptr:*const u8)->usize{ptr +as usize}pub fn float_cast(a:f32,b:f64)->(f64,f32 ){((a as f64,b as f32))}pub fn +int_to_float(a:u8,b:i32)->(f64,f32){((a as f64,b as f32))}pub fn make_array()->[ +u8;3]{[42,0,5] }pub fn some_promoted_tuple()->&'static(&'static str,&'static str +){&("abc","some")}pub fn index_slice(s: &[u8])->u8{s[2]}pub struct StrWrapper{s: +str,}pub fn str_wrapper_get(w:&StrWrapper)->&str{ &w.s}pub fn i16_as_i8(a:i16)-> +i8{((((((((((((((((((a as i8))))))))))))))))))}pub struct Unsized(u8,str);pub fn +get_sized_field_ref_from_unsized_type(u:&Unsized)->&u8{(((((((&u.0)))))))}pub fn +get_unsized_field_ref_from_unsized_type(u:&Unsized)->&str {(((((&u.1)))))}pub fn +reuse_byref_argument_storage(a:(u8,u16,u32))->u8{a.0}//loop{break};loop{break;}; diff --git a/compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs b/compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs index a71217a554b57..0b2d18783b539 100644 --- a/compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs +++ b/compiler/rustc_codegen_cranelift/example/float-minmax-pass.rs @@ -1,50 +1,12 @@ -// Copied from https://github.com/rust-lang/rust/blob/3fe3b89cd57229343eeca753fdd8c63d9b03c65c/src/test/ui/simd/intrinsic/float-minmax-pass.rs -// run-pass -// ignore-emscripten - -// Test that the simd_f{min,max} intrinsics produce the correct results. - -#![feature(repr_simd, core_intrinsics)] -#![allow(non_camel_case_types)] - -#[repr(simd)] -#[derive(Copy, Clone, PartialEq, Debug)] -struct f32x4(pub f32, pub f32, pub f32, pub f32); - -use std::intrinsics::simd::*; - -fn main() { - let x = f32x4(1.0, 2.0, 3.0, 4.0); - let y = f32x4(2.0, 1.0, 4.0, 3.0); - - #[cfg(not(any(target_arch = "mips", target_arch = "mips64")))] - let nan = f32::NAN; - // MIPS hardware except MIPS R6 treats f32::NAN as SNAN. Clear the signaling bit. - // See https://github.com/rust-lang/rust/issues/52746. - #[cfg(any(target_arch = "mips", target_arch = "mips64"))] - let nan = f32::from_bits(f32::NAN.to_bits() - 1); - - let n = f32x4(nan, nan, nan, nan); - - unsafe { - let min0 = simd_fmin(x, y); - let min1 = simd_fmin(y, x); - assert_eq!(min0, min1); - let e = f32x4(1.0, 1.0, 3.0, 3.0); - assert_eq!(min0, e); - let minn = simd_fmin(x, n); - assert_eq!(minn, x); - let minn = simd_fmin(y, n); - assert_eq!(minn, y); - - let max0 = simd_fmax(x, y); - let max1 = simd_fmax(y, x); - assert_eq!(max0, max1); - let e = f32x4(2.0, 2.0, 4.0, 4.0); - assert_eq!(max0, e); - let maxn = simd_fmax(x, n); - assert_eq!(maxn, x); - let maxn = simd_fmax(y, n); - assert_eq!(maxn, y); - } -} +#![feature(repr_simd,core_intrinsics)]#![allow(non_camel_case_types)]#[repr(//3; +simd)]#[derive(Copy,Clone,PartialEq,Debug) ]struct f32x4(pub f32,pub f32,pub f32 +,pub f32);use std::intrinsics::simd::*;fn main(){;let x=f32x4(1.0,2.0,3.0,4.0);; +let y=f32x4(2.0,1.0,4.0,3.0);();();#[cfg(not(any(target_arch="mips",target_arch= +"mips64")))]let nan=f32::NAN;;#[cfg(any(target_arch="mips",target_arch="mips64") +)]let nan=f32::from_bits(f32::NAN.to_bits()-1);3;;let n=f32x4(nan,nan,nan,nan);; +unsafe{;let min0=simd_fmin(x,y);;;let min1=simd_fmin(y,x);assert_eq!(min0,min1); +let e=f32x4(1.0,1.0,3.0,3.0);3;3;assert_eq!(min0,e);;;let minn=simd_fmin(x,n);;; +assert_eq!(minn,x);3;3;let minn=simd_fmin(y,n);3;;assert_eq!(minn,y);;;let max0= +simd_fmax(x,y);;;let max1=simd_fmax(y,x);;assert_eq!(max0,max1);let e=f32x4(2.0, +2.0,4.0,4.0);;;assert_eq!(max0,e);let maxn=simd_fmax(x,n);assert_eq!(maxn,x);let +maxn=simd_fmax(y,n);loop{break;};loop{break;};assert_eq!(maxn,y);loop{break;};}} diff --git a/compiler/rustc_codegen_cranelift/example/issue-59326.rs b/compiler/rustc_codegen_cranelift/example/issue-59326.rs index 70b7c94e15c11..9ddf9cf02ce12 100644 --- a/compiler/rustc_codegen_cranelift/example/issue-59326.rs +++ b/compiler/rustc_codegen_cranelift/example/issue-59326.rs @@ -1,27 +1,5 @@ -// Based on https://github.com/rust-lang/rust/blob/689511047a75a30825e367d4fd45c74604d0b15e/tests/ui/issues/issue-59326.rs#L1 -// check-pass -trait Service { - type S; -} - -trait Framing { - type F; -} - -impl Framing for () { - type F = (); -} - -trait HttpService: Service {} - -type BoxService = Box>; - -fn build_server BoxService>(_: F) {} - -fn make_server() -> Box> { - unimplemented!() -} - -fn main() { - build_server(|| make_server()) -} +trait Service{type S;}trait Framing{type F; }impl Framing for(){type F=();}trait +HttpService:Service{}type BoxService=Box>;fn build_server BoxService>(_:F){}fn make_server +()->Box>{ (unimplemented!())}fn main(){build_server(|| +make_server())}//*&*&();((),());((),());((),());((),());((),());((),());((),()); diff --git a/compiler/rustc_codegen_cranelift/example/issue-72793.rs b/compiler/rustc_codegen_cranelift/example/issue-72793.rs index 166b006004385..23f63df4b8422 100644 --- a/compiler/rustc_codegen_cranelift/example/issue-72793.rs +++ b/compiler/rustc_codegen_cranelift/example/issue-72793.rs @@ -1,26 +1,4 @@ -// Adapted from rustc ui test suite (ui/type-alias-impl-trait/issue-72793.rs) - -#![feature(type_alias_impl_trait)] - -trait T { - type Item; -} - -type Alias<'a> = impl T; - -struct S; -impl<'a> T for &'a S { - type Item = &'a (); -} - -fn filter_positive<'a>() -> Alias<'a> { - &S -} - -fn with_positive(fun: impl Fn(Alias<'_>)) { - fun(filter_positive()); -} - -fn main() { - with_positive(|_| ()); -} +#![feature(type_alias_impl_trait)]trait T{type Item;}type Alias<'a>=impl T;struct S;impl<'a>T for&'a S{type Item=&'a();}fn filter_positive<'a>()-> +Alias<'a>{&S}fn with_positive(fun:impl Fn(Alias<'_>)){;fun(filter_positive());;} +fn main(){loop{break};loop{break};with_positive(|_|());loop{break};loop{break};} diff --git a/compiler/rustc_codegen_cranelift/example/mod_bench.rs b/compiler/rustc_codegen_cranelift/example/mod_bench.rs index f15e48acc41e5..0687475c40012 100644 --- a/compiler/rustc_codegen_cranelift/example/mod_bench.rs +++ b/compiler/rustc_codegen_cranelift/example/mod_bench.rs @@ -1,36 +1,8 @@ -#![feature(start, core_intrinsics, lang_items)] -#![no_std] - -#[cfg_attr(unix, link(name = "c"))] -#[cfg_attr(target_env = "msvc", link(name = "msvcrt"))] -extern "C" {} - -#[panic_handler] -fn panic_handler(_: &core::panic::PanicInfo<'_>) -> ! { - core::intrinsics::abort(); -} - -#[lang = "eh_personality"] -fn eh_personality() {} - -// Required for rustc_codegen_llvm -#[no_mangle] -unsafe extern "C" fn _Unwind_Resume() { - core::intrinsics::unreachable(); -} - -#[start] -fn main(_argc: isize, _argv: *const *const u8) -> isize { - for i in 2..10_000_000 { - black_box((i + 1) % i); - } - - 0 -} - -#[inline(never)] -fn black_box(i: u32) { - if i != 1 { - core::intrinsics::abort(); - } -} +#![feature(start,core_intrinsics,lang_items)]#![no_std]#[cfg_attr(unix,link(//3; +name="c"))]#[cfg_attr(target_env="msvc",link(name="msvcrt"))]extern "C"{}#[//(); +panic_handler]fn panic_handler(_:&core::panic::PanicInfo<'_>)->!{let _=();core:: +intrinsics::abort();3;}#[lang="eh_personality"]fn eh_personality(){}#[no_mangle] +unsafe extern "C" fn _Unwind_Resume(){;core::intrinsics::unreachable();}#[start] +fn main(_argc:isize,_argv:*const*const u8)->isize{for i in 2..10_000_000{*&*&(); +black_box((i+1)%i);{;};}0}#[inline(never)]fn black_box(i:u32){if i!=1{{;};core:: +intrinsics::abort();if let _=(){};*&*&();((),());if let _=(){};*&*&();((),());}} diff --git a/compiler/rustc_codegen_cranelift/example/neon.rs b/compiler/rustc_codegen_cranelift/example/neon.rs index bad26947967dc..2a6379f64788a 100644 --- a/compiler/rustc_codegen_cranelift/example/neon.rs +++ b/compiler/rustc_codegen_cranelift/example/neon.rs @@ -1,234 +1,73 @@ -// Most of these tests are copied from https://github.com/japaric/stdsimd/blob/0f4413d01c4f0c3ffbc5a69e9a37fbc7235b31a9/coresimd/arm/neon.rs - -#![feature(portable_simd)] - -#[cfg(target_arch = "aarch64")] -use std::arch::aarch64::*; -use std::mem::transmute; -use std::simd::*; - -#[cfg(target_arch = "aarch64")] -unsafe fn test_vpmin_s8() { - let a = i8x8::from([1, -2, 3, -4, 5, 6, 7, 8]); - let b = i8x8::from([0, 3, 2, 5, 4, 7, 6, 9]); - let e = i8x8::from([-2, -4, 5, 7, 0, 2, 4, 6]); - let r: i8x8 = transmute(vpmin_s8(transmute(a), transmute(b))); - assert_eq!(r, e); -} - -#[cfg(target_arch = "aarch64")] -unsafe fn test_vpmin_s16() { - let a = i16x4::from([1, 2, 3, -4]); - let b = i16x4::from([0, 3, 2, 5]); - let e = i16x4::from([1, -4, 0, 2]); - let r: i16x4 = transmute(vpmin_s16(transmute(a), transmute(b))); - assert_eq!(r, e); -} - -#[cfg(target_arch = "aarch64")] -unsafe fn test_vpmin_s32() { - let a = i32x2::from([1, -2]); - let b = i32x2::from([0, 3]); - let e = i32x2::from([-2, 0]); - let r: i32x2 = transmute(vpmin_s32(transmute(a), transmute(b))); - assert_eq!(r, e); -} - -#[cfg(target_arch = "aarch64")] -unsafe fn test_vpmin_u8() { - let a = u8x8::from([1, 2, 3, 4, 5, 6, 7, 8]); - let b = u8x8::from([0, 3, 2, 5, 4, 7, 6, 9]); - let e = u8x8::from([1, 3, 5, 7, 0, 2, 4, 6]); - let r: u8x8 = transmute(vpmin_u8(transmute(a), transmute(b))); - assert_eq!(r, e); -} - -#[cfg(target_arch = "aarch64")] -unsafe fn test_vpmin_u16() { - let a = u16x4::from([1, 2, 3, 4]); - let b = u16x4::from([0, 3, 2, 5]); - let e = u16x4::from([1, 3, 0, 2]); - let r: u16x4 = transmute(vpmin_u16(transmute(a), transmute(b))); - assert_eq!(r, e); -} - -#[cfg(target_arch = "aarch64")] -unsafe fn test_vpmin_u32() { - let a = u32x2::from([1, 2]); - let b = u32x2::from([0, 3]); - let e = u32x2::from([1, 0]); - let r: u32x2 = transmute(vpmin_u32(transmute(a), transmute(b))); - assert_eq!(r, e); -} - -#[cfg(target_arch = "aarch64")] -unsafe fn test_vpmin_f32() { - let a = f32x2::from([1., -2.]); - let b = f32x2::from([0., 3.]); - let e = f32x2::from([-2., 0.]); - let r: f32x2 = transmute(vpmin_f32(transmute(a), transmute(b))); - assert_eq!(r, e); -} - -#[cfg(target_arch = "aarch64")] -unsafe fn test_vpmax_s8() { - let a = i8x8::from([1, -2, 3, -4, 5, 6, 7, 8]); - let b = i8x8::from([0, 3, 2, 5, 4, 7, 6, 9]); - let e = i8x8::from([1, 3, 6, 8, 3, 5, 7, 9]); - let r: i8x8 = transmute(vpmax_s8(transmute(a), transmute(b))); - assert_eq!(r, e); -} - -#[cfg(target_arch = "aarch64")] -unsafe fn test_vpmax_s16() { - let a = i16x4::from([1, 2, 3, -4]); - let b = i16x4::from([0, 3, 2, 5]); - let e = i16x4::from([2, 3, 3, 5]); - let r: i16x4 = transmute(vpmax_s16(transmute(a), transmute(b))); - assert_eq!(r, e); -} - -#[cfg(target_arch = "aarch64")] -unsafe fn test_vpmax_s32() { - let a = i32x2::from([1, -2]); - let b = i32x2::from([0, 3]); - let e = i32x2::from([1, 3]); - let r: i32x2 = transmute(vpmax_s32(transmute(a), transmute(b))); - assert_eq!(r, e); -} - -#[cfg(target_arch = "aarch64")] -unsafe fn test_vpmax_u8() { - let a = u8x8::from([1, 2, 3, 4, 5, 6, 7, 8]); - let b = u8x8::from([0, 3, 2, 5, 4, 7, 6, 9]); - let e = u8x8::from([2, 4, 6, 8, 3, 5, 7, 9]); - let r: u8x8 = transmute(vpmax_u8(transmute(a), transmute(b))); - assert_eq!(r, e); -} - -#[cfg(target_arch = "aarch64")] -unsafe fn test_vpmax_u16() { - let a = u16x4::from([1, 2, 3, 4]); - let b = u16x4::from([0, 3, 2, 5]); - let e = u16x4::from([2, 4, 3, 5]); - let r: u16x4 = transmute(vpmax_u16(transmute(a), transmute(b))); - assert_eq!(r, e); -} - -#[cfg(target_arch = "aarch64")] -unsafe fn test_vpmax_u32() { - let a = u32x2::from([1, 2]); - let b = u32x2::from([0, 3]); - let e = u32x2::from([2, 3]); - let r: u32x2 = transmute(vpmax_u32(transmute(a), transmute(b))); - assert_eq!(r, e); -} - -#[cfg(target_arch = "aarch64")] -unsafe fn test_vpmax_f32() { - let a = f32x2::from([1., -2.]); - let b = f32x2::from([0., 3.]); - let e = f32x2::from([1., 3.]); - let r: f32x2 = transmute(vpmax_f32(transmute(a), transmute(b))); - assert_eq!(r, e); -} - -#[cfg(target_arch = "aarch64")] -unsafe fn test_vpadd_s16() { - let a = i16x4::from([1, 2, 3, 4]); - let b = i16x4::from([0, -1, -2, -3]); - let r: i16x4 = transmute(vpadd_s16(transmute(a), transmute(b))); - let e = i16x4::from([3, 7, -1, -5]); - assert_eq!(r, e); -} -#[cfg(target_arch = "aarch64")] -unsafe fn test_vpadd_s32() { - let a = i32x2::from([1, 2]); - let b = i32x2::from([0, -1]); - let r: i32x2 = transmute(vpadd_s32(transmute(a), transmute(b))); - let e = i32x2::from([3, -1]); - assert_eq!(r, e); -} -#[cfg(target_arch = "aarch64")] -unsafe fn test_vpadd_s8() { - let a = i8x8::from([1, 2, 3, 4, 5, 6, 7, 8]); - let b = i8x8::from([0, -1, -2, -3, -4, -5, -6, -7]); - let r: i8x8 = transmute(vpadd_s8(transmute(a), transmute(b))); - let e = i8x8::from([3, 7, 11, 15, -1, -5, -9, -13]); - assert_eq!(r, e); -} -#[cfg(target_arch = "aarch64")] -unsafe fn test_vpadd_u16() { - let a = u16x4::from([1, 2, 3, 4]); - let b = u16x4::from([30, 31, 32, 33]); - let r: u16x4 = transmute(vpadd_u16(transmute(a), transmute(b))); - let e = u16x4::from([3, 7, 61, 65]); - assert_eq!(r, e); -} -#[cfg(target_arch = "aarch64")] -unsafe fn test_vpadd_u32() { - let a = u32x2::from([1, 2]); - let b = u32x2::from([30, 31]); - let r: u32x2 = transmute(vpadd_u32(transmute(a), transmute(b))); - let e = u32x2::from([3, 61]); - assert_eq!(r, e); -} -#[cfg(target_arch = "aarch64")] -unsafe fn test_vpadd_u8() { - let a = u8x8::from([1, 2, 3, 4, 5, 6, 7, 8]); - let b = u8x8::from([30, 31, 32, 33, 34, 35, 36, 37]); - let r: u8x8 = transmute(vpadd_u8(transmute(a), transmute(b))); - let e = u8x8::from([3, 7, 11, 15, 61, 65, 69, 73]); - assert_eq!(r, e); -} - -#[cfg(target_arch = "aarch64")] -unsafe fn test_vqsub_u8() { - let a = u8x8::from([1, 2, 3, 4, 5, 6, 7, 0xff]); - let b = u8x8::from([30, 1, 1, 1, 34, 0xff, 36, 37]); - let r: u8x8 = transmute(vqsub_u8(transmute(a), transmute(b))); - let e = u8x8::from([0, 1, 2, 3, 0, 0, 0, 218]); - assert_eq!(r, e); -} - -#[cfg(target_arch = "aarch64")] -unsafe fn test_vqadd_u8() { - let a = u8x8::from([1, 2, 3, 4, 5, 6, 7, 0xff]); - let b = u8x8::from([30, 1, 1, 1, 34, 0xff, 36, 37]); - let r: u8x8 = transmute(vqadd_u8(transmute(a), transmute(b))); - let e = u8x8::from([31, 3, 4, 5, 39, 0xff, 43, 0xff]); - assert_eq!(r, e); -} - -#[cfg(target_arch = "aarch64")] -fn main() { - unsafe { - test_vpmin_s8(); - test_vpmin_s16(); - test_vpmin_s32(); - test_vpmin_u8(); - test_vpmin_u16(); - test_vpmin_u32(); - test_vpmin_f32(); - test_vpmax_s8(); - test_vpmax_s16(); - test_vpmax_s32(); - test_vpmax_u8(); - test_vpmax_u16(); - test_vpmax_u32(); - test_vpmax_f32(); - - test_vpadd_s16(); - test_vpadd_s32(); - test_vpadd_s8(); - test_vpadd_u16(); - test_vpadd_u32(); - test_vpadd_u8(); - - test_vqsub_u8(); - test_vqadd_u8(); - } -} - -#[cfg(not(target_arch = "aarch64"))] -fn main() {} +#![feature(portable_simd)]#[cfg( target_arch="aarch64")]use std::arch::aarch64:: +*;use std::mem::transmute;use std::simd::*;#[cfg(target_arch="aarch64")]unsafe// +fn test_vpmin_s8(){;let a=i8x8::from([1,-2,3,-4,5,6,7,8]);let b=i8x8::from([0,3, +2,5,4,7,6,9]);3;3;let e=i8x8::from([-2,-4,5,7,0,2,4,6]);3;;let r:i8x8=transmute( +vpmin_s8(transmute(a),transmute(b)));();();assert_eq!(r,e);3;}#[cfg(target_arch= +"aarch64")]unsafe fn test_vpmin_s16(){;let a=i16x4::from([1,2,3,-4]);let b=i16x4 +::from([0,3,2,5]);;let e=i16x4::from([1,-4,0,2]);let r:i16x4=transmute(vpmin_s16 +(transmute(a),transmute(b)));3;3;assert_eq!(r,e);;}#[cfg(target_arch="aarch64")] +unsafe fn test_vpmin_s32(){;let a=i32x2::from([1,-2]);;let b=i32x2::from([0,3]); +let e=i32x2::from([-2,0]);({});{;};let r:i32x2=transmute(vpmin_s32(transmute(a), +transmute(b)));{;};();assert_eq!(r,e);();}#[cfg(target_arch="aarch64")]unsafe fn +test_vpmin_u8(){;let a=u8x8::from([1,2,3,4,5,6,7,8]);let b=u8x8::from([0,3,2,5,4 +,7,6,9]);3;;let e=u8x8::from([1,3,5,7,0,2,4,6]);;;let r:u8x8=transmute(vpmin_u8( +transmute(a),transmute(b)));3;3;assert_eq!(r,e);3;}#[cfg(target_arch="aarch64")] +unsafe fn test_vpmin_u16(){;let a=u16x4::from([1,2,3,4]);let b=u16x4::from([0,3, +2,5]);;let e=u16x4::from([1,3,0,2]);let r:u16x4=transmute(vpmin_u16(transmute(a) +,transmute(b)));();();assert_eq!(r,e);();}#[cfg(target_arch="aarch64")]unsafe fn +test_vpmin_u32(){;let a=u32x2::from([1,2]);;let b=u32x2::from([0,3]);let e=u32x2 +::from([1,0]);3;3;let r:u32x2=transmute(vpmin_u32(transmute(a),transmute(b)));;; +assert_eq!(r,e);;}#[cfg(target_arch="aarch64")]unsafe fn test_vpmin_f32(){let a= +f32x2::from([1.,-2.]);;;let b=f32x2::from([0.,3.]);;let e=f32x2::from([-2.,0.]); +let r:f32x2=transmute(vpmin_f32(transmute(a),transmute(b)));;assert_eq!(r,e);}#[ +cfg(target_arch="aarch64")]unsafe fn test_vpmax_s8(){;let a=i8x8::from([1,-2,3,- +4,5,6,7,8]);;let b=i8x8::from([0,3,2,5,4,7,6,9]);let e=i8x8::from([1,3,6,8,3,5,7 +,9]);;let r:i8x8=transmute(vpmax_s8(transmute(a),transmute(b)));assert_eq!(r,e); +}#[cfg(target_arch="aarch64")]unsafe fn test_vpmax_s16(){;let a=i16x4::from([1,2 +,3,-4]);;;let b=i16x4::from([0,3,2,5]);let e=i16x4::from([2,3,3,5]);let r:i16x4= +transmute(vpmax_s16(transmute(a),transmute(b)));();();assert_eq!(r,e);();}#[cfg( +target_arch="aarch64")]unsafe fn test_vpmax_s32(){;let a=i32x2::from([1,-2]);let +b=i32x2::from([0,3]);;;let e=i32x2::from([1,3]);let r:i32x2=transmute(vpmax_s32( +transmute(a),transmute(b)));3;3;assert_eq!(r,e);3;}#[cfg(target_arch="aarch64")] +unsafe fn test_vpmax_u8(){;let a=u8x8::from([1,2,3,4,5,6,7,8]);let b=u8x8::from( +[0,3,2,5,4,7,6,9]);;;let e=u8x8::from([2,4,6,8,3,5,7,9]);;;let r:u8x8=transmute( +vpmax_u8(transmute(a),transmute(b)));();();assert_eq!(r,e);3;}#[cfg(target_arch= +"aarch64")]unsafe fn test_vpmax_u16(){;let a=u16x4::from([1,2,3,4]);;let b=u16x4 +::from([0,3,2,5]);;let e=u16x4::from([2,4,3,5]);let r:u16x4=transmute(vpmax_u16( +transmute(a),transmute(b)));3;3;assert_eq!(r,e);3;}#[cfg(target_arch="aarch64")] +unsafe fn test_vpmax_u32(){;let a=u32x2::from([1,2]);;;let b=u32x2::from([0,3]); +let e=u32x2::from([2,3]);;let r:u32x2=transmute(vpmax_u32(transmute(a),transmute +(b)));;assert_eq!(r,e);}#[cfg(target_arch="aarch64")]unsafe fn test_vpmax_f32(){ +let a=f32x2::from([1.,-2.]);;let b=f32x2::from([0.,3.]);let e=f32x2::from([1.,3. +]);;let r:f32x2=transmute(vpmax_f32(transmute(a),transmute(b)));assert_eq!(r,e); +}#[cfg(target_arch="aarch64")]unsafe fn test_vpadd_s16(){;let a=i16x4::from([1,2 +,3,4]);();3;let b=i16x4::from([0,-1,-2,-3]);3;3;let r:i16x4=transmute(vpadd_s16( +transmute(a),transmute(b)));;;let e=i16x4::from([3,7,-1,-5]);assert_eq!(r,e);}#[ +cfg(target_arch="aarch64")]unsafe fn test_vpadd_s32(){;let a=i32x2::from([1,2]); +let b=i32x2::from([0,-1]);({});{;};let r:i32x2=transmute(vpadd_s32(transmute(a), +transmute(b)));;;let e=i32x2::from([3,-1]);;;assert_eq!(r,e);}#[cfg(target_arch= +"aarch64")]unsafe fn test_vpadd_s8(){;let a=i8x8::from([1,2,3,4,5,6,7,8]);let b= +i8x8::from([0,-1,-2,-3,-4,-5,-6,-7]);;let r:i8x8=transmute(vpadd_s8(transmute(a) +,transmute(b)));;;let e=i8x8::from([3,7,11,15,-1,-5,-9,-13]);assert_eq!(r,e);}#[ +cfg(target_arch="aarch64")]unsafe fn test_vpadd_u16(){;let a=u16x4::from([1,2,3, +4]);;let b=u16x4::from([30,31,32,33]);let r:u16x4=transmute(vpadd_u16(transmute( +a),transmute(b)));3;3;let e=u16x4::from([3,7,61,65]);3;;assert_eq!(r,e);;}#[cfg( +target_arch="aarch64")]unsafe fn test_vpadd_u32(){;let a=u32x2::from([1,2]);;let +b=u32x2::from([30,31]);;let r:u32x2=transmute(vpadd_u32(transmute(a),transmute(b +)));;;let e=u32x2::from([3,61]);;;assert_eq!(r,e);}#[cfg(target_arch="aarch64")] +unsafe fn test_vpadd_u8(){;let a=u8x8::from([1,2,3,4,5,6,7,8]);let b=u8x8::from( +[30,31,32,33,34,35,36,37]);;let r:u8x8=transmute(vpadd_u8(transmute(a),transmute +(b)));3;3;let e=u8x8::from([3,7,11,15,61,65,69,73]);3;3;assert_eq!(r,e);;}#[cfg( +target_arch="aarch64")]unsafe fn test_vqsub_u8(){;let a=u8x8::from([1,2,3,4,5,6, +7,0xff]);3;3;let b=u8x8::from([30,1,1,1,34,0xff,36,37]);3;;let r:u8x8=transmute( +vqsub_u8(transmute(a),transmute(b)));3;;let e=u8x8::from([0,1,2,3,0,0,0,218]);;; +assert_eq!(r,e);;}#[cfg(target_arch="aarch64")]unsafe fn test_vqadd_u8(){;let a= +u8x8::from([1,2,3,4,5,6,7,0xff]);;let b=u8x8::from([30,1,1,1,34,0xff,36,37]);let +r:u8x8=transmute(vqadd_u8(transmute(a),transmute(b)));;;let e=u8x8::from([31,3,4 +,5,39,0xff,43,0xff]);;;assert_eq!(r,e);;}#[cfg(target_arch="aarch64")]fn main(){ +unsafe{;test_vpmin_s8();;;test_vpmin_s16();;;test_vpmin_s32();;;test_vpmin_u8(); +test_vpmin_u16();3;3;test_vpmin_u32();3;3;test_vpmin_f32();3;;test_vpmax_s8();;; +test_vpmax_s16();3;3;test_vpmax_s32();3;3;test_vpmax_u8();3;;test_vpmax_u16();;; +test_vpmax_u32();3;3;test_vpmax_f32();3;3;test_vpadd_s16();;;test_vpadd_s32();;; +test_vpadd_s8();;test_vpadd_u16();test_vpadd_u32();test_vpadd_u8();test_vqsub_u8 +();({});({});test_vqadd_u8();{;};}}#[cfg(not(target_arch="aarch64"))]fn main(){} diff --git a/compiler/rustc_codegen_cranelift/example/polymorphize_coroutine.rs b/compiler/rustc_codegen_cranelift/example/polymorphize_coroutine.rs index c965b34e13b90..0999df4024bdc 100644 --- a/compiler/rustc_codegen_cranelift/example/polymorphize_coroutine.rs +++ b/compiler/rustc_codegen_cranelift/example/polymorphize_coroutine.rs @@ -1,16 +1,3 @@ -#![feature(coroutines, coroutine_trait)] - -use std::ops::Coroutine; -use std::pin::Pin; - -fn main() { - run_coroutine::(); -} - -fn run_coroutine() { - let mut coroutine = || { - yield; - return; - }; - Pin::new(&mut coroutine).resume(()); -} +#![feature(coroutines,coroutine_trait)]use std::ops::Coroutine;use std::pin:://; +Pin;fn main(){;run_coroutine::();;}fn run_coroutine(){let mut coroutine= +||{{;};yield;{;};{;};return;{;};};();();Pin::new(&mut coroutine).resume(());();} diff --git a/compiler/rustc_codegen_cranelift/example/std_example.rs b/compiler/rustc_codegen_cranelift/example/std_example.rs index 2fee912e52ccf..83a9af5a30fe6 100644 --- a/compiler/rustc_codegen_cranelift/example/std_example.rs +++ b/compiler/rustc_codegen_cranelift/example/std_example.rs @@ -1,482 +1,143 @@ -#![feature( - core_intrinsics, - coroutines, - coroutine_trait, - is_sorted, - repr_simd, - tuple_trait, - unboxed_closures -)] - -#[cfg(target_arch = "x86_64")] -use std::arch::x86_64::*; -use std::hint::black_box; -use std::io::Write; -use std::ops::Coroutine; - -fn main() { - println!("{:?}", std::env::args().collect::>()); - - let mutex = std::sync::Mutex::new(()); - let _guard = mutex.lock().unwrap(); - - let _ = ::std::iter::repeat('a' as u8).take(10).collect::>(); - let stderr = ::std::io::stderr(); - let mut stderr = stderr.lock(); - - std::thread::spawn(move || { - println!("Hello from another thread!"); - }); - - writeln!(stderr, "some {} text", "").unwrap(); - - let _ = std::process::Command::new("true").env("c", "d").spawn(); - - println!("cargo:rustc-link-lib=z"); - - static ONCE: std::sync::Once = std::sync::Once::new(); - ONCE.call_once(|| {}); - - let _eq = LoopState::Continue(()) == LoopState::Break(()); - - // Make sure ByValPair values with differently sized components are correctly passed - map(None::<(u8, Box)>); - - println!("{}", 2.3f32.exp()); - println!("{}", 2.3f32.exp2()); - println!("{}", 2.3f32.abs()); - println!("{}", 2.3f32.sqrt()); - println!("{}", 2.3f32.floor()); - println!("{}", 2.3f32.ceil()); - println!("{}", 2.3f32.min(1.0)); - println!("{}", 2.3f32.max(1.0)); - println!("{}", 2.3f32.powi(2)); - println!("{}", 2.3f32.log2()); - assert_eq!(2.3f32.copysign(-1.0), -2.3f32); - println!("{}", 2.3f32.powf(2.0)); - - assert_eq!(i64::MAX.checked_mul(2), None); - - assert_eq!(-128i8, (-128i8).saturating_sub(1)); - assert_eq!(127i8, 127i8.saturating_sub(-128)); - assert_eq!(-128i8, (-128i8).saturating_add(-128)); - assert_eq!(127i8, 127i8.saturating_add(1)); - - assert_eq!(0b0000000000000000000000000010000010000000000000000000000000000000_0000000000100000000000000000000000001000000000000100000000000000u128.leading_zeros(), 26); - assert_eq!(0b0000000000000000000000000010000000000000000000000000000000000000_0000000000000000000000000000000000001000000000000000000010000000u128.trailing_zeros(), 7); - assert_eq!( - core::intrinsics::saturating_sub(0, -170141183460469231731687303715884105728i128), - 170141183460469231731687303715884105727i128 - ); - - std::hint::black_box(std::hint::black_box(7571400400375753350092698930310845914i128) * 10); - assert!(0i128.checked_div(2i128).is_some()); - assert!(0u128.checked_div(2u128).is_some()); - assert_eq!(1u128 + 2, 3); - - assert_eq!(0b100010000000000000000000000000000u128 >> 10, 0b10001000000000000000000u128); - assert_eq!(0xFEDCBA987654321123456789ABCDEFu128 >> 64, 0xFEDCBA98765432u128); - assert_eq!(0xFEDCBA987654321123456789ABCDEFu128 as i128 >> 64, 0xFEDCBA98765432i128); - - let tmp = 353985398u128; - assert_eq!(tmp * 932490u128, 330087843781020u128); - - let tmp = -0x1234_5678_9ABC_DEF0i64; - assert_eq!(tmp as i128, -0x1234_5678_9ABC_DEF0i128); - - // Check that all u/i128 <-> float casts work correctly. - let houndred_u128 = 100u128; - let houndred_i128 = 100i128; - let houndred_f32 = 100.0f32; - let houndred_f64 = 100.0f64; - assert_eq!(houndred_u128 as f32, 100.0); - assert_eq!(houndred_u128 as f64, 100.0); - assert_eq!(houndred_f32 as u128, 100); - assert_eq!(houndred_f64 as u128, 100); - assert_eq!(houndred_i128 as f32, 100.0); - assert_eq!(houndred_i128 as f64, 100.0); - assert_eq!(houndred_f32 as i128, 100); - assert_eq!(houndred_f64 as i128, 100); - assert_eq!(1u128.rotate_left(2), 4); - - assert_eq!(black_box(f32::NAN) as i128, 0); - assert_eq!(black_box(f32::NAN) as u128, 0); - - // Test signed 128bit comparing - let max = usize::MAX as i128; - if 100i128 < 0i128 || 100i128 > max { - panic!(); - } - - test_checked_mul(); - - let _a = 1u32 << 2u8; - - let empty: [i32; 0] = []; - assert!(empty.is_sorted()); - - println!("{:?}", std::intrinsics::caller_location()); - - #[cfg(target_arch = "x86_64")] - unsafe { - test_simd(); - } - - Box::pin(move |mut _task_context| { - yield (); - }) - .as_mut() - .resume(0); - - #[derive(Copy, Clone)] - enum Nums { - NegOne = -1, - } - - let kind = Nums::NegOne; - assert_eq!(-1i128, kind as i128); - - let options = [1u128]; - match options[0] { - 1 => (), - 0 => loop {}, - v => panic(v), - }; - - if black_box(false) { - // Based on https://github.com/rust-lang/rust/blob/2f320a224e827b400be25966755a621779f797cc/src/test/ui/debuginfo/debuginfo_with_uninhabitable_field_and_unsized.rs - let _ = Foo::::new(); - - #[allow(dead_code)] - struct Foo { - base: Never, - value: T, - } - - impl Foo { - pub fn new() -> Box> { - todo!() - } - } - - enum Never {} - } - - foo(I64X2(0, 0)); - - transmute_fat_pointer(); - - rust_call_abi(); - - const fn no_str() -> Option> { - None - } - - static STATIC_WITH_MAYBE_NESTED_BOX: &Option> = &no_str(); - - println!("{:?}", STATIC_WITH_MAYBE_NESTED_BOX); -} - -fn panic(_: u128) { - panic!(); -} - -use std::mem::transmute; - -#[cfg(target_pointer_width = "32")] -type TwoPtrs = i64; -#[cfg(target_pointer_width = "64")] -type TwoPtrs = i128; - -fn transmute_fat_pointer() -> TwoPtrs { - unsafe { transmute::<_, TwoPtrs>("true !") } -} - -extern "rust-call" fn rust_call_abi_callee(_: T) {} - -fn rust_call_abi() { - rust_call_abi_callee(()); - rust_call_abi_callee((1, 2)); -} - -#[repr(simd)] -struct I64X2(i64, i64); - -#[allow(improper_ctypes_definitions)] -extern "C" fn foo(_a: I64X2) {} - -#[cfg(target_arch = "x86_64")] -#[target_feature(enable = "sse2")] -unsafe fn test_simd() { - assert!(is_x86_feature_detected!("sse2")); - - let x = _mm_setzero_si128(); - let y = _mm_set1_epi16(7); - let or = _mm_or_si128(x, y); - let cmp_eq = _mm_cmpeq_epi8(y, y); - let cmp_lt = _mm_cmplt_epi8(y, y); - - let (zero0, zero1) = std::mem::transmute::<_, (u64, u64)>(x); - assert_eq!((zero0, zero1), (0, 0)); - assert_eq!(std::mem::transmute::<_, [u16; 8]>(or), [7, 7, 7, 7, 7, 7, 7, 7]); - assert_eq!( - std::mem::transmute::<_, [u16; 8]>(cmp_eq), - [0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff] - ); - assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_lt), [0, 0, 0, 0, 0, 0, 0, 0]); - - test_mm_slli_si128(); - test_mm_movemask_epi8(); - test_mm256_movemask_epi8(); - test_mm_add_epi8(); - test_mm_add_pd(); - test_mm_cvtepi8_epi16(); - test_mm_cvtsi128_si64(); - - test_mm_extract_epi8(); - test_mm_insert_epi16(); - test_mm_shuffle_epi8(); - - test_mm256_shuffle_epi8(); - test_mm256_permute2x128_si256(); - - #[rustfmt::skip] - let mask1 = _mm_movemask_epi8(dbg!(_mm_setr_epi8(255u8 as i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))); - assert_eq!(mask1, 1); -} - -#[cfg(target_arch = "x86_64")] -#[target_feature(enable = "sse2")] -unsafe fn test_mm_slli_si128() { - #[rustfmt::skip] - let a = _mm_setr_epi8( - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, - ); - let r = _mm_slli_si128(a, 1); - let e = _mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - assert_eq_m128i(r, e); - - #[rustfmt::skip] - let a = _mm_setr_epi8( - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, - ); - let r = _mm_slli_si128(a, 15); - let e = _mm_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); - assert_eq_m128i(r, e); - - #[rustfmt::skip] - let a = _mm_setr_epi8( - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, - ); - let r = _mm_slli_si128(a, 16); - assert_eq_m128i(r, _mm_set1_epi8(0)); -} - -#[cfg(target_arch = "x86_64")] -#[target_feature(enable = "sse2")] -unsafe fn test_mm_movemask_epi8() { - #[rustfmt::skip] - let a = _mm_setr_epi8( - 0b1000_0000u8 as i8, 0b0, 0b1000_0000u8 as i8, 0b01, - 0b0101, 0b1111_0000u8 as i8, 0, 0, - 0, 0, 0b1111_0000u8 as i8, 0b0101, - 0b01, 0b1000_0000u8 as i8, 0b0, 0b1000_0000u8 as i8, - ); - let r = _mm_movemask_epi8(a); - assert_eq!(r, 0b10100100_00100101); -} - -#[cfg(target_arch = "x86_64")] -#[target_feature(enable = "avx2")] -unsafe fn test_mm256_movemask_epi8() { - let a = _mm256_set1_epi8(-1); - let r = _mm256_movemask_epi8(a); - let e = -1; - assert_eq!(r, e); -} - -#[cfg(target_arch = "x86_64")] -#[target_feature(enable = "sse2")] -unsafe fn test_mm_add_epi8() { - let a = _mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - #[rustfmt::skip] - let b = _mm_setr_epi8( - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - ); - let r = _mm_add_epi8(a, b); - #[rustfmt::skip] - let e = _mm_setr_epi8( - 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, - ); - assert_eq_m128i(r, e); -} - -#[cfg(target_arch = "x86_64")] -#[target_feature(enable = "sse2")] -unsafe fn test_mm_add_pd() { - let a = _mm_setr_pd(1.0, 2.0); - let b = _mm_setr_pd(5.0, 10.0); - let r = _mm_add_pd(a, b); - assert_eq_m128d(r, _mm_setr_pd(6.0, 12.0)); -} - -#[cfg(target_arch = "x86_64")] -fn assert_eq_m128i(x: std::arch::x86_64::__m128i, y: std::arch::x86_64::__m128i) { - unsafe { - assert_eq!(std::mem::transmute::<_, [u8; 16]>(x), std::mem::transmute::<_, [u8; 16]>(y)); - } -} - -#[cfg(target_arch = "x86_64")] -#[target_feature(enable = "sse2")] -pub unsafe fn assert_eq_m128d(a: __m128d, b: __m128d) { - if _mm_movemask_pd(_mm_cmpeq_pd(a, b)) != 0b11 { - panic!("{:?} != {:?}", a, b); - } -} - -#[cfg(target_arch = "x86_64")] -#[target_feature(enable = "avx")] -pub unsafe fn assert_eq_m256i(a: __m256i, b: __m256i) { - assert_eq!(std::mem::transmute::<_, [u64; 4]>(a), std::mem::transmute::<_, [u64; 4]>(b)) -} - -#[cfg(target_arch = "x86_64")] -#[target_feature(enable = "sse2")] -unsafe fn test_mm_cvtsi128_si64() { - let r = _mm_cvtsi128_si64(std::mem::transmute::<[i64; 2], _>([5, 0])); - assert_eq!(r, 5); -} - -#[cfg(target_arch = "x86_64")] -#[target_feature(enable = "sse4.1")] -unsafe fn test_mm_cvtepi8_epi16() { - let a = _mm_set1_epi8(10); - let r = _mm_cvtepi8_epi16(a); - let e = _mm_set1_epi16(10); - assert_eq_m128i(r, e); - let a = _mm_set1_epi8(-10); - let r = _mm_cvtepi8_epi16(a); - let e = _mm_set1_epi16(-10); - assert_eq_m128i(r, e); -} - -#[cfg(target_arch = "x86_64")] -#[target_feature(enable = "sse4.1")] -unsafe fn test_mm_extract_epi8() { - #[rustfmt::skip] - let a = _mm_setr_epi8( - -1, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15 - ); - let r1 = _mm_extract_epi8(a, 0); - let r2 = _mm_extract_epi8(a, 3); - assert_eq!(r1, 0xFF); - assert_eq!(r2, 3); -} - -#[cfg(target_arch = "x86_64")] -#[target_feature(enable = "sse2")] -unsafe fn test_mm_insert_epi16() { - let a = _mm_setr_epi16(0, 1, 2, 3, 4, 5, 6, 7); - let r = _mm_insert_epi16(a, 9, 0); - let e = _mm_setr_epi16(9, 1, 2, 3, 4, 5, 6, 7); - assert_eq_m128i(r, e); -} - -#[cfg(target_arch = "x86_64")] -#[target_feature(enable = "ssse3")] -unsafe fn test_mm_shuffle_epi8() { - #[rustfmt::skip] - let a = _mm_setr_epi8( - 1, 2, 3, 4, 5, 6, 7, 8, - 9, 10, 11, 12, 13, 14, 15, 16, - ); - #[rustfmt::skip] - let b = _mm_setr_epi8( - 4, 128_u8 as i8, 4, 3, - 24, 12, 6, 19, - 12, 5, 5, 10, - 4, 1, 8, 0, - ); - let expected = _mm_setr_epi8(5, 0, 5, 4, 9, 13, 7, 4, 13, 6, 6, 11, 5, 2, 9, 1); - let r = _mm_shuffle_epi8(a, b); - assert_eq_m128i(r, expected); -} - -#[cfg(target_arch = "x86_64")] -#[target_feature(enable = "avx2")] -unsafe fn test_mm256_shuffle_epi8() { - #[rustfmt::skip] - let a = _mm256_setr_epi8( - 1, 2, 3, 4, 5, 6, 7, 8, - 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, - ); - #[rustfmt::skip] - let b = _mm256_setr_epi8( - 4, 128u8 as i8, 4, 3, 24, 12, 6, 19, - 12, 5, 5, 10, 4, 1, 8, 0, - 4, 128u8 as i8, 4, 3, 24, 12, 6, 19, - 12, 5, 5, 10, 4, 1, 8, 0, - ); - #[rustfmt::skip] - let expected = _mm256_setr_epi8( - 5, 0, 5, 4, 9, 13, 7, 4, - 13, 6, 6, 11, 5, 2, 9, 1, - 21, 0, 21, 20, 25, 29, 23, 20, - 29, 22, 22, 27, 21, 18, 25, 17, - ); - let r = _mm256_shuffle_epi8(a, b); - assert_eq_m256i(r, expected); -} - -#[cfg(target_arch = "x86_64")] -#[target_feature(enable = "avx2")] -unsafe fn test_mm256_permute2x128_si256() { - let a = _mm256_setr_epi64x(100, 200, 500, 600); - let b = _mm256_setr_epi64x(300, 400, 700, 800); - let r = _mm256_permute2x128_si256::<0b00_01_00_11>(a, b); - let e = _mm256_setr_epi64x(700, 800, 500, 600); - assert_eq_m256i(r, e); -} - -fn test_checked_mul() { - let u: Option = u8::from_str_radix("1000", 10).ok(); - assert_eq!(u, None); - - assert_eq!(1u8.checked_mul(255u8), Some(255u8)); - assert_eq!(255u8.checked_mul(255u8), None); - assert_eq!(1i8.checked_mul(127i8), Some(127i8)); - assert_eq!(127i8.checked_mul(127i8), None); - assert_eq!((-1i8).checked_mul(-127i8), Some(127i8)); - assert_eq!(1i8.checked_mul(-128i8), Some(-128i8)); - assert_eq!((-128i8).checked_mul(-128i8), None); - - assert_eq!(1u64.checked_mul(u64::MAX), Some(u64::MAX)); - assert_eq!(u64::MAX.checked_mul(u64::MAX), None); - assert_eq!(1i64.checked_mul(i64::MAX), Some(i64::MAX)); - assert_eq!(i64::MAX.checked_mul(i64::MAX), None); - assert_eq!((-1i64).checked_mul(i64::MIN + 1), Some(i64::MAX)); - assert_eq!(1i64.checked_mul(i64::MIN), Some(i64::MIN)); - assert_eq!(i64::MIN.checked_mul(i64::MIN), None); -} - -#[derive(PartialEq)] -enum LoopState { - Continue(()), - Break(()), -} - -pub enum Instruction { - Increment, - Loop, -} - -fn map(a: Option<(u8, Box)>) -> Option> { - match a { - None => None, - Some((_, instr)) => Some(instr), - } -} +#![feature(core_intrinsics,coroutines,coroutine_trait,is_sorted,repr_simd,//{;}; +tuple_trait,unboxed_closures)]#[cfg(target_arch ="x86_64")]use std::arch::x86_64 +::*;use std::hint::black_box;use std:: io::Write;use std::ops::Coroutine;fn main +(){;println!("{:?}",std::env::args().collect::>());;let mutex=std::sync:: +Mutex::new(());;;let _guard=mutex.lock().unwrap();;let _=::std::iter::repeat('a' +as u8).take(10).collect::>();3;3;let stderr=::std::io::stderr();;;let mut +stderr=stderr.lock();((),());((),());std::thread::spawn(move||{((),());println!( +"Hello from another thread!");;});;;writeln!(stderr,"some {} text",""). +unwrap();;let _=std::process::Command::new("true").env("c","d").spawn();println! +("cargo:rustc-link-lib=z");;;static ONCE:std::sync::Once=std::sync::Once::new(); +ONCE.call_once(||{});;let _eq=LoopState::Continue(())==LoopState::Break(());map( +None::<(u8,Box)>);;println!("{}",2.3f32.exp());println!("{}",2.3f32 +.exp2());;println!("{}",2.3f32.abs());println!("{}",2.3f32.sqrt());println!("{}" +,2.3f32.floor());;;println!("{}",2.3f32.ceil());;println!("{}",2.3f32.min(1.0)); +println!("{}",2.3f32.max(1.0));3;;println!("{}",2.3f32.powi(2));;;println!("{}", +2.3f32.log2());;;assert_eq!(2.3f32.copysign(-1.0),-2.3f32);println!("{}",2.3f32. +powf(2.0));;assert_eq!(i64::MAX.checked_mul(2),None);assert_eq!(-128i8,(-128i8). +saturating_sub(1));;;assert_eq!(127i8,127i8.saturating_sub(-128));;;assert_eq!(- +128i8,(-128i8).saturating_add(-128));;assert_eq!(127i8,127i8.saturating_add(1)); +assert_eq!(//((),());((),());((),());let _=();((),());let _=();((),());let _=(); +0b0000000000000000000000000010000010000000000000000000000000000000_0000000000100000000000000000000000001000000000000100000000000000u128 +.leading_zeros(),26);loop{break};loop{break};loop{break};loop{break};assert_eq!( +0b0000000000000000000000000010000000000000000000000000000000000000_0000000000000000000000000000000000001000000000000000000010000000u128 +.trailing_zeros(),7);{();};{();};assert_eq!(core::intrinsics::saturating_sub(0,- +170141183460469231731687303715884105728i128),//((),());((),());((),());let _=(); +170141183460469231731687303715884105727i128);3;;std::hint::black_box(std::hint:: +black_box(7571400400375753350092698930310845914i128)*10);({});{;};assert!(0i128. +checked_div(2i128).is_some());3;3;assert!(0u128.checked_div(2u128).is_some());;; +assert_eq!(1u128+2,3);3;;assert_eq!(0b100010000000000000000000000000000u128>>10, +0b10001000000000000000000u128);;;assert_eq!(0xFEDCBA987654321123456789ABCDEFu128 +>>64,0xFEDCBA98765432u128);3;;assert_eq!(0xFEDCBA987654321123456789ABCDEFu128 as +i128>>64,0xFEDCBA98765432i128);;let tmp=353985398u128;assert_eq!(tmp*932490u128, +330087843781020u128);;let tmp=-0x1234_5678_9ABC_DEF0i64;assert_eq!(tmp as i128,- +0x1234_5678_9ABC_DEF0i128);;let houndred_u128=100u128;let houndred_i128=100i128; +let houndred_f32=100.0f32;;let houndred_f64=100.0f64;assert_eq!(houndred_u128 as +f32,100.0);;;assert_eq!(houndred_u128 as f64,100.0);;;assert_eq!(houndred_f32 as +u128,100);;assert_eq!(houndred_f64 as u128,100);assert_eq!(houndred_i128 as f32, +100.0);;;assert_eq!(houndred_i128 as f64,100.0);assert_eq!(houndred_f32 as i128, +100);;;assert_eq!(houndred_f64 as i128,100);;assert_eq!(1u128.rotate_left(2),4); +assert_eq!(black_box(f32::NAN)as i128,0);;assert_eq!(black_box(f32::NAN)as u128, +0);3;3;let max=usize::MAX as i128;3;if 100i128<0i128||100i128>max{3;panic!();;}; +test_checked_mul();3;3;let _a=1u32<<2u8;3;;let empty:[i32;0]=[];;;assert!(empty. +is_sorted());();();println!("{:?}",std::intrinsics::caller_location());();#[cfg( +target_arch="x86_64")]unsafe{3;test_simd();;};Box::pin(move|mut _task_context|{; +yield();;}).as_mut().resume(0);;;#[derive(Copy,Clone)]enum Nums{NegOne=-1,};;let +kind=Nums::NegOne;;;assert_eq!(-1i128,kind as i128);;;let options=[1u128];match +options[0]{1=>(),0=>loop{},v=>panic(v),};3;if black_box(false){3;let _=Foo::::new();;#[allow(dead_code)]struct Foo{base:Never,value:T,}implFoo{pub fn new()->Box>{todo!()}};enum Never{}}foo(I64X2(0,0)); +transmute_fat_pointer();;;rust_call_abi();;;const fn no_str()->Option>{ +None};;static STATIC_WITH_MAYBE_NESTED_BOX:&Option>=&no_str();println!( +"{:?}",STATIC_WITH_MAYBE_NESTED_BOX);;}fn panic(_:u128){panic!();}use std::mem:: +transmute;#[cfg(target_pointer_width="32")]type TwoPtrs=i64;#[cfg(//loop{break}; +target_pointer_width="64")]type TwoPtrs=i128;fn transmute_fat_pointer()->//({}); +TwoPtrs{unsafe{(((transmute::<_,TwoPtrs>((("true !"))))))}}extern "rust-call" fn +rust_call_abi_callee(_:T){}fn rust_call_abi(){loop{break}; +rust_call_abi_callee(());;rust_call_abi_callee((1,2));}#[repr(simd)]struct I64X2 +(i64,i64);#[allow(improper_ctypes_definitions)]extern "C" fn foo(_a:I64X2){}#[// +cfg(target_arch="x86_64")]#[target_feature( enable="sse2")]unsafe fn test_simd() +{;assert!(is_x86_feature_detected!("sse2"));;;let x=_mm_setzero_si128();;;let y= +_mm_set1_epi16(7);;;let or=_mm_or_si128(x,y);;let cmp_eq=_mm_cmpeq_epi8(y,y);let +cmp_lt=_mm_cmplt_epi8(y,y);;let(zero0,zero1)=std::mem::transmute::<_,(u64,u64)>( +x);;assert_eq!((zero0,zero1),(0,0));assert_eq!(std::mem::transmute::<_,[u16;8]>( +or),[7,7,7,7,7,7,7,7]);3;3;assert_eq!(std::mem::transmute::<_,[u16;8]>(cmp_eq),[ +0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff]);;assert_eq!(std::mem:: +transmute::<_,[u16;8]>(cmp_lt),[0,0,0,0,0,0,0,0]);();3;test_mm_slli_si128();3;3; +test_mm_movemask_epi8();3;3;test_mm256_movemask_epi8();3;3;test_mm_add_epi8();;; +test_mm_add_pd();();();test_mm_cvtepi8_epi16();();3;test_mm_cvtsi128_si64();3;3; +test_mm_extract_epi8();3;3;test_mm_insert_epi16();3;3;test_mm_shuffle_epi8();3;; +test_mm256_shuffle_epi8();;;test_mm256_permute2x128_si256();;#[rustfmt::skip]let +mask1=_mm_movemask_epi8(dbg!(_mm_setr_epi8(255u8 as i8,0,0 ,0,0,0,0,0,0,0,0,0,0, +0,0,0)));3;3;assert_eq!(mask1,1);;}#[cfg(target_arch="x86_64")]#[target_feature( +enable="sse2")]unsafe fn test_mm_slli_si128(){loop{break};#[rustfmt::skip]let a= +_mm_setr_epi8(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,);;let r=_mm_slli_si128(a,1 +);;let e=_mm_setr_epi8(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15);assert_eq_m128i(r, +e);;#[rustfmt::skip]let a=_mm_setr_epi8(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,) +;;let r=_mm_slli_si128(a,15);let e=_mm_setr_epi8(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 +);;assert_eq_m128i(r,e);#[rustfmt::skip]let a=_mm_setr_epi8(1,2,3,4,5,6,7,8,9,10 +,11,12,13,14,15,16,);;let r=_mm_slli_si128(a,16);assert_eq_m128i(r,_mm_set1_epi8 +(0));({});}#[cfg(target_arch="x86_64")]#[target_feature(enable="sse2")]unsafe fn +test_mm_movemask_epi8(){;#[rustfmt::skip]let a=_mm_setr_epi8(0b1000_0000u8 as i8 +,(0b0),0b1000_0000u8 as i8,0b01,0b0101,0b1111_0000u8 as i8,0,0,0,0,0b1111_0000u8 +as i8,0b0101,0b01,0b1000_0000u8 as i8,0b0,0b1000_0000u8 as i8,);({});({});let r= +_mm_movemask_epi8(a);3;3;assert_eq!(r,0b10100100_00100101);3;}#[cfg(target_arch= +"x86_64")]#[target_feature(enable="avx2")]unsafe fn test_mm256_movemask_epi8(){; +let a=_mm256_set1_epi8(-1);;let r=_mm256_movemask_epi8(a);let e=-1;assert_eq!(r, +e);*&*&();}#[cfg(target_arch="x86_64")]#[target_feature(enable="sse2")]unsafe fn +test_mm_add_epi8(){;let a=_mm_setr_epi8(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15);# +[rustfmt::skip]let b=_mm_setr_epi8(16,17,18,19,20,21 ,22,23,24,25,26,27,28,29,30 +,31,);;;let r=_mm_add_epi8(a,b);#[rustfmt::skip]let e=_mm_setr_epi8(16,18,20,22, +24,26,28,30,32,34,36,38,40,42,44,46,);;;assert_eq_m128i(r,e);}#[cfg(target_arch= +"x86_64")]#[target_feature(enable="sse2")]unsafe fn test_mm_add_pd(){({});let a= +_mm_setr_pd(1.0,2.0);3;3;let b=_mm_setr_pd(5.0,10.0);3;;let r=_mm_add_pd(a,b);;; +assert_eq_m128d(r,_mm_setr_pd(6.0,12.0));((),());}#[cfg(target_arch="x86_64")]fn +assert_eq_m128i(x:std::arch::x86_64::__m128i,y:std::arch::x86_64::__m128i){//(); +unsafe{;assert_eq!(std::mem::transmute::<_,[u8;16]>(x),std::mem::transmute::<_,[ +u8;16]>(y));();}}#[cfg(target_arch="x86_64")]#[target_feature(enable="sse2")]pub +unsafe fn assert_eq_m128d(a:__m128d,b: __m128d){if _mm_movemask_pd(_mm_cmpeq_pd( +a,b))!=0b11{({});panic!("{:?} != {:?}",a,b);{;};}}#[cfg(target_arch="x86_64")]#[ +target_feature(enable="avx")]pub unsafe fn assert_eq_m256i(a:__m256i,b:__m256i) +{assert_eq!(std::mem::transmute::<_,[u64;4] >(a),std::mem::transmute::<_,[u64;4] +>(b))}#[cfg(target_arch="x86_64")]#[target_feature(enable="sse2")]unsafe fn//(); +test_mm_cvtsi128_si64(){;let r=_mm_cvtsi128_si64(std::mem::transmute::<[i64;2],_ +>([5,0]));;assert_eq!(r,5);}#[cfg(target_arch="x86_64")]#[target_feature(enable= +"sse4.1")]unsafe fn test_mm_cvtepi8_epi16(){3;let a=_mm_set1_epi8(10);3;3;let r= +_mm_cvtepi8_epi16(a);3;;let e=_mm_set1_epi16(10);;;assert_eq_m128i(r,e);;;let a= +_mm_set1_epi8(-10);3;3;let r=_mm_cvtepi8_epi16(a);;;let e=_mm_set1_epi16(-10);;; +assert_eq_m128i(r,e);{();};}#[cfg(target_arch="x86_64")]#[target_feature(enable= +"sse4.1")]unsafe fn test_mm_extract_epi8(){;#[rustfmt::skip]let a=_mm_setr_epi8( +-1,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15);;;let r1=_mm_extract_epi8(a,0);;;let r2= +_mm_extract_epi8(a,3);;;assert_eq!(r1,0xFF);assert_eq!(r2,3);}#[cfg(target_arch= +"x86_64")]#[target_feature(enable="sse2")]unsafe fn test_mm_insert_epi16(){3;let +a=_mm_setr_epi16(0,1,2,3,4,5,6,7);();();let r=_mm_insert_epi16(a,9,0);3;3;let e= +_mm_setr_epi16(9,1,2,3,4,5,6,7);();();assert_eq_m128i(r,e);3;}#[cfg(target_arch= +"x86_64")]#[target_feature(enable="ssse3")]unsafe fn test_mm_shuffle_epi8(){3;#[ +rustfmt::skip]let a=_mm_setr_epi8(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,);3;;#[ +rustfmt::skip]let b=_mm_setr_epi8(4,128_u8 as i8,4,3,24, 12,6,19,12,5,5,10,4,1,8 +,0,);3;3;let expected=_mm_setr_epi8(5,0,5,4,9,13,7,4,13,6,6,11,5,2,9,1);;;let r= +_mm_shuffle_epi8(a,b);;assert_eq_m128i(r,expected);}#[cfg(target_arch="x86_64")] +#[target_feature(enable="avx2")]unsafe fn test_mm256_shuffle_epi8(){;#[rustfmt:: +skip]let a=_mm256_setr_epi8(1,2,3,4,5,6,7,8,9, 10,11,12,13,14,15,16,17,18,19,20, +21,22,23,24,25,26,27,28,29,30,31,32,);;#[rustfmt::skip]let b=_mm256_setr_epi8(4, +128u8 as i8,4,3,24,12,6,19,12,5,5,10,4,1 ,8,0,4,128u8 as i8,4,3,24,12,6,19,12,5, +5,10,4,1,8,0,);;;#[rustfmt::skip]let expected=_mm256_setr_epi8(5,0,5,4,9,13,7,4, +13,6,6,11,5,2,9,1,21,0,21,20,25,29,23,20,29,22,22,27,21,18,25,17,);{;};();let r= +_mm256_shuffle_epi8(a,b);();();assert_eq_m256i(r,expected);3;}#[cfg(target_arch= +"x86_64")]#[target_feature(enable="avx2")]unsafe fn//loop{break;};if let _=(){}; +test_mm256_permute2x128_si256(){;let a=_mm256_setr_epi64x(100,200,500,600);let b +=_mm256_setr_epi64x(300,400,700,800);({});{;};let r=_mm256_permute2x128_si256::< +0b00_01_00_11>(a,b);;let e=_mm256_setr_epi64x(700,800,500,600);assert_eq_m256i(r +,e);;}fn test_checked_mul(){let u:Option=u8::from_str_radix("1000",10).ok(); +assert_eq!(u,None);;;assert_eq!(1u8.checked_mul(255u8),Some(255u8));;assert_eq!( +255u8.checked_mul(255u8),None);;;assert_eq!(1i8.checked_mul(127i8),Some(127i8)); +assert_eq!(127i8.checked_mul(127i8),None);;assert_eq!((-1i8).checked_mul(-127i8) +,Some(127i8));;;assert_eq!(1i8.checked_mul(-128i8),Some(-128i8));;;assert_eq!((- +128i8).checked_mul(-128i8),None);;assert_eq!(1u64.checked_mul(u64::MAX),Some(u64 +::MAX));3;3;assert_eq!(u64::MAX.checked_mul(u64::MAX),None);3;3;assert_eq!(1i64. +checked_mul(i64::MAX),Some(i64::MAX));;assert_eq!(i64::MAX.checked_mul(i64::MAX) +,None);;;assert_eq!((-1i64).checked_mul(i64::MIN+1),Some(i64::MAX));;assert_eq!( +1i64.checked_mul(i64::MIN),Some(i64::MIN));;;assert_eq!(i64::MIN.checked_mul(i64 +::MIN),None);{;};}#[derive(PartialEq)]enum LoopState{Continue(()),Break(()),}pub +enum Instruction{Increment,Loop,}fn map(a:Option<(u8,Box)>)->//{;}; +Option>{match a{None=>None,Some ((_,instr))=>((Some(instr))),}} diff --git a/compiler/rustc_codegen_cranelift/example/subslice-patterns-const-eval.rs b/compiler/rustc_codegen_cranelift/example/subslice-patterns-const-eval.rs index 3c87891666399..e0373365fc386 100644 --- a/compiler/rustc_codegen_cranelift/example/subslice-patterns-const-eval.rs +++ b/compiler/rustc_codegen_cranelift/example/subslice-patterns-const-eval.rs @@ -1,102 +1,23 @@ -// Based on https://github.com/rust-lang/rust/blob/c5840f9d252c2f5cc16698dbf385a29c5de3ca07/src/test/ui/array-slice-vec/subslice-patterns-const-eval-match.rs - -// Test that array subslice patterns are correctly handled in const evaluation. - -// run-pass - -#[derive(PartialEq, Debug, Clone)] -struct N(u8); - -#[derive(PartialEq, Debug, Clone)] -struct Z; - -macro_rules! n { - ($($e:expr),* $(,)?) => { - [$(N($e)),*] - } -} - -// This macro has an unused variable so that it can be repeated base on the -// number of times a repeated variable (`$e` in `z`) occurs. -macro_rules! zed { - ($e:expr) => { - Z - }; -} - -macro_rules! z { - ($($e:expr),* $(,)?) => { - [$(zed!($e)),*] - } -} - -// Compare constant evaluation and runtime evaluation of a given expression. -macro_rules! compare_evaluation { - ($e:expr, $t:ty $(,)?) => {{ - const CONST_EVAL: $t = $e; - const fn const_eval() -> $t { - $e - } - static CONST_EVAL2: $t = const_eval(); - let runtime_eval = $e; - assert_eq!(CONST_EVAL, runtime_eval); - assert_eq!(CONST_EVAL2, runtime_eval); - }}; -} - -// Repeat `$test`, substituting the given macro variables with the given -// identifiers. -// -// For example: -// -// repeat! { -// ($name); X; Y: -// struct $name; -// } -// -// Expands to: -// -// struct X; struct Y; -// -// This is used to repeat the tests using both the `N` and `Z` -// types. -macro_rules! repeat { - (($($dollar:tt $placeholder:ident)*); $($($values:ident),+);*: $($test:tt)*) => { - macro_rules! single { - ($($dollar $placeholder:ident),*) => { $($test)* } - } - $(single!($($values),+);)* - } -} - -#[rustfmt::skip] -fn main() { - repeat! { - ($arr $Ty); n, N; z, Z: - compare_evaluation!({ let [_, x @ .., _] = $arr!(1, 2, 3, 4); x }, [$Ty; 2]); - compare_evaluation!({ let [_, ref x @ .., _] = $arr!(1, 2, 3, 4); x }, &'static [$Ty; 2]); - compare_evaluation!({ let [_, x @ .., _] = &$arr!(1, 2, 3, 4); x }, &'static [$Ty; 2]); - - compare_evaluation!({ let [_, _, x @ .., _, _] = $arr!(1, 2, 3, 4); x }, [$Ty; 0]); - compare_evaluation!( - { let [_, _, ref x @ .., _, _] = $arr!(1, 2, 3, 4); x }, - &'static [$Ty; 0], - ); - compare_evaluation!( - { let [_, _, x @ .., _, _] = &$arr!(1, 2, 3, 4); x }, - &'static [$Ty; 0], - ); - - compare_evaluation!({ let [_, .., x] = $arr!(1, 2, 3, 4); x }, $Ty); - compare_evaluation!({ let [_, .., ref x] = $arr!(1, 2, 3, 4); x }, &'static $Ty); - compare_evaluation!({ let [_, _y @ .., x] = &$arr!(1, 2, 3, 4); x }, &'static $Ty); - } - - compare_evaluation!({ let [_, .., N(x)] = n!(1, 2, 3, 4); x }, u8); - compare_evaluation!({ let [_, .., N(ref x)] = n!(1, 2, 3, 4); x }, &'static u8); - compare_evaluation!({ let [_, .., N(x)] = &n!(1, 2, 3, 4); x }, &'static u8); - - compare_evaluation!({ let [N(x), .., _] = n!(1, 2, 3, 4); x }, u8); - compare_evaluation!({ let [N(ref x), .., _] = n!(1, 2, 3, 4); x }, &'static u8); - compare_evaluation!({ let [N(x), .., _] = &n!(1, 2, 3, 4); x }, &'static u8); -} +#[derive(PartialEq,Debug,Clone)]struct N(u8);#[derive(PartialEq,Debug,Clone)]//; +struct Z;macro_rules!n{($($e:expr),*$(,)?) =>{[$(N($e)),*]}}macro_rules!zed{($e: +expr)=>{Z};}macro_rules!z{($($e:expr),*$(,)?)=>{[$(zed!($e)),*]}}macro_rules!//; +compare_evaluation{($e:expr,$t:ty$(,)?)=>{{const CONST_EVAL:$t=$e;const fn//{;}; +const_eval()->$t{$e}static CONST_EVAL2:$t=const_eval();let runtime_eval=$e;//(); +assert_eq!(CONST_EVAL,runtime_eval);assert_eq!(CONST_EVAL2,runtime_eval);}};}//; +macro_rules!repeat{(($($dollar:tt$placeholder:ident) *);$($($values:ident),+);*: +$($test:tt)*)=>{macro_rules!single{($( $dollar$placeholder:ident),*)=>{$($test)* +}}$(single!($($values),+);)*}}#[rustfmt ::skip]fn main(){repeat!{($arr$Ty);n,N;z +,Z:compare_evaluation!({let[_,x@..,_]=$arr!(1,2,3,4);x},[$Ty;2]);//loop{break;}; +compare_evaluation!({let[_,ref x@..,_]=$arr!(1,2,3,4);x},&'static[$Ty;2]);//{;}; +compare_evaluation!({let[_,x@..,_]=&$arr!(1,2,3,4);x},&'static[$Ty;2]);//*&*&(); +compare_evaluation!({let[_,_,x@..,_,_]=$arr!(1,2,3,4);x},[$Ty;0]);//loop{break}; +compare_evaluation!({let[_,_,ref x@..,_,_]=$arr! (1,2,3,4);x},&'static[$Ty;0],); +compare_evaluation!({let[_,_,x@..,_,_]=&$arr!(1,2,3,4);x},&'static[$Ty;0],);//3; +compare_evaluation!({let[_,..,x]=$arr!(1,2,3,4);x},$Ty);compare_evaluation!({//; +let[_,..,ref x]=$arr!(1,2,3,4 );x},&'static$Ty);compare_evaluation!({let[_,_y@.. +,x]=&$arr!(1,2,3,4);x},&'static$Ty);};compare_evaluation!({let[_,..,N(x)]=n!(1,2 +,3,4);x},u8);;compare_evaluation!({let[_,..,N(ref x)]=n!(1,2,3,4);x},&'static u8 +);{;};();compare_evaluation!({let[_,..,N(x)]=&n!(1,2,3,4);x},&'static u8);();(); +compare_evaluation!({let[N(x),..,_]=n!(1,2,3,4);x},u8);;compare_evaluation!({let +[N(ref x),..,_]=n!(1,2,3,4);x},&'static u8);;compare_evaluation!({let[N(x),..,_] +=&n!(1,2,3,4);x},&'static u8);loop{break};loop{break};loop{break};loop{break;};} diff --git a/compiler/rustc_codegen_cranelift/example/track-caller-attribute.rs b/compiler/rustc_codegen_cranelift/example/track-caller-attribute.rs index 93bab17e46b27..ea0faeaf4ab20 100644 --- a/compiler/rustc_codegen_cranelift/example/track-caller-attribute.rs +++ b/compiler/rustc_codegen_cranelift/example/track-caller-attribute.rs @@ -1,40 +1,10 @@ -// Based on https://github.com/anp/rust/blob/175631311716d7dfeceec40d2587cde7142ffa8c/src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs - -// run-pass - -use std::panic::Location; - -#[track_caller] -fn tracked() -> &'static Location<'static> { - Location::caller() -} - -fn nested_intrinsic() -> &'static Location<'static> { - Location::caller() -} - -fn nested_tracked() -> &'static Location<'static> { - tracked() -} - -fn main() { - let location = Location::caller(); - assert_eq!(location.file(), file!()); - assert_eq!(location.line(), 21); - assert_eq!(location.column(), 20); - - let tracked = tracked(); - assert_eq!(tracked.file(), file!()); - assert_eq!(tracked.line(), 26); - assert_eq!(tracked.column(), 19); - - let nested = nested_intrinsic(); - assert_eq!(nested.file(), file!()); - assert_eq!(nested.line(), 13); - assert_eq!(nested.column(), 5); - - let contained = nested_tracked(); - assert_eq!(contained.file(), file!()); - assert_eq!(contained.line(), 17); - assert_eq!(contained.column(), 5); -} +use std::panic::Location;#[track_caller] fn tracked()->&'static Location<'static +>{Location::caller()}fn nested_intrinsic ()->&'static Location<'static>{Location +::caller()}fn nested_tracked()->&'static Location<'static>{tracked()}fn main(){; +let location=Location::caller();;assert_eq!(location.file(),file!());assert_eq!( +location.line(),21);;;assert_eq!(location.column(),20);;;let tracked=tracked();; +assert_eq!(tracked.file(),file!());;;assert_eq!(tracked.line(),26);;;assert_eq!( +tracked.column(),19);;;let nested=nested_intrinsic();;;assert_eq!(nested.file(), +file!());3;3;assert_eq!(nested.line(),13);3;;assert_eq!(nested.column(),5);;;let +contained=nested_tracked();3;;assert_eq!(contained.file(),file!());;;assert_eq!( +contained.line(),17);let _=();((),());assert_eq!(contained.column(),5);((),());} diff --git a/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs b/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs index 1e14f41d4a2c2..19cd0f56d696e 100644 --- a/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs +++ b/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs @@ -1,96 +1,30 @@ -use std::env; -#[cfg(unix)] -use std::os::unix::process::CommandExt; -use std::process::Command; - -include!("../build_system/shared_utils.rs"); - -fn main() { - let current_exe = env::current_exe().unwrap(); - let mut sysroot = current_exe.parent().unwrap(); - if sysroot.file_name().unwrap().to_str().unwrap() == "bin" { - sysroot = sysroot.parent().unwrap(); - } - - let mut rustflags = vec!["-Cpanic=abort".to_owned(), "-Zpanic-abort-tests".to_owned()]; - if let Some(name) = option_env!("BUILTIN_BACKEND") { - rustflags.push(format!("-Zcodegen-backend={name}")); - } else { - let dylib = sysroot.join(if cfg!(windows) { "bin" } else { "lib" }).join( - env::consts::DLL_PREFIX.to_string() - + "rustc_codegen_cranelift" - + env::consts::DLL_SUFFIX, - ); - rustflags.push(format!("-Zcodegen-backend={}", dylib.to_str().unwrap())); - } - rustflags.push("--sysroot".to_owned()); - rustflags.push(sysroot.to_str().unwrap().to_owned()); - - let cargo = if let Some(cargo) = option_env!("CARGO") { - cargo - } else { - // Ensure that the right toolchain is used - env::set_var("RUSTUP_TOOLCHAIN", option_env!("TOOLCHAIN_NAME").expect("TOOLCHAIN_NAME")); - "cargo" - }; - - let mut args = env::args().skip(1).collect::>(); - if args.get(0).map(|arg| &**arg) == Some("clif") { - // Avoid infinite recursion when invoking `cargo-clif` as cargo subcommand using - // `cargo clif`. - args.remove(0); - } - - let args: Vec<_> = match args.get(0).map(|arg| &**arg) { - Some("jit") => { - rustflags.push("-Cprefer-dynamic".to_owned()); - args.remove(0); - IntoIterator::into_iter(["rustc".to_string()]) - .chain(args) - .chain([ - "--".to_string(), - "-Zunstable-options".to_string(), - "-Cllvm-args=mode=jit".to_string(), - ]) - .collect() - } - Some("lazy-jit") => { - rustflags.push("-Cprefer-dynamic".to_owned()); - args.remove(0); - IntoIterator::into_iter(["rustc".to_string()]) - .chain(args) - .chain([ - "--".to_string(), - "-Zunstable-options".to_string(), - "-Cllvm-args=mode=jit-lazy".to_string(), - ]) - .collect() - } - _ => args, - }; - - let mut cmd = Command::new(cargo); - cmd.args(args); - rustflags_to_cmd_env( - &mut cmd, - "RUSTFLAGS", - &rustflags_from_env("RUSTFLAGS") - .into_iter() - .chain(rustflags.iter().map(|flag| flag.clone())) - .collect::>(), - ); - rustflags_to_cmd_env( - &mut cmd, - "RUSTDOCFLAGS", - &rustflags_from_env("RUSTDOCFLAGS") - .into_iter() - .chain(rustflags.iter().map(|flag| flag.clone())) - .collect::>(), - ); - - #[cfg(unix)] - panic!("Failed to spawn cargo: {}", cmd.exec()); - - #[cfg(not(unix))] - std::process::exit(cmd.spawn().unwrap().wait().unwrap().code().unwrap_or(1)); -} +use std::env;#[cfg(unix)]use std::os::unix::process::CommandExt;use std:://({}); +process::Command;include!("../build_system/shared_utils.rs");fn main(){{();};let +current_exe=env::current_exe().unwrap();3;;let mut sysroot=current_exe.parent(). +unwrap();();if sysroot.file_name().unwrap().to_str().unwrap()=="bin"{();sysroot= +sysroot.parent().unwrap();3;};let mut rustflags=vec!["-Cpanic=abort".to_owned(), +"-Zpanic-abort-tests".to_owned()];((),());((),());if let Some(name)=option_env!( +"BUILTIN_BACKEND"){;rustflags.push(format!("-Zcodegen-backend={name}"));;}else{; +let dylib=(sysroot.join(if cfg!(windows){ "bin"}else{"lib"})).join(env::consts:: +DLL_PREFIX.to_string()+"rustc_codegen_cranelift"+env::consts::DLL_SUFFIX,);();3; +rustflags.push(format!("-Zcodegen-backend={}",dylib.to_str().unwrap()));{;};}(); +rustflags.push("--sysroot".to_owned());;rustflags.push(sysroot.to_str().unwrap() +.to_owned());;let cargo=if let Some(cargo)=option_env!("CARGO"){cargo}else{env:: +set_var((((("RUSTUP_TOOLCHAIN")))),((((option_env!("TOOLCHAIN_NAME"))))).expect( +"TOOLCHAIN_NAME"));;"cargo"};let mut args=env::args().skip(1).collect::>( +);;if args.get(0).map(|arg|&**arg)==Some("clif"){args.remove(0);}let args:Vec<_> +=match args.get(0).map(|arg|&**arg){Some("jit")=>{*&*&();((),());rustflags.push( +"-Cprefer-dynamic".to_owned());;args.remove(0);IntoIterator::into_iter(["rustc". +to_string()]).chain(args).chain( [((("--").to_string())),("-Zunstable-options"). +to_string(),"-Cllvm-args=mode=jit".to_string(),]).collect()}Some("lazy-jit")=>{; +rustflags.push("-Cprefer-dynamic".to_owned());3;3;args.remove(0);;IntoIterator:: +into_iter(([(("rustc").to_string())])).chain( args).chain([(("--").to_string()), +"-Zunstable-options".to_string(),(("-Cllvm-args=mode=jit-lazy").to_string()),]). +collect()}_=>args,};();3;let mut cmd=Command::new(cargo);3;3;cmd.args(args);3;3; +rustflags_to_cmd_env((&mut cmd),("RUSTFLAGS"), &rustflags_from_env("RUSTFLAGS"). +into_iter().chain(rustflags.iter().map(|flag| flag.clone())).collect::>() +,);{();};{();};rustflags_to_cmd_env(&mut cmd,"RUSTDOCFLAGS",&rustflags_from_env( +"RUSTDOCFLAGS").into_iter().chain(((rustflags.iter()).map(|flag|flag.clone()))). +collect::>(),);;#[cfg(unix)]panic!("Failed to spawn cargo: {}",cmd.exec() +);;#[cfg(not(unix))]std::process::exit(cmd.spawn().unwrap().wait().unwrap().code +().unwrap_or(1));*&*&();((),());((),());((),());*&*&();((),());((),());((),());} diff --git a/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs b/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs index 03912b18ea5f2..8397ecd8a9511 100755 --- a/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs +++ b/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs @@ -1,125 +1,50 @@ -#!/usr/bin/env bash -#![forbid(unsafe_code)]/* This line is ignored by bash -# This block is ignored by rustc -pushd $(dirname "$0")/../ -RUSTC="$(pwd)/dist/rustc-clif" -popd -PROFILE=$1 OUTPUT=$2 exec $RUSTC -Zunstable-options -Cllvm-args=mode=jit -Cprefer-dynamic $0 -#*/ - -//! This program filters away uninteresting samples and trims uninteresting frames for stackcollapse -//! profiles. -//! -//! Usage: ./filter_profile.rs -//! -//! This file is specially crafted to be both a valid bash script and valid rust source file. If -//! executed as bash script this will run the rust source using cg_clif in JIT mode. - -use std::io::Write; - -fn main() -> Result<(), Box> { - let profile_name = std::env::var("PROFILE").unwrap(); - let output_name = std::env::var("OUTPUT").unwrap(); - if profile_name.is_empty() || output_name.is_empty() { - println!("Usage: ./filter_profile.rs "); - std::process::exit(1); - } - let profile = std::fs::read_to_string(profile_name) - .map_err(|err| format!("Failed to read profile {}", err))?; - let mut output = std::fs::OpenOptions::new() - .create(true) - .write(true) - .truncate(true) - .open(output_name)?; - - for line in profile.lines() { - let mut stack = &line[..line.rfind(" ").unwrap()]; - let count = &line[line.rfind(" ").unwrap() + 1..]; - - // Filter away uninteresting samples - if !stack.contains("rustc_codegen_cranelift") { - continue; - } - - if stack.contains("rustc_monomorphize::partitioning::collect_and_partition_mono_items") - || stack.contains("rustc_incremental::assert_dep_graph::assert_dep_graph") - || stack.contains("rustc_symbol_mangling::test::report_symbol_names") - { - continue; - } - - // Trim start - if let Some(index) = stack.find("rustc_interface::passes::configure_and_expand") { - stack = &stack[index..]; - } else if let Some(index) = stack.find("rustc_interface::passes::analysis") { - stack = &stack[index..]; - } else if let Some(index) = stack.find("rustc_interface::passes::start_codegen") { - stack = &stack[index..]; - } else if let Some(index) = stack.find("rustc_interface::queries::Linker::link") { - stack = &stack[index..]; - } - - if let Some(index) = stack.find("rustc_codegen_cranelift::driver::aot::module_codegen") { - stack = &stack[index..]; - } - - // Trim end - const MALLOC: &str = "malloc"; - if let Some(index) = stack.find(MALLOC) { - stack = &stack[..index + MALLOC.len()]; - } - - const FREE: &str = "free"; - if let Some(index) = stack.find(FREE) { - stack = &stack[..index + FREE.len()]; - } - - const TYPECK_ITEM_BODIES: &str = "rustc_typeck::check::typeck_item_bodies"; - if let Some(index) = stack.find(TYPECK_ITEM_BODIES) { - stack = &stack[..index + TYPECK_ITEM_BODIES.len()]; - } - - const COLLECT_AND_PARTITION_MONO_ITEMS: &str = - "rustc_monomorphize::partitioning::collect_and_partition_mono_items"; - if let Some(index) = stack.find(COLLECT_AND_PARTITION_MONO_ITEMS) { - stack = &stack[..index + COLLECT_AND_PARTITION_MONO_ITEMS.len()]; - } - - const ASSERT_DEP_GRAPH: &str = "rustc_incremental::assert_dep_graph::assert_dep_graph"; - if let Some(index) = stack.find(ASSERT_DEP_GRAPH) { - stack = &stack[..index + ASSERT_DEP_GRAPH.len()]; - } - - const REPORT_SYMBOL_NAMES: &str = "rustc_symbol_mangling::test::report_symbol_names"; - if let Some(index) = stack.find(REPORT_SYMBOL_NAMES) { - stack = &stack[..index + REPORT_SYMBOL_NAMES.len()]; - } - - const ENCODE_METADATA: &str = "rustc_metadata::rmeta::encoder::encode_metadata"; - if let Some(index) = stack.find(ENCODE_METADATA) { - stack = &stack[..index + ENCODE_METADATA.len()]; - } - - const INSTANTIATE_AND_NORMALIZE_ERASING_REGIONS: &str = "rustc_middle::ty::normalize_erasing_regions::::instantiate_and_normalize_erasing_regions"; - if let Some(index) = stack.find(INSTANTIATE_AND_NORMALIZE_ERASING_REGIONS) { - stack = &stack[..index + INSTANTIATE_AND_NORMALIZE_ERASING_REGIONS.len()]; - } - - const NORMALIZE_ERASING_LATE_BOUND_REGIONS: &str = "rustc_middle::ty::normalize_erasing_regions::::normalize_erasing_late_bound_regions"; - if let Some(index) = stack.find(NORMALIZE_ERASING_LATE_BOUND_REGIONS) { - stack = &stack[..index + NORMALIZE_ERASING_LATE_BOUND_REGIONS.len()]; - } - - const INST_BUILD: &str = "::build"; - if let Some(index) = stack.find(INST_BUILD) { - stack = &stack[..index + INST_BUILD.len()]; - } - - output.write_all(stack.as_bytes())?; - output.write_all(&*b" ")?; - output.write_all(count.as_bytes())?; - output.write_all(&*b"\n")?; - } - - Ok(()) -} +#!/usr/bin/env bash #![forbid(unsafe_code )]use std::io::Write;fn main()->Result +<(),Box>{{();};let profile_name=std::env::var("PROFILE"). +unwrap();3;3;let output_name=std::env::var("OUTPUT").unwrap();3;if profile_name. +is_empty()||output_name.is_empty(){let _=();let _=();let _=();let _=();println!( +"Usage: ./filter_profile.rs ");;; +std::process::exit(1);{;};}();let profile=std::fs::read_to_string(profile_name). +map_err(|err|format!("Failed to read profile {}",err))?;;;let mut output=std::fs +::OpenOptions::new().create(true).write( true).truncate(true).open(output_name)? +;;for line in profile.lines(){;let mut stack=&line[..line.rfind(" ").unwrap()];; +let count=&line[line.rfind(" ").unwrap()+1..];((),());((),());if!stack.contains( +"rustc_codegen_cranelift"){loop{break;};continue;loop{break};}if stack.contains( +"rustc_monomorphize::partitioning::collect_and_partition_mono_items")||stack.//; +contains(((("rustc_incremental::assert_dep_graph::assert_dep_graph")))) ||stack. +contains("rustc_symbol_mangling::test::report_symbol_names"){3;continue;;}if let +Some(index)=stack.find("rustc_interface::passes::configure_and_expand"){;stack=& +stack[index..];if let _=(){};*&*&();((),());}else if let Some(index)=stack.find( +"rustc_interface::passes::analysis"){3;stack=&stack[index..];;}else if let Some( +index)=stack.find("rustc_interface::passes::start_codegen"){3;stack=&stack[index +..];if true{};if true{};if true{};if true{};}else if let Some(index)=stack.find( +"rustc_interface::queries::Linker::link"){3;stack=&stack[index..];;}if let Some( +index)=stack.find("rustc_codegen_cranelift::driver::aot::module_codegen"){;stack +=&stack[index..];3;}3;const MALLOC:&str="malloc";;if let Some(index)=stack.find( +MALLOC){;stack=&stack[..index+MALLOC.len()];}const FREE:&str="free";if let Some( +index)=stack.find(FREE){{();};stack=&stack[..index+FREE.len()];{();};}({});const +TYPECK_ITEM_BODIES:&str="rustc_typeck::check::typeck_item_bodies";3;if let Some( +index)=stack.find(TYPECK_ITEM_BODIES){3;stack=&stack[..index+TYPECK_ITEM_BODIES. +len()];if let _=(){};}if let _=(){};const COLLECT_AND_PARTITION_MONO_ITEMS:&str= +"rustc_monomorphize::partitioning::collect_and_partition_mono_items";({});if let +Some(index)=stack.find(COLLECT_AND_PARTITION_MONO_ITEMS){3;stack=&stack[..index+ +COLLECT_AND_PARTITION_MONO_ITEMS.len()];{();};}({});const ASSERT_DEP_GRAPH:&str= +"rustc_incremental::assert_dep_graph::assert_dep_graph";({});if let Some(index)= +stack.find(ASSERT_DEP_GRAPH){3;stack=&stack[..index+ASSERT_DEP_GRAPH.len()];3;}; +const REPORT_SYMBOL_NAMES:&str=//let _=||();loop{break};loop{break};loop{break}; +"rustc_symbol_mangling::test::report_symbol_names";{;};if let Some(index)=stack. +find(REPORT_SYMBOL_NAMES){3;stack=&stack[..index+REPORT_SYMBOL_NAMES.len()];3;}; +const ENCODE_METADATA:&str="rustc_metadata::rmeta::encoder::encode_metadata";;if +let Some(index)=stack.find(ENCODE_METADATA){*&*&();((),());stack=&stack[..index+ +ENCODE_METADATA.len()];3;};const INSTANTIATE_AND_NORMALIZE_ERASING_REGIONS:&str= +"rustc_middle::ty::normalize_erasing_regions::::instantiate_and_normalize_erasing_regions" +;;if let Some(index)=stack.find(INSTANTIATE_AND_NORMALIZE_ERASING_REGIONS){stack +=&stack[..index+INSTANTIATE_AND_NORMALIZE_ERASING_REGIONS.len()];({});}{;};const +NORMALIZE_ERASING_LATE_BOUND_REGIONS:&str=//let _=();let _=();let _=();let _=(); +"rustc_middle::ty::normalize_erasing_regions::::normalize_erasing_late_bound_regions" +;3;if let Some(index)=stack.find(NORMALIZE_ERASING_LATE_BOUND_REGIONS){3;stack=& +stack[..index+NORMALIZE_ERASING_LATE_BOUND_REGIONS.len()];3;};const INST_BUILD:& +str=//let _=();let _=();let _=();if true{};let _=();let _=();let _=();if true{}; +"::build" +;;if let Some(index)=stack.find(INST_BUILD){stack=&stack[..index+INST_BUILD.len( +)];3;};output.write_all(stack.as_bytes())?;;;output.write_all(&*b" ")?;;;output. +write_all(count.as_bytes())?;{();};({});output.write_all(&*b"\n")?;({});}Ok(())} diff --git a/compiler/rustc_codegen_cranelift/src/abi/comments.rs b/compiler/rustc_codegen_cranelift/src/abi/comments.rs index a318cae1722b6..8a0b9dc1bfb1f 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/comments.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/comments.rs @@ -1,97 +1,28 @@ -//! Annotate the clif ir with comments describing how arguments are passed into the current function -//! and where all locals are stored. - -use std::borrow::Cow; - -use rustc_target::abi::call::PassMode; - -use crate::prelude::*; - -pub(super) fn add_args_header_comment(fx: &mut FunctionCx<'_, '_, '_>) { - if fx.clif_comments.enabled() { - fx.add_global_comment( - "kind loc.idx param pass mode ty".to_string(), - ); - } -} - -pub(super) fn add_arg_comment<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - kind: &str, - local: Option, - local_field: Option, - params: &[Value], - arg_abi_mode: &PassMode, - arg_layout: TyAndLayout<'tcx>, -) { - if !fx.clif_comments.enabled() { - return; - } - - let local = if let Some(local) = local { - Cow::Owned(format!("{:?}", local)) - } else { - Cow::Borrowed("???") - }; - let local_field = if let Some(local_field) = local_field { - Cow::Owned(format!(".{}", local_field)) - } else { - Cow::Borrowed("") - }; - - let params = match params { - [] => Cow::Borrowed("-"), - [param] => Cow::Owned(format!("= {:?}", param)), - [param_a, param_b] => Cow::Owned(format!("= {:?},{:?}", param_a, param_b)), - params => Cow::Owned(format!( - "= {}", - params.iter().map(ToString::to_string).collect::>().join(",") - )), - }; - - let pass_mode = format!("{:?}", arg_abi_mode); - fx.add_global_comment(format!( - "{kind:5}{local:>3}{local_field:<5} {params:10} {pass_mode:36} {ty:?}", - kind = kind, - local = local, - local_field = local_field, - params = params, - pass_mode = pass_mode, - ty = arg_layout.ty, - )); -} - -pub(super) fn add_locals_header_comment(fx: &mut FunctionCx<'_, '_, '_>) { - if fx.clif_comments.enabled() { - fx.add_global_comment(String::new()); - fx.add_global_comment( - "kind local ty size align (abi,pref)".to_string(), - ); - } -} - -pub(super) fn add_local_place_comments<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - place: CPlace<'tcx>, - local: Local, -) { - if !fx.clif_comments.enabled() { - return; - } - let TyAndLayout { ty, layout } = place.layout(); - let rustc_target::abi::LayoutS { size, align, .. } = layout.0.0; - - let (kind, extra) = place.debug_comment(); - - fx.add_global_comment(format!( - "{:<5} {:5} {:30} {:4}b {}, {}{}{}", - kind, - format!("{:?}", local), - format!("{:?}", ty), - size.bytes(), - align.abi.bytes(), - align.pref.bytes(), - if extra.is_empty() { "" } else { " " }, - extra, - )); -} +use std::borrow::Cow;use rustc_target:: abi::call::PassMode;use crate::prelude:: +*;pub(super)fn add_args_header_comment(fx:&mut FunctionCx<'_,'_,'_>){if fx.//(); +clif_comments.enabled(){((),());let _=();((),());let _=();fx.add_global_comment( +"kind loc.idx param pass mode ty".to_string (), +);;}}pub(super)fn add_arg_comment<'tcx>(fx:&mut FunctionCx<'_,'_,'tcx>,kind:&str +,local:Option,local_field:Option,params:&[Value],//if true{}; +arg_abi_mode:&PassMode,arg_layout:TyAndLayout<'tcx>,){if!fx.clif_comments.//{;}; +enabled(){;return;}let local=if let Some(local)=local{Cow::Owned(format!("{:?}", +local))}else{Cow::Borrowed("???")};3;3;let local_field=if let Some(local_field)= +local_field{Cow::Owned(format!(".{}",local_field))}else{Cow::Borrowed("")};;;let +params=match params{[]=>Cow::Borrowed("-" ),[param]=>Cow::Owned(format!("= {:?}" +,param)),[param_a,param_b]=>Cow:: Owned(format!("= {:?},{:?}",param_a,param_b)), +params=>Cow::Owned(format!("= {}",params.iter().map(ToString::to_string).//({}); +collect::>().join(","))),};;let pass_mode=format!("{:?}",arg_abi_mode);fx +.add_global_comment(format!(//loop{break};loop{break;};loop{break};loop{break;}; +"{kind:5}{local:>3}{local_field:<5} {params:10} {pass_mode:36} {ty:?}",kind=//3; +kind,local=local,local_field=local_field,params=params,pass_mode=pass_mode,ty=// +arg_layout.ty,));;}pub(super)fn add_locals_header_comment(fx:&mut FunctionCx<'_, +'_,'_>){if fx.clif_comments.enabled(){;fx.add_global_comment(String::new());;fx. +add_global_comment(//if let _=(){};*&*&();((),());*&*&();((),());*&*&();((),()); +"kind local ty size align (abi,pref)". to_string() +,);;}}pub(super)fn add_local_place_comments<'tcx>(fx:&mut FunctionCx<'_,'_,'tcx> +,place:CPlace<'tcx>,local:Local,){if!fx.clif_comments.enabled(){3;return;3;};let +TyAndLayout{ty,layout}=place.layout();;let rustc_target::abi::LayoutS{size,align +,..}=layout.0.0;;;let(kind,extra)=place.debug_comment();;;fx.add_global_comment( +format!("{:<5} {:5} {:30} {:4}b {}, {}{}{}",kind,format! ("{:?}",local),format!( +"{:?}",ty),size.bytes(),align.abi.bytes (),align.pref.bytes(),if extra.is_empty( +){""}else{" "},extra,));if true{};let _=||();if true{};let _=||();} diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 6363a0d59a4f2..a256a0e2ea9b3 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -1,696 +1,219 @@ -//! Handling of everything related to the calling convention. Also fills `fx.local_map`. - -mod comments; -mod pass_mode; -mod returning; - -use std::borrow::Cow; - -use cranelift_codegen::ir::SigRef; -use cranelift_module::ModuleError; -use rustc_codegen_ssa::errors::CompilerBuiltinsCannotCall; -use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::ty::layout::FnAbiOf; -use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization; -use rustc_session::Session; -use rustc_span::source_map::Spanned; -use rustc_target::abi::call::{Conv, FnAbi}; -use rustc_target::spec::abi::Abi; - -use self::pass_mode::*; -pub(crate) use self::returning::codegen_return; -use crate::prelude::*; - -fn clif_sig_from_fn_abi<'tcx>( - tcx: TyCtxt<'tcx>, - default_call_conv: CallConv, - fn_abi: &FnAbi<'tcx, Ty<'tcx>>, -) -> Signature { - let call_conv = conv_to_call_conv(tcx.sess, fn_abi.conv, default_call_conv); - - let inputs = fn_abi.args.iter().flat_map(|arg_abi| arg_abi.get_abi_param(tcx).into_iter()); - - let (return_ptr, returns) = fn_abi.ret.get_abi_return(tcx); - // Sometimes the first param is a pointer to the place where the return value needs to be stored. - let params: Vec<_> = return_ptr.into_iter().chain(inputs).collect(); - - Signature { params, returns, call_conv } -} - -pub(crate) fn conv_to_call_conv(sess: &Session, c: Conv, default_call_conv: CallConv) -> CallConv { - match c { - Conv::Rust | Conv::C => default_call_conv, - Conv::Cold | Conv::PreserveMost | Conv::PreserveAll => CallConv::Cold, - Conv::X86_64SysV => CallConv::SystemV, - Conv::X86_64Win64 => CallConv::WindowsFastcall, - - // Should already get a back compat warning - Conv::X86Fastcall | Conv::X86Stdcall | Conv::X86ThisCall | Conv::X86VectorCall => { - default_call_conv - } - - Conv::X86Intr | Conv::RiscvInterrupt { .. } => { - sess.dcx().fatal(format!("interrupt call conv {c:?} not yet implemented")) - } - - Conv::ArmAapcs => sess.dcx().fatal("aapcs call conv not yet implemented"), - Conv::CCmseNonSecureCall => { - sess.dcx().fatal("C-cmse-nonsecure-call call conv is not yet implemented"); - } - - Conv::Msp430Intr | Conv::PtxKernel | Conv::AvrInterrupt | Conv::AvrNonBlockingInterrupt => { - unreachable!("tried to use {c:?} call conv which only exists on an unsupported target"); - } - } -} - -pub(crate) fn get_function_sig<'tcx>( - tcx: TyCtxt<'tcx>, - default_call_conv: CallConv, - inst: Instance<'tcx>, -) -> Signature { - assert!(!inst.args.has_infer()); - clif_sig_from_fn_abi( - tcx, - default_call_conv, - &RevealAllLayoutCx(tcx).fn_abi_of_instance(inst, ty::List::empty()), - ) -} - -/// Instance must be monomorphized -pub(crate) fn import_function<'tcx>( - tcx: TyCtxt<'tcx>, - module: &mut dyn Module, - inst: Instance<'tcx>, -) -> FuncId { - let name = tcx.symbol_name(inst).name; - let sig = get_function_sig(tcx, module.target_config().default_call_conv, inst); - match module.declare_function(name, Linkage::Import, &sig) { - Ok(func_id) => func_id, - Err(ModuleError::IncompatibleDeclaration(_)) => tcx.dcx().fatal(format!( - "attempt to declare `{name}` as function, but it was already declared as static" - )), - Err(ModuleError::IncompatibleSignature(_, prev_sig, new_sig)) => tcx.dcx().fatal(format!( - "attempt to declare `{name}` with signature {new_sig:?}, \ +mod comments;mod pass_mode;mod returning;use std::borrow::Cow;use//loop{break;}; +cranelift_codegen::ir::SigRef;use cranelift_module::ModuleError;use//let _=||(); +rustc_codegen_ssa::errors::CompilerBuiltinsCannotCall;use rustc_middle::middle// +::codegen_fn_attrs::CodegenFnAttrFlags;use rustc_middle::ty::layout::FnAbiOf;//; +use rustc_middle::ty::print::with_no_trimmed_paths;use rustc_monomorphize:://(); +is_call_from_compiler_builtins_to_upstream_monomorphization;use rustc_session:: +Session;use rustc_span::source_map::Spanned; use rustc_target::abi::call::{Conv, +FnAbi};use rustc_target::spec::abi::Abi;use self::pass_mode::*;pub(crate)use//3; +self::returning::codegen_return;use crate::prelude::*;fn clif_sig_from_fn_abi(tcx:TyCtxt<'tcx>,default_call_conv:CallConv ,fn_abi:&FnAbi<'tcx,Ty<'tcx>>, +)->Signature{if let _=(){};let call_conv=conv_to_call_conv(tcx.sess,fn_abi.conv, +default_call_conv);();3;let inputs=fn_abi.args.iter().flat_map(|arg_abi|arg_abi. +get_abi_param(tcx).into_iter());*&*&();{();};let(return_ptr,returns)=fn_abi.ret. +get_abi_return(tcx);();3;let params:Vec<_>=return_ptr.into_iter().chain(inputs). +collect();();Signature{params,returns,call_conv}}pub(crate)fn conv_to_call_conv( +sess:&Session,c:Conv,default_call_conv:CallConv)->CallConv{match c{Conv::Rust|// +Conv::C=>default_call_conv,Conv::Cold|Conv::PreserveMost|Conv::PreserveAll=>//3; +CallConv::Cold,Conv::X86_64SysV=>CallConv::SystemV,Conv::X86_64Win64=>CallConv// +::WindowsFastcall,Conv::X86Fastcall|Conv::X86Stdcall|Conv::X86ThisCall|Conv:://; +X86VectorCall=>{default_call_conv}Conv::X86Intr|Conv ::RiscvInterrupt{..}=>{sess +.dcx().fatal((format !("interrupt call conv {c:?} not yet implemented")))}Conv:: +ArmAapcs=>(((sess.dcx()).fatal(("aapcs call conv not yet implemented")))),Conv:: +CCmseNonSecureCall=>{if true{};let _=||();if true{};let _=||();sess.dcx().fatal( +"C-cmse-nonsecure-call call conv is not yet implemented");{;};}Conv::Msp430Intr| +Conv::PtxKernel|Conv::AvrInterrupt|Conv::AvrNonBlockingInterrupt=>{;unreachable! +("tried to use {c:?} call conv which only exists on an unsupported target");;}}} +pub(crate)fn get_function_sig<'tcx> (tcx:TyCtxt<'tcx>,default_call_conv:CallConv +,inst:Instance<'tcx>,)->Signature{*&*&();assert!(!inst.args.has_infer());*&*&(); +clif_sig_from_fn_abi(tcx,default_call_conv,& ((((((RevealAllLayoutCx(tcx))))))). +fn_abi_of_instance(inst,ty::List::empty()) ,)}pub(crate)fn import_function<'tcx> +(tcx:TyCtxt<'tcx>,module:&mut dyn Module,inst:Instance<'tcx>,)->FuncId{;let name +=tcx.symbol_name(inst).name;;let sig=get_function_sig(tcx,module.target_config() +.default_call_conv,inst);();match module.declare_function(name,Linkage::Import,& +sig){Ok(func_id)=>func_id,Err (ModuleError::IncompatibleDeclaration(_))=>tcx.dcx +().fatal(format!(//*&*&();((),());*&*&();((),());*&*&();((),());((),());((),()); +"attempt to declare `{name}` as function, but it was already declared as static" +)),Err(ModuleError::IncompatibleSignature(_,prev_sig ,new_sig))=>tcx.dcx().fatal +(format!(//((),());let _=();((),());let _=();((),());let _=();let _=();let _=(); +"attempt to declare `{name}` with signature {new_sig:?}, \ but it was already declared with signature {prev_sig:?}" - )), - Err(err) => Err::<_, _>(err).unwrap(), - } -} - -impl<'tcx> FunctionCx<'_, '_, 'tcx> { - /// Instance must be monomorphized - pub(crate) fn get_function_ref(&mut self, inst: Instance<'tcx>) -> FuncRef { - let func_id = import_function(self.tcx, self.module, inst); - let func_ref = self.module.declare_func_in_func(func_id, &mut self.bcx.func); - - if self.clif_comments.enabled() { - self.add_comment(func_ref, format!("{:?}", inst)); - } - - func_ref - } - - pub(crate) fn lib_call( - &mut self, - name: &str, - params: Vec, - returns: Vec, - args: &[Value], - ) -> Cow<'_, [Value]> { - if self.tcx.sess.target.is_like_windows { - let (mut params, mut args): (Vec<_>, Vec<_>) = params - .into_iter() - .zip(args) - .map(|(param, &arg)| { - if param.value_type == types::I128 { - let arg_ptr = self.create_stack_slot(16, 16); - arg_ptr.store(self, arg, MemFlags::trusted()); - (AbiParam::new(self.pointer_type), arg_ptr.get_addr(self)) - } else { - (param, arg) - } - }) - .unzip(); - - let indirect_ret_val = returns.len() == 1 && returns[0].value_type == types::I128; - - if indirect_ret_val { - params.insert(0, AbiParam::new(self.pointer_type)); - let ret_ptr = self.create_stack_slot(16, 16); - args.insert(0, ret_ptr.get_addr(self)); - self.lib_call_unadjusted(name, params, vec![], &args); - return Cow::Owned(vec![ret_ptr.load(self, types::I128, MemFlags::trusted())]); - } else { - return self.lib_call_unadjusted(name, params, returns, &args); - } - } - - self.lib_call_unadjusted(name, params, returns, args) - } - - pub(crate) fn lib_call_unadjusted( - &mut self, - name: &str, - params: Vec, - returns: Vec, - args: &[Value], - ) -> Cow<'_, [Value]> { - let sig = Signature { params, returns, call_conv: self.target_config.default_call_conv }; - let func_id = self.module.declare_function(name, Linkage::Import, &sig).unwrap(); - let func_ref = self.module.declare_func_in_func(func_id, &mut self.bcx.func); - if self.clif_comments.enabled() { - self.add_comment(func_ref, format!("{:?}", name)); - } - let call_inst = self.bcx.ins().call(func_ref, args); - if self.clif_comments.enabled() { - self.add_comment(call_inst, format!("lib_call {}", name)); - } - let results = self.bcx.inst_results(call_inst); - assert!(results.len() <= 2, "{}", results.len()); - Cow::Borrowed(results) - } -} - -/// Make a [`CPlace`] capable of holding value of the specified type. -fn make_local_place<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - local: Local, - layout: TyAndLayout<'tcx>, - is_ssa: bool, -) -> CPlace<'tcx> { - if layout.is_unsized() { - fx.tcx.dcx().span_fatal( - fx.mir.local_decls[local].source_info.span, - "unsized locals are not yet supported", - ); - } - let place = if is_ssa { - if let rustc_target::abi::Abi::ScalarPair(_, _) = layout.abi { - CPlace::new_var_pair(fx, local, layout) - } else { - CPlace::new_var(fx, local, layout) - } - } else { - CPlace::new_stack_slot(fx, layout) - }; - - self::comments::add_local_place_comments(fx, place, local); - - place -} - -pub(crate) fn codegen_fn_prelude<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, start_block: Block) { - fx.bcx.append_block_params_for_function_params(start_block); - - fx.bcx.switch_to_block(start_block); - fx.bcx.ins().nop(); - - let ssa_analyzed = crate::analyze::analyze(fx); - - self::comments::add_args_header_comment(fx); - - let mut block_params_iter = fx.bcx.func.dfg.block_params(start_block).to_vec().into_iter(); - let ret_place = - self::returning::codegen_return_param(fx, &ssa_analyzed, &mut block_params_iter); - assert_eq!(fx.local_map.push(ret_place), RETURN_PLACE); - - // None means pass_mode == NoPass - enum ArgKind<'tcx> { - Normal(Option>), - Spread(Vec>>), - } - - // FIXME implement variadics in cranelift - if fx.fn_abi.c_variadic { - fx.tcx.dcx().span_fatal( - fx.mir.span, - "Defining variadic functions is not yet supported by Cranelift", - ); - } - - let mut arg_abis_iter = fx.fn_abi.args.iter(); - - let func_params = fx - .mir - .args_iter() - .map(|local| { - let arg_ty = fx.monomorphize(fx.mir.local_decls[local].ty); - - // Adapted from https://github.com/rust-lang/rust/blob/145155dc96757002c7b2e9de8489416e2fdbbd57/src/librustc_codegen_llvm/mir/mod.rs#L442-L482 - if Some(local) == fx.mir.spread_arg { - // This argument (e.g. the last argument in the "rust-call" ABI) - // is a tuple that was spread at the ABI level and now we have - // to reconstruct it into a tuple local variable, from multiple - // individual function arguments. - - let tupled_arg_tys = match arg_ty.kind() { - ty::Tuple(ref tys) => tys, - _ => bug!("spread argument isn't a tuple?! but {:?}", arg_ty), - }; - - let mut params = Vec::new(); - for (i, _arg_ty) in tupled_arg_tys.iter().enumerate() { - let arg_abi = arg_abis_iter.next().unwrap(); - let param = - cvalue_for_param(fx, Some(local), Some(i), arg_abi, &mut block_params_iter); - params.push(param); - } - - (local, ArgKind::Spread(params), arg_ty) - } else { - let arg_abi = arg_abis_iter.next().unwrap(); - let param = - cvalue_for_param(fx, Some(local), None, arg_abi, &mut block_params_iter); - (local, ArgKind::Normal(param), arg_ty) - } - }) - .collect::, Ty<'tcx>)>>(); - - assert!(fx.caller_location.is_none()); - if fx.instance.def.requires_caller_location(fx.tcx) { - // Store caller location for `#[track_caller]`. - let arg_abi = arg_abis_iter.next().unwrap(); - fx.caller_location = - Some(cvalue_for_param(fx, None, None, arg_abi, &mut block_params_iter).unwrap()); - } - - assert!(arg_abis_iter.next().is_none(), "ArgAbi left behind"); - assert!(block_params_iter.next().is_none(), "arg_value left behind"); - - self::comments::add_locals_header_comment(fx); - - for (local, arg_kind, ty) in func_params { - // While this is normally an optimization to prevent an unnecessary copy when an argument is - // not mutated by the current function, this is necessary to support unsized arguments. - if let ArgKind::Normal(Some(val)) = arg_kind { - if let Some((addr, meta)) = val.try_to_ptr() { - // Ownership of the value at the backing storage for an argument is passed to the - // callee per the ABI, so it is fine to borrow the backing storage of this argument - // to prevent a copy. - - let place = if let Some(meta) = meta { - CPlace::for_ptr_with_extra(addr, meta, val.layout()) - } else { - CPlace::for_ptr(addr, val.layout()) - }; - - self::comments::add_local_place_comments(fx, place, local); - - assert_eq!(fx.local_map.push(place), local); - continue; - } - } - - let layout = fx.layout_of(ty); - let is_ssa = ssa_analyzed[local].is_ssa(fx, ty); - let place = make_local_place(fx, local, layout, is_ssa); - assert_eq!(fx.local_map.push(place), local); - - match arg_kind { - ArgKind::Normal(param) => { - if let Some(param) = param { - place.write_cvalue(fx, param); - } - } - ArgKind::Spread(params) => { - for (i, param) in params.into_iter().enumerate() { - if let Some(param) = param { - place.place_field(fx, FieldIdx::new(i)).write_cvalue(fx, param); - } - } - } - } - } - - for local in fx.mir.vars_and_temps_iter() { - let ty = fx.monomorphize(fx.mir.local_decls[local].ty); - let layout = fx.layout_of(ty); - - let is_ssa = ssa_analyzed[local].is_ssa(fx, ty); - - let place = make_local_place(fx, local, layout, is_ssa); - assert_eq!(fx.local_map.push(place), local); - } - - fx.bcx.ins().jump(*fx.block_map.get(START_BLOCK).unwrap(), &[]); -} - -struct CallArgument<'tcx> { - value: CValue<'tcx>, - is_owned: bool, -} - -// FIXME avoid intermediate `CValue` before calling `adjust_arg_for_abi` -fn codegen_call_argument_operand<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - operand: &Operand<'tcx>, -) -> CallArgument<'tcx> { - CallArgument { - value: codegen_operand(fx, operand), - is_owned: matches!(operand, Operand::Move(_)), - } -} - -pub(crate) fn codegen_terminator_call<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - source_info: mir::SourceInfo, - func: &Operand<'tcx>, - args: &[Spanned>], - destination: Place<'tcx>, - target: Option, -) { - let func = codegen_operand(fx, func); - let fn_sig = func.layout().ty.fn_sig(fx.tcx); - - let ret_place = codegen_place(fx, destination); - - // Handle special calls like intrinsics and empty drop glue. - let instance = if let ty::FnDef(def_id, fn_args) = *func.layout().ty.kind() { - let instance = - ty::Instance::expect_resolve(fx.tcx, ty::ParamEnv::reveal_all(), def_id, fn_args) - .polymorphize(fx.tcx); - - if is_call_from_compiler_builtins_to_upstream_monomorphization(fx.tcx, instance) { - if target.is_some() { - let caller = with_no_trimmed_paths!(fx.tcx.def_path_str(fx.instance.def_id())); - let callee = with_no_trimmed_paths!(fx.tcx.def_path_str(def_id)); - fx.tcx.dcx().emit_err(CompilerBuiltinsCannotCall { caller, callee }); - } else { - fx.bcx.ins().trap(TrapCode::User(0)); - return; - } - } - - if fx.tcx.symbol_name(instance).name.starts_with("llvm.") { - crate::intrinsics::codegen_llvm_intrinsic_call( - fx, - &fx.tcx.symbol_name(instance).name, - fn_args, - args, - ret_place, - target, - source_info.span, - ); - return; - } - - match instance.def { - InstanceDef::Intrinsic(_) => { - match crate::intrinsics::codegen_intrinsic_call( - fx, - instance, - args, - ret_place, - target, - source_info, - ) { - Ok(()) => return, - Err(instance) => Some(instance), - } - } - InstanceDef::DropGlue(_, None) => { - // empty drop glue - a nop. - let dest = target.expect("Non terminating drop_in_place_real???"); - let ret_block = fx.get_block(dest); - fx.bcx.ins().jump(ret_block, &[]); - return; - } - _ => Some(instance), - } - } else { - None - }; - - let extra_args = &args[fn_sig.inputs().skip_binder().len()..]; - let extra_args = fx.tcx.mk_type_list_from_iter( - extra_args.iter().map(|op_arg| fx.monomorphize(op_arg.node.ty(fx.mir, fx.tcx))), - ); - let fn_abi = if let Some(instance) = instance { - RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(instance, extra_args) - } else { - RevealAllLayoutCx(fx.tcx).fn_abi_of_fn_ptr(fn_sig, extra_args) - }; - - let is_cold = if fn_sig.abi() == Abi::RustCold { - true - } else { - instance.is_some_and(|inst| { - fx.tcx.codegen_fn_attrs(inst.def_id()).flags.contains(CodegenFnAttrFlags::COLD) - }) - }; - if is_cold { - fx.bcx.set_cold_block(fx.bcx.current_block().unwrap()); - if let Some(destination_block) = target { - fx.bcx.set_cold_block(fx.get_block(destination_block)); - } - } - - // Unpack arguments tuple for closures - let mut args = if fn_sig.abi() == Abi::RustCall { - let (self_arg, pack_arg) = match args { - [pack_arg] => (None, codegen_call_argument_operand(fx, &pack_arg.node)), - [self_arg, pack_arg] => ( - Some(codegen_call_argument_operand(fx, &self_arg.node)), - codegen_call_argument_operand(fx, &pack_arg.node), - ), - _ => panic!("rust-call abi requires one or two arguments"), - }; - - let tupled_arguments = match pack_arg.value.layout().ty.kind() { - ty::Tuple(ref tupled_arguments) => tupled_arguments, - _ => bug!("argument to function with \"rust-call\" ABI is not a tuple"), - }; - - let mut args = Vec::with_capacity(1 + tupled_arguments.len()); - args.extend(self_arg); - for i in 0..tupled_arguments.len() { - args.push(CallArgument { - value: pack_arg.value.value_field(fx, FieldIdx::new(i)), - is_owned: pack_arg.is_owned, - }); - } - args - } else { - args.iter().map(|arg| codegen_call_argument_operand(fx, &arg.node)).collect::>() - }; - - // Pass the caller location for `#[track_caller]`. - if instance.is_some_and(|inst| inst.def.requires_caller_location(fx.tcx)) { - let caller_location = fx.get_caller_location(source_info); - args.push(CallArgument { value: caller_location, is_owned: false }); - } - - let args = args; - assert_eq!(fn_abi.args.len(), args.len()); - - enum CallTarget { - Direct(FuncRef), - Indirect(SigRef, Value), - } - - let (func_ref, first_arg_override) = match instance { - // Trait object call - Some(Instance { def: InstanceDef::Virtual(_, idx), .. }) => { - if fx.clif_comments.enabled() { - let nop_inst = fx.bcx.ins().nop(); - fx.add_comment( - nop_inst, - format!("virtual call; self arg pass mode: {:?}", &fn_abi.args[0]), - ); - } - - let (ptr, method) = crate::vtable::get_ptr_and_method_ref(fx, args[0].value, idx); - 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.get_addr(fx))) - } - - // Normal call - Some(instance) => { - let func_ref = fx.get_function_ref(instance); - (CallTarget::Direct(func_ref), None) - } - - // Indirect call - None => { - if fx.clif_comments.enabled() { - let nop_inst = fx.bcx.ins().nop(); - fx.add_comment(nop_inst, "indirect call"); - } - - let func = func.load_scalar(fx); - 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, func), None) - } - }; - - self::returning::codegen_with_call_return_arg(fx, &fn_abi.ret, ret_place, |fx, return_ptr| { - let call_args = return_ptr - .into_iter() - .chain(first_arg_override.into_iter()) - .chain( - args.into_iter() - .enumerate() - .skip(if first_arg_override.is_some() { 1 } else { 0 }) - .flat_map(|(i, arg)| { - adjust_arg_for_abi(fx, arg.value, &fn_abi.args[i], arg.is_owned).into_iter() - }), - ) - .collect::>(); - - let call_inst = match func_ref { - CallTarget::Direct(func_ref) => fx.bcx.ins().call(func_ref, &call_args), - CallTarget::Indirect(sig, func_ptr) => { - fx.bcx.ins().call_indirect(sig, func_ptr, &call_args) - } - }; - - // FIXME find a cleaner way to support varargs - if fn_sig.c_variadic() { - if !matches!(fn_sig.abi(), Abi::C { .. }) { - fx.tcx.dcx().span_fatal( - source_info.span, - format!("Variadic call for non-C abi {:?}", fn_sig.abi()), - ); - } - let sig_ref = fx.bcx.func.dfg.call_signature(call_inst).unwrap(); - let abi_params = call_args - .into_iter() - .map(|arg| { - let ty = fx.bcx.func.dfg.value_type(arg); - if !ty.is_int() { - // FIXME set %al to upperbound on float args once floats are supported - fx.tcx.dcx().span_fatal( - source_info.span, - format!("Non int ty {:?} for variadic call", ty), - ); - } - AbiParam::new(ty) - }) - .collect::>(); - fx.bcx.func.dfg.signatures[sig_ref].params = abi_params; - } - - call_inst - }); - - if let Some(dest) = target { - let ret_block = fx.get_block(dest); - fx.bcx.ins().jump(ret_block, &[]); - } else { - fx.bcx.ins().trap(TrapCode::UnreachableCodeReached); - } -} - -pub(crate) fn codegen_drop<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - source_info: mir::SourceInfo, - drop_place: CPlace<'tcx>, -) { - let ty = drop_place.layout().ty; - let drop_instance = Instance::resolve_drop_in_place(fx.tcx, ty).polymorphize(fx.tcx); - - if let ty::InstanceDef::DropGlue(_, None) = drop_instance.def { - // we don't actually need to drop anything - } else { - match ty.kind() { - ty::Dynamic(_, _, ty::Dyn) => { - // IN THIS ARM, WE HAVE: - // ty = *mut (dyn Trait) - // which is: exists ( *mut T, Vtable ) - // args[0] args[1] - // - // args = ( Data, Vtable ) - // | - // v - // /-------\ - // | ... | - // \-------/ - // - let (ptr, vtable) = drop_place.to_ptr_unsized(); - let ptr = ptr.get_addr(fx); - let drop_fn = crate::vtable::drop_fn_of_obj(fx, vtable); - - // FIXME(eddyb) perhaps move some of this logic into - // `Instance::resolve_drop_in_place`? - let virtual_drop = Instance { - def: ty::InstanceDef::Virtual(drop_instance.def_id(), 0), - args: drop_instance.args, - }; - 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, &[ptr]); - } - ty::Dynamic(_, _, ty::DynStar) => { - // IN THIS ARM, WE HAVE: - // ty = *mut (dyn* Trait) - // which is: *mut exists (T, Vtable) - // - // 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), - args: drop_instance.args, - }; - 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(_, _))); - - let fn_abi = - RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(drop_instance, ty::List::empty()); - - let arg_value = drop_place.place_ref( - fx, - fx.layout_of(Ty::new_mut_ref(fx.tcx, fx.tcx.lifetimes.re_erased, ty)), - ); - let arg_value = adjust_arg_for_abi(fx, arg_value, &fn_abi.args[0], true); - - let mut call_args: Vec = arg_value.into_iter().collect::>(); - - if drop_instance.def.requires_caller_location(fx.tcx) { - // Pass the caller location for `#[track_caller]`. - let caller_location = fx.get_caller_location(source_info); - call_args.extend( - adjust_arg_for_abi(fx, caller_location, &fn_abi.args[1], false).into_iter(), - ); - } - - let func_ref = fx.get_function_ref(drop_instance); - fx.bcx.ins().call(func_ref, &call_args); - } - } - } -} +)),Err(err)=>(Err::<_,_>(err) .unwrap()),}}impl<'tcx>FunctionCx<'_,'_,'tcx>{pub( +crate)fn get_function_ref(&mut self,inst:Instance<'tcx>)->FuncRef{3;let func_id= +import_function(self.tcx,self.module,inst);{();};{();};let func_ref=self.module. +declare_func_in_func(func_id,&mut self.bcx.func);;if self.clif_comments.enabled( +){{;};self.add_comment(func_ref,format!("{:?}",inst));{;};}func_ref}pub(crate)fn +lib_call(&mut self,name:&str,params:Vec ,returns:Vec,args:&[ +Value],)->Cow<'_,[Value]>{if self.tcx.sess.target.is_like_windows{*&*&();let(mut +params,mut args):(Vec<_>,Vec<_>)= params.into_iter().zip(args).map(|(param,&arg) +|{if param.value_type==types::I128{;let arg_ptr=self.create_stack_slot(16,16);;; +arg_ptr.store(self,arg,MemFlags::trusted());3;(AbiParam::new(self.pointer_type), +arg_ptr.get_addr(self))}else{(param,arg)}}).unzip();{;};();let indirect_ret_val= +returns.len()==1&&returns[0].value_type==types::I128;;if indirect_ret_val{params +.insert(0,AbiParam::new(self.pointer_type));;let ret_ptr=self.create_stack_slot( +16,16);3;;args.insert(0,ret_ptr.get_addr(self));;;self.lib_call_unadjusted(name, +params,vec![],&args);();();return Cow::Owned(vec![ret_ptr.load(self,types::I128, +MemFlags::trusted())]);{;};}else{();return self.lib_call_unadjusted(name,params, +returns,&args);3;}}self.lib_call_unadjusted(name,params,returns,args)}pub(crate) +fn lib_call_unadjusted(&mut self,name:&str,params:Vec,returns:Vec,args:&[Value],)->Cow<'_,[Value]>{{;};let sig=Signature{params,returns, +call_conv:self.target_config.default_call_conv};{;};{;};let func_id=self.module. +declare_function(name,Linkage::Import,&sig).unwrap();;;let func_ref=self.module. +declare_func_in_func(func_id,&mut self.bcx.func);;if self.clif_comments.enabled( +){;self.add_comment(func_ref,format!("{:?}",name));}let call_inst=self.bcx.ins() +.call(func_ref,args);;if self.clif_comments.enabled(){self.add_comment(call_inst +,format!("lib_call {}",name));;};let results=self.bcx.inst_results(call_inst);;; +assert!(results.len()<=2,"{}",results.len());let _=();Cow::Borrowed(results)}}fn +make_local_place<'tcx>(fx:&mut FunctionCx<'_,'_,'tcx>,local:Local,layout://({}); +TyAndLayout<'tcx>,is_ssa:bool,)->CPlace<'tcx>{if layout.is_unsized(){;fx.tcx.dcx +().span_fatal((((((((((((fx.mir. local_decls[local]))))))))))).source_info.span, +"unsized locals are not yet supported",);{();};}{();};let place=if is_ssa{if let +rustc_target::abi::Abi::ScalarPair(_,_)=layout.abi{CPlace::new_var_pair(fx,//(); +local,layout)}else{(((((((CPlace::new_var(fx,local,layout))))))))}}else{CPlace:: +new_stack_slot(fx,layout)};3;;self::comments::add_local_place_comments(fx,place, +local);{;};place}pub(crate)fn codegen_fn_prelude<'tcx>(fx:&mut FunctionCx<'_,'_, +'tcx>,start_block:Block){((),());fx.bcx.append_block_params_for_function_params( +start_block);3;3;fx.bcx.switch_to_block(start_block);3;;fx.bcx.ins().nop();;;let +ssa_analyzed=crate::analyze::analyze(fx);loop{break};let _=||();self::comments:: +add_args_header_comment(fx);({});({});let mut block_params_iter=fx.bcx.func.dfg. +block_params(start_block).to_vec().into_iter();;;let ret_place=self::returning:: +codegen_return_param(fx,&ssa_analyzed,&mut block_params_iter);3;3;assert_eq!(fx. +local_map.push(ret_place),RETURN_PLACE);;enum ArgKind<'tcx>{Normal(Option>),Spread(Vec>>),};if fx.fn_abi.c_variadic{fx.tcx.dcx( +).span_fatal(fx.mir.span,//loop{break;};loop{break;};loop{break;};if let _=(){}; +"Defining variadic functions is not yet supported by Cranelift",);();}();let mut +arg_abis_iter=fx.fn_abi.args.iter();3;3;let func_params=fx.mir.args_iter().map(| +local|{;let arg_ty=fx.monomorphize(fx.mir.local_decls[local].ty);;if Some(local) +==fx.mir.spread_arg{;let tupled_arg_tys=match arg_ty.kind(){ty::Tuple(ref tys)=> +tys,_=>bug!("spread argument isn't a tuple?! but {:?}",arg_ty),};;let mut params +=Vec::new();();for(i,_arg_ty)in tupled_arg_tys.iter().enumerate(){3;let arg_abi= +arg_abis_iter.next().unwrap();;let param=cvalue_for_param(fx,Some(local),Some(i) +,arg_abi,&mut block_params_iter);3;;params.push(param);;}(local,ArgKind::Spread( +params),arg_ty)}else{();let arg_abi=arg_abis_iter.next().unwrap();3;3;let param= +cvalue_for_param(fx,Some(local),None,arg_abi,&mut block_params_iter);{;};(local, +ArgKind::Normal(param),arg_ty)}}).collect::,Ty<'tcx>)// +>>();{();};{();};assert!(fx.caller_location.is_none());{();};if fx.instance.def. +requires_caller_location(fx.tcx){;let arg_abi=arg_abis_iter.next().unwrap();;fx. +caller_location=Some(cvalue_for_param(fx,None,None,arg_abi,&mut//*&*&();((),()); +block_params_iter).unwrap());{();};}({});assert!(arg_abis_iter.next().is_none(), +"ArgAbi left behind");((),());*&*&();assert!(block_params_iter.next().is_none(), +"arg_value left behind");3;3;self::comments::add_locals_header_comment(fx);;for( +local,arg_kind,ty)in func_params{if let ArgKind::Normal(Some(val))=arg_kind{if// +let Some((addr,meta))=val.try_to_ptr(){3;let place=if let Some(meta)=meta{CPlace +::for_ptr_with_extra(addr,meta,((val.layout())) )}else{CPlace::for_ptr(addr,val. +layout())};;self::comments::add_local_place_comments(fx,place,local);assert_eq!( +fx.local_map.push(place),local);;;continue;;}};let layout=fx.layout_of(ty);;;let +is_ssa=ssa_analyzed[local].is_ssa(fx,ty);3;;let place=make_local_place(fx,local, +layout,is_ssa);();3;assert_eq!(fx.local_map.push(place),local);3;match arg_kind{ +ArgKind::Normal(param)=>{if let Some(param)=param{;place.write_cvalue(fx,param); +}}ArgKind::Spread(params)=>{for(i,param)in ((params.into_iter()).enumerate()){if +let Some(param)=param{();place.place_field(fx,FieldIdx::new(i)).write_cvalue(fx, +param);;}}}}}for local in fx.mir.vars_and_temps_iter(){let ty=fx.monomorphize(fx +.mir.local_decls[local].ty);;let layout=fx.layout_of(ty);let is_ssa=ssa_analyzed +[local].is_ssa(fx,ty);3;3;let place=make_local_place(fx,local,layout,is_ssa);3;; +assert_eq!(fx.local_map.push(place),local);;}fx.bcx.ins().jump(*fx.block_map.get +(START_BLOCK).unwrap(),&[]);{();};}struct CallArgument<'tcx>{value:CValue<'tcx>, +is_owned:bool,}fn codegen_call_argument_operand<'tcx> (fx:&mut FunctionCx<'_,'_, +'tcx>,operand:&Operand<'tcx>,)->CallArgument<'tcx>{CallArgument{value://((),()); +codegen_operand(fx,operand),is_owned:(matches!(operand,Operand::Move(_))),}}pub( +crate)fn codegen_terminator_call<'tcx>(fx:&mut FunctionCx<'_,'_,'tcx>,//((),()); +source_info:mir::SourceInfo,func:&Operand<'tcx> ,args:&[Spanned>], +destination:Place<'tcx>,target:Option,){;let func=codegen_operand(fx +,func);;;let fn_sig=func.layout().ty.fn_sig(fx.tcx);let ret_place=codegen_place( +fx,destination);;let instance=if let ty::FnDef(def_id,fn_args)=*func.layout().ty +.kind(){let _=();let instance=ty::Instance::expect_resolve(fx.tcx,ty::ParamEnv:: +reveal_all(),def_id,fn_args).polymorphize(fx.tcx);loop{break;};if let _=(){};if +is_call_from_compiler_builtins_to_upstream_monomorphization(fx.tcx ,instance){if +target.is_some(){{();};let caller=with_no_trimmed_paths!(fx.tcx.def_path_str(fx. +instance.def_id()));();();let callee=with_no_trimmed_paths!(fx.tcx.def_path_str( +def_id));;fx.tcx.dcx().emit_err(CompilerBuiltinsCannotCall{caller,callee});}else +{;fx.bcx.ins().trap(TrapCode::User(0));return;}}if fx.tcx.symbol_name(instance). +name.starts_with("llvm."){;crate::intrinsics::codegen_llvm_intrinsic_call(fx,&fx +.tcx.symbol_name(instance).name, fn_args,args,ret_place,target,source_info.span, +);{;};();return;();}match instance.def{InstanceDef::Intrinsic(_)=>{match crate:: +intrinsics::codegen_intrinsic_call(fx,instance,args,ret_place,target,//let _=(); +source_info,){Ok(())=>((return)),Err(instance)=>(Some(instance)),}}InstanceDef:: +DropGlue(_,None)=>{let _=();if true{};let _=();if true{};let dest=target.expect( +"Non terminating drop_in_place_real???");;;let ret_block=fx.get_block(dest);;fx. +bcx.ins().jump(ret_block,&[]);3;3;return;3;}_=>Some(instance),}}else{None};;;let +extra_args=&args[fn_sig.inputs().skip_binder().len()..];;;let extra_args=fx.tcx. +mk_type_list_from_iter(((extra_args.iter())).map(|op_arg|fx.monomorphize(op_arg. +node.ty(fx.mir,fx.tcx))),);{();};({});let fn_abi=if let Some(instance)=instance{ +RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(instance,extra_args)}else{//*&*&(); +RevealAllLayoutCx(fx.tcx).fn_abi_of_fn_ptr(fn_sig,extra_args)};;;let is_cold=if +fn_sig.abi()==Abi::RustCold{(((true)))}else {instance.is_some_and(|inst|{fx.tcx. +codegen_fn_attrs(inst.def_id()).flags.contains(CodegenFnAttrFlags::COLD)})};3;if +is_cold{();fx.bcx.set_cold_block(fx.bcx.current_block().unwrap());3;if let Some( +destination_block)=target{;fx.bcx.set_cold_block(fx.get_block(destination_block) +);3;}};let mut args=if fn_sig.abi()==Abi::RustCall{;let(self_arg,pack_arg)=match +args{[pack_arg]=>((None,(codegen_call_argument_operand(fx,(&pack_arg.node))))),[ +self_arg,pack_arg]=>((Some((codegen_call_argument_operand(fx,&self_arg.node)))), +codegen_call_argument_operand(fx,(((((((((&pack_arg.node)))))))))) ,),_=>panic!( +"rust-call abi requires one or two arguments"),};3;3;let tupled_arguments=match +pack_arg.value.layout().ty.kind(){ty::Tuple(ref tupled_arguments)=>//let _=||(); +tupled_arguments,_=>bug!(//loop{break;};loop{break;};loop{break;};if let _=(){}; +"argument to function with \"rust-call\" ABI is not a tuple"),};3;;let mut args= +Vec::with_capacity(1+tupled_arguments.len());;args.extend(self_arg);for i in 0.. +tupled_arguments.len(){;args.push(CallArgument{value:pack_arg.value.value_field( +fx,FieldIdx::new(i)),is_owned:pack_arg.is_owned,});;}args}else{args.iter().map(| +arg|codegen_call_argument_operand(fx,&arg.node)).collect::>()};*&*&();if +instance.is_some_and(|inst|inst.def.requires_caller_location(fx.tcx)){*&*&();let +caller_location=fx.get_caller_location(source_info);();3;args.push(CallArgument{ +value:caller_location,is_owned:false});;};let args=args;;assert_eq!(fn_abi.args. +len(),args.len());;;enum CallTarget{Direct(FuncRef),Indirect(SigRef,Value),}let( +func_ref,first_arg_override)=match instance{Some(Instance{def:InstanceDef:://(); +Virtual(_,idx),..})=>{if fx.clif_comments.enabled(){3;let nop_inst=fx.bcx.ins(). +nop();;fx.add_comment(nop_inst,format!("virtual call; self arg pass mode: {:?}", +&fn_abi.args[0]),);3;};let(ptr,method)=crate::vtable::get_ptr_and_method_ref(fx, +args[0].value,idx);{;};{;};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.get_addr(fx)))}Some(instance)=>{3;let func_ref=fx. +get_function_ref(instance);{;};(CallTarget::Direct(func_ref),None)}None=>{if fx. +clif_comments.enabled(){;let nop_inst=fx.bcx.ins().nop();fx.add_comment(nop_inst +,"indirect call");;};let func=func.load_scalar(fx);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,func),None)}};self::returning:: +codegen_with_call_return_arg(fx,&fn_abi.ret,ret_place,|fx,return_ptr|{*&*&();let +call_args=(return_ptr.into_iter().chain( first_arg_override.into_iter())).chain( +args.into_iter().enumerate().skip(if (first_arg_override .is_some()){1}else{0}). +flat_map(|(i,arg)|{adjust_arg_for_abi(fx,arg .value,&fn_abi.args[i],arg.is_owned +).into_iter()}),).collect::>();({});{;};let call_inst=match func_ref{ +CallTarget::Direct(func_ref)=>fx.bcx.ins( ).call(func_ref,&call_args),CallTarget +::Indirect(sig,func_ptr)=>{fx.bcx.ins ().call_indirect(sig,func_ptr,&call_args)} +};();if fn_sig.c_variadic(){if!matches!(fn_sig.abi(),Abi::C{..}){3;fx.tcx.dcx(). +span_fatal(source_info.span,format!("Variadic call for non-C abi {:?}",fn_sig.// +abi()),);;};let sig_ref=fx.bcx.func.dfg.call_signature(call_inst).unwrap();;;let +abi_params=call_args.into_iter().map(|arg|{();let ty=fx.bcx.func.dfg.value_type( +arg);{();};if!ty.is_int(){({});fx.tcx.dcx().span_fatal(source_info.span,format!( +"Non int ty {:?} for variadic call",ty),);();}AbiParam::new(ty)}).collect::>();;fx.bcx.func.dfg.signatures[sig_ref].params=abi_params;}call_inst}) +;;if let Some(dest)=target{;let ret_block=fx.get_block(dest);;fx.bcx.ins().jump( +ret_block,&[]);;}else{fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);}}pub( +crate)fn codegen_drop<'tcx>(fx:&mut FunctionCx<'_,'_,'tcx>,source_info:mir:://3; +SourceInfo,drop_place:CPlace<'tcx>,){{;};let ty=drop_place.layout().ty;();();let +drop_instance=Instance::resolve_drop_in_place(fx.tcx,ty).polymorphize(fx.tcx);3; +if let ty::InstanceDef::DropGlue(_,None) =drop_instance.def{}else{match ty.kind( +){ty::Dynamic(_,_,ty::Dyn)=>{3;let(ptr,vtable)=drop_place.to_ptr_unsized();;;let +ptr=ptr.get_addr(fx);;;let drop_fn=crate::vtable::drop_fn_of_obj(fx,vtable);;let +virtual_drop=Instance{def:(ty::InstanceDef::Virtual( drop_instance.def_id(),0)), +args:drop_instance.args,};let _=();((),());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);3;3;fx.bcx.ins().call_indirect(sig,drop_fn,&[ptr]);3;}ty:: +Dynamic(_,_,ty::DynStar)=>{let _=||();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);3;;let virtual_drop=Instance{def:ty::InstanceDef::Virtual(drop_instance. +def_id(),0),args:drop_instance.args,};();3;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);3;;fx.bcx.ins().call_indirect(sig,drop_fn,&[data]);;}_=>{; +assert!(!matches!(drop_instance.def,InstanceDef::Virtual(_,_)));();3;let fn_abi= +RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(drop_instance,ty::List::empty());;; +let arg_value=drop_place.place_ref(fx,fx.layout_of(Ty::new_mut_ref(fx.tcx,fx.//; +tcx.lifetimes.re_erased,ty)),);;;let arg_value=adjust_arg_for_abi(fx,arg_value,& +fn_abi.args[0],true);;let mut call_args:Vec=arg_value.into_iter().collect +::>();({});if drop_instance.def.requires_caller_location(fx.tcx){({});let +caller_location=fx.get_caller_location(source_info);{();};({});call_args.extend( +adjust_arg_for_abi(fx,caller_location,&fn_abi.args[1],false).into_iter(),);;}let +func_ref=fx.get_function_ref(drop_instance);{;};{;};fx.bcx.ins().call(func_ref,& +call_args);((),());((),());((),());((),());((),());((),());((),());let _=();}}}} diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs index 0652267002910..5b5831326b604 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs @@ -1,303 +1,100 @@ -//! Argument passing - -use cranelift_codegen::ir::{ArgumentExtension, ArgumentPurpose}; -use rustc_target::abi::call::{ - ArgAbi, ArgAttributes, ArgExtension as RustcArgExtension, CastTarget, PassMode, Reg, RegKind, -}; -use smallvec::{smallvec, SmallVec}; - -use crate::prelude::*; -use crate::value_and_place::assert_assignable; - -pub(super) trait ArgAbiExt<'tcx> { - fn get_abi_param(&self, tcx: TyCtxt<'tcx>) -> SmallVec<[AbiParam; 2]>; - fn get_abi_return(&self, tcx: TyCtxt<'tcx>) -> (Option, Vec); -} - -fn reg_to_abi_param(reg: Reg) -> AbiParam { - let clif_ty = match (reg.kind, reg.size.bytes()) { - (RegKind::Integer, 1) => types::I8, - (RegKind::Integer, 2) => types::I16, - (RegKind::Integer, 3..=4) => types::I32, - (RegKind::Integer, 5..=8) => types::I64, - (RegKind::Integer, 9..=16) => types::I128, - (RegKind::Float, 4) => types::F32, - (RegKind::Float, 8) => types::F64, - (RegKind::Vector, size) => types::I8.by(u32::try_from(size).unwrap()).unwrap(), - _ => unreachable!("{:?}", reg), - }; - AbiParam::new(clif_ty) -} - -fn apply_arg_attrs_to_abi_param(mut param: AbiParam, arg_attrs: ArgAttributes) -> AbiParam { - match arg_attrs.arg_ext { - RustcArgExtension::None => {} - RustcArgExtension::Zext => param.extension = ArgumentExtension::Uext, - RustcArgExtension::Sext => param.extension = ArgumentExtension::Sext, - } - param -} - -fn cast_target_to_abi_params(cast: &CastTarget) -> SmallVec<[AbiParam; 2]> { - let (rest_count, rem_bytes) = if cast.rest.unit.size.bytes() == 0 { - (0, 0) - } else { - ( - cast.rest.total.bytes() / cast.rest.unit.size.bytes(), - cast.rest.total.bytes() % cast.rest.unit.size.bytes(), - ) - }; - - // Note: Unlike the LLVM equivalent of this code we don't have separate branches for when there - // is no prefix as a single unit, an array and a heterogeneous struct are not represented using - // different types in Cranelift IR. Instead a single array of primitive types is used. - - // Create list of fields in the main structure - let mut args = cast - .prefix - .iter() - .flatten() - .map(|®| reg_to_abi_param(reg)) - .chain((0..rest_count).map(|_| reg_to_abi_param(cast.rest.unit))) - .collect::>(); - - // Append final integer - if rem_bytes != 0 { - // Only integers can be really split further. - assert_eq!(cast.rest.unit.kind, RegKind::Integer); - args.push(reg_to_abi_param(Reg { - kind: RegKind::Integer, - size: Size::from_bytes(rem_bytes), - })); - } - - args -} - -impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { - fn get_abi_param(&self, tcx: TyCtxt<'tcx>) -> SmallVec<[AbiParam; 2]> { - match self.mode { - PassMode::Ignore => smallvec![], - PassMode::Direct(attrs) => match self.layout.abi { - Abi::Scalar(scalar) => smallvec![apply_arg_attrs_to_abi_param( - AbiParam::new(scalar_to_clif_type(tcx, scalar)), - attrs - )], - Abi::Vector { .. } => { - let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout); - smallvec![AbiParam::new(vector_ty)] - } - _ => unreachable!("{:?}", self.layout.abi), - }, - PassMode::Pair(attrs_a, attrs_b) => match self.layout.abi { - Abi::ScalarPair(a, b) => { - let a = scalar_to_clif_type(tcx, a); - let b = scalar_to_clif_type(tcx, b); - smallvec![ - apply_arg_attrs_to_abi_param(AbiParam::new(a), attrs_a), - apply_arg_attrs_to_abi_param(AbiParam::new(b), attrs_b), - ] - } - _ => unreachable!("{:?}", self.layout.abi), - }, - PassMode::Cast { ref cast, pad_i32 } => { - assert!(!pad_i32, "padding support not yet implemented"); - cast_target_to_abi_params(cast) - } - PassMode::Indirect { attrs, meta_attrs: None, on_stack } => { - if on_stack { - // Abi requires aligning struct size to pointer size - let size = self.layout.size.align_to(tcx.data_layout.pointer_align.abi); - let size = u32::try_from(size.bytes()).unwrap(); - smallvec![apply_arg_attrs_to_abi_param( - AbiParam::special(pointer_ty(tcx), ArgumentPurpose::StructArgument(size),), - attrs - )] - } else { - smallvec![apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs)] - } - } - PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack } => { - assert!(!on_stack); - smallvec![ - apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs), - apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), meta_attrs), - ] - } - } - } - - fn get_abi_return(&self, tcx: TyCtxt<'tcx>) -> (Option, Vec) { - match self.mode { - PassMode::Ignore => (None, vec![]), - PassMode::Direct(_) => match self.layout.abi { - Abi::Scalar(scalar) => { - (None, vec![AbiParam::new(scalar_to_clif_type(tcx, scalar))]) - } - Abi::Vector { .. } => { - let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout); - (None, vec![AbiParam::new(vector_ty)]) - } - _ => unreachable!("{:?}", self.layout.abi), - }, - PassMode::Pair(_, _) => match self.layout.abi { - Abi::ScalarPair(a, b) => { - let a = scalar_to_clif_type(tcx, a); - let b = scalar_to_clif_type(tcx, b); - (None, vec![AbiParam::new(a), AbiParam::new(b)]) - } - _ => unreachable!("{:?}", self.layout.abi), - }, - PassMode::Cast { ref cast, .. } => { - (None, cast_target_to_abi_params(cast).into_iter().collect()) - } - PassMode::Indirect { attrs: _, meta_attrs: None, on_stack } => { - assert!(!on_stack); - (Some(AbiParam::special(pointer_ty(tcx), ArgumentPurpose::StructReturn)), vec![]) - } - PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => { - unreachable!("unsized return value") - } - } - } -} - -pub(super) fn to_casted_value<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - arg: CValue<'tcx>, - cast: &CastTarget, -) -> SmallVec<[Value; 2]> { - let (ptr, meta) = arg.force_stack(fx); - assert!(meta.is_none()); - let mut offset = 0; - cast_target_to_abi_params(cast) - .into_iter() - .map(|param| { - let val = ptr.offset_i64(fx, offset).load(fx, param.value_type, MemFlags::new()); - offset += i64::from(param.value_type.bytes()); - val - }) - .collect() -} - -pub(super) fn from_casted_value<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - block_params: &[Value], - layout: TyAndLayout<'tcx>, - cast: &CastTarget, -) -> CValue<'tcx> { - let abi_params = cast_target_to_abi_params(cast); - let abi_param_size: u32 = abi_params.iter().map(|param| param.value_type.bytes()).sum(); - let layout_size = u32::try_from(layout.size.bytes()).unwrap(); - let ptr = fx.create_stack_slot( - // 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. - std::cmp::max(abi_param_size, layout_size), - u32::try_from(layout.align.pref.bytes()).unwrap(), - ); - let mut offset = 0; - let mut block_params_iter = block_params.iter().copied(); - for param in abi_params { - let val = ptr.offset_i64(fx, offset).store( - fx, - block_params_iter.next().unwrap(), - MemFlags::new(), - ); - offset += i64::from(param.value_type.bytes()); - val - } - assert_eq!(block_params_iter.next(), None, "Leftover block param"); - CValue::by_ref(ptr, layout) -} - -/// Get a set of values to be passed as function arguments. -pub(super) fn adjust_arg_for_abi<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - arg: CValue<'tcx>, - arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, - is_owned: bool, -) -> SmallVec<[Value; 2]> { - assert_assignable(fx, arg.layout().ty, arg_abi.layout.ty, 16); - match arg_abi.mode { - PassMode::Ignore => smallvec![], - PassMode::Direct(_) => smallvec![arg.load_scalar(fx)], - PassMode::Pair(_, _) => { - let (a, b) = arg.load_scalar_pair(fx); - smallvec![a, b] - } - PassMode::Cast { ref cast, .. } => to_casted_value(fx, arg, cast), - PassMode::Indirect { .. } => { - if is_owned { - match arg.force_stack(fx) { - (ptr, None) => smallvec![ptr.get_addr(fx)], - (ptr, Some(meta)) => smallvec![ptr.get_addr(fx), meta], - } - } else { - // Ownership of the value at the backing storage for an argument is passed to the - // callee per the ABI, so we must make a copy of the argument unless the argument - // local is moved. - let place = CPlace::new_stack_slot(fx, arg.layout()); - place.write_cvalue(fx, arg); - smallvec![place.to_ptr().get_addr(fx)] - } - } - } -} - -/// Create a [`CValue`] containing the value of a function parameter adding clif function parameters -/// as necessary. -pub(super) fn cvalue_for_param<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - local: Option, - local_field: Option, - arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, - block_params_iter: &mut impl Iterator, -) -> Option> { - let block_params = arg_abi - .get_abi_param(fx.tcx) - .into_iter() - .map(|abi_param| { - let block_param = block_params_iter.next().unwrap(); - assert_eq!(fx.bcx.func.dfg.value_type(block_param), abi_param.value_type); - block_param - }) - .collect::>(); - - crate::abi::comments::add_arg_comment( - fx, - "arg", - local, - local_field, - &block_params, - &arg_abi.mode, - arg_abi.layout, - ); - - match arg_abi.mode { - PassMode::Ignore => None, - PassMode::Direct(_) => { - assert_eq!(block_params.len(), 1, "{:?}", block_params); - Some(CValue::by_val(block_params[0], arg_abi.layout)) - } - PassMode::Pair(_, _) => { - assert_eq!(block_params.len(), 2, "{:?}", block_params); - Some(CValue::by_val_pair(block_params[0], block_params[1], arg_abi.layout)) - } - PassMode::Cast { ref cast, .. } => { - Some(from_casted_value(fx, &block_params, arg_abi.layout, cast)) - } - PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => { - assert_eq!(block_params.len(), 1, "{:?}", block_params); - Some(CValue::by_ref(Pointer::new(block_params[0]), arg_abi.layout)) - } - PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => { - assert_eq!(block_params.len(), 2, "{:?}", block_params); - Some(CValue::by_ref_unsized( - Pointer::new(block_params[0]), - block_params[1], - arg_abi.layout, - )) - } - } -} +use cranelift_codegen::ir::{ ArgumentExtension,ArgumentPurpose};use rustc_target +::abi::call::{ArgAbi, ArgAttributes,ArgExtension as RustcArgExtension,CastTarget +,PassMode,Reg,RegKind,};use smallvec:: {smallvec,SmallVec};use crate::prelude::* +;use crate::value_and_place::assert_assignable;pub (super)trait ArgAbiExt<'tcx>{ +fn get_abi_param(&self,tcx:TyCtxt<'tcx> )->SmallVec<[AbiParam;((((((2))))))]>;fn +get_abi_return(&self,tcx:TyCtxt<'tcx>)->(Option,Vec);}fn//3; +reg_to_abi_param(reg:Reg)->AbiParam{;let clif_ty=match(reg.kind,reg.size.bytes() +){(RegKind::Integer,1)=>types::I8,(RegKind::Integer,2)=>types::I16,(RegKind:://; +Integer,(3)..=(4))=>types::I32,(RegKind::Integer,(5)..=8)=>types::I64,(RegKind:: +Integer,(9)..=16)=>types::I128,(RegKind::Float,4)=>types::F32,(RegKind::Float,8) +=>types::F64,(RegKind::Vector,size)=>types::I8 .by(u32::try_from(size).unwrap()) +.unwrap(),_=>unreachable!("{:?}",reg),};*&*&();((),());AbiParam::new(clif_ty)}fn +apply_arg_attrs_to_abi_param(mut param:AbiParam,arg_attrs:ArgAttributes)->//{;}; +AbiParam{match arg_attrs.arg_ext{ RustcArgExtension::None=>{}RustcArgExtension:: +Zext=>(param.extension=ArgumentExtension:: Uext),RustcArgExtension::Sext=>param. +extension=ArgumentExtension::Sext,}param}fn cast_target_to_abi_params(cast:&//3; +CastTarget)->SmallVec<[AbiParam;2]>{;let(rest_count,rem_bytes)=if cast.rest.unit +.size.bytes()==0{(0,0)}else {(cast.rest.total.bytes()/cast.rest.unit.size.bytes( +),cast.rest.total.bytes()%cast.rest.unit.size.bytes(),)};();3;let mut args=cast. +prefix.iter().flatten().map(|®|reg_to_abi_param (reg)).chain((0..rest_count). +map(|_|reg_to_abi_param(cast.rest.unit))).collect::>();;if rem_bytes +!=0{;assert_eq!(cast.rest.unit.kind,RegKind::Integer);args.push(reg_to_abi_param +(Reg{kind:RegKind::Integer,size:Size::from_bytes(rem_bytes),}));;}args}impl<'tcx +>ArgAbiExt<'tcx>for ArgAbi<'tcx,Ty<'tcx>>{fn get_abi_param(&self,tcx:TyCtxt)->SmallVec<[AbiParam;(2)]>{match self.mode{PassMode::Ignore=>smallvec![], +PassMode::Direct(attrs)=>match self.layout.abi{Abi::Scalar(scalar)=>smallvec![// +apply_arg_attrs_to_abi_param(AbiParam::new(scalar_to_clif_type(tcx,scalar)),//3; +attrs)],Abi::Vector{..}=>{;let vector_ty=crate::intrinsics::clif_vector_type(tcx +,self.layout);3;smallvec![AbiParam::new(vector_ty)]}_=>unreachable!("{:?}",self. +layout.abi),},PassMode::Pair(attrs_a,attrs_b)=>match self.layout.abi{Abi:://{;}; +ScalarPair(a,b)=>{;let a=scalar_to_clif_type(tcx,a);;;let b=scalar_to_clif_type( +tcx,b);((),());smallvec![apply_arg_attrs_to_abi_param(AbiParam::new(a),attrs_a), +apply_arg_attrs_to_abi_param(AbiParam::new(b),attrs_b) ,]}_=>unreachable!("{:?}" +,self.layout.abi),},PassMode::Cast{ref cast,pad_i32}=>{((),());assert!(!pad_i32, +"padding support not yet implemented");;cast_target_to_abi_params(cast)}PassMode +::Indirect{attrs,meta_attrs:None,on_stack}=>{if on_stack{3;let size=self.layout. +size.align_to(tcx.data_layout.pointer_align.abi);3;;let size=u32::try_from(size. +bytes()).unwrap();({});smallvec![apply_arg_attrs_to_abi_param(AbiParam::special( +pointer_ty(tcx),ArgumentPurpose::StructArgument(size), ),attrs)]}else{smallvec![ +apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx) ),attrs)]}}PassMode:: +Indirect{attrs,meta_attrs:Some(meta_attrs),on_stack}=>{();assert!(!on_stack);(); +smallvec![apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)),attrs),//; +apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)),meta_attrs),]}}}fn// +get_abi_return(&self,tcx:TyCtxt<'tcx>)->(Option,Vec){match// +self.mode{PassMode::Ignore=>(((None,(vec![])))),PassMode::Direct(_)=>match self. +layout.abi{Abi::Scalar(scalar)=>{(None,vec![AbiParam::new(scalar_to_clif_type(// +tcx,scalar))])}Abi::Vector{..}=>{if let _=(){};let vector_ty=crate::intrinsics:: +clif_vector_type(tcx,self.layout);({});(None,vec![AbiParam::new(vector_ty)])}_=> +unreachable!("{:?}",self.layout.abi),},PassMode::Pair(_,_)=>match self.layout.// +abi{Abi::ScalarPair(a,b)=>{({});let a=scalar_to_clif_type(tcx,a);({});{;};let b= +scalar_to_clif_type(tcx,b);();(None,vec![AbiParam::new(a),AbiParam::new(b)])}_=> +unreachable!("{:?}",self.layout.abi),},PassMode::Cast{ref cast,..}=>{(None,//(); +cast_target_to_abi_params(cast).into_iter(). collect())}PassMode::Indirect{attrs +:_,meta_attrs:None,on_stack}=>{();assert!(!on_stack);();(Some(AbiParam::special( +pointer_ty(tcx),ArgumentPurpose::StructReturn)) ,((vec![])))}PassMode::Indirect{ +attrs:_,meta_attrs:Some(_),on_stack: _}=>{unreachable!("unsized return value")}} +}}pub(super)fn to_casted_value<'tcx>(fx: &mut FunctionCx<'_,'_,'tcx>,arg:CValue< +'tcx>,cast:&CastTarget,)->SmallVec<[Value;2]>{;let(ptr,meta)=arg.force_stack(fx) +;3;;assert!(meta.is_none());;;let mut offset=0;;cast_target_to_abi_params(cast). +into_iter().map(|param|{((),());let val=ptr.offset_i64(fx,offset).load(fx,param. +value_type,MemFlags::new());;;offset+=i64::from(param.value_type.bytes());val}). +collect()}pub(super)fn from_casted_value<'tcx>(fx:&mut FunctionCx<'_,'_,'tcx>,// +block_params:&[Value],layout:TyAndLayout<'tcx >,cast:&CastTarget,)->CValue<'tcx> +{();let abi_params=cast_target_to_abi_params(cast);();();let abi_param_size:u32= +abi_params.iter().map(|param|param.value_type.bytes()).sum();3;;let layout_size= +u32::try_from(layout.size.bytes()).unwrap();;;let ptr=fx.create_stack_slot(std:: +cmp::max(abi_param_size,layout_size),(u32::try_from(layout.align.pref.bytes())). +unwrap(),);3;3;let mut offset=0;;;let mut block_params_iter=block_params.iter(). +copied();3;for param in abi_params{3;let val=ptr.offset_i64(fx,offset).store(fx, +block_params_iter.next().unwrap(),MemFlags::new(),);3;3;offset+=i64::from(param. +value_type.bytes());((),());val}*&*&();assert_eq!(block_params_iter.next(),None, +"Leftover block param");((),());let _=();CValue::by_ref(ptr,layout)}pub(super)fn +adjust_arg_for_abi<'tcx>(fx:&mut FunctionCx<'_,'_,'tcx>,arg:CValue<'tcx>,//({}); +arg_abi:&ArgAbi<'tcx,Ty<'tcx>>,is_owned:bool,)->SmallVec<[Value;2]>{loop{break}; +assert_assignable(fx,arg.layout().ty,arg_abi.layout.ty,16);3;match arg_abi.mode{ +PassMode::Ignore=>smallvec![],PassMode:: Direct(_)=>smallvec![arg.load_scalar(fx +)],PassMode::Pair(_,_)=>{();let(a,b)=arg.load_scalar_pair(fx);();smallvec![a,b]} +PassMode::Cast{ref cast,..}=>to_casted_value (fx,arg,cast),PassMode::Indirect{.. +}=>{if is_owned{match arg.force_stack(fx) {(ptr,None)=>smallvec![ptr.get_addr(fx +)],(ptr,Some(meta))=>smallvec![ptr.get_addr(fx),meta],}}else{;let place=CPlace:: +new_stack_slot(fx,arg.layout());3;3;place.write_cvalue(fx,arg);;smallvec![place. +to_ptr().get_addr(fx)]}}}}pub(super)fn cvalue_for_param<'tcx>(fx:&mut//let _=(); +FunctionCx<'_,'_,'tcx>,local:Option,local_field:Option,//{;}; +arg_abi:&ArgAbi<'tcx,Ty<'tcx>>, block_params_iter:&mut impl Iterator +,)->Option>{((),());let block_params=arg_abi.get_abi_param(fx.tcx). +into_iter().map(|abi_param|{;let block_param=block_params_iter.next().unwrap();; +assert_eq!(fx.bcx.func.dfg.value_type(block_param),abi_param.value_type);*&*&(); +block_param}).collect::>();((),());*&*&();crate::abi::comments:: +add_arg_comment(fx,"arg",local,local_field, &block_params,&arg_abi.mode,arg_abi. +layout,);{;};match arg_abi.mode{PassMode::Ignore=>None,PassMode::Direct(_)=>{(); +assert_eq!(block_params.len(),1,"{:?}",block_params);*&*&();Some(CValue::by_val( +block_params[0],arg_abi.layout))}PassMode::Pair(_,_)=>{;assert_eq!(block_params. +len(),2,"{:?}",block_params);if true{};Some(CValue::by_val_pair(block_params[0], +block_params[((((((1))))))],arg_abi.layout))}PassMode::Cast{ref cast,..}=>{Some( +from_casted_value(fx,((&block_params)),arg_abi.layout,cast))}PassMode::Indirect{ +attrs:_,meta_attrs:None,on_stack:_}=>{();assert_eq!(block_params.len(),1,"{:?}", +block_params);;Some(CValue::by_ref(Pointer::new(block_params[0]),arg_abi.layout) +)}PassMode::Indirect{attrs:_,meta_attrs:Some(_),on_stack:_}=>{*&*&();assert_eq!( +block_params.len(),2,"{:?}",block_params);;Some(CValue::by_ref_unsized(Pointer:: +new((((block_params[(((0)))])))),(((block_params[ ((1))]))),arg_abi.layout,))}}} diff --git a/compiler/rustc_codegen_cranelift/src/abi/returning.rs b/compiler/rustc_codegen_cranelift/src/abi/returning.rs index e0f399e616e5d..5f423731fdced 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/returning.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/returning.rs @@ -1,130 +1,47 @@ -//! Return value handling - -use rustc_target::abi::call::{ArgAbi, PassMode}; -use smallvec::{smallvec, SmallVec}; - -use crate::prelude::*; - -/// Return a place where the return value of the current function can be written to. If necessary -/// this adds an extra parameter pointing to where the return value needs to be stored. -pub(super) fn codegen_return_param<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - ssa_analyzed: &rustc_index::IndexSlice, - block_params_iter: &mut impl Iterator, -) -> CPlace<'tcx> { - let (ret_place, ret_param): (_, SmallVec<[_; 2]>) = match fx.fn_abi.ret.mode { - PassMode::Ignore | PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast { .. } => { - let is_ssa = ssa_analyzed[RETURN_PLACE].is_ssa(fx, fx.fn_abi.ret.layout.ty); - (super::make_local_place(fx, RETURN_PLACE, fx.fn_abi.ret.layout, is_ssa), smallvec![]) - } - PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => { - let ret_param = block_params_iter.next().unwrap(); - assert_eq!(fx.bcx.func.dfg.value_type(ret_param), fx.pointer_type); - (CPlace::for_ptr(Pointer::new(ret_param), fx.fn_abi.ret.layout), smallvec![ret_param]) - } - PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => { - unreachable!("unsized return value") - } - }; - - crate::abi::comments::add_arg_comment( - fx, - "ret", - Some(RETURN_PLACE), - None, - &ret_param, - &fx.fn_abi.ret.mode, - fx.fn_abi.ret.layout, - ); - - ret_place -} - -/// Invokes the closure with if necessary a value representing the return pointer. When the closure -/// returns the call return value(s) if any are written to the correct place. -pub(super) fn codegen_with_call_return_arg<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - ret_arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, - ret_place: CPlace<'tcx>, - f: impl FnOnce(&mut FunctionCx<'_, '_, 'tcx>, Option) -> Inst, -) { - let (ret_temp_place, return_ptr) = match ret_arg_abi.mode { - PassMode::Ignore => (None, None), - PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => { - if let Some(ret_ptr) = ret_place.try_to_ptr() { - // This is an optimization to prevent unnecessary copies of the return value when - // the return place is already a memory place as opposed to a register. - // This match arm can be safely removed. - (None, Some(ret_ptr.get_addr(fx))) - } else { - let place = CPlace::new_stack_slot(fx, ret_arg_abi.layout); - (Some(place), Some(place.to_ptr().get_addr(fx))) - } - } - PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => { - unreachable!("unsized return value") - } - PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast { .. } => (None, None), - }; - - let call_inst = f(fx, return_ptr); - - match ret_arg_abi.mode { - PassMode::Ignore => {} - PassMode::Direct(_) => { - let ret_val = fx.bcx.inst_results(call_inst)[0]; - ret_place.write_cvalue(fx, CValue::by_val(ret_val, ret_arg_abi.layout)); - } - PassMode::Pair(_, _) => { - let ret_val_a = fx.bcx.inst_results(call_inst)[0]; - let ret_val_b = fx.bcx.inst_results(call_inst)[1]; - ret_place - .write_cvalue(fx, CValue::by_val_pair(ret_val_a, ret_val_b, ret_arg_abi.layout)); - } - PassMode::Cast { ref cast, .. } => { - let results = - fx.bcx.inst_results(call_inst).iter().copied().collect::>(); - let result = - super::pass_mode::from_casted_value(fx, &results, ret_place.layout(), cast); - ret_place.write_cvalue(fx, result); - } - PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => { - if let Some(ret_temp_place) = ret_temp_place { - // If ret_temp_place is None, it is not necessary to copy the return value. - let ret_temp_value = ret_temp_place.to_cvalue(fx); - ret_place.write_cvalue(fx, ret_temp_value); - } - } - PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => { - unreachable!("unsized return value") - } - } -} - -/// Codegen a return instruction with the right return value(s) if any. -pub(crate) fn codegen_return(fx: &mut FunctionCx<'_, '_, '_>) { - match fx.fn_abi.ret.mode { - PassMode::Ignore | PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => { - fx.bcx.ins().return_(&[]); - } - PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => { - unreachable!("unsized return value") - } - PassMode::Direct(_) => { - let place = fx.get_local_place(RETURN_PLACE); - let ret_val = place.to_cvalue(fx).load_scalar(fx); - fx.bcx.ins().return_(&[ret_val]); - } - PassMode::Pair(_, _) => { - let place = fx.get_local_place(RETURN_PLACE); - let (ret_val_a, ret_val_b) = place.to_cvalue(fx).load_scalar_pair(fx); - fx.bcx.ins().return_(&[ret_val_a, ret_val_b]); - } - PassMode::Cast { ref cast, .. } => { - let place = fx.get_local_place(RETURN_PLACE); - let ret_val = place.to_cvalue(fx); - let ret_vals = super::pass_mode::to_casted_value(fx, ret_val, cast); - fx.bcx.ins().return_(&ret_vals); - } - } -} +use rustc_target::abi::call::{ArgAbi, PassMode};use smallvec::{smallvec,SmallVec +};use crate::prelude::*;pub(super)fn codegen_return_param<'tcx>(fx:&mut//*&*&(); +FunctionCx<'_,'_,'tcx>,ssa_analyzed:&rustc_index::IndexSlice,block_params_iter:&mut impl Iterator,)->CPlace{{;};let(ret_place,ret_param):(_,SmallVec<[_;2]>)=match fx.fn_abi.ret.mode{ +PassMode::Ignore|PassMode::Direct(_)|PassMode::Pair(_,_)|PassMode::Cast{..}=>{3; +let is_ssa=ssa_analyzed[RETURN_PLACE].is_ssa(fx,fx.fn_abi.ret.layout.ty);;(super +::make_local_place(fx,RETURN_PLACE,fx.fn_abi.ret.layout ,is_ssa),(smallvec![]))} +PassMode::Indirect{attrs:_,meta_attrs:None,on_stack:_}=>{let _=();let ret_param= +block_params_iter.next().unwrap();{;};{;};assert_eq!(fx.bcx.func.dfg.value_type( +ret_param),fx.pointer_type);;(CPlace::for_ptr(Pointer::new(ret_param),fx.fn_abi. +ret.layout),smallvec![ret_param]) }PassMode::Indirect{attrs:_,meta_attrs:Some(_) +,on_stack:_}=>{unreachable!("unsized return value")}};3;3;crate::abi::comments:: +add_arg_comment(fx,"ret",Some(RETURN_PLACE),None ,&ret_param,&fx.fn_abi.ret.mode +,fx.fn_abi.ret.layout,);{;};ret_place}pub(super)fn codegen_with_call_return_arg< +'tcx>(fx:&mut FunctionCx<'_,'_,'tcx>,ret_arg_abi:&ArgAbi<'tcx,Ty<'tcx>>,//{();}; +ret_place:CPlace<'tcx>,f:impl FnOnce(&mut FunctionCx<'_,'_,'tcx>,Option) +->Inst,){;let(ret_temp_place,return_ptr)=match ret_arg_abi.mode{PassMode::Ignore +=>((None,None)),PassMode::Indirect{attrs: _,meta_attrs:None,on_stack:_}=>{if let +Some(ret_ptr)=ret_place.try_to_ptr(){(None,Some(ret_ptr.get_addr(fx)))}else{;let +place=CPlace::new_stack_slot(fx,ret_arg_abi.layout);{;};(Some(place),Some(place. +to_ptr().get_addr(fx)))}} PassMode::Indirect{attrs:_,meta_attrs:Some(_),on_stack +:_}=>{unreachable!("unsized return value") }PassMode::Direct(_)|PassMode::Pair(_ +,_)|PassMode::Cast{..}=>(None,None),};3;3;let call_inst=f(fx,return_ptr);3;match +ret_arg_abi.mode{PassMode::Ignore=>{}PassMode::Direct(_)=>{3;let ret_val=fx.bcx. +inst_results(call_inst)[0];3;3;ret_place.write_cvalue(fx,CValue::by_val(ret_val, +ret_arg_abi.layout));;}PassMode::Pair(_,_)=>{;let ret_val_a=fx.bcx.inst_results( +call_inst)[0];3;3;let ret_val_b=fx.bcx.inst_results(call_inst)[1];3;3;ret_place. +write_cvalue(fx,CValue::by_val_pair(ret_val_a,ret_val_b,ret_arg_abi.layout));3;} +PassMode::Cast{ref cast,..}=>{;let results=fx.bcx.inst_results(call_inst).iter() +.copied().collect::>();{;};{;};let result=super::pass_mode:: +from_casted_value(fx,&results,ret_place.layout(),cast);;;ret_place.write_cvalue( +fx,result);({});}PassMode::Indirect{attrs:_,meta_attrs:None,on_stack:_}=>{if let +Some(ret_temp_place)=ret_temp_place{;let ret_temp_value=ret_temp_place.to_cvalue +(fx);3;;ret_place.write_cvalue(fx,ret_temp_value);;}}PassMode::Indirect{attrs:_, +meta_attrs:Some(_),on_stack:_}=>{((unreachable!("unsized return value")))}}}pub( +crate)fn codegen_return(fx:&mut FunctionCx<'_, '_,'_>){match fx.fn_abi.ret.mode{ +PassMode::Ignore|PassMode::Indirect{attrs:_,meta_attrs:None,on_stack:_}=>{();fx. +bcx.ins().return_(&[]);;}PassMode::Indirect{attrs:_,meta_attrs:Some(_),on_stack: +_}=>{unreachable!("unsized return value")}PassMode::Direct(_)=>{();let place=fx. +get_local_place(RETURN_PLACE);;;let ret_val=place.to_cvalue(fx).load_scalar(fx); +fx.bcx.ins().return_(&[ret_val]);{();};}PassMode::Pair(_,_)=>{({});let place=fx. +get_local_place(RETURN_PLACE);();3;let(ret_val_a,ret_val_b)=place.to_cvalue(fx). +load_scalar_pair(fx);;;fx.bcx.ins().return_(&[ret_val_a,ret_val_b]);;}PassMode:: +Cast{ref cast,..}=>{3;let place=fx.get_local_place(RETURN_PLACE);3;;let ret_val= +place.to_cvalue(fx);;;let ret_vals=super::pass_mode::to_casted_value(fx,ret_val, +cast);loop{break;};loop{break;};fx.bcx.ins().return_(&ret_vals);loop{break;};}}} diff --git a/compiler/rustc_codegen_cranelift/src/allocator.rs b/compiler/rustc_codegen_cranelift/src/allocator.rs index e8af3e8c2555f..9c6e1a8cfbcf2 100644 --- a/compiler/rustc_codegen_cranelift/src/allocator.rs +++ b/compiler/rustc_codegen_cranelift/src/allocator.rs @@ -1,104 +1,34 @@ -//! Allocator shim -// Adapted from rustc - -use rustc_ast::expand::allocator::{ - alloc_error_handler_name, default_fn_name, global_fn_name, AllocatorKind, AllocatorTy, - ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE, -}; -use rustc_codegen_ssa::base::allocator_kind_for_codegen; -use rustc_session::config::OomStrategy; - -use crate::prelude::*; - -/// Returns whether an allocator shim was created -pub(crate) fn codegen( - tcx: TyCtxt<'_>, - module: &mut impl Module, - unwind_context: &mut UnwindContext, -) -> bool { - let Some(kind) = allocator_kind_for_codegen(tcx) else { return false }; - codegen_inner( - module, - unwind_context, - kind, - tcx.alloc_error_handler_kind(()).unwrap(), - tcx.sess.opts.unstable_opts.oom, - ); - true -} - -fn codegen_inner( - module: &mut impl Module, - unwind_context: &mut UnwindContext, - kind: AllocatorKind, - alloc_error_handler_kind: AllocatorKind, - oom_strategy: OomStrategy, -) { - let usize_ty = module.target_config().pointer_type(); - - if kind == AllocatorKind::Default { - for method in ALLOCATOR_METHODS { - let mut arg_tys = Vec::with_capacity(method.inputs.len()); - for input in method.inputs.iter() { - match input.ty { - AllocatorTy::Layout => { - arg_tys.push(usize_ty); // size - arg_tys.push(usize_ty); // align - } - AllocatorTy::Ptr => arg_tys.push(usize_ty), - AllocatorTy::Usize => arg_tys.push(usize_ty), - - AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"), - } - } - let output = match method.output { - AllocatorTy::ResultPtr => Some(usize_ty), - AllocatorTy::Unit => None, - - AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => { - panic!("invalid allocator output") - } - }; - - let sig = Signature { - call_conv: module.target_config().default_call_conv, - params: arg_tys.iter().cloned().map(AbiParam::new).collect(), - returns: output.into_iter().map(AbiParam::new).collect(), - }; - crate::common::create_wrapper_function( - module, - unwind_context, - sig, - &global_fn_name(method.name), - &default_fn_name(method.name), - ); - } - } - - let sig = Signature { - call_conv: module.target_config().default_call_conv, - params: vec![AbiParam::new(usize_ty), AbiParam::new(usize_ty)], - returns: vec![], - }; - crate::common::create_wrapper_function( - module, - unwind_context, - sig, - "__rust_alloc_error_handler", - &alloc_error_handler_name(alloc_error_handler_kind), - ); - - let data_id = module.declare_data(OomStrategy::SYMBOL, Linkage::Export, false, false).unwrap(); - let mut data = DataDescription::new(); - data.set_align(1); - let val = oom_strategy.should_panic(); - data.define(Box::new([val])); - module.define_data(data_id, &data).unwrap(); - - let data_id = - module.declare_data(NO_ALLOC_SHIM_IS_UNSTABLE, Linkage::Export, false, false).unwrap(); - let mut data = DataDescription::new(); - data.set_align(1); - data.define(Box::new([0])); - module.define_data(data_id, &data).unwrap(); -} +use rustc_ast::expand::allocator::{alloc_error_handler_name,default_fn_name,//3; +global_fn_name,AllocatorKind,AllocatorTy,ALLOCATOR_METHODS,//let _=();if true{}; +NO_ALLOC_SHIM_IS_UNSTABLE,};use rustc_codegen_ssa::base:://if true{};let _=||(); +allocator_kind_for_codegen;use rustc_session::config::OomStrategy;use crate:://; +prelude::*;pub(crate)fn codegen(tcx:TyCtxt<'_>,module:&mut impl Module,//*&*&(); +unwind_context:&mut UnwindContext,)->bool{let _=||();loop{break};let Some(kind)= +allocator_kind_for_codegen(tcx)else{return false};({});{;};codegen_inner(module, +unwind_context,kind,((tcx.alloc_error_handler_kind(())).unwrap()),tcx.sess.opts. +unstable_opts.oom,);if let _=(){};true}fn codegen_inner(module:&mut impl Module, +unwind_context:&mut UnwindContext,kind:AllocatorKind,alloc_error_handler_kind:// +AllocatorKind,oom_strategy:OomStrategy,){();let usize_ty=module.target_config(). +pointer_type();;if kind==AllocatorKind::Default{for method in ALLOCATOR_METHODS{ +let mut arg_tys=Vec::with_capacity(method.inputs.len());{;};for input in method. +inputs.iter(){match input.ty{AllocatorTy::Layout=>{3;arg_tys.push(usize_ty);3;3; +arg_tys.push(usize_ty);3;}AllocatorTy::Ptr=>arg_tys.push(usize_ty),AllocatorTy:: +Usize=>arg_tys.push(usize_ty), AllocatorTy::ResultPtr|AllocatorTy::Unit=>panic!( +"invalid allocator arg"),}}let _=();let output=match method.output{AllocatorTy:: +ResultPtr=>(((((Some(usize_ty)))))),AllocatorTy::Unit=>None,AllocatorTy::Layout| +AllocatorTy::Usize|AllocatorTy::Ptr=>{panic!("invalid allocator output")}};;;let +sig=Signature{call_conv:module.target_config( ).default_call_conv,params:arg_tys +.iter().cloned().map(AbiParam::new). collect(),returns:(output.into_iter()).map( +AbiParam::new).collect(),};{;};();crate::common::create_wrapper_function(module, +unwind_context,sig,&global_fn_name(method.name) ,&default_fn_name(method.name),) +;;}}let sig=Signature{call_conv:module.target_config().default_call_conv,params: +vec![AbiParam::new(usize_ty),AbiParam::new(usize_ty)],returns:vec![],};;;crate:: +common::create_wrapper_function(module,unwind_context,sig,//if true{};if true{}; +"__rust_alloc_error_handler", &alloc_error_handler_name(alloc_error_handler_kind +),);;;let data_id=module.declare_data(OomStrategy::SYMBOL,Linkage::Export,false, +false).unwrap();;;let mut data=DataDescription::new();data.set_align(1);let val= +oom_strategy.should_panic();;;data.define(Box::new([val]));;;module.define_data( +data_id,&data).unwrap();loop{break};loop{break};let data_id=module.declare_data( +NO_ALLOC_SHIM_IS_UNSTABLE,Linkage::Export,false,false).unwrap();3;;let mut data= +DataDescription::new();;;data.set_align(1);;;data.define(Box::new([0]));;module. +define_data(data_id,&data).unwrap();if true{};let _=||();let _=||();let _=||();} diff --git a/compiler/rustc_codegen_cranelift/src/analyze.rs b/compiler/rustc_codegen_cranelift/src/analyze.rs index c5762638a6b13..5cda1a5e270a5 100644 --- a/compiler/rustc_codegen_cranelift/src/analyze.rs +++ b/compiler/rustc_codegen_cranelift/src/analyze.rs @@ -1,39 +1,11 @@ -//! SSA analysis - -use rustc_index::IndexVec; -use rustc_middle::mir::StatementKind::*; - -use crate::prelude::*; - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub(crate) enum SsaKind { - NotSsa, - MaybeSsa, -} - -impl SsaKind { - pub(crate) fn is_ssa<'tcx>(self, fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool { - self == SsaKind::MaybeSsa && (fx.clif_type(ty).is_some() || fx.clif_pair_type(ty).is_some()) - } -} - -pub(crate) fn analyze(fx: &FunctionCx<'_, '_, '_>) -> IndexVec { - let mut flag_map = - fx.mir.local_decls.iter().map(|_| SsaKind::MaybeSsa).collect::>(); - - for bb in fx.mir.basic_blocks.iter() { - for stmt in bb.statements.iter() { - match &stmt.kind { - Assign(place_and_rval) => match &place_and_rval.1 { - Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => { - flag_map[place.local] = SsaKind::NotSsa; - } - _ => {} - }, - _ => {} - } - } - } - - flag_map -} +use rustc_index::IndexVec;use rustc_middle::mir::StatementKind::*;use crate:://; +prelude::*;#[derive(Copy,Clone,Debug, PartialEq,Eq,Hash)]pub(crate)enum SsaKind{ +NotSsa,MaybeSsa,}impl SsaKind{pub(crate)fn is_ssa<'tcx>(self,fx:&FunctionCx<'_, +'_,'tcx>,ty:Ty<'tcx>)->bool{self== SsaKind::MaybeSsa&&(fx.clif_type(ty).is_some( +)||fx.clif_pair_type(ty).is_some()) }}pub(crate)fn analyze(fx:&FunctionCx<'_,'_, +'_>)->IndexVec{;let mut flag_map=fx.mir.local_decls.iter().map(|_ +|SsaKind::MaybeSsa).collect::>();{();};for bb in fx.mir. +basic_blocks.iter(){for stmt in (bb.statements.iter()){match(&stmt.kind){Assign( +place_and_rval)=>match((((&place_and_rval.1)))){Rvalue ::Ref(_,_,place)|Rvalue:: +AddressOf(_,place)=>{();flag_map[place.local]=SsaKind::NotSsa;3;}_=>{}},_=>{}}}} +flag_map}//((),());let _=();((),());let _=();((),());let _=();let _=();let _=(); diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs index 414d3db1c51a1..7078bbf6cd0ea 100644 --- a/compiler/rustc_codegen_cranelift/src/archive.rs +++ b/compiler/rustc_codegen_cranelift/src/archive.rs @@ -1,25 +1,9 @@ -use std::path::{Path, PathBuf}; - -use rustc_codegen_ssa::back::archive::{ - get_native_object_symbols, ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, -}; -use rustc_session::Session; - -pub(crate) struct ArArchiveBuilderBuilder; - -impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { - fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box { - Box::new(ArArchiveBuilder::new(sess, get_native_object_symbols)) - } - - fn create_dll_import_lib( - &self, - _sess: &Session, - _lib_name: &str, - _dll_imports: &[rustc_session::cstore::DllImport], - _tmpdir: &Path, - _is_direct_dependency: bool, - ) -> PathBuf { - unimplemented!("creating dll imports is not yet supported"); - } -} +use std::path::{Path,PathBuf};use rustc_codegen_ssa::back::archive::{//let _=(); +get_native_object_symbols,ArArchiveBuilder ,ArchiveBuilder,ArchiveBuilderBuilder +,};use rustc_session::Session;pub(crate)struct ArArchiveBuilderBuilder;impl//(); +ArchiveBuilderBuilder for ArArchiveBuilderBuilder{fn new_archive_builder<'a>(&// +self,sess:&'a Session)->Box{Box::new(ArArchiveBuilder::// +new(sess,get_native_object_symbols))}fn create_dll_import_lib(&self,_sess:&//(); +Session,_lib_name:&str,_dll_imports: &[rustc_session::cstore::DllImport],_tmpdir +:&Path,_is_direct_dependency:bool,)->PathBuf{if true{};if true{};unimplemented!( +"creating dll imports is not yet supported");((),());((),());((),());let _=();}} diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 8d0b84f62dc76..1cd8333561b27 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -1,1013 +1,331 @@ -//! Codegen of a single function - -use cranelift_codegen::ir::UserFuncName; -use cranelift_codegen::CodegenError; -use cranelift_module::ModuleError; -use rustc_ast::InlineAsmOptions; -use rustc_index::IndexVec; -use rustc_middle::ty::adjustment::PointerCoercion; -use rustc_middle::ty::layout::FnAbiOf; -use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization; - -use crate::constant::ConstantCx; -use crate::debuginfo::{FunctionDebugContext, TypeDebugContext}; -use crate::prelude::*; -use crate::pretty_clif::CommentWriter; - -pub(crate) struct CodegenedFunction { - symbol_name: String, - func_id: FuncId, - func: Function, - clif_comments: CommentWriter, - func_debug_cx: Option, -} - -pub(crate) fn codegen_fn<'tcx>( - tcx: TyCtxt<'tcx>, - cx: &mut crate::CodegenCx, - type_dbg: &mut TypeDebugContext<'tcx>, - cached_func: Function, - module: &mut dyn Module, - instance: Instance<'tcx>, -) -> CodegenedFunction { - debug_assert!(!instance.args.has_infer()); - - let symbol_name = tcx.symbol_name(instance).name.to_string(); - let _timer = tcx.prof.generic_activity_with_arg("codegen fn", &*symbol_name); - - let mir = tcx.instance_mir(instance.def); - let _mir_guard = crate::PrintOnPanic(|| { - let mut buf = Vec::new(); - with_no_trimmed_paths!({ - rustc_middle::mir::pretty::write_mir_fn(tcx, mir, &mut |_, _| Ok(()), &mut buf) - .unwrap(); - }); - String::from_utf8_lossy(&buf).into_owned() - }); - - // Declare function - let sig = get_function_sig(tcx, module.target_config().default_call_conv, instance); - let func_id = module.declare_function(&symbol_name, Linkage::Local, &sig).unwrap(); - - // Make the FunctionBuilder - let mut func_ctx = FunctionBuilderContext::new(); - let mut func = cached_func; - func.clear(); - func.name = UserFuncName::user(0, func_id.as_u32()); - func.signature = sig; - func.collect_debug_info(); - - let mut bcx = FunctionBuilder::new(&mut func, &mut func_ctx); - - // Predefine blocks - let start_block = bcx.create_block(); - let block_map: IndexVec = - (0..mir.basic_blocks.len()).map(|_| bcx.create_block()).collect(); - - // Make FunctionCx - let target_config = module.target_config(); - let pointer_type = target_config.pointer_type(); - let clif_comments = crate::pretty_clif::CommentWriter::new(tcx, instance); - - let fn_abi = RevealAllLayoutCx(tcx).fn_abi_of_instance(instance, ty::List::empty()); - - let func_debug_cx = if let Some(debug_context) = &mut cx.debug_context { - Some(debug_context.define_function(tcx, type_dbg, instance, fn_abi, &symbol_name, mir.span)) - } else { - None - }; - - let mut fx = FunctionCx { - cx, - module, - tcx, - target_config, - pointer_type, - constants_cx: ConstantCx::new(), - func_debug_cx, - - instance, - symbol_name, - mir, - fn_abi, - - bcx, - block_map, - local_map: IndexVec::with_capacity(mir.local_decls.len()), - caller_location: None, // set by `codegen_fn_prelude` - - clif_comments, - next_ssa_var: 0, - }; - - tcx.prof.generic_activity("codegen clif ir").run(|| codegen_fn_body(&mut fx, start_block)); - fx.bcx.seal_all_blocks(); - fx.bcx.finalize(); - - // Recover all necessary data from fx, before accessing func will prevent future access to it. - let symbol_name = fx.symbol_name; - let clif_comments = fx.clif_comments; - let func_debug_cx = fx.func_debug_cx; - - fx.constants_cx.finalize(fx.tcx, &mut *fx.module); - - if cx.should_write_ir { - crate::pretty_clif::write_clif_file( - tcx.output_filenames(()), - &symbol_name, - "unopt", - module.isa(), - &func, - &clif_comments, - ); - } - - // Verify function - verify_func(tcx, &clif_comments, &func); - - CodegenedFunction { symbol_name, func_id, func, clif_comments, func_debug_cx } -} - -pub(crate) fn compile_fn( - cx: &mut crate::CodegenCx, - cached_context: &mut Context, - module: &mut dyn Module, - codegened_func: CodegenedFunction, -) { - let _timer = - cx.profiler.generic_activity_with_arg("compile function", &*codegened_func.symbol_name); - - let clif_comments = codegened_func.clif_comments; - - // Store function in context - let context = cached_context; - context.clear(); - context.func = codegened_func.func; - - #[cfg(any())] // This is never true - let _clif_guard = { - use std::fmt::Write; - - let func_clone = context.func.clone(); - let clif_comments_clone = clif_comments.clone(); - let mut clif = String::new(); - for flag in module.isa().flags().iter() { - writeln!(clif, "set {}", flag).unwrap(); - } - write!(clif, "target {}", module.isa().triple().architecture.to_string()).unwrap(); - for isa_flag in module.isa().isa_flags().iter() { - write!(clif, " {}", isa_flag).unwrap(); - } - writeln!(clif, "\n").unwrap(); - writeln!(clif, "; symbol {}", codegened_func.symbol_name).unwrap(); - crate::PrintOnPanic(move || { - let mut clif = clif.clone(); - ::cranelift_codegen::write::decorate_function( - &mut &clif_comments_clone, - &mut clif, - &func_clone, - ) - .unwrap(); - clif - }) - }; - - // Define function - cx.profiler.generic_activity("define function").run(|| { - context.want_disasm = cx.should_write_ir; - match module.define_function(codegened_func.func_id, context) { - Ok(()) => {} - Err(ModuleError::Compilation(CodegenError::ImplLimitExceeded)) => { - let early_dcx = rustc_session::EarlyDiagCtxt::new( - rustc_session::config::ErrorOutputType::default(), - ); - early_dcx.early_fatal(format!( - "backend implementation limit exceeded while compiling {name}", - name = codegened_func.symbol_name - )); - } - Err(err) => { - panic!("Error while defining {name}: {err:?}", name = codegened_func.symbol_name); - } - } - }); - - if cx.should_write_ir { - // Write optimized function to file for debugging - crate::pretty_clif::write_clif_file( - &cx.output_filenames, - &codegened_func.symbol_name, - "opt", - module.isa(), - &context.func, - &clif_comments, - ); - - if let Some(disasm) = &context.compiled_code().unwrap().vcode { - crate::pretty_clif::write_ir_file( - &cx.output_filenames, - &format!("{}.vcode", codegened_func.symbol_name), - |file| file.write_all(disasm.as_bytes()), - ) - } - } - - // Define debuginfo for function - let isa = module.isa(); - let debug_context = &mut cx.debug_context; - let unwind_context = &mut cx.unwind_context; - cx.profiler.generic_activity("generate debug info").run(|| { - if let Some(debug_context) = debug_context { - codegened_func.func_debug_cx.unwrap().finalize( - debug_context, - codegened_func.func_id, - context, - ); - } - unwind_context.add_function(codegened_func.func_id, &context, isa); - }); -} - -pub(crate) fn verify_func( - tcx: TyCtxt<'_>, - writer: &crate::pretty_clif::CommentWriter, - func: &Function, -) { - tcx.prof.generic_activity("verify clif ir").run(|| { - let flags = cranelift_codegen::settings::Flags::new(cranelift_codegen::settings::builder()); - match cranelift_codegen::verify_function(&func, &flags) { - Ok(_) => {} - Err(err) => { - tcx.dcx().err(format!("{:?}", err)); - let pretty_error = cranelift_codegen::print_errors::pretty_verifier_error( - &func, - Some(Box::new(writer)), - err, - ); - tcx.dcx().fatal(format!("cranelift verify error:\n{}", pretty_error)); - } - } - }); -} - -fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { - let arg_uninhabited = fx - .mir - .args_iter() - .any(|arg| fx.layout_of(fx.monomorphize(fx.mir.local_decls[arg].ty)).abi.is_uninhabited()); - if arg_uninhabited { - fx.bcx.append_block_params_for_function_params(fx.block_map[START_BLOCK]); - fx.bcx.switch_to_block(fx.block_map[START_BLOCK]); - fx.bcx.ins().trap(TrapCode::UnreachableCodeReached); - return; - } - fx.tcx - .prof - .generic_activity("codegen prelude") - .run(|| crate::abi::codegen_fn_prelude(fx, start_block)); - - for (bb, bb_data) in fx.mir.basic_blocks.iter_enumerated() { - let block = fx.get_block(bb); - fx.bcx.switch_to_block(block); - - if bb_data.is_cleanup { - // Unwinding after panicking is not supported - continue; - - // FIXME Once unwinding is supported and Cranelift supports marking blocks as cold, do - // so for cleanup blocks. - } - - fx.bcx.ins().nop(); - for stmt in &bb_data.statements { - fx.set_debug_loc(stmt.source_info); - codegen_stmt(fx, block, stmt); - } - - if fx.clif_comments.enabled() { - let mut terminator_head = "\n".to_string(); - with_no_trimmed_paths!({ - bb_data.terminator().kind.fmt_head(&mut terminator_head).unwrap(); - }); - let inst = fx.bcx.func.layout.last_inst(block).unwrap(); - fx.add_comment(inst, terminator_head); - } - - let source_info = bb_data.terminator().source_info; - fx.set_debug_loc(source_info); - - let _print_guard = - crate::PrintOnPanic(|| format!("terminator {:?}", bb_data.terminator().kind)); - - match &bb_data.terminator().kind { - TerminatorKind::Goto { target } => { - if let TerminatorKind::Return = fx.mir[*target].terminator().kind { - let mut can_immediately_return = true; - for stmt in &fx.mir[*target].statements { - if let StatementKind::StorageDead(_) = stmt.kind { - } else { - // FIXME Can sometimes happen, see rust-lang/rust#70531 - can_immediately_return = false; - break; - } - } - - if can_immediately_return { - crate::abi::codegen_return(fx); - continue; - } - } - - let block = fx.get_block(*target); - fx.bcx.ins().jump(block, &[]); - } - TerminatorKind::Return => { - crate::abi::codegen_return(fx); - } - TerminatorKind::Assert { cond, expected, msg, target, unwind: _ } => { - if !fx.tcx.sess.overflow_checks() && msg.is_optional_overflow_check() { - let target = fx.get_block(*target); - fx.bcx.ins().jump(target, &[]); - continue; - } - let cond = codegen_operand(fx, cond).load_scalar(fx); - - let target = fx.get_block(*target); - let failure = fx.bcx.create_block(); - fx.bcx.set_cold_block(failure); - - if *expected { - fx.bcx.ins().brif(cond, target, &[], failure, &[]); - } else { - fx.bcx.ins().brif(cond, failure, &[], target, &[]); - }; - - fx.bcx.switch_to_block(failure); - fx.bcx.ins().nop(); - - match &**msg { - AssertKind::BoundsCheck { ref len, ref index } => { - let len = codegen_operand(fx, len).load_scalar(fx); - let index = codegen_operand(fx, index).load_scalar(fx); - let location = fx.get_caller_location(source_info).load_scalar(fx); - - codegen_panic_inner( - fx, - rustc_hir::LangItem::PanicBoundsCheck, - &[index, len, location], - Some(source_info.span), - ); - } - AssertKind::MisalignedPointerDereference { ref required, ref found } => { - let required = codegen_operand(fx, required).load_scalar(fx); - let found = codegen_operand(fx, found).load_scalar(fx); - let location = fx.get_caller_location(source_info).load_scalar(fx); - - codegen_panic_inner( - fx, - rustc_hir::LangItem::PanicMisalignedPointerDereference, - &[required, found, location], - Some(source_info.span), - ); - } - _ => { - let location = fx.get_caller_location(source_info).load_scalar(fx); - - codegen_panic_inner( - fx, - msg.panic_function(), - &[location], - Some(source_info.span), - ); - } - } - } - - TerminatorKind::SwitchInt { discr, targets } => { - let discr = codegen_operand(fx, discr); - let switch_ty = discr.layout().ty; - let discr = discr.load_scalar(fx); - - let use_bool_opt = switch_ty.kind() == fx.tcx.types.bool.kind() - || (targets.iter().count() == 1 && targets.iter().next().unwrap().0 == 0); - if use_bool_opt { - assert_eq!(targets.iter().count(), 1); - let (then_value, then_block) = targets.iter().next().unwrap(); - let then_block = fx.get_block(then_block); - let else_block = fx.get_block(targets.otherwise()); - let test_zero = match then_value { - 0 => true, - 1 => false, - _ => unreachable!("{:?}", targets), - }; - - let (discr, is_inverted) = - crate::optimize::peephole::maybe_unwrap_bool_not(&mut fx.bcx, discr); - let test_zero = if is_inverted { !test_zero } else { test_zero }; - if let Some(taken) = crate::optimize::peephole::maybe_known_branch_taken( - &fx.bcx, discr, test_zero, - ) { - if taken { - fx.bcx.ins().jump(then_block, &[]); - } else { - fx.bcx.ins().jump(else_block, &[]); - } - } else { - if test_zero { - fx.bcx.ins().brif(discr, else_block, &[], then_block, &[]); - } else { - fx.bcx.ins().brif(discr, then_block, &[], else_block, &[]); - } - } - } else { - let mut switch = ::cranelift_frontend::Switch::new(); - for (value, block) in targets.iter() { - let block = fx.get_block(block); - switch.set_entry(value, block); - } - let otherwise_block = fx.get_block(targets.otherwise()); - switch.emit(&mut fx.bcx, discr, otherwise_block); - } - } - TerminatorKind::Call { - func, - args, - destination, - target, - fn_span, - unwind: _, - call_source: _, - } => { - fx.tcx.prof.generic_activity("codegen call").run(|| { - crate::abi::codegen_terminator_call( - fx, - mir::SourceInfo { span: *fn_span, ..source_info }, - func, - args, - *destination, - *target, - ) - }); - } - TerminatorKind::InlineAsm { - template, - operands, - options, - targets, - line_spans: _, - unwind: _, - } => { - if options.contains(InlineAsmOptions::MAY_UNWIND) { - fx.tcx.dcx().span_fatal( - source_info.span, - "cranelift doesn't support unwinding from inline assembly.", - ); - } - - let have_labels = if options.contains(InlineAsmOptions::NORETURN) { - !targets.is_empty() - } else { - targets.len() > 1 - }; - if have_labels { - fx.tcx.dcx().span_fatal( - source_info.span, - "cranelift doesn't support labels in inline assembly.", - ); - } - - crate::inline_asm::codegen_inline_asm_terminator( - fx, - source_info.span, - template, - operands, - *options, - targets.get(0).copied(), - ); - } - TerminatorKind::UnwindTerminate(reason) => { - codegen_unwind_terminate(fx, source_info, *reason); - } - TerminatorKind::UnwindResume => { - // FIXME implement unwinding - fx.bcx.ins().trap(TrapCode::UnreachableCodeReached); - } - TerminatorKind::Unreachable => { - fx.bcx.ins().trap(TrapCode::UnreachableCodeReached); - } - TerminatorKind::Yield { .. } - | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::CoroutineDrop => { - bug!("shouldn't exist at codegen {:?}", bb_data.terminator()); - } - TerminatorKind::Drop { place, target, unwind: _, replace: _ } => { - let drop_place = codegen_place(fx, *place); - crate::abi::codegen_drop(fx, source_info, drop_place); - - let target_block = fx.get_block(*target); - fx.bcx.ins().jump(target_block, &[]); - } - }; - } -} - -fn codegen_stmt<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - #[allow(unused_variables)] cur_block: Block, - stmt: &Statement<'tcx>, -) { - let _print_guard = crate::PrintOnPanic(|| format!("stmt {:?}", stmt)); - - fx.set_debug_loc(stmt.source_info); - - match &stmt.kind { - StatementKind::StorageLive(..) | StatementKind::StorageDead(..) => {} // Those are not very useful - _ => { - if fx.clif_comments.enabled() { - let inst = fx.bcx.func.layout.last_inst(cur_block).unwrap(); - with_no_trimmed_paths!({ - fx.add_comment(inst, format!("{:?}", stmt)); - }); - } - } - } - - match &stmt.kind { - StatementKind::SetDiscriminant { place, variant_index } => { - let place = codegen_place(fx, **place); - crate::discriminant::codegen_set_discriminant(fx, place, *variant_index); - } - StatementKind::Assign(to_place_and_rval) => { - let lval = codegen_place(fx, to_place_and_rval.0); - let dest_layout = lval.layout(); - match to_place_and_rval.1 { - Rvalue::Use(ref operand) => { - let val = codegen_operand(fx, operand); - lval.write_cvalue(fx, val); - } - Rvalue::CopyForDeref(place) => { - let cplace = codegen_place(fx, place); - let val = cplace.to_cvalue(fx); - lval.write_cvalue(fx, val) - } - Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => { - let place = codegen_place(fx, place); - let ref_ = place.place_ref(fx, lval.layout()); - lval.write_cvalue(fx, ref_); - } - Rvalue::ThreadLocalRef(def_id) => { - let val = crate::constant::codegen_tls_ref(fx, def_id, lval.layout()); - lval.write_cvalue(fx, val); - } - Rvalue::BinaryOp(bin_op, ref lhs_rhs) => { - let lhs = codegen_operand(fx, &lhs_rhs.0); - let rhs = codegen_operand(fx, &lhs_rhs.1); - - let res = crate::num::codegen_binop(fx, bin_op, lhs, rhs); - lval.write_cvalue(fx, res); - } - Rvalue::CheckedBinaryOp(bin_op, ref lhs_rhs) => { - let lhs = codegen_operand(fx, &lhs_rhs.0); - let rhs = codegen_operand(fx, &lhs_rhs.1); - - let res = crate::num::codegen_checked_int_binop(fx, bin_op, lhs, rhs); - lval.write_cvalue(fx, res); - } - Rvalue::UnaryOp(un_op, ref operand) => { - let operand = codegen_operand(fx, operand); - let layout = operand.layout(); - let val = operand.load_scalar(fx); - let res = match un_op { - UnOp::Not => match layout.ty.kind() { - ty::Bool => { - let res = fx.bcx.ins().icmp_imm(IntCC::Equal, val, 0); - CValue::by_val(res, layout) - } - ty::Uint(_) | ty::Int(_) => { - CValue::by_val(fx.bcx.ins().bnot(val), layout) - } - _ => unreachable!("un op Not for {:?}", layout.ty), - }, - UnOp::Neg => match layout.ty.kind() { - ty::Int(_) => CValue::by_val(fx.bcx.ins().ineg(val), layout), - ty::Float(_) => CValue::by_val(fx.bcx.ins().fneg(val), layout), - _ => unreachable!("un op Neg for {:?}", layout.ty), - }, - }; - lval.write_cvalue(fx, res); - } - Rvalue::Cast( - CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer), - ref operand, - to_ty, - ) => { - let from_ty = fx.monomorphize(operand.ty(&fx.mir.local_decls, fx.tcx)); - let to_layout = fx.layout_of(fx.monomorphize(to_ty)); - match *from_ty.kind() { - ty::FnDef(def_id, args) => { - let func_ref = fx.get_function_ref( - Instance::resolve_for_fn_ptr( - fx.tcx, - ParamEnv::reveal_all(), - def_id, - args, - ) - .unwrap() - .polymorphize(fx.tcx), - ); - let func_addr = fx.bcx.ins().func_addr(fx.pointer_type, func_ref); - lval.write_cvalue(fx, CValue::by_val(func_addr, to_layout)); - } - _ => bug!("Trying to ReifyFnPointer on non FnDef {:?}", from_ty), - } - } - Rvalue::Cast( - CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer), - ref operand, - to_ty, - ) - | Rvalue::Cast( - CastKind::PointerCoercion(PointerCoercion::MutToConstPointer), - ref operand, - to_ty, - ) - | Rvalue::Cast( - CastKind::PointerCoercion(PointerCoercion::ArrayToPointer), - ref operand, - to_ty, - ) => { - let to_layout = fx.layout_of(fx.monomorphize(to_ty)); - let operand = codegen_operand(fx, operand); - lval.write_cvalue(fx, operand.cast_pointer_to(to_layout)); - } - Rvalue::Cast( - CastKind::IntToInt - | CastKind::FloatToFloat - | CastKind::FloatToInt - | CastKind::IntToFloat - | CastKind::FnPtrToPtr - | CastKind::PtrToPtr - | CastKind::PointerExposeAddress - | CastKind::PointerFromExposedAddress, - ref operand, - to_ty, - ) => { - let operand = codegen_operand(fx, operand); - let from_ty = operand.layout().ty; - let to_ty = fx.monomorphize(to_ty); - - fn is_fat_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool { - ty.builtin_deref(true).is_some_and( - |ty::TypeAndMut { ty: pointee_ty, mutbl: _ }| { - has_ptr_meta(fx.tcx, pointee_ty) - }, - ) - } - - if is_fat_ptr(fx, from_ty) { - if is_fat_ptr(fx, to_ty) { - // fat-ptr -> fat-ptr - lval.write_cvalue(fx, operand.cast_pointer_to(dest_layout)); - } else { - // fat-ptr -> thin-ptr - let (ptr, _extra) = operand.load_scalar_pair(fx); - lval.write_cvalue(fx, CValue::by_val(ptr, dest_layout)) - } - } else { - let to_clif_ty = fx.clif_type(to_ty).unwrap(); - let from = operand.load_scalar(fx); - - let res = clif_int_or_float_cast( - fx, - from, - type_sign(from_ty), - to_clif_ty, - type_sign(to_ty), - ); - lval.write_cvalue(fx, CValue::by_val(res, dest_layout)); - } - } - Rvalue::Cast( - CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_)), - ref operand, - _to_ty, - ) => { - let operand = codegen_operand(fx, operand); - match *operand.layout().ty.kind() { - ty::Closure(def_id, args) => { - let instance = Instance::resolve_closure( - fx.tcx, - def_id, - args, - ty::ClosureKind::FnOnce, - ) - .polymorphize(fx.tcx); - let func_ref = fx.get_function_ref(instance); - let func_addr = fx.bcx.ins().func_addr(fx.pointer_type, func_ref); - lval.write_cvalue(fx, CValue::by_val(func_addr, lval.layout())); - } - _ => bug!("{} cannot be cast to a fn ptr", operand.layout().ty), - } - } - Rvalue::Cast( - CastKind::PointerCoercion(PointerCoercion::Unsize), - ref operand, - _to_ty, - ) => { - let operand = codegen_operand(fx, operand); - crate::unsize::coerce_unsized_into(fx, operand, lval); - } - Rvalue::Cast(CastKind::DynStar, ref operand, _) => { - let operand = codegen_operand(fx, operand); - crate::unsize::coerce_dyn_star(fx, operand, lval); - } - Rvalue::Cast(CastKind::Transmute, ref operand, _to_ty) => { - let operand = codegen_operand(fx, operand); - lval.write_cvalue_transmute(fx, operand); - } - Rvalue::Discriminant(place) => { - let place = codegen_place(fx, place); - let value = place.to_cvalue(fx); - crate::discriminant::codegen_get_discriminant(fx, lval, value, dest_layout); - } - Rvalue::Repeat(ref operand, times) => { - let operand = codegen_operand(fx, operand); - let times = - fx.monomorphize(times).eval_target_usize(fx.tcx, ParamEnv::reveal_all()); - if operand.layout().size.bytes() == 0 { - // Do nothing for ZST's - } else if fx.clif_type(operand.layout().ty) == Some(types::I8) { - let times = fx.bcx.ins().iconst(fx.pointer_type, times as i64); - // FIXME use emit_small_memset where possible - let addr = lval.to_ptr().get_addr(fx); - let val = operand.load_scalar(fx); - fx.bcx.call_memset(fx.target_config, addr, val, times); - } else { - let loop_block = fx.bcx.create_block(); - let loop_block2 = fx.bcx.create_block(); - let done_block = fx.bcx.create_block(); - let index = fx.bcx.append_block_param(loop_block, fx.pointer_type); - let zero = fx.bcx.ins().iconst(fx.pointer_type, 0); - fx.bcx.ins().jump(loop_block, &[zero]); - - fx.bcx.switch_to_block(loop_block); - let done = fx.bcx.ins().icmp_imm(IntCC::Equal, index, times as i64); - fx.bcx.ins().brif(done, done_block, &[], loop_block2, &[]); - - fx.bcx.switch_to_block(loop_block2); - let to = lval.place_index(fx, index); - to.write_cvalue(fx, operand); - let index = fx.bcx.ins().iadd_imm(index, 1); - fx.bcx.ins().jump(loop_block, &[index]); - - fx.bcx.switch_to_block(done_block); - fx.bcx.ins().nop(); - } - } - Rvalue::Len(place) => { - let place = codegen_place(fx, place); - let usize_layout = fx.layout_of(fx.tcx.types.usize); - let len = codegen_array_len(fx, place); - lval.write_cvalue(fx, CValue::by_val(len, usize_layout)); - } - Rvalue::ShallowInitBox(ref operand, content_ty) => { - let content_ty = fx.monomorphize(content_ty); - let box_layout = fx.layout_of(Ty::new_box(fx.tcx, content_ty)); - let operand = codegen_operand(fx, operand); - let operand = operand.load_scalar(fx); - lval.write_cvalue(fx, CValue::by_val(operand, box_layout)); - } - Rvalue::NullaryOp(ref null_op, ty) => { - assert!(lval.layout().ty.is_sized(fx.tcx, ParamEnv::reveal_all())); - let layout = fx.layout_of(fx.monomorphize(ty)); - let val = match null_op { - NullOp::SizeOf => layout.size.bytes(), - NullOp::AlignOf => layout.align.abi.bytes(), - NullOp::OffsetOf(fields) => { - layout.offset_of_subfield(fx, fields.iter()).bytes() - } - NullOp::UbChecks => { - let val = fx.tcx.sess.opts.debug_assertions; - let val = CValue::by_val( - fx.bcx.ins().iconst(types::I8, i64::try_from(val).unwrap()), - fx.layout_of(fx.tcx.types.bool), - ); - lval.write_cvalue(fx, val); - return; - } - }; - let val = CValue::by_val( - fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(val).unwrap()), - fx.layout_of(fx.tcx.types.usize), - ); - lval.write_cvalue(fx, val); - } - Rvalue::Aggregate(ref kind, ref operands) => { - let (variant_index, variant_dest, active_field_index) = match **kind { - mir::AggregateKind::Adt(_, variant_index, _, _, active_field_index) => { - let variant_dest = lval.downcast_variant(fx, variant_index); - (variant_index, variant_dest, active_field_index) - } - _ => (FIRST_VARIANT, lval, None), - }; - if active_field_index.is_some() { - assert_eq!(operands.len(), 1); - } - for (i, operand) in operands.iter_enumerated() { - let operand = codegen_operand(fx, operand); - let field_index = active_field_index.unwrap_or(i); - let to = if let mir::AggregateKind::Array(_) = **kind { - let array_index = i64::from(field_index.as_u32()); - let index = fx.bcx.ins().iconst(fx.pointer_type, array_index); - variant_dest.place_index(fx, index) - } else { - variant_dest.place_field(fx, field_index) - }; - to.write_cvalue(fx, operand); - } - crate::discriminant::codegen_set_discriminant(fx, lval, variant_index); - } - } - } - StatementKind::StorageLive(_) - | StatementKind::StorageDead(_) - | StatementKind::Deinit(_) - | StatementKind::ConstEvalCounter - | StatementKind::Nop - | StatementKind::FakeRead(..) - | StatementKind::Retag { .. } - | StatementKind::PlaceMention(..) - | StatementKind::AscribeUserType(..) => {} - - StatementKind::Coverage { .. } => fx.tcx.dcx().fatal("-Zcoverage is unimplemented"), - StatementKind::Intrinsic(ref intrinsic) => match &**intrinsic { - // We ignore `assume` intrinsics, they are only useful for optimizations - NonDivergingIntrinsic::Assume(_) => {} - NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping { - src, - dst, - count, - }) => { - let dst = codegen_operand(fx, dst); - let pointee = dst - .layout() - .pointee_info_at(fx, rustc_target::abi::Size::ZERO) - .expect("Expected pointer"); - let dst = dst.load_scalar(fx); - let src = codegen_operand(fx, src).load_scalar(fx); - let count = codegen_operand(fx, count).load_scalar(fx); - let elem_size: u64 = pointee.size.bytes(); - let bytes = if elem_size != 1 { - fx.bcx.ins().imul_imm(count, elem_size as i64) - } else { - count - }; - fx.bcx.call_memcpy(fx.target_config, dst, src, bytes); - } - }, - } -} - -fn codegen_array_len<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, place: CPlace<'tcx>) -> Value { - match *place.layout().ty.kind() { - ty::Array(_elem_ty, len) => { - let len = fx.monomorphize(len).eval_target_usize(fx.tcx, ParamEnv::reveal_all()) as i64; - fx.bcx.ins().iconst(fx.pointer_type, len) - } - ty::Slice(_elem_ty) => place.to_ptr_unsized().1, - _ => bug!("Rvalue::Len({:?})", place), - } -} - -pub(crate) fn codegen_place<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - place: Place<'tcx>, -) -> CPlace<'tcx> { - let mut cplace = fx.get_local_place(place.local); - - for elem in place.projection { - match elem { - PlaceElem::Deref => { - cplace = cplace.place_deref(fx); - } - PlaceElem::OpaqueCast(ty) => bug!("encountered OpaqueCast({ty}) in codegen"), - PlaceElem::Subtype(ty) => cplace = cplace.place_transmute_type(fx, fx.monomorphize(ty)), - PlaceElem::Field(field, _ty) => { - cplace = cplace.place_field(fx, field); - } - PlaceElem::Index(local) => { - let index = fx.get_local_place(local).to_cvalue(fx).load_scalar(fx); - cplace = cplace.place_index(fx, index); - } - PlaceElem::ConstantIndex { offset, min_length: _, from_end } => { - let offset: u64 = offset; - let index = if !from_end { - fx.bcx.ins().iconst(fx.pointer_type, offset as i64) - } else { - let len = codegen_array_len(fx, cplace); - fx.bcx.ins().iadd_imm(len, -(offset as i64)) - }; - cplace = cplace.place_index(fx, index); - } - PlaceElem::Subslice { from, to, from_end } => { - // These indices are generated by slice patterns. - // slice[from:-to] in Python terms. - - let from: u64 = from; - let to: u64 = to; - - match cplace.layout().ty.kind() { - ty::Array(elem_ty, _len) => { - assert!(!from_end, "array subslices are never `from_end`"); - let elem_layout = fx.layout_of(*elem_ty); - let ptr = cplace.to_ptr(); - cplace = CPlace::for_ptr( - ptr.offset_i64(fx, elem_layout.size.bytes() as i64 * (from as i64)), - fx.layout_of(Ty::new_array(fx.tcx, *elem_ty, to - from)), - ); - } - ty::Slice(elem_ty) => { - assert!(from_end, "slice subslices should be `from_end`"); - let elem_layout = fx.layout_of(*elem_ty); - let (ptr, len) = cplace.to_ptr_unsized(); - cplace = CPlace::for_ptr_with_extra( - ptr.offset_i64(fx, elem_layout.size.bytes() as i64 * (from as i64)), - fx.bcx.ins().iadd_imm(len, -(from as i64 + to as i64)), - cplace.layout(), - ); - } - _ => unreachable!(), - } - } - PlaceElem::Downcast(_adt_def, variant) => { - cplace = cplace.downcast_variant(fx, variant); - } - } - } - - cplace -} - -pub(crate) fn codegen_operand<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - operand: &Operand<'tcx>, -) -> CValue<'tcx> { - match operand { - Operand::Move(place) | Operand::Copy(place) => { - let cplace = codegen_place(fx, *place); - cplace.to_cvalue(fx) - } - Operand::Constant(const_) => crate::constant::codegen_constant_operand(fx, const_), - } -} - -pub(crate) fn codegen_panic_nounwind<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - msg_str: &str, - span: Option, -) { - let msg_ptr = fx.anonymous_str(msg_str); - let msg_len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(msg_str.len()).unwrap()); - let args = [msg_ptr, msg_len]; - - codegen_panic_inner(fx, rustc_hir::LangItem::PanicNounwind, &args, span); -} - -pub(crate) fn codegen_unwind_terminate<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - source_info: mir::SourceInfo, - reason: UnwindTerminateReason, -) { - let args = []; - - codegen_panic_inner(fx, reason.lang_item(), &args, Some(source_info.span)); -} - -fn codegen_panic_inner<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - lang_item: rustc_hir::LangItem, - args: &[Value], - span: Option, -) { - let def_id = fx.tcx.require_lang_item(lang_item, span); - - let instance = Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx); - - if is_call_from_compiler_builtins_to_upstream_monomorphization(fx.tcx, instance) { - fx.bcx.ins().trap(TrapCode::User(0)); - return; - } - - let symbol_name = fx.tcx.symbol_name(instance).name; - - fx.lib_call( - symbol_name, - args.iter().map(|&arg| AbiParam::new(fx.bcx.func.dfg.value_type(arg))).collect(), - vec![], - args, - ); - - fx.bcx.ins().trap(TrapCode::UnreachableCodeReached); -} +use cranelift_codegen::ir::UserFuncName ;use cranelift_codegen::CodegenError;use +cranelift_module::ModuleError;use rustc_ast::InlineAsmOptions;use rustc_index//; +::IndexVec;use rustc_middle::ty ::adjustment::PointerCoercion;use rustc_middle:: +ty::layout::FnAbiOf;use rustc_middle::ty::print::with_no_trimmed_paths;use//{;}; +rustc_monomorphize ::is_call_from_compiler_builtins_to_upstream_monomorphization +;use crate::constant::ConstantCx;use crate::debuginfo::{FunctionDebugContext,//; +TypeDebugContext};use crate::prelude::*;use crate::pretty_clif::CommentWriter;// +pub(crate)struct CodegenedFunction{symbol_name:String,func_id:FuncId,func://{;}; +Function,clif_comments:CommentWriter, func_debug_cx:Option +,}pub(crate)fn codegen_fn<'tcx>(tcx:TyCtxt<'tcx>,cx:&mut crate::CodegenCx,//{;}; +type_dbg:&mut TypeDebugContext<'tcx>,cached_func:Function,module:&mut dyn//({}); +Module,instance:Instance<'tcx>,)->CodegenedFunction{{;};debug_assert!(!instance. +args.has_infer());;;let symbol_name=tcx.symbol_name(instance).name.to_string();; +let _timer=tcx.prof.generic_activity_with_arg("codegen fn",&*symbol_name);3;;let +mir=tcx.instance_mir(instance.def);3;;let _mir_guard=crate::PrintOnPanic(||{;let +mut buf=Vec::new();({});({});with_no_trimmed_paths!({rustc_middle::mir::pretty:: +write_mir_fn(tcx,mir,&mut|_,_|Ok(()),&mut buf).unwrap();});loop{break;};String:: +from_utf8_lossy(&buf).into_owned()});{;};();let sig=get_function_sig(tcx,module. +target_config().default_call_conv,instance);;let func_id=module.declare_function +(&symbol_name,Linkage::Local,&sig).unwrap();if true{};let _=();let mut func_ctx= +FunctionBuilderContext::new();;;let mut func=cached_func;func.clear();func.name= +UserFuncName::user(0,func_id.as_u32());({});{;};func.signature=sig;{;};{;};func. +collect_debug_info();;let mut bcx=FunctionBuilder::new(&mut func,&mut func_ctx); +let start_block=bcx.create_block();;;let block_map:IndexVec=(0 +..mir.basic_blocks.len()).map(|_|bcx.create_block()).collect();*&*&();*&*&();let +target_config=module.target_config();{();};{();};let pointer_type=target_config. +pointer_type();3;3;let clif_comments=crate::pretty_clif::CommentWriter::new(tcx, +instance);3;3;let fn_abi=RevealAllLayoutCx(tcx).fn_abi_of_instance(instance,ty:: +List::empty());{();};{();};let func_debug_cx=if let Some(debug_context)=&mut cx. +debug_context{Some(debug_context.define_function (tcx,type_dbg,instance,fn_abi,& +symbol_name,mir.span))}else{None};({});({});let mut fx=FunctionCx{cx,module,tcx, +target_config,pointer_type,constants_cx:((((ConstantCx::new())))),func_debug_cx, +instance,symbol_name,mir,fn_abi,bcx ,block_map,local_map:IndexVec::with_capacity +(mir.local_decls.len()),caller_location:None,clif_comments,next_ssa_var:0,};;tcx +.prof.generic_activity((("codegen clif ir"))).run(||codegen_fn_body(((&mut fx)), +start_block));;;fx.bcx.seal_all_blocks();;;fx.bcx.finalize();let symbol_name=fx. +symbol_name;();();let clif_comments=fx.clif_comments;();();let func_debug_cx=fx. +func_debug_cx;{;};{;};fx.constants_cx.finalize(fx.tcx,&mut*fx.module);{;};if cx. +should_write_ir{3;crate::pretty_clif::write_clif_file(tcx.output_filenames(()),& +symbol_name,"unopt",module.isa(),&func,&clif_comments,);();}();verify_func(tcx,& +clif_comments,&func);3;CodegenedFunction{symbol_name,func_id,func,clif_comments, +func_debug_cx}}pub(crate)fn compile_fn (cx:&mut crate::CodegenCx,cached_context: +&mut Context,module:&mut dyn Module,codegened_func:CodegenedFunction,){{();};let +_timer=cx.profiler.generic_activity_with_arg(((((((("compile function"))))))),&* +codegened_func.symbol_name);;;let clif_comments=codegened_func.clif_comments;let +context=cached_context;;;context.clear();context.func=codegened_func.func;#[cfg( +any())]let _clif_guard={;use std::fmt::Write;let func_clone=context.func.clone() +;;;let clif_comments_clone=clif_comments.clone();;let mut clif=String::new();for +flag in module.isa().flags().iter(){3;writeln!(clif,"set {}",flag).unwrap();3;}; +write!(clif,"target {}",module.isa(). triple().architecture.to_string()).unwrap( +);;for isa_flag in module.isa().isa_flags().iter(){;write!(clif," {}",isa_flag). +unwrap();{;};}();writeln!(clif,"\n").unwrap();();();writeln!(clif,"; symbol {}", +codegened_func.symbol_name).unwrap();3;crate::PrintOnPanic(move||{;let mut clif= +clif.clone();((),());((),());::cranelift_codegen::write::decorate_function(&mut& +clif_comments_clone,&mut clif,&func_clone,).unwrap();();clif})};3;3;cx.profiler. +generic_activity("define function").run(||{if let _=(){};context.want_disasm=cx. +should_write_ir;;match module.define_function(codegened_func.func_id,context){Ok +(())=>{}Err(ModuleError::Compilation(CodegenError::ImplLimitExceeded))=>{{;};let +early_dcx=rustc_session::EarlyDiagCtxt::new(rustc_session::config:://let _=||(); +ErrorOutputType::default(),);let _=||();if true{};early_dcx.early_fatal(format!( +"backend implementation limit exceeded while compiling {name}",name=//if true{}; +codegened_func.symbol_name));((),());((),());}Err(err)=>{((),());((),());panic!( +"Error while defining {name}: {err:?}",name=codegened_func.symbol_name);;}}});if +cx.should_write_ir{();crate::pretty_clif::write_clif_file(&cx.output_filenames,& +codegened_func.symbol_name,"opt",module.isa(),&context.func,&clif_comments,);;if +let Some(disasm)=(&context.compiled_code( ).unwrap().vcode){crate::pretty_clif:: +write_ir_file((((((&cx.output_filenames))))),&format!("{}.vcode",codegened_func. +symbol_name),|file|file.write_all(disasm.as_bytes()),)}};let isa=module.isa();;; +let debug_context=&mut cx.debug_context;*&*&();{();};let unwind_context=&mut cx. +unwind_context;3;3;cx.profiler.generic_activity("generate debug info").run(||{if +let Some(debug_context)=debug_context{{;};codegened_func.func_debug_cx.unwrap(). +finalize(debug_context,codegened_func.func_id,context,);{;};}{;};unwind_context. +add_function(codegened_func.func_id,&context,isa);;});}pub(crate)fn verify_func( +tcx:TyCtxt<'_>,writer:&crate::pretty_clif::CommentWriter,func:&Function,){3;tcx. +prof.generic_activity("verify clif ir").run(||{{;};let flags=cranelift_codegen:: +settings::Flags::new(cranelift_codegen::settings::builder());loop{break;};match +cranelift_codegen::verify_function(&func,&flags){Ok(_)=>{}Err(err)=>{;tcx.dcx(). +err(format!("{:?}",err));();3;let pretty_error=cranelift_codegen::print_errors:: +pretty_verifier_error(&func,Some(Box::new(writer)),err,);;tcx.dcx().fatal(format +!("cranelift verify error:\n{}",pretty_error));;}}});}fn codegen_fn_body(fx:&mut +FunctionCx<'_,'_,'_>,start_block:Block){3;let arg_uninhabited=fx.mir.args_iter() +.any(|arg|((fx.layout_of((fx.monomorphize((fx.mir.local_decls[arg]).ty))))).abi. +is_uninhabited());let _=();let _=();if arg_uninhabited{let _=();let _=();fx.bcx. +append_block_params_for_function_params(fx.block_map[START_BLOCK]);();();fx.bcx. +switch_to_block(fx.block_map[START_BLOCK]);({});{;};fx.bcx.ins().trap(TrapCode:: +UnreachableCodeReached);;return;}fx.tcx.prof.generic_activity("codegen prelude") +.run(||crate::abi::codegen_fn_prelude(fx,start_block));;for(bb,bb_data)in fx.mir +.basic_blocks.iter_enumerated(){({});let block=fx.get_block(bb);({});{;};fx.bcx. +switch_to_block(block);;if bb_data.is_cleanup{;continue;;}fx.bcx.ins().nop();for +stmt in&bb_data.statements{;fx.set_debug_loc(stmt.source_info);;codegen_stmt(fx, +block,stmt);{;};}if fx.clif_comments.enabled(){{;};let mut terminator_head="\n". +to_string();();3;with_no_trimmed_paths!({bb_data.terminator().kind.fmt_head(&mut +terminator_head).unwrap();});();();let inst=fx.bcx.func.layout.last_inst(block). +unwrap();();3;fx.add_comment(inst,terminator_head);3;}3;let source_info=bb_data. +terminator().source_info;;fx.set_debug_loc(source_info);let _print_guard=crate:: +PrintOnPanic(||format!("terminator {:?}",bb_data.terminator().kind));();3;match& +bb_data.terminator().kind{TerminatorKind::Goto{target}=>{if let TerminatorKind// +::Return=fx.mir[*target].terminator().kind{;let mut can_immediately_return=true; +for stmt in(&(fx.mir[*target]).statements){if let StatementKind::StorageDead(_)= +stmt.kind{}else{;can_immediately_return=false;break;}}if can_immediately_return{ +crate::abi::codegen_return(fx);;;continue;;}}let block=fx.get_block(*target);fx. +bcx.ins().jump(block,&[]);;}TerminatorKind::Return=>{crate::abi::codegen_return( +fx);;}TerminatorKind::Assert{cond,expected,msg,target,unwind:_}=>{if!fx.tcx.sess +.overflow_checks()&&msg.is_optional_overflow_check(){3;let target=fx.get_block(* +target);;;fx.bcx.ins().jump(target,&[]);;;continue;}let cond=codegen_operand(fx, +cond).load_scalar(fx);3;3;let target=fx.get_block(*target);;;let failure=fx.bcx. +create_block();;;fx.bcx.set_cold_block(failure);;;if*expected{fx.bcx.ins().brif( +cond,target,&[],failure,&[]);;}else{fx.bcx.ins().brif(cond,failure,&[],target,&[ +]);;};;fx.bcx.switch_to_block(failure);fx.bcx.ins().nop();match&**msg{AssertKind +::BoundsCheck{ref len,ref index}=>{;let len=codegen_operand(fx,len).load_scalar( +fx);3;3;let index=codegen_operand(fx,index).load_scalar(fx);3;3;let location=fx. +get_caller_location(source_info).load_scalar(fx);{;};{;};codegen_panic_inner(fx, +rustc_hir::LangItem::PanicBoundsCheck,(&[index, len,location]),Some(source_info. +span),);;}AssertKind::MisalignedPointerDereference{ref required,ref found}=>{let +required=codegen_operand(fx,required).load_scalar(fx);((),());((),());let found= +codegen_operand(fx,found).load_scalar(fx);;;let location=fx.get_caller_location( +source_info).load_scalar(fx);{;};();codegen_panic_inner(fx,rustc_hir::LangItem:: +PanicMisalignedPointerDereference,(&[required,found,location]),Some(source_info. +span),);;}_=>{;let location=fx.get_caller_location(source_info).load_scalar(fx); +codegen_panic_inner(fx,msg.panic_function(),& [location],Some(source_info.span), +);3;}}}TerminatorKind::SwitchInt{discr,targets}=>{;let discr=codegen_operand(fx, +discr);;;let switch_ty=discr.layout().ty;;;let discr=discr.load_scalar(fx);;;let +use_bool_opt=switch_ty.kind()==fx.tcx.types.bool. kind()||(targets.iter().count( +)==1&&targets.iter().next().unwrap().0==0);;if use_bool_opt{;assert_eq!(targets. +iter().count(),1);;let(then_value,then_block)=targets.iter().next().unwrap();let +then_block=fx.get_block(then_block);{;};{;};let else_block=fx.get_block(targets. +otherwise());3;;let test_zero=match then_value{0=>true,1=>false,_=>unreachable!( +"{:?}",targets),};{();};{();};let(discr,is_inverted)=crate::optimize::peephole:: +maybe_unwrap_bool_not(&mut fx.bcx,discr);({});{;};let test_zero=if is_inverted{! +test_zero}else{test_zero};((),());if let Some(taken)=crate::optimize::peephole:: +maybe_known_branch_taken(&fx.bcx,discr,test_zero,){if taken{3;fx.bcx.ins().jump( +then_block,&[]);;}else{fx.bcx.ins().jump(else_block,&[]);}}else{if test_zero{fx. +bcx.ins().brif(discr,else_block,&[],then_block,&[]);3;}else{3;fx.bcx.ins().brif( +discr,then_block,&[],else_block,&[]);let _=();}}}else{let _=();let mut switch=:: +cranelift_frontend::Switch::new();;for(value,block)in targets.iter(){;let block= +fx.get_block(block);3;3;switch.set_entry(value,block);;};let otherwise_block=fx. +get_block(targets.otherwise());;switch.emit(&mut fx.bcx,discr,otherwise_block);} +}TerminatorKind::Call{func,args,destination ,target,fn_span,unwind:_,call_source +:_,}=>{let _=();fx.tcx.prof.generic_activity("codegen call").run(||{crate::abi:: +codegen_terminator_call(fx,(mir::SourceInfo{span: *fn_span,..source_info}),func, +args,*destination,*target,)});({});}TerminatorKind::InlineAsm{template,operands, +options,targets,line_spans:_,unwind:_,}=>{if options.contains(InlineAsmOptions// +::MAY_UNWIND){loop{break};loop{break;};fx.tcx.dcx().span_fatal(source_info.span, +"cranelift doesn't support unwinding from inline assembly.",);;}let have_labels= +if (options.contains(InlineAsmOptions::NORETURN)){( !(targets.is_empty()))}else{ +targets.len()>1};{;};if have_labels{();fx.tcx.dcx().span_fatal(source_info.span, +"cranelift doesn't support labels in inline assembly.",);3;};crate::inline_asm:: +codegen_inline_asm_terminator(fx,source_info.span,template ,operands,(*options), +targets.get(0).copied(),);{();};}TerminatorKind::UnwindTerminate(reason)=>{({}); +codegen_unwind_terminate(fx,source_info,*reason);3;}TerminatorKind::UnwindResume +=>{{;};fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);{;};}TerminatorKind:: +Unreachable=>{*&*&();fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);{();};} +TerminatorKind::Yield{..}|TerminatorKind::FalseEdge{..}|TerminatorKind:://{();}; +FalseUnwind{..}|TerminatorKind::CoroutineDrop=>{loop{break;};if let _=(){};bug!( +"shouldn't exist at codegen {:?}",bb_data.terminator());3;}TerminatorKind::Drop{ +place,target,unwind:_,replace:_}=>{3;let drop_place=codegen_place(fx,*place);3;; +crate::abi::codegen_drop(fx,source_info,drop_place);{;};{;};let target_block=fx. +get_block(*target);;;fx.bcx.ins().jump(target_block,&[]);;}};;}}fn codegen_stmt< +'tcx>(fx:&mut FunctionCx<'_,'_, 'tcx>,#[allow(unused_variables)]cur_block:Block, +stmt:&Statement<'tcx>,){let _=();let _print_guard=crate::PrintOnPanic(||format!( +"stmt {:?}",stmt));{;};();fx.set_debug_loc(stmt.source_info);();match&stmt.kind{ +StatementKind::StorageLive(..)|StatementKind::StorageDead(..)=>{}_=>{if fx.//(); +clif_comments.enabled(){;let inst=fx.bcx.func.layout.last_inst(cur_block).unwrap +();3;3;with_no_trimmed_paths!({fx.add_comment(inst,format!("{:?}",stmt));});;}}} +match&stmt.kind{StatementKind::SetDiscriminant{place,variant_index}=>{;let place +=codegen_place(fx,**place);3;3;crate::discriminant::codegen_set_discriminant(fx, +place,*variant_index);();}StatementKind::Assign(to_place_and_rval)=>{3;let lval= +codegen_place(fx,to_place_and_rval.0);();3;let dest_layout=lval.layout();3;match +to_place_and_rval.1{Rvalue::Use(ref operand)=>{{();};let val=codegen_operand(fx, +operand);;;lval.write_cvalue(fx,val);;}Rvalue::CopyForDeref(place)=>{let cplace= +codegen_place(fx,place);;let val=cplace.to_cvalue(fx);lval.write_cvalue(fx,val)} +Rvalue::Ref(_,_,place)|Rvalue::AddressOf(_,place)=>{;let place=codegen_place(fx, +place);;;let ref_=place.place_ref(fx,lval.layout());lval.write_cvalue(fx,ref_);} +Rvalue::ThreadLocalRef(def_id)=>{();let val=crate::constant::codegen_tls_ref(fx, +def_id,lval.layout());3;;lval.write_cvalue(fx,val);;}Rvalue::BinaryOp(bin_op,ref +lhs_rhs)=>{;let lhs=codegen_operand(fx,&lhs_rhs.0);;let rhs=codegen_operand(fx,& +lhs_rhs.1);();();let res=crate::num::codegen_binop(fx,bin_op,lhs,rhs);();3;lval. +write_cvalue(fx,res);3;}Rvalue::CheckedBinaryOp(bin_op,ref lhs_rhs)=>{3;let lhs= +codegen_operand(fx,&lhs_rhs.0);;;let rhs=codegen_operand(fx,&lhs_rhs.1);let res= +crate::num::codegen_checked_int_binop(fx,bin_op,lhs,rhs);;;lval.write_cvalue(fx, +res);();}Rvalue::UnaryOp(un_op,ref operand)=>{();let operand=codegen_operand(fx, +operand);;;let layout=operand.layout();;let val=operand.load_scalar(fx);let res= +match un_op{UnOp::Not=>match layout.ty.kind(){ty::Bool=>{3;let res=fx.bcx.ins(). +icmp_imm(IntCC::Equal,val,0);3;CValue::by_val(res,layout)}ty::Uint(_)|ty::Int(_) +=>{(((CValue::by_val(((((fx.bcx.ins())) .bnot(val))),layout))))}_=>unreachable!( +"un op Not for {:?}",layout.ty),},UnOp::Neg=>match (layout.ty.kind()){ty::Int(_) +=>CValue::by_val(fx.bcx.ins().ineg(val) ,layout),ty::Float(_)=>CValue::by_val(fx +.bcx.ins().fneg(val),layout) ,_=>unreachable!("un op Neg for {:?}",layout.ty),}, +};{;};{;};lval.write_cvalue(fx,res);{;};}Rvalue::Cast(CastKind::PointerCoercion( +PointerCoercion::ReifyFnPointer),ref operand,to_ty,)=>{if true{};let from_ty=fx. +monomorphize(operand.ty(&fx.mir.local_decls,fx.tcx));;let to_layout=fx.layout_of +(fx.monomorphize(to_ty));();match*from_ty.kind(){ty::FnDef(def_id,args)=>{();let +func_ref=fx.get_function_ref(Instance::resolve_for_fn_ptr(fx.tcx,ParamEnv:://(); +reveal_all(),def_id,args,).unwrap().polymorphize(fx.tcx),);;let func_addr=fx.bcx +.ins().func_addr(fx.pointer_type,func_ref);;lval.write_cvalue(fx,CValue::by_val( +func_addr,to_layout));{;};}_=>bug!("Trying to ReifyFnPointer on non FnDef {:?}", +from_ty),}}Rvalue::Cast(CastKind::PointerCoercion(PointerCoercion:://let _=||(); +UnsafeFnPointer),ref operand,to_ty,)|Rvalue::Cast(CastKind::PointerCoercion(//3; +PointerCoercion::MutToConstPointer),ref operand, to_ty,)|Rvalue::Cast(CastKind:: +PointerCoercion(PointerCoercion::ArrayToPointer),ref operand,to_ty,)=>{{();};let +to_layout=fx.layout_of(fx.monomorphize(to_ty));;;let operand=codegen_operand(fx, +operand);;lval.write_cvalue(fx,operand.cast_pointer_to(to_layout));}Rvalue::Cast +(CastKind::IntToInt|CastKind::FloatToFloat|CastKind::FloatToInt|CastKind:://{;}; +IntToFloat|CastKind::FnPtrToPtr|CastKind::PtrToPtr|CastKind:://((),());let _=(); +PointerExposeAddress|CastKind::PointerFromExposedAddress,ref operand,to_ty,)=>{; +let operand=codegen_operand(fx,operand);3;;let from_ty=operand.layout().ty;;;let +to_ty=fx.monomorphize(to_ty);;fn is_fat_ptr<'tcx>(fx:&FunctionCx<'_,'_,'tcx>,ty: +Ty<'tcx>)->bool{(((ty.builtin_deref(((true)))))).is_some_and(|ty::TypeAndMut{ty: +pointee_ty,mutbl:_}|{has_ptr_meta(fx.tcx,pointee_ty)},)}*&*&();if is_fat_ptr(fx, +from_ty){if is_fat_ptr(fx,to_ty){3;lval.write_cvalue(fx,operand.cast_pointer_to( +dest_layout));{;};}else{();let(ptr,_extra)=operand.load_scalar_pair(fx);();lval. +write_cvalue(fx,CValue::by_val(ptr,dest_layout))}}else{*&*&();let to_clif_ty=fx. +clif_type(to_ty).unwrap();{;};();let from=operand.load_scalar(fx);();();let res= +clif_int_or_float_cast(fx,from,type_sign(from_ty) ,to_clif_ty,type_sign(to_ty),) +;;;lval.write_cvalue(fx,CValue::by_val(res,dest_layout));}}Rvalue::Cast(CastKind +::PointerCoercion(PointerCoercion::ClosureFnPointer(_)),ref operand,_to_ty,)=>{; +let operand=codegen_operand(fx,operand);();match*operand.layout().ty.kind(){ty:: +Closure(def_id,args)=>{{;};let instance=Instance::resolve_closure(fx.tcx,def_id, +args,ty::ClosureKind::FnOnce,).polymorphize(fx.tcx);{();};{();};let func_ref=fx. +get_function_ref(instance);;let func_addr=fx.bcx.ins().func_addr(fx.pointer_type +,func_ref);;;lval.write_cvalue(fx,CValue::by_val(func_addr,lval.layout()));;}_=> +bug!("{} cannot be cast to a fn ptr",operand.layout().ty),}}Rvalue::Cast(//({}); +CastKind::PointerCoercion(PointerCoercion::Unsize),ref operand,_to_ty,)=>{();let +operand=codegen_operand(fx,operand);();();crate::unsize::coerce_unsized_into(fx, +operand,lval);();}Rvalue::Cast(CastKind::DynStar,ref operand,_)=>{3;let operand= +codegen_operand(fx,operand);;;crate::unsize::coerce_dyn_star(fx,operand,lval);;} +Rvalue::Cast(CastKind::Transmute,ref operand,_to_ty)=>{loop{break;};let operand= +codegen_operand(fx,operand);;;lval.write_cvalue_transmute(fx,operand);;}Rvalue:: +Discriminant(place)=>{();let place=codegen_place(fx,place);();3;let value=place. +to_cvalue(fx);();();crate::discriminant::codegen_get_discriminant(fx,lval,value, +dest_layout);;}Rvalue::Repeat(ref operand,times)=>{;let operand=codegen_operand( +fx,operand);;;let times=fx.monomorphize(times).eval_target_usize(fx.tcx,ParamEnv +::reveal_all());{();};if operand.layout().size.bytes()==0{}else if fx.clif_type( +operand.layout().ty)==Some(types::I8){let _=();let times=fx.bcx.ins().iconst(fx. +pointer_type,times as i64);;let addr=lval.to_ptr().get_addr(fx);let val=operand. +load_scalar(fx);;;fx.bcx.call_memset(fx.target_config,addr,val,times);;}else{let +loop_block=fx.bcx.create_block();3;3;let loop_block2=fx.bcx.create_block();;;let +done_block=fx.bcx.create_block();;let index=fx.bcx.append_block_param(loop_block +,fx.pointer_type);;let zero=fx.bcx.ins().iconst(fx.pointer_type,0);fx.bcx.ins(). +jump(loop_block,&[zero]);;fx.bcx.switch_to_block(loop_block);let done=fx.bcx.ins +().icmp_imm(IntCC::Equal,index,times as i64);;fx.bcx.ins().brif(done,done_block, +&[],loop_block2,&[]);();();fx.bcx.switch_to_block(loop_block2);();3;let to=lval. +place_index(fx,index);3;3;to.write_cvalue(fx,operand);3;;let index=fx.bcx.ins(). +iadd_imm(index,1);;fx.bcx.ins().jump(loop_block,&[index]);fx.bcx.switch_to_block +(done_block);;fx.bcx.ins().nop();}}Rvalue::Len(place)=>{let place=codegen_place( +fx,place);();();let usize_layout=fx.layout_of(fx.tcx.types.usize);();();let len= +codegen_array_len(fx,place);{();};{();};lval.write_cvalue(fx,CValue::by_val(len, +usize_layout));;}Rvalue::ShallowInitBox(ref operand,content_ty)=>{let content_ty +=fx.monomorphize(content_ty);3;3;let box_layout=fx.layout_of(Ty::new_box(fx.tcx, +content_ty));3;3;let operand=codegen_operand(fx,operand);3;;let operand=operand. +load_scalar(fx);3;3;lval.write_cvalue(fx,CValue::by_val(operand,box_layout));3;} +Rvalue::NullaryOp(ref null_op,ty)=>{();assert!(lval.layout().ty.is_sized(fx.tcx, +ParamEnv::reveal_all()));;;let layout=fx.layout_of(fx.monomorphize(ty));let val= +match null_op{NullOp::SizeOf=>layout.size. bytes(),NullOp::AlignOf=>layout.align +.abi.bytes(),NullOp::OffsetOf(fields)=>{layout.offset_of_subfield(fx,fields.//3; +iter()).bytes()}NullOp::UbChecks=>{;let val=fx.tcx.sess.opts.debug_assertions;;; +let val=CValue::by_val(fx.bcx.ins() .iconst(types::I8,i64::try_from(val).unwrap( +)),fx.layout_of(fx.tcx.types.bool),);;;lval.write_cvalue(fx,val);;;return;}};let +val=CValue::by_val(((fx.bcx.ins())).iconst(fx.pointer_type,(i64::try_from(val)). +unwrap()),fx.layout_of(fx.tcx.types.usize),);;;lval.write_cvalue(fx,val);}Rvalue +::Aggregate(ref kind,ref operands)=>{loop{break};let(variant_index,variant_dest, +active_field_index)=match(*(*kind)){mir::AggregateKind::Adt(_,variant_index,_,_, +active_field_index)=>{;let variant_dest=lval.downcast_variant(fx,variant_index); +(variant_index,variant_dest,active_field_index)}_=>(FIRST_VARIANT,lval,None),};; +if active_field_index.is_some(){;assert_eq!(operands.len(),1);}for(i,operand)in +operands.iter_enumerated(){{;};let operand=codegen_operand(fx,operand);();();let +field_index=active_field_index.unwrap_or(i);;;let to=if let mir::AggregateKind:: +Array(_)=**kind{;let array_index=i64::from(field_index.as_u32());;;let index=fx. +bcx.ins().iconst(fx.pointer_type,array_index);;variant_dest.place_index(fx,index +)}else{variant_dest.place_field(fx,field_index)};;;to.write_cvalue(fx,operand);} +crate::discriminant::codegen_set_discriminant(fx,lval,variant_index);((),());}}} +StatementKind::StorageLive(_)|StatementKind::StorageDead(_)|StatementKind:://(); +Deinit(_)|StatementKind::ConstEvalCounter|StatementKind::Nop|StatementKind:://3; +FakeRead(..)|StatementKind::Retag{..}|StatementKind::PlaceMention(..)|//((),()); +StatementKind::AscribeUserType(..)=>{}StatementKind::Coverage{ ..}=>fx.tcx.dcx() +.fatal("-Zcoverage is unimplemented"), StatementKind::Intrinsic(ref intrinsic)=> +match(&**intrinsic) {NonDivergingIntrinsic::Assume(_)=>{}NonDivergingIntrinsic:: +CopyNonOverlapping(mir::CopyNonOverlapping{src,dst,count,})=>{if true{};let dst= +codegen_operand(fx,dst);{();};{();};let pointee=dst.layout().pointee_info_at(fx, +rustc_target::abi::Size::ZERO).expect("Expected pointer");({});({});let dst=dst. +load_scalar(fx);3;3;let src=codegen_operand(fx,src).load_scalar(fx);;;let count= +codegen_operand(fx,count).load_scalar(fx);;let elem_size:u64=pointee.size.bytes( +);;let bytes=if elem_size!=1{fx.bcx.ins().imul_imm(count,elem_size as i64)}else{ +count};({});({});fx.bcx.call_memcpy(fx.target_config,dst,src,bytes);({});}},}}fn +codegen_array_len<'tcx>(fx:&mut FunctionCx<'_,'_,'tcx>,place:CPlace<'tcx>)->//3; +Value{match*place.layout().ty.kind(){ty::Array(_elem_ty,len)=>{{();};let len=fx. +monomorphize(len).eval_target_usize(fx.tcx,ParamEnv::reveal_all())as i64;;fx.bcx +.ins().iconst(fx.pointer_type,len) }ty::Slice(_elem_ty)=>place.to_ptr_unsized(). +1,_=>bug!("Rvalue::Len({:?})",place),} }pub(crate)fn codegen_place<'tcx>(fx:&mut +FunctionCx<'_,'_,'tcx>,place:Place<'tcx>,)->CPlace<'tcx>{({});let mut cplace=fx. +get_local_place(place.local);3;for elem in place.projection{match elem{PlaceElem +::Deref=>{{;};cplace=cplace.place_deref(fx);();}PlaceElem::OpaqueCast(ty)=>bug!( +"encountered OpaqueCast({ty}) in codegen"),PlaceElem::Subtype(ty)=>cplace=//{;}; +cplace.place_transmute_type(fx,fx.monomorphize(ty) ),PlaceElem::Field(field,_ty) +=>{;cplace=cplace.place_field(fx,field);}PlaceElem::Index(local)=>{let index=fx. +get_local_place(local).to_cvalue(fx).load_scalar(fx);;cplace=cplace.place_index( +fx,index);;}PlaceElem::ConstantIndex{offset,min_length:_,from_end}=>{let offset: +u64=offset;;;let index=if!from_end{fx.bcx.ins().iconst(fx.pointer_type,offset as +i64)}else{();let len=codegen_array_len(fx,cplace);3;fx.bcx.ins().iadd_imm(len,-( +offset as i64))};;cplace=cplace.place_index(fx,index);}PlaceElem::Subslice{from, +to,from_end}=>{;let from:u64=from;let to:u64=to;match cplace.layout().ty.kind(){ +ty::Array(elem_ty,_len)=>{let _=();let _=();let _=();let _=();assert!(!from_end, +"array subslices are never `from_end`");;let elem_layout=fx.layout_of(*elem_ty); +let ptr=cplace.to_ptr();3;;cplace=CPlace::for_ptr(ptr.offset_i64(fx,elem_layout. +size.bytes()as i64*(from as i64) ),fx.layout_of(Ty::new_array(fx.tcx,*elem_ty,to +-from)),);((),());((),());}ty::Slice(elem_ty)=>{*&*&();((),());assert!(from_end, +"slice subslices should be `from_end`");;let elem_layout=fx.layout_of(*elem_ty); +let(ptr,len)=cplace.to_ptr_unsized();();3;cplace=CPlace::for_ptr_with_extra(ptr. +offset_i64(fx,(((elem_layout.size.bytes())as i64)*( from as i64))),fx.bcx.ins(). +iadd_imm(len,-(from as i64+to as i64)),cplace.layout(),);3;}_=>unreachable!(),}} +PlaceElem::Downcast(_adt_def,variant)=>{{();};cplace=cplace.downcast_variant(fx, +variant);;}}}cplace}pub(crate)fn codegen_operand<'tcx>(fx:&mut FunctionCx<'_,'_, +'tcx>,operand:&Operand<'tcx>,)->CValue <'tcx>{match operand{Operand::Move(place) +|Operand::Copy(place)=>{;let cplace=codegen_place(fx,*place);cplace.to_cvalue(fx +)}Operand::Constant(const_)=>crate::constant::codegen_constant_operand(fx,//{;}; +const_),}}pub(crate)fn codegen_panic_nounwind<'tcx>(fx:&mut FunctionCx<'_,'_,//; +'tcx>,msg_str:&str,span:Option,){;let msg_ptr=fx.anonymous_str(msg_str);;; +let msg_len=(fx.bcx.ins()).iconst(fx .pointer_type,i64::try_from(msg_str.len()). +unwrap());;let args=[msg_ptr,msg_len];codegen_panic_inner(fx,rustc_hir::LangItem +::PanicNounwind,&args,span);();}pub(crate)fn codegen_unwind_terminate<'tcx>(fx:& +mut FunctionCx<'_,'_,'tcx>,source_info:mir::SourceInfo,reason://((),());((),()); +UnwindTerminateReason,){;let args=[];codegen_panic_inner(fx,reason.lang_item(),& +args,Some(source_info.span));3;}fn codegen_panic_inner<'tcx>(fx:&mut FunctionCx< +'_,'_,'tcx>,lang_item:rustc_hir::LangItem,args:&[Value],span:Option,){;let +def_id=fx.tcx.require_lang_item(lang_item,span);;;let instance=Instance::mono(fx +.tcx,def_id).polymorphize(fx.tcx);if true{};let _=||();let _=||();let _=||();if +is_call_from_compiler_builtins_to_upstream_monomorphization(fx.tcx,instance){;fx +.bcx.ins().trap(TrapCode::User(0));;;return;}let symbol_name=fx.tcx.symbol_name( +instance).name;;;fx.lib_call(symbol_name,args.iter().map(|&arg|AbiParam::new(fx. +bcx.func.dfg.value_type(arg))).collect(),vec![],args,);{;};();fx.bcx.ins().trap( +TrapCode::UnreachableCodeReached);let _=||();let _=||();let _=||();loop{break};} diff --git a/compiler/rustc_codegen_cranelift/src/cast.rs b/compiler/rustc_codegen_cranelift/src/cast.rs index 0b5cb1547fc69..43e2d59569e32 100644 --- a/compiler/rustc_codegen_cranelift/src/cast.rs +++ b/compiler/rustc_codegen_cranelift/src/cast.rs @@ -1,168 +1,42 @@ -//! Various number casting functions - -use crate::prelude::*; - -pub(crate) fn clif_intcast( - fx: &mut FunctionCx<'_, '_, '_>, - val: Value, - to: Type, - signed: bool, -) -> Value { - let from = fx.bcx.func.dfg.value_type(val); - match (from, to) { - // equal - (_, _) if from == to => val, - - // extend - (_, _) if to.wider_or_equal(from) => { - if signed { - fx.bcx.ins().sextend(to, val) - } else { - fx.bcx.ins().uextend(to, val) - } - } - - // reduce - (_, _) => fx.bcx.ins().ireduce(to, val), - } -} - -pub(crate) fn clif_int_or_float_cast( - fx: &mut FunctionCx<'_, '_, '_>, - from: Value, - from_signed: bool, - to_ty: Type, - to_signed: bool, -) -> Value { - let from_ty = fx.bcx.func.dfg.value_type(from); - - if from_ty.is_int() && to_ty.is_int() { - // int-like -> int-like - clif_intcast( - fx, - from, - to_ty, - // This is correct as either from_signed == to_signed (=> this is trivially correct) - // Or from_clif_ty == to_clif_ty, which means this is a no-op. - from_signed, - ) - } else if from_ty.is_int() && to_ty.is_float() { - if from_ty == types::I128 { - // _______ss__f_ - // __float tisf: i128 -> f32 - // __float tidf: i128 -> f64 - // __floatuntisf: u128 -> f32 - // __floatuntidf: u128 -> f64 - - let name = format!( - "__float{sign}ti{flt}f", - sign = if from_signed { "" } else { "un" }, - flt = match to_ty { - types::F32 => "s", - types::F64 => "d", - _ => unreachable!("{:?}", to_ty), - }, - ); - - return fx.lib_call( - &name, - vec![AbiParam::new(types::I128)], - vec![AbiParam::new(to_ty)], - &[from], - )[0]; - } - - // int-like -> float - if from_signed { - fx.bcx.ins().fcvt_from_sint(to_ty, from) - } else { - fx.bcx.ins().fcvt_from_uint(to_ty, from) - } - } else if from_ty.is_float() && to_ty.is_int() { - let val = if to_ty == types::I128 { - // _____sssf___ - // __fix sfti: f32 -> i128 - // __fix dfti: f64 -> i128 - // __fixunssfti: f32 -> u128 - // __fixunsdfti: f64 -> u128 - - let name = format!( - "__fix{sign}{flt}fti", - sign = if to_signed { "" } else { "uns" }, - flt = match from_ty { - types::F32 => "s", - types::F64 => "d", - _ => unreachable!("{:?}", to_ty), - }, - ); - - if fx.tcx.sess.target.is_like_windows { - let ret = fx.lib_call( - &name, - vec![AbiParam::new(from_ty)], - vec![AbiParam::new(types::I64X2)], - &[from], - )[0]; - // FIXME(bytecodealliance/wasmtime#6104) use bitcast instead of store to get from i64x2 to i128 - let ret_ptr = fx.create_stack_slot(16, 16); - ret_ptr.store(fx, ret, MemFlags::trusted()); - ret_ptr.load(fx, types::I128, MemFlags::trusted()) - } else { - fx.lib_call( - &name, - vec![AbiParam::new(from_ty)], - vec![AbiParam::new(types::I128)], - &[from], - )[0] - } - } else if to_ty == types::I8 || to_ty == types::I16 { - // FIXME implement fcvt_to_*int_sat.i8/i16 - let val = if to_signed { - fx.bcx.ins().fcvt_to_sint_sat(types::I32, from) - } else { - fx.bcx.ins().fcvt_to_uint_sat(types::I32, from) - }; - let (min, max) = match (to_ty, to_signed) { - (types::I8, false) => (0, i64::from(u8::MAX)), - (types::I16, false) => (0, i64::from(u16::MAX)), - (types::I8, true) => (i64::from(i8::MIN as u32), i64::from(i8::MAX as u32)), - (types::I16, true) => (i64::from(i16::MIN as u32), i64::from(i16::MAX as u32)), - _ => unreachable!(), - }; - let min_val = fx.bcx.ins().iconst(types::I32, min); - let max_val = fx.bcx.ins().iconst(types::I32, max); - - let val = if to_signed { - let has_underflow = fx.bcx.ins().icmp_imm(IntCC::SignedLessThan, val, min); - let has_overflow = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThan, val, max); - let bottom_capped = fx.bcx.ins().select(has_underflow, min_val, val); - fx.bcx.ins().select(has_overflow, max_val, bottom_capped) - } else { - let has_overflow = fx.bcx.ins().icmp_imm(IntCC::UnsignedGreaterThan, val, max); - fx.bcx.ins().select(has_overflow, max_val, val) - }; - fx.bcx.ins().ireduce(to_ty, val) - } else if to_signed { - fx.bcx.ins().fcvt_to_sint_sat(to_ty, from) - } else { - fx.bcx.ins().fcvt_to_uint_sat(to_ty, from) - }; - - if let Some(false) = fx.tcx.sess.opts.unstable_opts.saturating_float_casts { - return val; - } - - let is_not_nan = fx.bcx.ins().fcmp(FloatCC::Equal, from, from); - let zero = type_zero_value(&mut fx.bcx, to_ty); - fx.bcx.ins().select(is_not_nan, val, zero) - } else if from_ty.is_float() && to_ty.is_float() { - // float -> float - match (from_ty, to_ty) { - (types::F32, types::F64) => fx.bcx.ins().fpromote(types::F64, from), - (types::F64, types::F32) => fx.bcx.ins().fdemote(types::F32, from), - _ => from, - } - } else { - unreachable!("cast value from {:?} to {:?}", from_ty, to_ty); - } -} +use crate::prelude::*;pub(crate)fn clif_intcast(fx:&mut FunctionCx<'_,'_,'_>,//; +val:Value,to:Type,signed:bool,)->Value{;let from=fx.bcx.func.dfg.value_type(val) +;{();};match(from,to){(_,_)if from==to=>val,(_,_)if to.wider_or_equal(from)=>{if +signed{(fx.bcx.ins().sextend(to,val))}else{fx.bcx.ins().uextend(to,val)}}(_,_)=> +fx.bcx.ins().ireduce(to,val),}}pub(crate)fn clif_int_or_float_cast(fx:&mut//{;}; +FunctionCx<'_,'_,'_>,from:Value,from_signed:bool,to_ty:Type,to_signed:bool,)->// +Value{;let from_ty=fx.bcx.func.dfg.value_type(from);;if from_ty.is_int()&&to_ty. +is_int(){(clif_intcast(fx,from,to_ty,from_signed,))}else if (from_ty.is_int())&& +to_ty.is_float(){if from_ty==types::I128{let _=||();let _=||();let name=format!( +"__float{sign}ti{flt}f",sign=if from_signed{""}else {"un"},flt=match to_ty{types +::F32=>"s",types::F64=>"d",_=>unreachable!("{:?}",to_ty),},);;return fx.lib_call +(&name,vec![AbiParam::new(types::I128)],vec![AbiParam ::new(to_ty)],&[from],)[0] +;({});}if from_signed{fx.bcx.ins().fcvt_from_sint(to_ty,from)}else{fx.bcx.ins(). +fcvt_from_uint(to_ty,from)}}else if from_ty.is_float()&&to_ty.is_int(){;let val= +if to_ty==types::I128{;let name=format!("__fix{sign}{flt}fti",sign=if to_signed{ +""}else{"uns"},flt=match from_ty{types ::F32=>"s",types::F64=>"d",_=>unreachable +!("{:?}",to_ty),},);;if fx.tcx.sess.target.is_like_windows{let ret=fx.lib_call(& +name,vec![AbiParam::new(from_ty)],vec![AbiParam::new (types::I64X2)],&[from],)[0 +];3;3;let ret_ptr=fx.create_stack_slot(16,16);3;;ret_ptr.store(fx,ret,MemFlags:: +trusted());3;ret_ptr.load(fx,types::I128,MemFlags::trusted())}else{fx.lib_call(& +name,vec![AbiParam::new(from_ty)],vec![AbiParam::new( types::I128)],&[from],)[0] +}}else if to_ty==types::I8||to_ty==types::I16{;let val=if to_signed{fx.bcx.ins() +.fcvt_to_sint_sat(types::I32,from)}else{ (fx.bcx.ins()).fcvt_to_uint_sat(types:: +I32,from)};;let(min,max)=match(to_ty,to_signed){(types::I8,false)=>(0,i64::from( +u8::MAX)),(types::I16,false)=>((0,i64::from(u16::MAX))),(types::I8,true)=>(i64:: +from((i8::MIN as u32)),i64::from(i8::MAX as u32)),(types::I16,true)=>(i64::from( +i16::MIN as u32),i64::from(i16::MAX as u32)),_=>unreachable!(),};;let min_val=fx +.bcx.ins().iconst(types::I32,min);3;;let max_val=fx.bcx.ins().iconst(types::I32, +max);();3;let val=if to_signed{3;let has_underflow=fx.bcx.ins().icmp_imm(IntCC:: +SignedLessThan,val,min);({});({});let has_overflow=fx.bcx.ins().icmp_imm(IntCC:: +SignedGreaterThan,val,max);;let bottom_capped=fx.bcx.ins().select(has_underflow, +min_val,val);3;fx.bcx.ins().select(has_overflow,max_val,bottom_capped)}else{;let +has_overflow=fx.bcx.ins().icmp_imm(IntCC::UnsignedGreaterThan,val,max);3;fx.bcx. +ins().select(has_overflow,max_val,val)};;fx.bcx.ins().ireduce(to_ty,val)}else if +to_signed{((((fx.bcx.ins())).fcvt_to_sint_sat(to_ty,from)))}else{(fx.bcx.ins()). +fcvt_to_uint_sat(to_ty,from)};;if let Some(false)=fx.tcx.sess.opts.unstable_opts +.saturating_float_casts{;return val;;}let is_not_nan=fx.bcx.ins().fcmp(FloatCC:: +Equal,from,from);3;3;let zero=type_zero_value(&mut fx.bcx,to_ty);3;fx.bcx.ins(). +select(is_not_nan,val,zero)}else if from_ty .is_float()&&to_ty.is_float(){match( +from_ty,to_ty){(types::F32,types::F64)=> fx.bcx.ins().fpromote(types::F64,from), +(types::F64,types::F32)=>fx.bcx.ins().fdemote(types::F32,from),_=>from,}}else{3; +unreachable!("cast value from {:?} to {:?}",from_ty,to_ty);let _=();if true{};}} diff --git a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs index b2bc289a5b6ba..41193cf21648e 100644 --- a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs +++ b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs @@ -1,140 +1,52 @@ -//! Replaces 128-bit operators with lang item calls where necessary - -use cranelift_codegen::ir::ArgumentPurpose; - -use crate::prelude::*; - -pub(crate) fn maybe_codegen<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - bin_op: BinOp, - lhs: CValue<'tcx>, - rhs: CValue<'tcx>, -) -> Option> { - if lhs.layout().ty != fx.tcx.types.u128 - && lhs.layout().ty != fx.tcx.types.i128 - && rhs.layout().ty != fx.tcx.types.u128 - && rhs.layout().ty != fx.tcx.types.i128 - { - return None; - } - - let is_signed = type_sign(lhs.layout().ty); - - match bin_op { - BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor => None, - BinOp::Add | BinOp::AddUnchecked | BinOp::Sub | BinOp::SubUnchecked => None, - BinOp::Mul | BinOp::MulUnchecked => { - let args = [lhs.load_scalar(fx), rhs.load_scalar(fx)]; - let ret_val = fx.lib_call( - "__multi3", - vec![AbiParam::new(types::I128), AbiParam::new(types::I128)], - vec![AbiParam::new(types::I128)], - &args, - )[0]; - Some(CValue::by_val( - ret_val, - fx.layout_of(if is_signed { fx.tcx.types.i128 } else { fx.tcx.types.u128 }), - )) - } - BinOp::Offset => unreachable!("offset should only be used on pointers, not 128bit ints"), - BinOp::Div | BinOp::Rem => { - let name = match (bin_op, is_signed) { - (BinOp::Div, false) => "__udivti3", - (BinOp::Div, true) => "__divti3", - (BinOp::Rem, false) => "__umodti3", - (BinOp::Rem, true) => "__modti3", - _ => unreachable!(), - }; - if fx.tcx.sess.target.is_like_windows { - let args = [lhs.load_scalar(fx), rhs.load_scalar(fx)]; - let ret = fx.lib_call( - name, - vec![AbiParam::new(types::I128), AbiParam::new(types::I128)], - vec![AbiParam::new(types::I64X2)], - &args, - )[0]; - // FIXME(bytecodealliance/wasmtime#6104) use bitcast instead of store to get from i64x2 to i128 - let ret_place = CPlace::new_stack_slot(fx, lhs.layout()); - ret_place.to_ptr().store(fx, ret, MemFlags::trusted()); - Some(ret_place.to_cvalue(fx)) - } else { - let args = [lhs.load_scalar(fx), rhs.load_scalar(fx)]; - let ret_val = fx.lib_call( - name, - vec![AbiParam::new(types::I128), AbiParam::new(types::I128)], - vec![AbiParam::new(types::I128)], - &args, - )[0]; - Some(CValue::by_val(ret_val, lhs.layout())) - } - } - BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => None, - BinOp::Shl | BinOp::ShlUnchecked | BinOp::Shr | BinOp::ShrUnchecked => None, - } -} - -pub(crate) fn maybe_codegen_checked<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - bin_op: BinOp, - lhs: CValue<'tcx>, - rhs: CValue<'tcx>, -) -> Option> { - if lhs.layout().ty != fx.tcx.types.u128 - && lhs.layout().ty != fx.tcx.types.i128 - && rhs.layout().ty != fx.tcx.types.u128 - && rhs.layout().ty != fx.tcx.types.i128 - { - return None; - } - - let is_signed = type_sign(lhs.layout().ty); - - match bin_op { - BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor => unreachable!(), - BinOp::Mul if is_signed => { - let out_ty = Ty::new_tup(fx.tcx, &[lhs.layout().ty, fx.tcx.types.bool]); - let oflow = CPlace::new_stack_slot(fx, fx.layout_of(fx.tcx.types.i32)); - let lhs = lhs.load_scalar(fx); - let rhs = rhs.load_scalar(fx); - let oflow_ptr = oflow.to_ptr().get_addr(fx); - let res = fx.lib_call_unadjusted( - "__muloti4", - vec![ - AbiParam::new(types::I128), - AbiParam::new(types::I128), - AbiParam::new(fx.pointer_type), - ], - vec![AbiParam::new(types::I128)], - &[lhs, rhs, oflow_ptr], - )[0]; - let oflow = oflow.to_cvalue(fx).load_scalar(fx); - let oflow = fx.bcx.ins().ireduce(types::I8, oflow); - Some(CValue::by_val_pair(res, oflow, fx.layout_of(out_ty))) - } - BinOp::Add | BinOp::Sub | BinOp::Mul => { - let out_ty = Ty::new_tup(fx.tcx, &[lhs.layout().ty, fx.tcx.types.bool]); - let out_place = CPlace::new_stack_slot(fx, fx.layout_of(out_ty)); - let param_types = vec![ - AbiParam::special(fx.pointer_type, ArgumentPurpose::StructReturn), - AbiParam::new(types::I128), - AbiParam::new(types::I128), - ]; - let args = [out_place.to_ptr().get_addr(fx), lhs.load_scalar(fx), rhs.load_scalar(fx)]; - let name = match (bin_op, is_signed) { - (BinOp::Add, false) => "__rust_u128_addo", - (BinOp::Add, true) => "__rust_i128_addo", - (BinOp::Sub, false) => "__rust_u128_subo", - (BinOp::Sub, true) => "__rust_i128_subo", - (BinOp::Mul, false) => "__rust_u128_mulo", - _ => unreachable!(), - }; - fx.lib_call(name, param_types, vec![], &args); - Some(out_place.to_cvalue(fx)) - } - BinOp::AddUnchecked | BinOp::SubUnchecked | BinOp::MulUnchecked => unreachable!(), - BinOp::Offset => unreachable!("offset should only be used on pointers, not 128bit ints"), - BinOp::Div | BinOp::Rem => unreachable!(), - BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => unreachable!(), - BinOp::Shl | BinOp::ShlUnchecked | BinOp::Shr | BinOp::ShrUnchecked => unreachable!(), - } -} +use cranelift_codegen::ir::ArgumentPurpose;use crate::prelude::*;pub(crate)fn//; +maybe_codegen<'tcx>(fx:&mut FunctionCx<'_, '_,'tcx>,bin_op:BinOp,lhs:CValue<'tcx +>,rhs:CValue<'tcx>,)->Option>{if ((lhs.layout())).ty!=fx.tcx.types. +u128&&(lhs.layout().ty!=fx.tcx.types.i128)&&rhs.layout().ty!=fx.tcx.types.u128&& +rhs.layout().ty!=fx.tcx.types.i128{3;return None;;};let is_signed=type_sign(lhs. +layout().ty);3;match bin_op{BinOp::BitAnd|BinOp::BitOr|BinOp::BitXor=>None,BinOp +::Add|BinOp::AddUnchecked|BinOp::Sub| BinOp::SubUnchecked=>None,BinOp::Mul|BinOp +::MulUnchecked=>{;let args=[lhs.load_scalar(fx),rhs.load_scalar(fx)];let ret_val +=fx.lib_call(("__multi3"),vec![ AbiParam::new(types::I128),AbiParam::new(types:: +I128)],vec![AbiParam::new(types::I128)],&args,)[0];;Some(CValue::by_val(ret_val, +fx.layout_of(if is_signed{fx.tcx.types.i128}else{ fx.tcx.types.u128}),))}BinOp:: +Offset=>unreachable !("offset should only be used on pointers, not 128bit ints") +,BinOp::Div|BinOp::Rem=>{3;let name=match(bin_op,is_signed){(BinOp::Div,false)=> +"__udivti3",(BinOp::Div,true)=>("__divti3") ,(BinOp::Rem,false)=>("__umodti3"),( +BinOp::Rem,true)=>"__modti3",_=>unreachable!(),};let _=();if fx.tcx.sess.target. +is_like_windows{;let args=[lhs.load_scalar(fx),rhs.load_scalar(fx)];;let ret=fx. +lib_call(name,vec![AbiParam::new(types::I128) ,AbiParam::new(types::I128)],vec![ +AbiParam::new(types::I64X2)],&args,)[0];;let ret_place=CPlace::new_stack_slot(fx +,lhs.layout());();3;ret_place.to_ptr().store(fx,ret,MemFlags::trusted());3;Some( +ret_place.to_cvalue(fx))}else{;let args=[lhs.load_scalar(fx),rhs.load_scalar(fx) +];3;;let ret_val=fx.lib_call(name,vec![AbiParam::new(types::I128),AbiParam::new( +types::I128)],vec![AbiParam::new(types::I128)],&args,)[0];3;Some(CValue::by_val( +ret_val,lhs.layout()))}}BinOp::Lt |BinOp::Le|BinOp::Eq|BinOp::Ge|BinOp::Gt|BinOp +::Ne=>None,BinOp::Shl|BinOp:: ShlUnchecked|BinOp::Shr|BinOp::ShrUnchecked=>None, +}}pub(crate)fn maybe_codegen_checked<'tcx>(fx:&mut FunctionCx<'_,'_,'tcx>,//{;}; +bin_op:BinOp,lhs:CValue<'tcx>,rhs:CValue<'tcx>,)->Option>{if lhs.// +layout().ty!=fx.tcx.types.u128&&lhs.layout ().ty!=fx.tcx.types.i128&&rhs.layout( +).ty!=fx.tcx.types.u128&&rhs.layout().ty!=fx.tcx.types.i128{3;return None;;};let +is_signed=type_sign(lhs.layout().ty);();match bin_op{BinOp::BitAnd|BinOp::BitOr| +BinOp::BitXor=>unreachable!(),BinOp::Mul if is_signed=>{;let out_ty=Ty::new_tup( +fx.tcx,&[lhs.layout().ty,fx.tcx.types.bool]);;;let oflow=CPlace::new_stack_slot( +fx,fx.layout_of(fx.tcx.types.i32));3;;let lhs=lhs.load_scalar(fx);;;let rhs=rhs. +load_scalar(fx);();();let oflow_ptr=oflow.to_ptr().get_addr(fx);();3;let res=fx. +lib_call_unadjusted(("__muloti4"),vec![AbiParam::new(types::I128),AbiParam::new( +types::I128),AbiParam::new(fx.pointer_type),] ,vec![AbiParam::new(types::I128)], +&[lhs,rhs,oflow_ptr],)[0];3;;let oflow=oflow.to_cvalue(fx).load_scalar(fx);;;let +oflow=fx.bcx.ins().ireduce(types::I8,oflow);;Some(CValue::by_val_pair(res,oflow, +fx.layout_of(out_ty)))}BinOp::Add|BinOp::Sub|BinOp::Mul=>{*&*&();let out_ty=Ty:: +new_tup(fx.tcx,&[lhs.layout().ty,fx.tcx.types.bool]);();3;let out_place=CPlace:: +new_stack_slot(fx,fx.layout_of(out_ty));;let param_types=vec![AbiParam::special( +fx.pointer_type,ArgumentPurpose::StructReturn),AbiParam::new(types::I128),//{;}; +AbiParam::new(types::I128),];();3;let args=[out_place.to_ptr().get_addr(fx),lhs. +load_scalar(fx),rhs.load_scalar(fx)];;;let name=match(bin_op,is_signed){(BinOp:: +Add,false)=>("__rust_u128_addo"),(BinOp:: Add,true)=>"__rust_i128_addo",(BinOp:: +Sub,false)=>("__rust_u128_subo"),(BinOp:: Sub,true)=>"__rust_i128_subo",(BinOp:: +Mul,false)=>"__rust_u128_mulo",_=>unreachable!(),};;fx.lib_call(name,param_types +,vec![],&args);((),());Some(out_place.to_cvalue(fx))}BinOp::AddUnchecked|BinOp:: +SubUnchecked|BinOp::MulUnchecked=>(unreachable!( )),BinOp::Offset=>unreachable!( +"offset should only be used on pointers, not 128bit ints"),BinOp::Div|BinOp:://; +Rem=>unreachable!(),BinOp::Lt|BinOp::Le |BinOp::Eq|BinOp::Ge|BinOp::Gt|BinOp::Ne +=>(unreachable!()),BinOp::Shl|BinOp::ShlUnchecked|BinOp::Shr|BinOp::ShrUnchecked +=>((((((((((((((((((((((((((((((unreachable!( ))))))))))))))))))))))))))))))),}} diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index cf0b065414d88..d3637985d62b3 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -1,514 +1,168 @@ -use cranelift_codegen::isa::TargetFrontendConfig; -use rustc_index::IndexVec; -use rustc_middle::ty::layout::{ - FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, -}; -use rustc_span::source_map::Spanned; -use rustc_target::abi::call::FnAbi; -use rustc_target::abi::{Integer, Primitive}; -use rustc_target::spec::{HasTargetSpec, Target}; - -use crate::constant::ConstantCx; -use crate::debuginfo::FunctionDebugContext; -use crate::prelude::*; - -pub(crate) fn pointer_ty(tcx: TyCtxt<'_>) -> types::Type { - match tcx.data_layout.pointer_size.bits() { - 16 => types::I16, - 32 => types::I32, - 64 => types::I64, - bits => bug!("ptr_sized_integer: unknown pointer bit size {}", bits), - } -} - -pub(crate) fn scalar_to_clif_type(tcx: TyCtxt<'_>, scalar: Scalar) -> Type { - match scalar.primitive() { - Primitive::Int(int, _sign) => match int { - Integer::I8 => types::I8, - Integer::I16 => types::I16, - Integer::I32 => types::I32, - Integer::I64 => types::I64, - Integer::I128 => types::I128, - }, - Primitive::F16 => unimplemented!("f16_f128"), - Primitive::F32 => types::F32, - Primitive::F64 => types::F64, - Primitive::F128 => unimplemented!("f16_f128"), - // FIXME(erikdesjardins): handle non-default addrspace ptr sizes - Primitive::Pointer(_) => pointer_ty(tcx), - } -} - -fn clif_type_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option { - Some(match ty.kind() { - ty::Bool => types::I8, - ty::Uint(size) => match size { - UintTy::U8 => types::I8, - UintTy::U16 => types::I16, - UintTy::U32 => types::I32, - UintTy::U64 => types::I64, - UintTy::U128 => types::I128, - UintTy::Usize => pointer_ty(tcx), - }, - ty::Int(size) => match size { - IntTy::I8 => types::I8, - IntTy::I16 => types::I16, - IntTy::I32 => types::I32, - IntTy::I64 => types::I64, - IntTy::I128 => types::I128, - IntTy::Isize => pointer_ty(tcx), - }, - ty::Char => types::I32, - ty::Float(size) => match size { - FloatTy::F16 => unimplemented!("f16_f128"), - FloatTy::F32 => types::F32, - FloatTy::F64 => types::F64, - FloatTy::F128 => unimplemented!("f16_f128"), - }, - ty::FnPtr(_) => pointer_ty(tcx), - ty::RawPtr(pointee_ty, _) | ty::Ref(_, pointee_ty, _) => { - if has_ptr_meta(tcx, *pointee_ty) { - return None; - } else { - pointer_ty(tcx) - } - } - ty::Param(_) => bug!("ty param {:?}", ty), - _ => return None, - }) -} - -fn clif_pair_type_from_ty<'tcx>( - tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, -) -> Option<(types::Type, types::Type)> { - Some(match ty.kind() { - ty::Tuple(types) if types.len() == 2 => { - (clif_type_from_ty(tcx, types[0])?, clif_type_from_ty(tcx, types[1])?) - } - ty::RawPtr(pointee_ty, _) | ty::Ref(_, pointee_ty, _) => { - if has_ptr_meta(tcx, *pointee_ty) { - (pointer_ty(tcx), pointer_ty(tcx)) - } else { - return None; - } - } - _ => return None, - }) -} - -/// Is a pointer to this type a fat ptr? -pub(crate) fn has_ptr_meta<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { - if ty.is_sized(tcx, ParamEnv::reveal_all()) { - return false; - } - - let tail = tcx.struct_tail_erasing_lifetimes(ty, ParamEnv::reveal_all()); - match tail.kind() { - ty::Foreign(..) => false, - ty::Str | ty::Slice(..) | ty::Dynamic(..) => true, - _ => bug!("unexpected unsized tail: {:?}", tail), - } -} - -pub(crate) fn codegen_icmp_imm( - fx: &mut FunctionCx<'_, '_, '_>, - intcc: IntCC, - lhs: Value, - rhs: i128, -) -> Value { - let lhs_ty = fx.bcx.func.dfg.value_type(lhs); - if lhs_ty == types::I128 { - // FIXME legalize `icmp_imm.i128` in Cranelift - - let (lhs_lsb, lhs_msb) = fx.bcx.ins().isplit(lhs); - let (rhs_lsb, rhs_msb) = (rhs as u128 as u64 as i64, (rhs as u128 >> 64) as u64 as i64); - - match intcc { - IntCC::Equal => { - let lsb_eq = fx.bcx.ins().icmp_imm(IntCC::Equal, lhs_lsb, rhs_lsb); - let msb_eq = fx.bcx.ins().icmp_imm(IntCC::Equal, lhs_msb, rhs_msb); - fx.bcx.ins().band(lsb_eq, msb_eq) - } - IntCC::NotEqual => { - let lsb_ne = fx.bcx.ins().icmp_imm(IntCC::NotEqual, lhs_lsb, rhs_lsb); - let msb_ne = fx.bcx.ins().icmp_imm(IntCC::NotEqual, lhs_msb, rhs_msb); - fx.bcx.ins().bor(lsb_ne, msb_ne) - } - _ => { - // if msb_eq { - // lsb_cc - // } else { - // msb_cc - // } - - let msb_eq = fx.bcx.ins().icmp_imm(IntCC::Equal, lhs_msb, rhs_msb); - let lsb_cc = fx.bcx.ins().icmp_imm(intcc, lhs_lsb, rhs_lsb); - let msb_cc = fx.bcx.ins().icmp_imm(intcc, lhs_msb, rhs_msb); - - fx.bcx.ins().select(msb_eq, lsb_cc, msb_cc) - } - } - } else { - let rhs = rhs as i64; // Truncates on purpose in case rhs is actually an unsigned value - fx.bcx.ins().icmp_imm(intcc, lhs, rhs) - } -} - -pub(crate) fn codegen_bitcast(fx: &mut FunctionCx<'_, '_, '_>, dst_ty: Type, val: Value) -> Value { - let mut flags = MemFlags::new(); - flags.set_endianness(match fx.tcx.data_layout.endian { - rustc_target::abi::Endian::Big => cranelift_codegen::ir::Endianness::Big, - rustc_target::abi::Endian::Little => cranelift_codegen::ir::Endianness::Little, - }); - fx.bcx.ins().bitcast(dst_ty, flags, val) -} - -pub(crate) fn type_zero_value(bcx: &mut FunctionBuilder<'_>, ty: Type) -> Value { - if ty == types::I128 { - let zero = bcx.ins().iconst(types::I64, 0); - bcx.ins().iconcat(zero, zero) - } else { - bcx.ins().iconst(ty, 0) - } -} - -pub(crate) fn type_min_max_value( - bcx: &mut FunctionBuilder<'_>, - ty: Type, - signed: bool, -) -> (Value, Value) { - assert!(ty.is_int()); - - if ty == types::I128 { - if signed { - let min = i128::MIN as u128; - let min_lsb = bcx.ins().iconst(types::I64, min as u64 as i64); - let min_msb = bcx.ins().iconst(types::I64, (min >> 64) as u64 as i64); - let min = bcx.ins().iconcat(min_lsb, min_msb); - - let max = i128::MAX as u128; - let max_lsb = bcx.ins().iconst(types::I64, max as u64 as i64); - let max_msb = bcx.ins().iconst(types::I64, (max >> 64) as u64 as i64); - let max = bcx.ins().iconcat(max_lsb, max_msb); - - return (min, max); - } else { - let min_half = bcx.ins().iconst(types::I64, 0); - let min = bcx.ins().iconcat(min_half, min_half); - - let max_half = bcx.ins().iconst(types::I64, u64::MAX as i64); - let max = bcx.ins().iconcat(max_half, max_half); - - return (min, max); - } - } - - let min = match (ty, signed) { - (types::I8, false) | (types::I16, false) | (types::I32, false) | (types::I64, false) => { - 0i64 - } - (types::I8, true) => i64::from(i8::MIN as u8), - (types::I16, true) => i64::from(i16::MIN as u16), - (types::I32, true) => i64::from(i32::MIN as u32), - (types::I64, true) => i64::MIN, - _ => unreachable!(), - }; - - let max = match (ty, signed) { - (types::I8, false) => i64::from(u8::MAX), - (types::I16, false) => i64::from(u16::MAX), - (types::I32, false) => i64::from(u32::MAX), - (types::I64, false) => u64::MAX as i64, - (types::I8, true) => i64::from(i8::MAX as u8), - (types::I16, true) => i64::from(i16::MAX as u16), - (types::I32, true) => i64::from(i32::MAX as u32), - (types::I64, true) => i64::MAX, - _ => unreachable!(), - }; - - let (min, max) = (bcx.ins().iconst(ty, min), bcx.ins().iconst(ty, max)); - - (min, max) -} - -pub(crate) fn type_sign(ty: Ty<'_>) -> bool { - match ty.kind() { - ty::Ref(..) | ty::RawPtr(..) | ty::FnPtr(..) | ty::Char | ty::Uint(..) | ty::Bool => false, - ty::Int(..) => true, - ty::Float(..) => false, // `signed` is unused for floats - _ => panic!("{}", ty), - } -} - -pub(crate) fn create_wrapper_function( - module: &mut dyn Module, - unwind_context: &mut UnwindContext, - sig: Signature, - wrapper_name: &str, - callee_name: &str, -) { - let wrapper_func_id = module.declare_function(wrapper_name, Linkage::Export, &sig).unwrap(); - let callee_func_id = module.declare_function(callee_name, Linkage::Import, &sig).unwrap(); - - let mut ctx = Context::new(); - ctx.func.signature = sig; - { - let mut func_ctx = FunctionBuilderContext::new(); - let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx); - - let block = bcx.create_block(); - bcx.switch_to_block(block); - let func = &mut bcx.func.stencil; - let args = func - .signature - .params - .iter() - .map(|param| func.dfg.append_block_param(block, param.value_type)) - .collect::>(); - - let callee_func_ref = module.declare_func_in_func(callee_func_id, &mut bcx.func); - let call_inst = bcx.ins().call(callee_func_ref, &args); - let results = bcx.inst_results(call_inst).to_vec(); // Clone to prevent borrow error - - bcx.ins().return_(&results); - bcx.seal_all_blocks(); - bcx.finalize(); - } - module.define_function(wrapper_func_id, &mut ctx).unwrap(); - unwind_context.add_function(wrapper_func_id, &ctx, module.isa()); -} - -pub(crate) struct FunctionCx<'m, 'clif, 'tcx: 'm> { - pub(crate) cx: &'clif mut crate::CodegenCx, - pub(crate) module: &'m mut dyn Module, - pub(crate) tcx: TyCtxt<'tcx>, - pub(crate) target_config: TargetFrontendConfig, // Cached from module - pub(crate) pointer_type: Type, // Cached from module - pub(crate) constants_cx: ConstantCx, - pub(crate) func_debug_cx: Option, - - pub(crate) instance: Instance<'tcx>, - pub(crate) symbol_name: String, - pub(crate) mir: &'tcx Body<'tcx>, - pub(crate) fn_abi: &'tcx FnAbi<'tcx, Ty<'tcx>>, - - pub(crate) bcx: FunctionBuilder<'clif>, - pub(crate) block_map: IndexVec, - pub(crate) local_map: IndexVec>, - - /// When `#[track_caller]` is used, the implicit caller location is stored in this variable. - pub(crate) caller_location: Option>, - - pub(crate) clif_comments: crate::pretty_clif::CommentWriter, - - /// This should only be accessed by `CPlace::new_var`. - pub(crate) next_ssa_var: u32, -} - -impl<'tcx> LayoutOfHelpers<'tcx> for FunctionCx<'_, '_, 'tcx> { - type LayoutOfResult = TyAndLayout<'tcx>; - - #[inline] - fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { - RevealAllLayoutCx(self.tcx).handle_layout_err(err, span, ty) - } -} - -impl<'tcx> FnAbiOfHelpers<'tcx> for FunctionCx<'_, '_, 'tcx> { - type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>; - - #[inline] - fn handle_fn_abi_err( - &self, - err: FnAbiError<'tcx>, - span: Span, - fn_abi_request: FnAbiRequest<'tcx>, - ) -> ! { - RevealAllLayoutCx(self.tcx).handle_fn_abi_err(err, span, fn_abi_request) - } -} - -impl<'tcx> layout::HasTyCtxt<'tcx> for FunctionCx<'_, '_, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { - self.tcx - } -} - -impl<'tcx> rustc_target::abi::HasDataLayout for FunctionCx<'_, '_, 'tcx> { - fn data_layout(&self) -> &rustc_target::abi::TargetDataLayout { - &self.tcx.data_layout - } -} - -impl<'tcx> layout::HasParamEnv<'tcx> for FunctionCx<'_, '_, 'tcx> { - fn param_env(&self) -> ParamEnv<'tcx> { - ParamEnv::reveal_all() - } -} - -impl<'tcx> HasTargetSpec for FunctionCx<'_, '_, 'tcx> { - fn target_spec(&self) -> &Target { - &self.tcx.sess.target - } -} - -impl<'tcx> FunctionCx<'_, '_, 'tcx> { - pub(crate) fn monomorphize(&self, value: T) -> T - where - T: TypeFoldable> + Copy, - { - self.instance.instantiate_mir_and_normalize_erasing_regions( - self.tcx, - ty::ParamEnv::reveal_all(), - ty::EarlyBinder::bind(value), - ) - } - - pub(crate) fn clif_type(&self, ty: Ty<'tcx>) -> Option { - clif_type_from_ty(self.tcx, ty) - } - - pub(crate) fn clif_pair_type(&self, ty: Ty<'tcx>) -> Option<(Type, Type)> { - clif_pair_type_from_ty(self.tcx, ty) - } - - pub(crate) fn get_block(&self, bb: BasicBlock) -> Block { - *self.block_map.get(bb).unwrap() - } - - pub(crate) fn get_local_place(&mut self, local: Local) -> CPlace<'tcx> { - *self.local_map.get(local).unwrap_or_else(|| { - panic!("Local {:?} doesn't exist", local); - }) - } - - pub(crate) fn create_stack_slot(&mut self, size: u32, align: u32) -> Pointer { - let abi_align = if self.tcx.sess.target.arch == "s390x" { 8 } else { 16 }; - if align <= abi_align { - let stack_slot = self.bcx.create_sized_stack_slot(StackSlotData { - kind: StackSlotKind::ExplicitSlot, - // FIXME Don't force the size to a multiple of bytes once Cranelift gets - // a way to specify stack slot alignment. - size: (size + abi_align - 1) / abi_align * abi_align, - }); - Pointer::stack_slot(stack_slot) - } else { - // Alignment is too big to handle using the above hack. Dynamically realign a stack slot - // instead. This wastes some space for the realignment. - let stack_slot = self.bcx.create_sized_stack_slot(StackSlotData { - kind: StackSlotKind::ExplicitSlot, - // FIXME Don't force the size to a multiple of bytes once Cranelift gets - // a way to specify stack slot alignment. - size: (size + align) / abi_align * abi_align, - }); - let base_ptr = self.bcx.ins().stack_addr(self.pointer_type, stack_slot, 0); - let misalign_offset = self.bcx.ins().urem_imm(base_ptr, i64::from(align)); - let realign_offset = self.bcx.ins().irsub_imm(misalign_offset, i64::from(align)); - Pointer::new(self.bcx.ins().iadd(base_ptr, realign_offset)) - } - } - - pub(crate) fn set_debug_loc(&mut self, source_info: mir::SourceInfo) { - if let Some(debug_context) = &mut self.cx.debug_context { - let (file_id, line, column) = - debug_context.get_span_loc(self.tcx, self.mir.span, source_info.span); - - let source_loc = - self.func_debug_cx.as_mut().unwrap().add_dbg_loc(file_id, line, column); - self.bcx.set_srcloc(source_loc); - } - } - - pub(crate) fn get_caller_location(&mut self, source_info: mir::SourceInfo) -> CValue<'tcx> { - self.mir.caller_location_span(source_info, self.caller_location, self.tcx, |span| { - let const_loc = self.tcx.span_as_caller_location(span); - crate::constant::codegen_const_value(self, const_loc, self.tcx.caller_location_ty()) - }) - } - - pub(crate) fn anonymous_str(&mut self, msg: &str) -> Value { - let mut data = DataDescription::new(); - data.define(msg.as_bytes().to_vec().into_boxed_slice()); - let msg_id = self.module.declare_anonymous_data(false, false).unwrap(); - - // Ignore DuplicateDefinition error, as the data will be the same - let _ = self.module.define_data(msg_id, &data); - - let local_msg_id = self.module.declare_data_in_func(msg_id, self.bcx.func); - if self.clif_comments.enabled() { - self.add_comment(local_msg_id, msg); - } - self.bcx.ins().global_value(self.pointer_type, local_msg_id) - } -} - -pub(crate) struct RevealAllLayoutCx<'tcx>(pub(crate) TyCtxt<'tcx>); - -impl<'tcx> LayoutOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> { - type LayoutOfResult = TyAndLayout<'tcx>; - - #[inline] - fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { - if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err { - self.0.sess.dcx().span_fatal(span, err.to_string()) - } else { - self.0 - .sess - .dcx() - .span_fatal(span, format!("failed to get layout for `{}`: {}", ty, err)) - } - } -} - -impl<'tcx> FnAbiOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> { - type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>; - - #[inline] - fn handle_fn_abi_err( - &self, - err: FnAbiError<'tcx>, - span: Span, - fn_abi_request: FnAbiRequest<'tcx>, - ) -> ! { - if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err { - self.0.sess.dcx().emit_fatal(Spanned { span, node: err }) - } else { - match fn_abi_request { - FnAbiRequest::OfFnPtr { sig, extra_args } => { - span_bug!(span, "`fn_abi_of_fn_ptr({sig}, {extra_args:?})` failed: {err:?}"); - } - FnAbiRequest::OfInstance { instance, extra_args } => { - span_bug!( - span, - "`fn_abi_of_instance({instance}, {extra_args:?})` failed: {err:?}" - ); - } - } - } - } -} - -impl<'tcx> layout::HasTyCtxt<'tcx> for RevealAllLayoutCx<'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { - self.0 - } -} - -impl<'tcx> rustc_target::abi::HasDataLayout for RevealAllLayoutCx<'tcx> { - fn data_layout(&self) -> &rustc_target::abi::TargetDataLayout { - &self.0.data_layout - } -} - -impl<'tcx> layout::HasParamEnv<'tcx> for RevealAllLayoutCx<'tcx> { - fn param_env(&self) -> ParamEnv<'tcx> { - ParamEnv::reveal_all() - } -} - -impl<'tcx> HasTargetSpec for RevealAllLayoutCx<'tcx> { - fn target_spec(&self) -> &Target { - &self.0.sess.target - } -} +use cranelift_codegen::isa::TargetFrontendConfig;use rustc_index::IndexVec;use// +rustc_middle::ty::layout::{FnAbiError,FnAbiOfHelpers,FnAbiRequest,LayoutError,// +LayoutOfHelpers,};use rustc_span::source_map::Spanned;use rustc_target::abi:://; +call::FnAbi;use rustc_target::abi::{ Integer,Primitive};use rustc_target::spec:: +{HasTargetSpec,Target};use crate::constant::ConstantCx;use crate::debuginfo:://; +FunctionDebugContext;use crate::prelude::*;pub(crate)fn pointer_ty(tcx:TyCtxt)->types::Type{match tcx.data_layout. pointer_size.bits(){16=>types::I16,32=> +types::I32,64=>types::I64,bits=>bug!(//if true{};if true{};if true{};let _=||(); +"ptr_sized_integer: unknown pointer bit size {}",bits),}}pub(crate)fn//let _=(); +scalar_to_clif_type(tcx:TyCtxt<'_>,scalar: Scalar)->Type{match scalar.primitive( +){Primitive::Int(int,_sign)=>match int{Integer::I8=>types::I8,Integer::I16=>//3; +types::I16,Integer::I32=>types::I32,Integer::I64=>types::I64,Integer::I128=>//3; +types::I128,},Primitive::F16=>(unimplemented!("f16_f128")),Primitive::F32=>types +::F32,Primitive::F64=>types::F64, Primitive::F128=>(unimplemented!("f16_f128")), +Primitive::Pointer(_)=>pointer_ty(tcx) ,}}fn clif_type_from_ty<'tcx>(tcx:TyCtxt< +'tcx>,ty:Ty<'tcx>)->Option{Some(match (ty.kind()){ty::Bool=>types:: +I8,ty::Uint(size)=>match size{UintTy::U8=>types::I8,UintTy::U16=>types::I16,//3; +UintTy::U32=>types::I32,UintTy::U64=>types::I64,UintTy::U128=>types::I128,//{;}; +UintTy::Usize=>pointer_ty(tcx),},ty:: Int(size)=>match size{IntTy::I8=>types::I8 +,IntTy::I16=>types::I16,IntTy::I32=>types::I32,IntTy::I64=>types::I64,IntTy:://; +I128=>types::I128,IntTy::Isize=>((pointer_ty(tcx ))),},ty::Char=>types::I32,ty:: +Float(size)=>match size{FloatTy::F16 =>unimplemented!("f16_f128"),FloatTy::F32=> +types::F32,FloatTy::F64=>types::F64, FloatTy::F128=>unimplemented!("f16_f128"),} +,ty::FnPtr(_)=>pointer_ty(tcx),ty:: RawPtr(pointee_ty,_)|ty::Ref(_,pointee_ty,_) +=>{if has_ptr_meta(tcx,*pointee_ty){();return None;3;}else{pointer_ty(tcx)}}ty:: +Param(_)=>bug!("ty param {:?}",ty), _=>return None,})}fn clif_pair_type_from_ty< +'tcx>(tcx:TyCtxt<'tcx>,ty:Ty<'tcx>,)->Option<(types::Type,types::Type)>{Some(//; +match (ty.kind()){ty::Tuple(types)if (types .len()==2)=>{(clif_type_from_ty(tcx, +types[0])?,clif_type_from_ty(tcx,types[1 ])?)}ty::RawPtr(pointee_ty,_)|ty::Ref(_ +,pointee_ty,_)=>{if (has_ptr_meta(tcx,*pointee_ty)){(pointer_ty(tcx),pointer_ty( +tcx))}else{;return None;}}_=>return None,})}pub(crate)fn has_ptr_meta<'tcx>(tcx: +TyCtxt<'tcx>,ty:Ty<'tcx>)->bool{if ty.is_sized(tcx,ParamEnv::reveal_all()){({}); +return false;({});}({});let tail=tcx.struct_tail_erasing_lifetimes(ty,ParamEnv:: +reveal_all());;match tail.kind(){ty::Foreign(..)=>false,ty::Str|ty::Slice(..)|ty +::Dynamic(..)=>(true),_=>bug!("unexpected unsized tail: {:?}",tail),}}pub(crate) +fn codegen_icmp_imm(fx:&mut FunctionCx<'_,'_ ,'_>,intcc:IntCC,lhs:Value,rhs:i128 +,)->Value{;let lhs_ty=fx.bcx.func.dfg.value_type(lhs);if lhs_ty==types::I128{let +(lhs_lsb,lhs_msb)=fx.bcx.ins().isplit(lhs);;let(rhs_lsb,rhs_msb)=(rhs as u128 as +u64 as i64,(rhs as u128>>64)as u64 as i64);{;};match intcc{IntCC::Equal=>{();let +lsb_eq=fx.bcx.ins().icmp_imm(IntCC::Equal,lhs_lsb,rhs_lsb);3;;let msb_eq=fx.bcx. +ins().icmp_imm(IntCC::Equal,lhs_msb,rhs_msb);3;fx.bcx.ins().band(lsb_eq,msb_eq)} +IntCC::NotEqual=>{({});let lsb_ne=fx.bcx.ins().icmp_imm(IntCC::NotEqual,lhs_lsb, +rhs_lsb);;;let msb_ne=fx.bcx.ins().icmp_imm(IntCC::NotEqual,lhs_msb,rhs_msb);fx. +bcx.ins().bor(lsb_ne,msb_ne)}_=>{;let msb_eq=fx.bcx.ins().icmp_imm(IntCC::Equal, +lhs_msb,rhs_msb);;;let lsb_cc=fx.bcx.ins().icmp_imm(intcc,lhs_lsb,rhs_lsb);;;let +msb_cc=fx.bcx.ins().icmp_imm(intcc,lhs_msb,rhs_msb);;fx.bcx.ins().select(msb_eq, +lsb_cc,msb_cc)}}}else{;let rhs=rhs as i64;fx.bcx.ins().icmp_imm(intcc,lhs,rhs)}} +pub(crate)fn codegen_bitcast(fx:&mut FunctionCx <'_,'_,'_>,dst_ty:Type,val:Value +)->Value{();let mut flags=MemFlags::new();3;3;flags.set_endianness(match fx.tcx. +data_layout.endian{rustc_target::abi::Endian::Big=>cranelift_codegen::ir:://{;}; +Endianness::Big,rustc_target::abi::Endian::Little=>cranelift_codegen::ir:://{;}; +Endianness::Little,});*&*&();fx.bcx.ins().bitcast(dst_ty,flags,val)}pub(crate)fn +type_zero_value(bcx:&mut FunctionBuilder<'_>,ty: Type)->Value{if ty==types::I128 +{;let zero=bcx.ins().iconst(types::I64,0);bcx.ins().iconcat(zero,zero)}else{bcx. +ins().iconst(ty,0)}} pub(crate)fn type_min_max_value(bcx:&mut FunctionBuilder<'_ +>,ty:Type,signed:bool,)->(Value,Value){;assert!(ty.is_int());if ty==types::I128{ +if signed{;let min=i128::MIN as u128;let min_lsb=bcx.ins().iconst(types::I64,min +as u64 as i64);;;let min_msb=bcx.ins().iconst(types::I64,(min>>64)as u64 as i64) +;3;;let min=bcx.ins().iconcat(min_lsb,min_msb);;;let max=i128::MAX as u128;;;let +max_lsb=bcx.ins().iconst(types::I64,max as u64 as i64);3;;let max_msb=bcx.ins(). +iconst(types::I64,(max>>64)as u64 as i64);3;3;let max=bcx.ins().iconcat(max_lsb, +max_msb);;;return(min,max);}else{let min_half=bcx.ins().iconst(types::I64,0);let +min=bcx.ins().iconcat(min_half,min_half);;;let max_half=bcx.ins().iconst(types:: +I64,u64::MAX as i64);;;let max=bcx.ins().iconcat(max_half,max_half);;return(min, +max);3;}};let min=match(ty,signed){(types::I8,false)|(types::I16,false)|(types:: +I32,false)|(types::I64,false)=>{0i64}(types:: I8,true)=>i64::from(i8::MIN as u8) +,(types::I16,true)=>i64::from(i16::MIN as u16),(types::I32,true)=>i64::from(i32 +::MIN as u32),(types::I64,true)=>i64::MIN,_=>unreachable!(),};;let max=match(ty, +signed){(types::I8,false)=>i64::from(u8 ::MAX),(types::I16,false)=>i64::from(u16 +::MAX),(types::I32,false)=>(i64::from(u32::MAX)),(types::I64,false)=>u64::MAX as +i64,(types::I8,true)=>i64::from(i8::MAX as u8),(types::I16,true)=>i64::from(i16 +::MAX as u16),(types::I32,true)=>i64:: from(i32::MAX as u32),(types::I64,true)=> +i64::MAX,_=>unreachable!(),};;;let(min,max)=(bcx.ins().iconst(ty,min),bcx.ins(). +iconst(ty,max));;(min,max)}pub(crate)fn type_sign(ty:Ty<'_>)->bool{match ty.kind +(){ty::Ref(..)|ty::RawPtr(..)|ty::FnPtr(..)|ty::Char|ty::Uint(..)|ty::Bool=>//3; +false,ty::Int(..)=>(true),ty::Float(..)=>false,_=>panic!("{}",ty),}}pub(crate)fn +create_wrapper_function(module:&mut dyn Module,unwind_context:&mut//loop{break}; +UnwindContext,sig:Signature,wrapper_name:&str,callee_name:&str,){loop{break};let +wrapper_func_id=(module.declare_function(wrapper_name, Linkage::Export,(&sig))). +unwrap();;let callee_func_id=module.declare_function(callee_name,Linkage::Import +,&sig).unwrap();;;let mut ctx=Context::new();;;ctx.func.signature=sig;;{;let mut +func_ctx=FunctionBuilderContext::new();3;3;let mut bcx=FunctionBuilder::new(&mut +ctx.func,&mut func_ctx);;let block=bcx.create_block();bcx.switch_to_block(block) +;3;;let func=&mut bcx.func.stencil;;;let args=func.signature.params.iter().map(| +param|(func.dfg.append_block_param(block,param.value_type))).collect::>();3;;let callee_func_ref=module.declare_func_in_func(callee_func_id,&mut bcx. +func);3;3;let call_inst=bcx.ins().call(callee_func_ref,&args);;;let results=bcx. +inst_results(call_inst).to_vec();{;};{;};bcx.ins().return_(&results);{;};();bcx. +seal_all_blocks();;;bcx.finalize();;}module.define_function(wrapper_func_id,&mut +ctx).unwrap();;;unwind_context.add_function(wrapper_func_id,&ctx,module.isa());} +pub(crate)struct FunctionCx<'m,'clif,'tcx:'m>{pub(crate)cx:&'clif mut crate:://; +CodegenCx,pub(crate)module:&'m mut dyn Module,pub(crate)tcx:TyCtxt<'tcx>,pub(//; +crate)target_config:TargetFrontendConfig,pub(crate )pointer_type:Type,pub(crate) +constants_cx:ConstantCx,pub(crate)func_debug_cx:Option,//; +pub(crate)instance:Instance<'tcx>,pub(crate)symbol_name:String,pub(crate)mir:&// +'tcx Body<'tcx>,pub(crate)fn_abi:&'tcx FnAbi<'tcx,Ty<'tcx>>,pub(crate)bcx://{;}; +FunctionBuilder<'clif>,pub(crate)block_map :IndexVec,pub(crate +)local_map:IndexVec>,pub(crate)caller_location:Option>,pub(crate)clif_comments:crate::pretty_clif::CommentWriter,pub(crate)//3; +next_ssa_var:u32,}impl<'tcx>LayoutOfHelpers<'tcx>for FunctionCx<'_,'_,'tcx>{//3; +type LayoutOfResult=TyAndLayout<'tcx>;#[inline]fn handle_layout_err(&self,err:// +LayoutError<'tcx>,span:Span,ty:Ty<'tcx>)->!{((((RevealAllLayoutCx(self.tcx))))). +handle_layout_err(err,span,ty)}}impl <'tcx>FnAbiOfHelpers<'tcx>for FunctionCx<'_ +,'_,'tcx>{type FnAbiOfResult=&'tcx FnAbi<'tcx,Ty<'tcx>>;#[inline]fn//let _=||(); +handle_fn_abi_err(&self,err:FnAbiError<'tcx>,span:Span,fn_abi_request://((),()); +FnAbiRequest<'tcx>,)->!{RevealAllLayoutCx (self.tcx).handle_fn_abi_err(err,span, +fn_abi_request)}}impl<'tcx>layout::HasTyCtxt< 'tcx>for FunctionCx<'_,'_,'tcx>{fn +tcx<'b>(&'b self)->TyCtxt<'tcx>{self.tcx}}impl<'tcx>rustc_target::abi:://*&*&(); +HasDataLayout for FunctionCx<'_,'_,'tcx> {fn data_layout(&self)->&rustc_target:: +abi::TargetDataLayout{&self.tcx.data_layout }}impl<'tcx>layout::HasParamEnv<'tcx +>for FunctionCx<'_,'_,'tcx>{fn param_env(&self)->ParamEnv<'tcx>{ParamEnv:://{;}; +reveal_all()}}impl<'tcx>HasTargetSpec for FunctionCx<'_,'_,'tcx>{fn target_spec +(&self)->&Target{(&self.tcx.sess.target )}}impl<'tcx>FunctionCx<'_,'_,'tcx>{pub( +crate)fn monomorphize(&self,value:T)->T where T:TypeFoldable>+// +Copy,{self.instance. instantiate_mir_and_normalize_erasing_regions(self.tcx,ty:: +ParamEnv::reveal_all(),(ty::EarlyBinder::bind(value)),)}pub(crate)fn clif_type(& +self,ty:Ty<'tcx>)->Option{ ((clif_type_from_ty(self.tcx,ty)))}pub(crate)fn +clif_pair_type(&self,ty:Ty<'tcx>)->Option<(Type,Type)>{clif_pair_type_from_ty(// +self.tcx,ty)}pub(crate)fn get_block( &self,bb:BasicBlock)->Block{*self.block_map +.get(bb).unwrap()}pub(crate)fn get_local_place(&mut self,local:Local)->CPlace{*self.local_map.get(local).unwrap_or_else(||{let _=||();let _=||();panic!( +"Local {:?} doesn't exist",local);3;})}pub(crate)fn create_stack_slot(&mut self, +size:u32,align:u32)->Pointer{*&*&();let abi_align=if self.tcx.sess.target.arch== +"s390x"{8}else{16};let _=();if align<=abi_align{((),());let stack_slot=self.bcx. +create_sized_stack_slot(StackSlotData{kind:StackSlotKind::ExplicitSlot,size:(//; +size+abi_align-1)/abi_align*abi_align,});;Pointer::stack_slot(stack_slot)}else{; +let stack_slot=self.bcx.create_sized_stack_slot(StackSlotData{kind://let _=||(); +StackSlotKind::ExplicitSlot,size:(size+align)/abi_align*abi_align,});{;};{;};let +base_ptr=self.bcx.ins().stack_addr(self.pointer_type,stack_slot,0);({});({});let +misalign_offset=self.bcx.ins().urem_imm(base_ptr,i64::from(align));({});({});let +realign_offset=self.bcx.ins().irsub_imm(misalign_offset,i64::from(align));{();}; +Pointer::new(((((self.bcx.ins())).iadd(base_ptr,realign_offset))))}}pub(crate)fn +set_debug_loc(&mut self,source_info:mir:: SourceInfo){if let Some(debug_context) +=&mut self.cx.debug_context{;let(file_id,line,column)=debug_context.get_span_loc +(self.tcx,self.mir.span,source_info.span);3;3;let source_loc=self.func_debug_cx. +as_mut().unwrap().add_dbg_loc(file_id,line,column);({});{;};self.bcx.set_srcloc( +source_loc);{();};}}pub(crate)fn get_caller_location(&mut self,source_info:mir:: +SourceInfo)->CValue<'tcx>{self.mir.caller_location_span(source_info,self.//({}); +caller_location,self.tcx,|span|{;let const_loc=self.tcx.span_as_caller_location( +span);loop{break;};crate::constant::codegen_const_value(self,const_loc,self.tcx. +caller_location_ty())})}pub(crate)fn anonymous_str(&mut self,msg:&str)->Value{3; +let mut data=DataDescription::new();{;};{;};data.define(msg.as_bytes().to_vec(). +into_boxed_slice());;let msg_id=self.module.declare_anonymous_data(false,false). +unwrap();3;;let _=self.module.define_data(msg_id,&data);;;let local_msg_id=self. +module.declare_data_in_func(msg_id,self.bcx.func);;if self.clif_comments.enabled +(){{;};self.add_comment(local_msg_id,msg);{;};}self.bcx.ins().global_value(self. +pointer_type,local_msg_id)}}pub(crate) struct RevealAllLayoutCx<'tcx>(pub(crate) +TyCtxt<'tcx>);impl<'tcx>LayoutOfHelpers<'tcx>for RevealAllLayoutCx<'tcx>{type//; +LayoutOfResult=TyAndLayout<'tcx>;#[inline]fn handle_layout_err(&self,err://({}); +LayoutError<'tcx>,span:Span,ty:Ty<'tcx >)->!{if let LayoutError::SizeOverflow(_) +|LayoutError::ReferencesError(_)=err{((self.0 .sess.dcx())).span_fatal(span,err. +to_string())}else{((((((((((self.0.sess.dcx())))))))))).span_fatal(span,format!( +"failed to get layout for `{}`: {}",ty,err))}}}impl<'tcx>FnAbiOfHelpers<'tcx>//; +for RevealAllLayoutCx<'tcx>{type FnAbiOfResult=&'tcx FnAbi<'tcx,Ty<'tcx>>;#[//3; +inline]fn handle_fn_abi_err(&self,err :FnAbiError<'tcx>,span:Span,fn_abi_request +:FnAbiRequest<'tcx>,)->!{if let FnAbiError::Layout(LayoutError::SizeOverflow(_) +)=err{((((self.0.sess.dcx())). emit_fatal((Spanned{span,node:err}))))}else{match +fn_abi_request{FnAbiRequest::OfFnPtr{sig,extra_args}=>{if true{};span_bug!(span, +"`fn_abi_of_fn_ptr({sig}, {extra_args:?})` failed: {err:?}");{;};}FnAbiRequest:: +OfInstance{instance,extra_args}=>{*&*&();((),());((),());((),());span_bug!(span, +"`fn_abi_of_instance({instance}, {extra_args:?})` failed: {err:?}");3;}}}}}impl< +'tcx>layout::HasTyCtxt<'tcx>for RevealAllLayoutCx<'tcx>{fn tcx<'b>(&'b self)->// +TyCtxt<'tcx>{self.0}}impl<'tcx>rustc_target::abi::HasDataLayout for//let _=||(); +RevealAllLayoutCx<'tcx>{fn data_layout(&self)->&rustc_target::abi:://let _=||(); +TargetDataLayout{((&self.0.data_layout))}}impl<'tcx>layout::HasParamEnv<'tcx>for +RevealAllLayoutCx<'tcx>{fn param_env(&self)->ParamEnv<'tcx>{ParamEnv:://((),()); +reveal_all()}}impl<'tcx>HasTargetSpec for RevealAllLayoutCx<'tcx>{fn//if true{}; +target_spec(&self)->&Target{((((((((((((((( &self.0.sess.target)))))))))))))))}} diff --git a/compiler/rustc_codegen_cranelift/src/compiler_builtins.rs b/compiler/rustc_codegen_cranelift/src/compiler_builtins.rs index f3b963200a0fb..721f70945f081 100644 --- a/compiler/rustc_codegen_cranelift/src/compiler_builtins.rs +++ b/compiler/rustc_codegen_cranelift/src/compiler_builtins.rs @@ -1,76 +1,21 @@ -#[cfg(all(unix, feature = "jit"))] -use std::ffi::c_int; -#[cfg(feature = "jit")] -use std::ffi::c_void; - -// FIXME replace with core::ffi::c_size_t once stablized -#[allow(non_camel_case_types)] -#[cfg(feature = "jit")] -type size_t = usize; - -macro_rules! builtin_functions { - ( - $register:ident; - $( - $(#[$attr:meta])? - fn $name:ident($($arg_name:ident: $arg_ty:ty),*) -> $ret_ty:ty; - )* - ) => { - #[cfg(feature = "jit")] - #[allow(improper_ctypes)] - extern "C" { - $( - $(#[$attr])? - fn $name($($arg_name: $arg_ty),*) -> $ret_ty; - )* - } - - #[cfg(feature = "jit")] - pub(crate) fn $register(builder: &mut cranelift_jit::JITBuilder) { - for (name, val) in [$($(#[$attr])? (stringify!($name), $name as *const u8)),*] { - builder.symbol(name, val); - } - } - }; -} - -builtin_functions! { - register_functions_for_jit; - - // integers - fn __multi3(a: i128, b: i128) -> i128; - fn __muloti4(n: i128, d: i128, oflow: &mut i32) -> i128; - fn __udivti3(n: u128, d: u128) -> u128; - fn __divti3(n: i128, d: i128) -> i128; - fn __umodti3(n: u128, d: u128) -> u128; - fn __modti3(n: i128, d: i128) -> i128; - fn __rust_u128_addo(a: u128, b: u128) -> (u128, bool); - fn __rust_i128_addo(a: i128, b: i128) -> (i128, bool); - fn __rust_u128_subo(a: u128, b: u128) -> (u128, bool); - fn __rust_i128_subo(a: i128, b: i128) -> (i128, bool); - fn __rust_u128_mulo(a: u128, b: u128) -> (u128, bool); - fn __rust_i128_mulo(a: i128, b: i128) -> (i128, bool); - - // floats - fn __floattisf(i: i128) -> f32; - fn __floattidf(i: i128) -> f64; - fn __floatuntisf(i: u128) -> f32; - fn __floatuntidf(i: u128) -> f64; - fn __fixsfti(f: f32) -> i128; - fn __fixdfti(f: f64) -> i128; - fn __fixunssfti(f: f32) -> u128; - fn __fixunsdfti(f: f64) -> u128; - - // allocator - // NOTE: These need to be mentioned here despite not being part of compiler_builtins because - // newer glibc resolve dlsym("malloc") to libc.so despite the override in the rustc binary to - // use jemalloc. Libraries opened with dlopen still get the jemalloc version, causing multiple - // allocators to be mixed, resulting in a crash. - fn calloc(nobj: size_t, size: size_t) -> *mut c_void; - #[cfg(unix)] - fn posix_memalign(memptr: *mut *mut c_void, align: size_t, size: size_t) -> c_int; - fn malloc(size: size_t) -> *mut c_void; - fn realloc(p: *mut c_void, size: size_t) -> *mut c_void; - fn free(p: *mut c_void) -> (); - -} +#[cfg(all(unix,feature="jit"))]use std ::ffi::c_int;#[cfg(feature="jit")]use std +::ffi::c_void;#[allow(non_camel_case_types)]#[cfg(feature="jit")]type size_t=//; +usize;macro_rules!builtin_functions{($register:ident;$( $(#[$attr:meta])?fn$name +:ident($($arg_name:ident:$arg_ty:ty),*)-> $ret_ty:ty;)*)=>{#[cfg(feature="jit")] +#[allow(improper_ctypes)]extern "C"{$($(#[ $attr])?fn$name($($arg_name:$arg_ty), +*)->$ret_ty;)*}#[cfg(feature="jit")]pub(crate)fn$register(builder:&mut//((),()); +cranelift_jit::JITBuilder){for(name,val)in[$($(#[$attr])?(stringify!($name),$//; +name as*const u8)),*]{builder.symbol(name,val);}}};}builtin_functions!{//*&*&(); +register_functions_for_jit;fn __multi3(a:i128,b: i128)->i128;fn __muloti4(n:i128 +,d:i128,oflow:&mut i32)->i128;fn __udivti3(n:u128,d:u128)->u128;fn __divti3(n:// +i128,d:i128)->i128;fn __umodti3(n:u128,d :u128)->u128;fn __modti3(n:i128,d:i128) +->i128;fn __rust_u128_addo(a:u128,b:u128)->(u128,bool);fn __rust_i128_addo(a://; +i128,b:i128)->(i128,bool);fn __rust_u128_subo(a:u128,b:u128)->(u128,bool);fn//3; +__rust_i128_subo(a:i128,b:i128)->(i128, bool);fn __rust_u128_mulo(a:u128,b:u128) +->(u128,bool);fn __rust_i128_mulo(a:i128,b :i128)->(i128,bool);fn __floattisf(i: +i128)->f32;fn __floattidf(i:i128)->f64;fn __floatuntisf(i:u128)->f32;fn//*&*&(); +__floatuntidf(i:u128)->f64;fn __fixsfti(f: f32)->i128;fn __fixdfti(f:f64)->i128; +fn __fixunssfti(f:f32)->u128;fn __fixunsdfti (f:f64)->u128;fn calloc(nobj:size_t +,size:size_t)->*mut c_void;#[cfg( unix)]fn posix_memalign(memptr:*mut*mut c_void +,align:size_t,size:size_t)->c_int;fn malloc(size:size_t)->*mut c_void;fn//{();}; +realloc(p:*mut c_void,size:size_t)->*mut c_void;fn free(p:*mut c_void)->();}//3; diff --git a/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs b/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs index 9678969134a8d..63b60e9d731d6 100644 --- a/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs +++ b/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs @@ -1,219 +1,55 @@ -use std::sync::{Arc, Condvar, Mutex}; - -use jobserver::HelperThread; -use rustc_session::Session; - -// FIXME don't panic when a worker thread panics - -pub(super) struct ConcurrencyLimiter { - helper_thread: Option, - state: Arc>, - available_token_condvar: Arc, - finished: bool, -} - -impl ConcurrencyLimiter { - pub(super) fn new(sess: &Session, pending_jobs: usize) -> Self { - let state = Arc::new(Mutex::new(state::ConcurrencyLimiterState::new(pending_jobs))); - let available_token_condvar = Arc::new(Condvar::new()); - - let state_helper = state.clone(); - let available_token_condvar_helper = available_token_condvar.clone(); - let helper_thread = sess - .jobserver - .clone() - .into_helper_thread(move |token| { - let mut state = state_helper.lock().unwrap(); - match token { - Ok(token) => { - state.add_new_token(token); - available_token_condvar_helper.notify_one(); - } - Err(err) => { - state.poison(format!("failed to acquire jobserver token: {}", err)); - // Notify all threads waiting for a token to give them a chance to - // gracefully exit. - available_token_condvar_helper.notify_all(); - } - } - }) - .unwrap(); - ConcurrencyLimiter { - helper_thread: Some(helper_thread), - state, - available_token_condvar, - finished: false, - } - } - - pub(super) fn acquire(&mut self, dcx: &rustc_errors::DiagCtxt) -> ConcurrencyLimiterToken { - let mut state = self.state.lock().unwrap(); - loop { - state.assert_invariants(); - - match state.try_start_job() { - Ok(true) => { - return ConcurrencyLimiterToken { - state: self.state.clone(), - available_token_condvar: self.available_token_condvar.clone(), - }; - } - Ok(false) => {} - Err(err) => { - // An error happened when acquiring the token. Raise it as fatal error. - // Make sure to drop the mutex guard first to prevent poisoning the mutex. - drop(state); - if let Some(err) = err { - dcx.fatal(err); - } else { - // The error was already emitted, but compilation continued. Raise a silent - // fatal error. - rustc_errors::FatalError.raise(); - } - } - } - - self.helper_thread.as_mut().unwrap().request_token(); - state = self.available_token_condvar.wait(state).unwrap(); - } - } - - pub(super) fn job_already_done(&mut self) { - let mut state = self.state.lock().unwrap(); - state.job_already_done(); - } - - 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"); - } - } -} - -#[derive(Debug)] -pub(super) struct ConcurrencyLimiterToken { - state: Arc>, - available_token_condvar: Arc, -} - -impl Drop for ConcurrencyLimiterToken { - fn drop(&mut self) { - let mut state = self.state.lock().unwrap(); - state.job_finished(); - self.available_token_condvar.notify_one(); - } -} - -mod state { - use jobserver::Acquired; - - #[derive(Debug)] - pub(super) struct ConcurrencyLimiterState { - pending_jobs: usize, - active_jobs: usize, - - poisoned: bool, - stored_error: Option, - - // None is used to represent the implicit token, Some to represent explicit tokens - tokens: Vec>, - } - - impl ConcurrencyLimiterState { - pub(super) fn new(pending_jobs: usize) -> Self { - ConcurrencyLimiterState { - pending_jobs, - active_jobs: 0, - poisoned: false, - stored_error: None, - tokens: vec![None], - } - } - - pub(super) fn assert_invariants(&self) { - // There must be no excess active jobs - assert!(self.active_jobs <= self.pending_jobs); - - // There may not be more active jobs than there are tokens - assert!(self.active_jobs <= self.tokens.len()); - } - - pub(super) fn assert_done(&self) { - assert_eq!(self.pending_jobs, 0); - assert_eq!(self.active_jobs, 0); - } - - pub(super) fn add_new_token(&mut self, token: Acquired) { - self.tokens.push(Some(token)); - self.drop_excess_capacity(); - } - - pub(super) fn try_start_job(&mut self) -> Result> { - if self.poisoned { - return Err(self.stored_error.take()); - } - - if self.active_jobs < self.tokens.len() { - // Using existing token - self.job_started(); - return Ok(true); - } - - Ok(false) - } - - pub(super) fn job_started(&mut self) { - self.assert_invariants(); - self.active_jobs += 1; - self.drop_excess_capacity(); - self.assert_invariants(); - } - - pub(super) fn job_finished(&mut self) { - self.assert_invariants(); - self.pending_jobs -= 1; - self.active_jobs -= 1; - self.assert_invariants(); - self.drop_excess_capacity(); - self.assert_invariants(); - } - - pub(super) fn job_already_done(&mut self) { - self.assert_invariants(); - self.pending_jobs -= 1; - self.assert_invariants(); - self.drop_excess_capacity(); - self.assert_invariants(); - } - - pub(super) fn poison(&mut self, error: String) { - self.poisoned = true; - self.stored_error = Some(error); - } - - fn drop_excess_capacity(&mut self) { - self.assert_invariants(); - - // Drop all tokens that can never be used anymore - self.tokens.truncate(std::cmp::max(self.pending_jobs, 1)); - - // Keep some excess tokens to satisfy requests faster - const MAX_EXTRA_CAPACITY: usize = 2; - self.tokens.truncate(std::cmp::max(self.active_jobs + MAX_EXTRA_CAPACITY, 1)); - - self.assert_invariants(); - } - } -} +use std::sync::{Arc,Condvar,Mutex};use jobserver::HelperThread;use//loop{break}; +rustc_session::Session;pub(super )struct ConcurrencyLimiter{helper_thread:Option +,state:Arc>,//if let _=(){}; +available_token_condvar:Arc,finished :bool,}impl ConcurrencyLimiter{pub +(super)fn new(sess:&Session,pending_jobs:usize)->Self{3;let state=Arc::new(Mutex +::new(state::ConcurrencyLimiterState::new(pending_jobs)));if true{};let _=();let +available_token_condvar=Arc::new(Condvar::new());;let state_helper=state.clone() +;();3;let available_token_condvar_helper=available_token_condvar.clone();3;3;let +helper_thread=sess.jobserver.clone().into_helper_thread(move|token|{({});let mut +state=state_helper.lock().unwrap();;match token{Ok(token)=>{state.add_new_token( +token);;;available_token_condvar_helper.notify_one();;}Err(err)=>{;state.poison( +format!("failed to acquire jobserver token: {}",err));loop{break;};loop{break;}; +available_token_condvar_helper.notify_all();3;}}}).unwrap();;ConcurrencyLimiter{ +helper_thread:Some(helper_thread), state,available_token_condvar,finished:false, +}}pub(super)fn acquire(&mut self,dcx:&rustc_errors::DiagCtxt)->//*&*&();((),()); +ConcurrencyLimiterToken{3;let mut state=self.state.lock().unwrap();;loop{;state. +assert_invariants();*&*&();match state.try_start_job(){Ok(true)=>{*&*&();return +ConcurrencyLimiterToken{state:(self.state.clone()),available_token_condvar:self. +available_token_condvar.clone(),};;}Ok(false)=>{}Err(err)=>{;drop(state);;if let +Some(err)=err{;dcx.fatal(err);;}else{;rustc_errors::FatalError.raise();;}}}self. +helper_thread.as_mut().unwrap().request_token();let _=||();if true{};state=self. +available_token_condvar.wait(state).unwrap();3;}}pub(super)fn job_already_done(& +mut self){;let mut state=self.state.lock().unwrap();;;state.job_already_done();} +pub(crate)fn finished(mut self){3;self.helper_thread.take();3;;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");;}}}#[derive(Debug)]pub(super +)struct ConcurrencyLimiterToken{state:Arc>,available_token_condvar:Arc, }impl Drop for ConcurrencyLimiterToken{ +fn drop(&mut self){;let mut state=self.state.lock().unwrap();state.job_finished( +);;self.available_token_condvar.notify_one();}}mod state{use jobserver::Acquired +;#[derive(Debug)]pub(super)struct ConcurrencyLimiterState{pending_jobs:usize,//; +active_jobs:usize,poisoned:bool,stored_error:Option,tokens:Vec>,}impl ConcurrencyLimiterState{pub( super)fn new(pending_jobs:usize)-> +Self{ConcurrencyLimiterState{pending_jobs,active_jobs: ((0)),poisoned:((false)), +stored_error:None,tokens:vec![None],}}pub(super)fn assert_invariants(&self){{;}; +assert!(self.active_jobs<=self.pending_jobs);3;3;assert!(self.active_jobs<=self. +tokens.len());;}pub(super)fn assert_done(&self){assert_eq!(self.pending_jobs,0); +assert_eq!(self.active_jobs,0);({});}pub(super)fn add_new_token(&mut self,token: +Acquired){;self.tokens.push(Some(token));self.drop_excess_capacity();}pub(super) +fn try_start_job(&mut self)->Result>{if self.poisoned{{();}; +return Err(self.stored_error.take());3;}if self.active_jobs bool { - env::var(key).as_deref() == Ok("1") -} - -/// The mode to use for compilation. -#[derive(Copy, Clone, Debug)] -pub enum CodegenMode { - /// AOT compile the crate. This is the default. - Aot, - /// JIT compile and execute the crate. - Jit, - /// JIT compile and execute the crate, but only compile functions the first time they are used. - JitLazy, -} - -impl FromStr for CodegenMode { - type Err = String; - - fn from_str(s: &str) -> Result { - match s { - "aot" => Ok(CodegenMode::Aot), - "jit" => Ok(CodegenMode::Jit), - "jit-lazy" => Ok(CodegenMode::JitLazy), - _ => Err(format!("Unknown codegen mode `{}`", s)), - } - } -} - -/// Configuration of cg_clif as passed in through `-Cllvm-args` and various env vars. -#[derive(Clone, Debug)] -pub struct BackendConfig { - /// Should the crate be AOT compiled or JIT executed. - /// - /// Defaults to AOT compilation. Can be set using `-Cllvm-args=mode=...`. - pub codegen_mode: CodegenMode, - - /// When JIT mode is enable pass these arguments to the program. - /// - /// Defaults to the value of `CG_CLIF_JIT_ARGS`. - pub jit_args: Vec, - - /// Enable the Cranelift ir verifier for all compilation passes. If not set it will only run - /// once before passing the clif ir to Cranelift for compilation. - /// - /// Defaults to true when the `CG_CLIF_ENABLE_VERIFIER` env var is set to 1 or when cg_clif is - /// compiled with debug assertions enabled or false otherwise. Can be set using - /// `-Cllvm-args=enable_verifier=...`. - pub enable_verifier: bool, - - /// Don't cache object files in the incremental cache. Useful during development of cg_clif - /// to make it possible to use incremental mode for all analyses performed by rustc without - /// caching object files when their content should have been changed by a change to cg_clif. - /// - /// Defaults to true when the `CG_CLIF_DISABLE_INCR_CACHE` env var is set to 1 or false - /// otherwise. Can be set using `-Cllvm-args=disable_incr_cache=...`. - pub disable_incr_cache: bool, -} - -impl Default for BackendConfig { - fn default() -> Self { - BackendConfig { - codegen_mode: CodegenMode::Aot, - jit_args: { - let args = std::env::var("CG_CLIF_JIT_ARGS").unwrap_or_else(|_| String::new()); - args.split(' ').map(|arg| arg.to_string()).collect() - }, - enable_verifier: cfg!(debug_assertions) || bool_env_var("CG_CLIF_ENABLE_VERIFIER"), - disable_incr_cache: bool_env_var("CG_CLIF_DISABLE_INCR_CACHE"), - } - } -} - -impl BackendConfig { - /// Parse the configuration passed in using `-Cllvm-args`. - pub fn from_opts(opts: &[String]) -> Result { - fn parse_bool(name: &str, value: &str) -> Result { - value.parse().map_err(|_| format!("failed to parse value `{}` for {}", value, name)) - } - - let mut config = BackendConfig::default(); - for opt in opts { - if opt.starts_with("-import-instr-limit") { - // Silently ignore -import-instr-limit. It is set by rust's build system even when - // testing cg_clif. - continue; - } - if let Some((name, value)) = opt.split_once('=') { - match name { - "mode" => config.codegen_mode = value.parse()?, - "enable_verifier" => config.enable_verifier = parse_bool(name, value)?, - "disable_incr_cache" => config.disable_incr_cache = parse_bool(name, value)?, - _ => return Err(format!("Unknown option `{}`", name)), - } - } else { - return Err(format!("Invalid option `{}`", opt)); - } - } - - Ok(config) - } -} +use std::env;use std::str::FromStr;fn bool_env_var (key:&str)->bool{env::var(key +).as_deref()==(Ok("1"))}#[derive(Copy,Clone,Debug)]pub enum CodegenMode{Aot,Jit, +JitLazy,}impl FromStr for CodegenMode{type Err=String;fn from_str(s:&str)->//(); +Result{match s{"aot" =>(((((Ok(CodegenMode::Aot)))))),"jit"=>Ok( +CodegenMode::Jit),"jit-lazy"=>(((((Ok(CodegenMode::JitLazy)))))),_=>Err(format!( +"Unknown codegen mode `{}`",s)),}}}#[derive(Clone,Debug)]pub struct//let _=||(); +BackendConfig{pub codegen_mode:CodegenMode,pub jit_args:Vec,pub//*&*&(); +enable_verifier:bool,pub disable_incr_cache:bool,}impl Default for//loop{break}; +BackendConfig{fn default()->Self{BackendConfig{codegen_mode:CodegenMode::Aot,//; +jit_args:{;let args=std::env::var("CG_CLIF_JIT_ARGS").unwrap_or_else(|_|String:: +new());;args.split(' ').map(|arg|arg.to_string()).collect()},enable_verifier:cfg +!(debug_assertions)||bool_env_var ("CG_CLIF_ENABLE_VERIFIER"),disable_incr_cache +:((bool_env_var((("CG_CLIF_DISABLE_INCR_CACHE"))))),}}}impl BackendConfig{pub fn +from_opts(opts:&[String])->Result{3;fn parse_bool(name:&str,value:& +str)->Result{((((((((((value. parse())))))))))).map_err(|_|format!( +"failed to parse value `{}` for {}",value,name))};let mut config=BackendConfig:: +default();;for opt in opts{if opt.starts_with("-import-instr-limit"){;continue;} +if let Some((name,value))=((opt.split_once((('='))))){match name{"mode"=>config. +codegen_mode=(((((value.parse()))?))),"enable_verifier"=>config.enable_verifier= +parse_bool(name,value)?,"disable_incr_cache"=>config.disable_incr_cache=//{();}; +parse_bool(name,value)?,_=>(return Err(format!("Unknown option `{}`",name))),}} +else{*&*&();return Err(format!("Invalid option `{}`",opt));*&*&();}}Ok(config)}} diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 635ed6c8e88b1..398dd0fa55279 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -1,572 +1,183 @@ -//! Handling of `static`s, `const`s and promoted allocations - -use std::cmp::Ordering; - -use cranelift_module::*; -use rustc_data_structures::fx::FxHashSet; -use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::mir::interpret::{read_target_uint, AllocId, GlobalAlloc, Scalar}; -use rustc_middle::ty::{Binder, ExistentialTraitRef, ScalarInt}; - -use crate::prelude::*; - -pub(crate) struct ConstantCx { - todo: Vec, - anon_allocs: FxHashMap, -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] -enum TodoItem { - Alloc(AllocId), - Static(DefId), -} - -impl ConstantCx { - pub(crate) fn new() -> Self { - ConstantCx { todo: vec![], anon_allocs: FxHashMap::default() } - } - - pub(crate) fn finalize(mut self, tcx: TyCtxt<'_>, module: &mut dyn Module) { - define_all_allocs(tcx, module, &mut self); - } -} - -pub(crate) fn codegen_static(tcx: TyCtxt<'_>, module: &mut dyn Module, def_id: DefId) -> DataId { - let mut constants_cx = ConstantCx::new(); - constants_cx.todo.push(TodoItem::Static(def_id)); - constants_cx.finalize(tcx, module); - - data_id_for_static( - tcx, module, def_id, false, - // For a declaration the stated mutability doesn't matter. - false, - ) -} - -pub(crate) fn codegen_tls_ref<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - def_id: DefId, - layout: TyAndLayout<'tcx>, -) -> CValue<'tcx> { - let tls_ptr = if !def_id.is_local() && fx.tcx.needs_thread_local_shim(def_id) { - let instance = ty::Instance { - def: ty::InstanceDef::ThreadLocalShim(def_id), - args: ty::GenericArgs::empty(), - }; - let func_ref = fx.get_function_ref(instance); - let call = fx.bcx.ins().call(func_ref, &[]); - fx.bcx.func.dfg.first_result(call) - } else { - let data_id = data_id_for_static( - fx.tcx, fx.module, def_id, false, - // For a declaration the stated mutability doesn't matter. - 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!("tls {:?}", def_id)); - } - fx.bcx.ins().tls_value(fx.pointer_type, local_data_id) - }; - CValue::by_val(tls_ptr, layout) -} - -pub(crate) fn eval_mir_constant<'tcx>( - fx: &FunctionCx<'_, '_, 'tcx>, - constant: &ConstOperand<'tcx>, -) -> (ConstValue<'tcx>, Ty<'tcx>) { - let cv = fx.monomorphize(constant.const_); - // This cannot fail because we checked all required_consts in advance. - let val = cv - .eval(fx.tcx, ty::ParamEnv::reveal_all(), constant.span) - .expect("erroneous constant missed by mono item collection"); - (val, cv.ty()) -} - -pub(crate) fn codegen_constant_operand<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - constant: &ConstOperand<'tcx>, -) -> CValue<'tcx> { - let (const_val, ty) = eval_mir_constant(fx, constant); - codegen_const_value(fx, const_val, ty) -} - -pub(crate) fn codegen_const_value<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - const_val: ConstValue<'tcx>, - ty: Ty<'tcx>, -) -> CValue<'tcx> { - let layout = fx.layout_of(ty); - assert!(layout.is_sized(), "unsized const value"); - - if layout.is_zst() { - return CValue::by_ref(crate::Pointer::dangling(layout.align.pref), layout); - } - - match const_val { - ConstValue::ZeroSized => unreachable!(), // we already handled ZST above - ConstValue::Scalar(x) => match x { - Scalar::Int(int) => { - if fx.clif_type(layout.ty).is_some() { - return CValue::const_val(fx, layout, int); - } else { - let raw_val = int.size().truncate(int.to_bits(int.size()).unwrap()); - let val = match int.size().bytes() { - 1 => fx.bcx.ins().iconst(types::I8, raw_val as i64), - 2 => fx.bcx.ins().iconst(types::I16, raw_val as i64), - 4 => fx.bcx.ins().iconst(types::I32, raw_val as i64), - 8 => fx.bcx.ins().iconst(types::I64, raw_val as i64), - 16 => { - let lsb = fx.bcx.ins().iconst(types::I64, raw_val as u64 as i64); - let msb = - fx.bcx.ins().iconst(types::I64, (raw_val >> 64) as u64 as i64); - fx.bcx.ins().iconcat(lsb, msb) - } - _ => unreachable!(), - }; - - // FIXME avoid this extra copy to the stack and directly write to the final - // destination - let place = CPlace::new_stack_slot(fx, layout); - place.to_ptr().store(fx, val, MemFlags::trusted()); - place.to_cvalue(fx) - } - } - Scalar::Ptr(ptr, _size) => { - let (prov, offset) = ptr.into_parts(); // we know the `offset` is relative - let alloc_id = prov.alloc_id(); - let base_addr = match fx.tcx.global_alloc(alloc_id) { - GlobalAlloc::Memory(alloc) => { - let data_id = data_id_for_alloc_id( - &mut fx.constants_cx, - fx.module, - alloc_id, - alloc.inner().mutability, - ); - 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!("{:?}", alloc_id)); - } - fx.bcx.ins().global_value(fx.pointer_type, local_data_id) - } - GlobalAlloc::Function(instance) => { - let func_id = crate::abi::import_function(fx.tcx, fx.module, instance); - let local_func_id = - fx.module.declare_func_in_func(func_id, &mut fx.bcx.func); - fx.bcx.ins().func_addr(fx.pointer_type, local_func_id) - } - GlobalAlloc::VTable(ty, trait_ref) => { - let data_id = data_id_for_vtable( - fx.tcx, - &mut fx.constants_cx, - fx.module, - ty, - trait_ref, - ); - let local_data_id = - fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); - fx.bcx.ins().global_value(fx.pointer_type, local_data_id) - } - GlobalAlloc::Static(def_id) => { - assert!(fx.tcx.is_static(def_id)); - let data_id = data_id_for_static( - fx.tcx, fx.module, def_id, false, - // For a declaration the stated mutability doesn't matter. - 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)); - } - fx.bcx.ins().global_value(fx.pointer_type, local_data_id) - } - }; - let val = if offset.bytes() != 0 { - fx.bcx.ins().iadd_imm(base_addr, i64::try_from(offset.bytes()).unwrap()) - } else { - base_addr - }; - CValue::by_val(val, layout) - } - }, - ConstValue::Indirect { alloc_id, offset } => CValue::by_ref( - pointer_for_allocation(fx, alloc_id) - .offset_i64(fx, i64::try_from(offset.bytes()).unwrap()), - layout, - ), - ConstValue::Slice { data, meta } => { - let alloc_id = fx.tcx.reserve_and_set_memory_alloc(data); - let ptr = pointer_for_allocation(fx, alloc_id).get_addr(fx); - let len = fx.bcx.ins().iconst(fx.pointer_type, meta as i64); - CValue::by_val_pair(ptr, len, layout) - } - } -} - -fn pointer_for_allocation<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - alloc_id: AllocId, -) -> crate::pointer::Pointer { - let alloc = fx.tcx.global_alloc(alloc_id).unwrap_memory(); - let data_id = - data_id_for_alloc_id(&mut fx.constants_cx, fx.module, alloc_id, alloc.inner().mutability); - - 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!("{:?}", alloc_id)); - } - let global_ptr = fx.bcx.ins().global_value(fx.pointer_type, local_data_id); - crate::pointer::Pointer::new(global_ptr) -} - -pub(crate) fn data_id_for_alloc_id( - cx: &mut ConstantCx, - module: &mut dyn Module, - alloc_id: AllocId, - mutability: rustc_hir::Mutability, -) -> DataId { - cx.todo.push(TodoItem::Alloc(alloc_id)); - *cx.anon_allocs - .entry(alloc_id) - .or_insert_with(|| module.declare_anonymous_data(mutability.is_mut(), false).unwrap()) -} - -pub(crate) fn data_id_for_vtable<'tcx>( - tcx: TyCtxt<'tcx>, - cx: &mut ConstantCx, - module: &mut dyn Module, - ty: Ty<'tcx>, - trait_ref: Option>>, -) -> DataId { - let alloc_id = tcx.vtable_allocation((ty, trait_ref)); - data_id_for_alloc_id(cx, module, alloc_id, Mutability::Not) -} - -fn data_id_for_static( - tcx: TyCtxt<'_>, - module: &mut dyn Module, - def_id: DefId, - definition: bool, - definition_writable: bool, -) -> DataId { - let attrs = tcx.codegen_fn_attrs(def_id); - - let instance = Instance::mono(tcx, def_id).polymorphize(tcx); - let symbol_name = tcx.symbol_name(instance).name; - - if let Some(import_linkage) = attrs.import_linkage { - assert!(!definition); - assert!(!tcx.is_mutable_static(def_id)); - - let ty = instance.ty(tcx, ParamEnv::reveal_all()); - let align = tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap().align.pref.bytes(); - - let linkage = if import_linkage == rustc_middle::mir::mono::Linkage::ExternalWeak - || import_linkage == rustc_middle::mir::mono::Linkage::WeakAny - { - Linkage::Preemptible - } else { - Linkage::Import - }; - - let data_id = match module.declare_data( - symbol_name, - linkage, - false, - attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL), - ) { - Ok(data_id) => data_id, - Err(ModuleError::IncompatibleDeclaration(_)) => tcx.dcx().fatal(format!( - "attempt to declare `{symbol_name}` as static, but it was already declared as function" - )), - Err(err) => Err::<_, _>(err).unwrap(), - }; - - // Comment copied from https://github.com/rust-lang/rust/blob/45060c2a66dfd667f88bd8b94261b28a58d85bd5/src/librustc_codegen_llvm/consts.rs#L141 - // Declare an internal global `extern_with_linkage_foo` which - // is initialized with the address of `foo`. If `foo` is - // discarded during linking (for example, if `foo` has weak - // linkage and there are no definitions), then - // `extern_with_linkage_foo` will instead be initialized to - // zero. - - let ref_name = format!("_rust_extern_with_linkage_{}", symbol_name); - let ref_data_id = module.declare_data(&ref_name, Linkage::Local, false, false).unwrap(); - let mut data = DataDescription::new(); - data.set_align(align); - let data_gv = module.declare_data_in_data(data_id, &mut data); - data.define(std::iter::repeat(0).take(pointer_ty(tcx).bytes() as usize).collect()); - data.write_data_addr(0, data_gv, 0); - match module.define_data(ref_data_id, &data) { - // Every time the static is referenced there will be another definition of this global, - // so duplicate definitions are expected and allowed. - Err(ModuleError::DuplicateDefinition(_)) => {} - res => res.unwrap(), - } - - return ref_data_id; - } - - let linkage = if definition { - crate::linkage::get_static_linkage(tcx, def_id) - } else if attrs.linkage == Some(rustc_middle::mir::mono::Linkage::ExternalWeak) - || attrs.linkage == Some(rustc_middle::mir::mono::Linkage::WeakAny) - { - Linkage::Preemptible - } else { - Linkage::Import - }; - - let data_id = match module.declare_data( - symbol_name, - linkage, - definition_writable, - attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL), - ) { - Ok(data_id) => data_id, - Err(ModuleError::IncompatibleDeclaration(_)) => tcx.dcx().fatal(format!( - "attempt to declare `{symbol_name}` as static, but it was already declared as function" - )), - Err(err) => Err::<_, _>(err).unwrap(), - }; - - data_id -} - -fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut ConstantCx) { - let mut done = FxHashSet::default(); - while let Some(todo_item) = cx.todo.pop() { - if !done.insert(todo_item) { - continue; - } - - let (data_id, alloc, section_name) = match todo_item { - TodoItem::Alloc(alloc_id) => { - let alloc = match tcx.global_alloc(alloc_id) { - GlobalAlloc::Memory(alloc) => alloc, - GlobalAlloc::Function(_) | GlobalAlloc::Static(_) | GlobalAlloc::VTable(..) => { - unreachable!() - } - }; - // FIXME: should we have a cache so we don't do this multiple times for the same `ConstAllocation`? - let data_id = *cx.anon_allocs.entry(alloc_id).or_insert_with(|| { - module.declare_anonymous_data(alloc.inner().mutability.is_mut(), false).unwrap() - }); - (data_id, alloc, None) - } - TodoItem::Static(def_id) => { - let section_name = tcx.codegen_fn_attrs(def_id).link_section; - - let alloc = tcx.eval_static_initializer(def_id).unwrap(); - - let data_id = data_id_for_static( - tcx, - module, - def_id, - true, - alloc.inner().mutability == Mutability::Mut, - ); - (data_id, alloc, section_name) - } - }; - - let mut data = DataDescription::new(); - let alloc = alloc.inner(); - data.set_align(alloc.align.bytes()); - - if let Some(section_name) = section_name { - let (segment_name, section_name) = if tcx.sess.target.is_like_osx { - let section_name = section_name.as_str(); - if let Some(names) = section_name.split_once(',') { - names - } else { - tcx.dcx().fatal(format!( - "#[link_section = \"{}\"] is not valid for macos target: must be segment and section separated by comma", - section_name - )); - } - } else { - ("", section_name.as_str()) - }; - data.set_segment_section(segment_name, section_name); - } - - let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()).to_vec(); - data.define(bytes.into_boxed_slice()); - - for &(offset, prov) in alloc.provenance().ptrs().iter() { - let alloc_id = prov.alloc_id(); - let addend = { - let endianness = tcx.data_layout.endian; - let offset = offset.bytes() as usize; - let ptr_size = tcx.data_layout.pointer_size; - let bytes = &alloc.inspect_with_uninit_and_ptr_outside_interpreter( - offset..offset + ptr_size.bytes() as usize, - ); - read_target_uint(endianness, bytes).unwrap() - }; - - let reloc_target_alloc = tcx.global_alloc(alloc_id); - let data_id = match reloc_target_alloc { - GlobalAlloc::Function(instance) => { - assert_eq!(addend, 0); - let func_id = - crate::abi::import_function(tcx, module, instance.polymorphize(tcx)); - let local_func_id = module.declare_func_in_data(func_id, &mut data); - data.write_function_addr(offset.bytes() as u32, local_func_id); - continue; - } - GlobalAlloc::Memory(target_alloc) => { - data_id_for_alloc_id(cx, module, alloc_id, target_alloc.inner().mutability) - } - GlobalAlloc::VTable(ty, trait_ref) => { - data_id_for_vtable(tcx, cx, module, ty, trait_ref) - } - GlobalAlloc::Static(def_id) => { - if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) - { - tcx.dcx().fatal(format!( - "Allocation {:?} contains reference to TLS value {:?}", - alloc_id, def_id - )); - } - - // Don't push a `TodoItem::Static` here, as it will cause statics used by - // multiple crates to be duplicated between them. It isn't necessary anyway, - // as it will get pushed by `codegen_static` when necessary. - data_id_for_static( - tcx, module, def_id, false, - // For a declaration the stated mutability doesn't matter. - false, - ) - } - }; - - let global_value = module.declare_data_in_data(data_id, &mut data); - data.write_data_addr(offset.bytes() as u32, global_value, addend as i64); - } - - module.define_data(data_id, &data).unwrap(); - } - - assert!(cx.todo.is_empty(), "{:?}", cx.todo); -} - -/// Used only for intrinsic implementations that need a compile-time constant -pub(crate) fn mir_operand_get_const_val<'tcx>( - fx: &FunctionCx<'_, '_, 'tcx>, - operand: &Operand<'tcx>, -) -> Option { - match operand { - Operand::Constant(const_) => eval_mir_constant(fx, const_).0.try_to_scalar_int(), - // FIXME(rust-lang/rust#85105): Casts like `IMM8 as u32` result in the const being stored - // inside a temporary before being passed to the intrinsic requiring the const argument. - // This code tries to find a single constant defining definition of the referenced local. - Operand::Copy(place) | Operand::Move(place) => { - if !place.projection.is_empty() { - return None; - } - let mut computed_scalar_int = None; - for bb_data in fx.mir.basic_blocks.iter() { - for stmt in &bb_data.statements { - match &stmt.kind { - StatementKind::Assign(local_and_rvalue) if &local_and_rvalue.0 == place => { - match &local_and_rvalue.1 { - Rvalue::Cast( - CastKind::IntToInt - | CastKind::FloatToFloat - | CastKind::FloatToInt - | CastKind::IntToFloat - | CastKind::FnPtrToPtr - | CastKind::PtrToPtr, - operand, - ty, - ) => { - if computed_scalar_int.is_some() { - return None; // local assigned twice - } - if !matches!(ty.kind(), ty::Uint(_) | ty::Int(_)) { - return None; - } - let scalar_int = mir_operand_get_const_val(fx, operand)?; - let scalar_int = match fx - .layout_of(*ty) - .size - .cmp(&scalar_int.size()) - { - Ordering::Equal => scalar_int, - Ordering::Less => match ty.kind() { - ty::Uint(_) => ScalarInt::try_from_uint( - scalar_int.try_to_uint(scalar_int.size()).unwrap(), - fx.layout_of(*ty).size, - ) - .unwrap(), - ty::Int(_) => ScalarInt::try_from_int( - scalar_int.try_to_int(scalar_int.size()).unwrap(), - fx.layout_of(*ty).size, - ) - .unwrap(), - _ => unreachable!(), - }, - Ordering::Greater => return None, - }; - computed_scalar_int = Some(scalar_int); - } - Rvalue::Use(operand) => { - computed_scalar_int = mir_operand_get_const_val(fx, operand) - } - _ => return None, - } - } - StatementKind::SetDiscriminant { place: stmt_place, variant_index: _ } - if &**stmt_place == place => - { - return None; - } - StatementKind::Intrinsic(ref intrinsic) => match **intrinsic { - NonDivergingIntrinsic::CopyNonOverlapping(..) => return None, - NonDivergingIntrinsic::Assume(..) => {} - }, - // conservative handling - StatementKind::Assign(_) - | StatementKind::FakeRead(_) - | StatementKind::SetDiscriminant { .. } - | StatementKind::Deinit(_) - | StatementKind::StorageLive(_) - | StatementKind::StorageDead(_) - | StatementKind::Retag(_, _) - | StatementKind::AscribeUserType(_, _) - | StatementKind::PlaceMention(..) - | StatementKind::Coverage(_) - | StatementKind::ConstEvalCounter - | StatementKind::Nop => {} - } - } - match &bb_data.terminator().kind { - TerminatorKind::Goto { .. } - | TerminatorKind::SwitchInt { .. } - | TerminatorKind::UnwindResume - | TerminatorKind::UnwindTerminate(_) - | TerminatorKind::Return - | TerminatorKind::Unreachable - | TerminatorKind::Drop { .. } - | TerminatorKind::Assert { .. } => {} - TerminatorKind::Yield { .. } - | TerminatorKind::CoroutineDrop - | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } => unreachable!(), - TerminatorKind::InlineAsm { .. } => return None, - TerminatorKind::Call { destination, target: Some(_), .. } - if destination == place => - { - return None; - } - TerminatorKind::Call { .. } => {} - } - } - computed_scalar_int - } - } -} +use std::cmp::Ordering;use cranelift_module::*;use rustc_data_structures::fx::// +FxHashSet;use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;use//3; +rustc_middle::mir::interpret::{read_target_uint ,AllocId,GlobalAlloc,Scalar};use +rustc_middle::ty::{Binder,ExistentialTraitRef,ScalarInt};use crate::prelude::*// +;pub(crate)struct ConstantCx{todo:Vec,anon_allocs:FxHashMap,}#[derive(Copy,Clone,Debug,Eq,PartialEq,Hash)]enum TodoItem{Alloc(//{;}; +AllocId),Static(DefId),}impl ConstantCx{pub(crate)fn new()->Self{ConstantCx{//3; +todo:(vec![]),anon_allocs:FxHashMap::default( )}}pub(crate)fn finalize(mut self, +tcx:TyCtxt<'_>,module:&mut dyn Module){;define_all_allocs(tcx,module,&mut self); +}}pub(crate)fn codegen_static(tcx:TyCtxt<'_>,module:&mut dyn Module,def_id://(); +DefId)->DataId{;let mut constants_cx=ConstantCx::new();;;constants_cx.todo.push( +TodoItem::Static(def_id));;constants_cx.finalize(tcx,module);data_id_for_static( +tcx,module,def_id,((false)),(false),)}pub(crate)fn codegen_tls_ref<'tcx>(fx:&mut +FunctionCx<'_,'_,'tcx>,def_id:DefId,layout:TyAndLayout<'tcx>,)->CValue<'tcx>{(); +let tls_ptr=if!def_id.is_local()&&fx.tcx.needs_thread_local_shim(def_id){{;};let +instance=ty::Instance{def:((ty::InstanceDef::ThreadLocalShim(def_id))),args:ty:: +GenericArgs::empty(),};;;let func_ref=fx.get_function_ref(instance);let call=fx. +bcx.ins().call(func_ref,&[]);{;};fx.bcx.func.dfg.first_result(call)}else{{;};let +data_id=data_id_for_static(fx.tcx,fx.module,def_id,false,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!("tls {:?}",def_id) +);{;};}fx.bcx.ins().tls_value(fx.pointer_type,local_data_id)};();CValue::by_val( +tls_ptr,layout)}pub(crate)fn eval_mir_constant< 'tcx>(fx:&FunctionCx<'_,'_,'tcx> +,constant:&ConstOperand<'tcx>,)->(ConstValue<'tcx>,Ty<'tcx>){let _=();let cv=fx. +monomorphize(constant.const_);;let val=cv.eval(fx.tcx,ty::ParamEnv::reveal_all() +,constant.span).expect("erroneous constant missed by mono item collection");();( +val,cv.ty())}pub(crate) fn codegen_constant_operand<'tcx>(fx:&mut FunctionCx<'_, +'_,'tcx>,constant:&ConstOperand<'tcx>,)->CValue<'tcx>{((),());let(const_val,ty)= +eval_mir_constant(fx,constant);3;codegen_const_value(fx,const_val,ty)}pub(crate) +fn codegen_const_value<'tcx>(fx:&mut FunctionCx<'_,'_,'tcx>,const_val://((),()); +ConstValue<'tcx>,ty:Ty<'tcx>,)->CValue<'tcx>{;let layout=fx.layout_of(ty);assert +!(layout.is_sized(),"unsized const value");3;if layout.is_zst(){;return CValue:: +by_ref(crate::Pointer::dangling(layout.align.pref),layout);{;};}match const_val{ +ConstValue::ZeroSized=>(unreachable!()),ConstValue ::Scalar(x)=>match x{Scalar:: +Int(int)=>{if fx.clif_type(layout.ty).is_some(){{;};return CValue::const_val(fx, +layout,int);();}else{();let raw_val=int.size().truncate(int.to_bits(int.size()). +unwrap());3;3;let val=match int.size().bytes(){1=>fx.bcx.ins().iconst(types::I8, +raw_val as i64),2=>fx.bcx.ins().iconst (types::I16,raw_val as i64),4=>fx.bcx.ins +().iconst(types::I32,(raw_val as i64)),8=>fx.bcx.ins().iconst(types::I64,raw_val +as i64),16=>{;let lsb=fx.bcx.ins().iconst(types::I64,raw_val as u64 as i64);;let +msb=fx.bcx.ins().iconst(types::I64,(raw_val>>64)as u64 as i64);{;};fx.bcx.ins(). +iconcat(lsb,msb)}_=>unreachable!(),};;let place=CPlace::new_stack_slot(fx,layout +);;;place.to_ptr().store(fx,val,MemFlags::trusted());place.to_cvalue(fx)}}Scalar +::Ptr(ptr,_size)=>{;let(prov,offset)=ptr.into_parts();let alloc_id=prov.alloc_id +();;let base_addr=match fx.tcx.global_alloc(alloc_id){GlobalAlloc::Memory(alloc) +=>{{;};let data_id=data_id_for_alloc_id(&mut fx.constants_cx,fx.module,alloc_id, +alloc.inner().mutability,);3;3;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!("{:?}",alloc_id));if true{};}fx.bcx.ins().global_value(fx. +pointer_type,local_data_id)}GlobalAlloc::Function(instance)=>{;let func_id=crate +::abi::import_function(fx.tcx,fx.module,instance);;;let local_func_id=fx.module. +declare_func_in_func(func_id,&mut fx.bcx.func);*&*&();fx.bcx.ins().func_addr(fx. +pointer_type,local_func_id)}GlobalAlloc::VTable(ty,trait_ref)=>{{;};let data_id= +data_id_for_vtable(fx.tcx,&mut fx.constants_cx,fx.module,ty,trait_ref,);();3;let +local_data_id=fx.module.declare_data_in_func(data_id,&mut fx.bcx.func);3;fx.bcx. +ins().global_value(fx.pointer_type, local_data_id)}GlobalAlloc::Static(def_id)=> +{3;assert!(fx.tcx.is_static(def_id));;;let data_id=data_id_for_static(fx.tcx,fx. +module,def_id,false,false,);3;;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));loop{break};}fx.bcx.ins().global_value(fx. +pointer_type,local_data_id)}};{;};{;};let val=if offset.bytes()!=0{fx.bcx.ins(). +iadd_imm(base_addr,i64::try_from(offset.bytes()).unwrap())}else{base_addr};({}); +CValue::by_val(val,layout)}},ConstValue::Indirect{alloc_id,offset}=>CValue:://3; +by_ref((pointer_for_allocation(fx,alloc_id)).offset_i64(fx,i64::try_from(offset. +bytes()).unwrap()),layout,),ConstValue::Slice{data,meta}=>{;let alloc_id=fx.tcx. +reserve_and_set_memory_alloc(data);;let ptr=pointer_for_allocation(fx,alloc_id). +get_addr(fx);;;let len=fx.bcx.ins().iconst(fx.pointer_type,meta as i64);CValue:: +by_val_pair(ptr,len,layout)}}}fn pointer_for_allocation<'tcx>(fx:&mut//let _=(); +FunctionCx<'_,'_,'tcx>,alloc_id:AllocId,)->crate::pointer::Pointer{;let alloc=fx +.tcx.global_alloc(alloc_id).unwrap_memory();;;let data_id=data_id_for_alloc_id(& +mut fx.constants_cx,fx.module,alloc_id,alloc.inner().mutability);{();};{();};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!("{:?}",alloc_id)); +};let global_ptr=fx.bcx.ins().global_value(fx.pointer_type,local_data_id);;crate +::pointer::Pointer::new(global_ptr)}pub(crate)fn data_id_for_alloc_id(cx:&mut//; +ConstantCx,module:&mut dyn Module,alloc_id:AllocId,mutability:rustc_hir:://({}); +Mutability,)->DataId{3;cx.todo.push(TodoItem::Alloc(alloc_id));;*cx.anon_allocs. +entry(alloc_id).or_insert_with(||module.declare_anonymous_data(mutability.//{;}; +is_mut(),false).unwrap()) }pub(crate)fn data_id_for_vtable<'tcx>(tcx:TyCtxt<'tcx +>,cx:&mut ConstantCx,module:&mut dyn Module,ty:Ty<'tcx>,trait_ref:Option>>,)->DataId{;let alloc_id=tcx.vtable_allocation( +(ty,trait_ref));({});data_id_for_alloc_id(cx,module,alloc_id,Mutability::Not)}fn +data_id_for_static(tcx:TyCtxt<'_>,module:&mut dyn Module,def_id:DefId,//((),()); +definition:bool,definition_writable:bool,)->DataId{*&*&();((),());let attrs=tcx. +codegen_fn_attrs(def_id);;;let instance=Instance::mono(tcx,def_id).polymorphize( +tcx);;let symbol_name=tcx.symbol_name(instance).name;if let Some(import_linkage) +=attrs.import_linkage{3;assert!(!definition);3;3;assert!(!tcx.is_mutable_static( +def_id));;let ty=instance.ty(tcx,ParamEnv::reveal_all());let align=tcx.layout_of +(ParamEnv::reveal_all().and(ty)).unwrap().align.pref.bytes();3;3;let linkage=if +import_linkage==rustc_middle::mir::mono::Linkage::ExternalWeak||import_linkage// +==rustc_middle::mir::mono::Linkage::WeakAny {Linkage::Preemptible}else{Linkage:: +Import};;;let data_id=match module.declare_data(symbol_name,linkage,false,attrs. +flags.contains(CodegenFnAttrFlags::THREAD_LOCAL),){Ok(data_id)=>data_id,Err(//3; +ModuleError::IncompatibleDeclaration(_))=>(((((((tcx.dcx()))))))).fatal(format!( +"attempt to declare `{symbol_name}` as static, but it was already declared as function" +)),Err(err)=>Err::<_,_>(err).unwrap(),};if true{};let _=();let ref_name=format!( +"_rust_extern_with_linkage_{}",symbol_name);;let ref_data_id=module.declare_data +(&ref_name,Linkage::Local,false,false).unwrap();;;let mut data=DataDescription:: +new();;;data.set_align(align);;let data_gv=module.declare_data_in_data(data_id,& +mut data);;data.define(std::iter::repeat(0).take(pointer_ty(tcx).bytes()as usize +).collect());();();data.write_data_addr(0,data_gv,0);3;match module.define_data( +ref_data_id,&data){Err(ModuleError::DuplicateDefinition (_))=>{}res=>res.unwrap( +),}({});return ref_data_id;({});}({});let linkage=if definition{crate::linkage:: +get_static_linkage(tcx,def_id)}else if attrs.linkage==Some(rustc_middle::mir::// +mono::Linkage::ExternalWeak)||attrs.linkage==Some(rustc_middle::mir::mono:://(); +Linkage::WeakAny){Linkage::Preemptible}else{Linkage::Import};;let data_id=match +module.declare_data(symbol_name,linkage,definition_writable,attrs.flags.//{();}; +contains(CodegenFnAttrFlags::THREAD_LOCAL),){Ok(data_id)=>data_id,Err(//((),()); +ModuleError::IncompatibleDeclaration(_))=>(((((((tcx.dcx()))))))).fatal(format!( +"attempt to declare `{symbol_name}` as static, but it was already declared as function" +)),Err(err)=>Err::<_,_>(err).unwrap(),};;data_id}fn define_all_allocs(tcx:TyCtxt +<'_>,module:&mut dyn Module,cx:&mut ConstantCx){;let mut done=FxHashSet::default +();;while let Some(todo_item)=cx.todo.pop(){if!done.insert(todo_item){continue;} +let(data_id,alloc,section_name)=match todo_item{TodoItem::Alloc(alloc_id)=>{;let +alloc=match (((tcx.global_alloc(alloc_id) ))){GlobalAlloc::Memory(alloc)=>alloc, +GlobalAlloc::Function(_)|GlobalAlloc::Static(_)|GlobalAlloc::VTable(..)=>{//{;}; +unreachable!()}};;let data_id=*cx.anon_allocs.entry(alloc_id).or_insert_with(||{ +module.declare_anonymous_data(alloc.inner().mutability. is_mut(),false).unwrap() +});{;};(data_id,alloc,None)}TodoItem::Static(def_id)=>{{;};let section_name=tcx. +codegen_fn_attrs(def_id).link_section;3;3;let alloc=tcx.eval_static_initializer( +def_id).unwrap();3;;let data_id=data_id_for_static(tcx,module,def_id,true,alloc. +inner().mutability==Mutability::Mut,);3;(data_id,alloc,section_name)}};;;let mut +data=DataDescription::new();;let alloc=alloc.inner();data.set_align(alloc.align. +bytes());;if let Some(section_name)=section_name{let(segment_name,section_name)= +if tcx.sess.target.is_like_osx{3;let section_name=section_name.as_str();3;if let +Some(names)=section_name.split_once(','){names}else{{;};tcx.dcx().fatal(format!( +"#[link_section = \"{}\"] is not valid for macos target: must be segment and section separated by comma" +,section_name));3;}}else{("",section_name.as_str())};;;data.set_segment_section( +segment_name,section_name);let _=();let _=();}let _=();let _=();let bytes=alloc. +inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()).to_vec();;;data. +define(bytes.into_boxed_slice());;for&(offset,prov)in alloc.provenance().ptrs(). +iter(){;let alloc_id=prov.alloc_id();let addend={let endianness=tcx.data_layout. +endian;();();let offset=offset.bytes()as usize;3;3;let ptr_size=tcx.data_layout. +pointer_size;;;let bytes=&alloc.inspect_with_uninit_and_ptr_outside_interpreter( +offset..offset+ptr_size.bytes()as usize,);();read_target_uint(endianness,bytes). +unwrap()};;;let reloc_target_alloc=tcx.global_alloc(alloc_id);;let data_id=match +reloc_target_alloc{GlobalAlloc::Function(instance)=>{;assert_eq!(addend,0);;;let +func_id=crate::abi::import_function(tcx,module,instance.polymorphize(tcx));;;let +local_func_id=module.declare_func_in_data(func_id,&mut data);*&*&();*&*&();data. +write_function_addr(offset.bytes()as u32,local_func_id);;continue;}GlobalAlloc:: +Memory(target_alloc)=>{data_id_for_alloc_id(cx,module,alloc_id,target_alloc.//3; +inner().mutability)}GlobalAlloc::VTable (ty,trait_ref)=>{data_id_for_vtable(tcx, +cx,module,ty,trait_ref)}GlobalAlloc::Static(def_id)=>{if tcx.codegen_fn_attrs(// +def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL){;tcx.dcx().fatal(format +!("Allocation {:?} contains reference to TLS value {:?}",alloc_id,def_id));{;};} +data_id_for_static(tcx,module,def_id,false,false,)}};3;;let global_value=module. +declare_data_in_data(data_id,&mut data);3;;data.write_data_addr(offset.bytes()as +u32,global_value,addend as i64);;};module.define_data(data_id,&data).unwrap();;} +assert!(cx.todo.is_empty(),"{:?}",cx.todo);loop{break};loop{break};}pub(crate)fn +mir_operand_get_const_val<'tcx>(fx:&FunctionCx<'_,'_,'tcx>,operand:&Operand,)->Option{match operand{Operand::Constant(const_)=>//if true{}; +eval_mir_constant(fx,const_).0.try_to_scalar_int (),Operand::Copy(place)|Operand +::Move(place)=>{if!place.projection.is_empty(){({});return None;{;};}{;};let mut +computed_scalar_int=None;;for bb_data in fx.mir.basic_blocks.iter(){for stmt in& +bb_data.statements{match(&stmt.kind ){StatementKind::Assign(local_and_rvalue)if& +local_and_rvalue.0==place=>{match((&local_and_rvalue.1)){Rvalue::Cast(CastKind:: +IntToInt|CastKind::FloatToFloat|CastKind::FloatToInt|CastKind::IntToFloat|//{;}; +CastKind::FnPtrToPtr|CastKind::PtrToPtr,operand,ty,)=>{if computed_scalar_int.// +is_some(){3;return None;3;}if!matches!(ty.kind(),ty::Uint(_)|ty::Int(_)){;return +None;3;};let scalar_int=mir_operand_get_const_val(fx,operand)?;;;let scalar_int= +match ((fx.layout_of((*ty))).size.cmp((&(scalar_int.size())))){Ordering::Equal=> +scalar_int,Ordering::Less=>match ((((((ty.kind( ))))))){ty::Uint(_)=>ScalarInt:: +try_from_uint(scalar_int.try_to_uint(scalar_int.size() ).unwrap(),fx.layout_of(* +ty).size,).unwrap(),ty::Int(_)=>ScalarInt::try_from_int(scalar_int.try_to_int(// +scalar_int.size()).unwrap(),fx.layout_of(*ty ).size,).unwrap(),_=>unreachable!() +,},Ordering::Greater=>return None,};3;3;computed_scalar_int=Some(scalar_int);3;} +Rvalue::Use(operand)=>{ computed_scalar_int=mir_operand_get_const_val(fx,operand +)}_=>((((((return None)))))) ,}}StatementKind::SetDiscriminant{place:stmt_place, +variant_index:_}if&**stmt_place==place=>{;return None;}StatementKind::Intrinsic( +ref intrinsic)=>match(**intrinsic){NonDivergingIntrinsic::CopyNonOverlapping(..) +=>(return None),NonDivergingIntrinsic::Assume(..)=>{}},StatementKind::Assign(_)| +StatementKind::FakeRead(_)|StatementKind::SetDiscriminant{..}|StatementKind:://; +Deinit(_)|StatementKind::StorageLive(_)|StatementKind::StorageDead(_)|//((),()); +StatementKind::Retag(_,_)|StatementKind::AscribeUserType(_,_)|StatementKind:://; +PlaceMention(..)|StatementKind::Coverage(_)|StatementKind::ConstEvalCounter|//3; +StatementKind::Nop=>{}}}match&bb_data .terminator().kind{TerminatorKind::Goto{.. +}|TerminatorKind::SwitchInt{..}|TerminatorKind::UnwindResume|TerminatorKind:://; +UnwindTerminate(_)|TerminatorKind::Return|TerminatorKind::Unreachable|//((),()); +TerminatorKind::Drop{..}|TerminatorKind::Assert {..}=>{}TerminatorKind::Yield{.. +}|TerminatorKind::CoroutineDrop|TerminatorKind::FalseEdge{..}|TerminatorKind::// +FalseUnwind{..}=>(unreachable!()), TerminatorKind::InlineAsm{..}=>(return None), +TerminatorKind::Call{destination,target:Some(_),..}if destination==place=>{({}); +return None;*&*&();((),());}TerminatorKind::Call{..}=>{}}}computed_scalar_int}}} diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs index 36af7d4450d04..44483f5eee91a 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs @@ -1,203 +1,60 @@ -//! Write the debuginfo into an object file. - -use cranelift_module::{DataId, FuncId}; -use cranelift_object::ObjectProduct; -use gimli::write::{Address, AttributeValue, EndianVec, Result, Sections, Writer}; -use gimli::{RunTimeEndian, SectionId}; -use rustc_data_structures::fx::FxHashMap; - -use super::object::WriteDebugInfo; -use super::DebugContext; - -pub(super) fn address_for_func(func_id: FuncId) -> Address { - let symbol = func_id.as_u32(); - assert!(symbol & 1 << 31 == 0); - Address::Symbol { symbol: symbol as usize, addend: 0 } -} - -pub(super) fn address_for_data(data_id: DataId) -> Address { - let symbol = data_id.as_u32(); - assert!(symbol & 1 << 31 == 0); - Address::Symbol { symbol: (symbol | 1 << 31) as usize, addend: 0 } -} - -impl DebugContext { - pub(crate) fn emit(&mut self, product: &mut ObjectProduct) { - let unit_range_list_id = self.dwarf.unit.ranges.add(self.unit_range_list.clone()); - let root = self.dwarf.unit.root(); - let root = self.dwarf.unit.get_mut(root); - root.set(gimli::DW_AT_ranges, AttributeValue::RangeListRef(unit_range_list_id)); - - let mut sections = Sections::new(WriterRelocate::new(self.endian)); - self.dwarf.write(&mut sections).unwrap(); - - let mut section_map = FxHashMap::default(); - let _: Result<()> = sections.for_each_mut(|id, section| { - if !section.writer.slice().is_empty() { - let section_id = product.add_debug_section(id, section.writer.take()); - section_map.insert(id, section_id); - } - Ok(()) - }); - - let _: Result<()> = sections.for_each(|id, section| { - if let Some(section_id) = section_map.get(&id) { - for reloc in §ion.relocs { - product.add_debug_reloc(§ion_map, section_id, reloc); - } - } - Ok(()) - }); - } -} - -#[derive(Clone)] -pub(crate) struct DebugReloc { - pub(crate) offset: u32, - pub(crate) size: u8, - pub(crate) name: DebugRelocName, - pub(crate) addend: i64, - pub(crate) kind: object::RelocationKind, -} - -#[derive(Clone)] -pub(crate) enum DebugRelocName { - Section(SectionId), - Symbol(usize), -} - -/// A [`Writer`] that collects all necessary relocations. -#[derive(Clone)] -pub(super) struct WriterRelocate { - pub(super) relocs: Vec, - pub(super) writer: EndianVec, -} - -impl WriterRelocate { - pub(super) fn new(endian: RunTimeEndian) -> Self { - WriterRelocate { relocs: Vec::new(), writer: EndianVec::new(endian) } - } - - /// Perform the collected relocations to be usable for JIT usage. - #[cfg(all(feature = "jit", not(windows)))] - pub(super) fn relocate_for_jit(mut self, jit_module: &cranelift_jit::JITModule) -> Vec { - for reloc in self.relocs.drain(..) { - match reloc.name { - super::DebugRelocName::Section(_) => unreachable!(), - super::DebugRelocName::Symbol(sym) => { - let addr = jit_module.get_finalized_function( - cranelift_module::FuncId::from_u32(sym.try_into().unwrap()), - ); - let val = (addr as u64 as i64 + reloc.addend) as u64; - self.writer.write_udata_at(reloc.offset as usize, val, reloc.size).unwrap(); - } - } - } - self.writer.into_vec() - } -} - -impl Writer for WriterRelocate { - type Endian = RunTimeEndian; - - fn endian(&self) -> Self::Endian { - self.writer.endian() - } - - fn len(&self) -> usize { - self.writer.len() - } - - fn write(&mut self, bytes: &[u8]) -> Result<()> { - self.writer.write(bytes) - } - - fn write_at(&mut self, offset: usize, bytes: &[u8]) -> Result<()> { - self.writer.write_at(offset, bytes) - } - - fn write_address(&mut self, address: Address, size: u8) -> Result<()> { - match address { - Address::Constant(val) => self.write_udata(val, size), - Address::Symbol { symbol, addend } => { - let offset = self.len() as u64; - self.relocs.push(DebugReloc { - offset: offset as u32, - size, - name: DebugRelocName::Symbol(symbol), - addend, - kind: object::RelocationKind::Absolute, - }); - self.write_udata(0, size) - } - } - } - - fn write_offset(&mut self, val: usize, section: SectionId, size: u8) -> Result<()> { - let offset = self.len() as u32; - self.relocs.push(DebugReloc { - offset, - size, - name: DebugRelocName::Section(section), - addend: val as i64, - kind: object::RelocationKind::Absolute, - }); - self.write_udata(0, size) - } - - fn write_offset_at( - &mut self, - offset: usize, - val: usize, - section: SectionId, - size: u8, - ) -> Result<()> { - self.relocs.push(DebugReloc { - offset: offset as u32, - size, - name: DebugRelocName::Section(section), - addend: val as i64, - kind: object::RelocationKind::Absolute, - }); - self.write_udata_at(offset, 0, size) - } - - fn write_eh_pointer(&mut self, address: Address, eh_pe: gimli::DwEhPe, size: u8) -> Result<()> { - match address { - // Address::Constant arm copied from gimli - Address::Constant(val) => { - // Indirect doesn't matter here. - let val = match eh_pe.application() { - gimli::DW_EH_PE_absptr => val, - gimli::DW_EH_PE_pcrel => { - // FIXME better handling of sign - let offset = self.len() as u64; - offset.wrapping_sub(val) - } - _ => { - return Err(gimli::write::Error::UnsupportedPointerEncoding(eh_pe)); - } - }; - self.write_eh_pointer_data(val, eh_pe.format(), size) - } - Address::Symbol { symbol, addend } => match eh_pe.application() { - gimli::DW_EH_PE_pcrel => { - let size = match eh_pe.format() { - gimli::DW_EH_PE_sdata4 => 4, - gimli::DW_EH_PE_sdata8 => 8, - _ => return Err(gimli::write::Error::UnsupportedPointerEncoding(eh_pe)), - }; - self.relocs.push(DebugReloc { - offset: self.len() as u32, - size, - name: DebugRelocName::Symbol(symbol), - addend, - kind: object::RelocationKind::Relative, - }); - self.write_udata(0, size) - } - _ => Err(gimli::write::Error::UnsupportedPointerEncoding(eh_pe)), - }, - } - } -} +use cranelift_module::{DataId,FuncId};use cranelift_object::ObjectProduct;use//; +gimli::write::{Address,AttributeValue,EndianVec,Result,Sections,Writer};use//(); +gimli::{RunTimeEndian,SectionId};use rustc_data_structures::fx::FxHashMap;use//; +super::object::WriteDebugInfo;use super::DebugContext;pub(super)fn//loop{break}; +address_for_func(func_id:FuncId)->Address{;let symbol=func_id.as_u32();;assert!( +symbol&1<<31==0);3;Address::Symbol{symbol:symbol as usize,addend:0}}pub(super)fn +address_for_data(data_id:DataId)->Address{;let symbol=data_id.as_u32();;assert!( +symbol&1<<31==0);();Address::Symbol{symbol:(symbol|1<<31)as usize,addend:0}}impl +DebugContext{pub(crate)fn emit(&mut self,product:&mut ObjectProduct){((),());let +unit_range_list_id=self.dwarf.unit.ranges.add(self.unit_range_list.clone());;let +root=self.dwarf.unit.root();;;let root=self.dwarf.unit.get_mut(root);;;root.set( +gimli::DW_AT_ranges,AttributeValue::RangeListRef(unit_range_list_id));3;;let mut +sections=Sections::new(WriterRelocate::new(self.endian));;;self.dwarf.write(&mut +sections).unwrap();;;let mut section_map=FxHashMap::default();;let _:Result<()>= +sections.for_each_mut(|id,section|{if!section.writer.slice().is_empty(){({});let +section_id=product.add_debug_section(id,section.writer.take());();3;section_map. +insert(id,section_id);;}Ok(())});let _:Result<()>=sections.for_each(|id,section| +{if let Some(section_id)=section_map.get(&id){for reloc in§ion.relocs{{();}; +product.add_debug_reloc(§ion_map,section_id,reloc);3;}}Ok(())});;}}#[derive( +Clone)]pub(crate)struct DebugReloc{pub(crate)offset:u32,pub(crate)size:u8,pub(// +crate)name:DebugRelocName,pub(crate)addend:i64,pub(crate)kind:object:://((),()); +RelocationKind,}#[derive(Clone)] pub(crate)enum DebugRelocName{Section(SectionId +),Symbol(usize),}#[derive(Clone)]pub(super)struct WriterRelocate{pub(super)//(); +relocs:Vec,pub(super)writer:EndianVec,}impl//((),()); +WriterRelocate{pub(super)fn new(endian:RunTimeEndian)->Self{WriterRelocate{//(); +relocs:(Vec::new()),writer:EndianVec::new( endian)}}#[cfg(all(feature="jit",not( +windows)))]pub(super)fn relocate_for_jit(mut self,jit_module:&cranelift_jit:://; +JITModule)->Vec{for reloc in self .relocs.drain(..){match reloc.name{super:: +DebugRelocName::Section(_)=>unreachable!( ),super::DebugRelocName::Symbol(sym)=> +{;let addr=jit_module.get_finalized_function(cranelift_module::FuncId::from_u32( +sym.try_into().unwrap()),);;let val=(addr as u64 as i64+reloc.addend)as u64;self +.writer.write_udata_at(reloc.offset as usize,val,reloc.size).unwrap();3;}}}self. +writer.into_vec()}}impl Writer for WriterRelocate{type Endian=RunTimeEndian;fn// +endian(&self)->Self::Endian{((self.writer.endian ()))}fn len(&self)->usize{self. +writer.len()}fn write(&mut self,bytes:&[u8])->Result<()>{self.writer.write(//(); +bytes)}fn write_at(&mut self,offset:usize,bytes :&[u8])->Result<()>{self.writer. +write_at(offset,bytes)}fn write_address(&mut self,address:Address,size:u8)->//3; +Result<()>{match address{Address::Constant(val)=>((self.write_udata(val,size))), +Address::Symbol{symbol,addend}=>{;let offset=self.len()as u64;;self.relocs.push( +DebugReloc{offset:offset as u32,size ,name:DebugRelocName::Symbol(symbol),addend +,kind:object::RelocationKind::Absolute,});let _=();self.write_udata(0,size)}}}fn +write_offset(&mut self,val:usize,section:SectionId,size:u8)->Result<()>{({});let +offset=self.len()as u32;{();};({});self.relocs.push(DebugReloc{offset,size,name: +DebugRelocName::Section(section),addend:(val as i64),kind:object::RelocationKind +::Absolute,});({});self.write_udata(0,size)}fn write_offset_at(&mut self,offset: +usize,val:usize,section:SectionId,size:u8,)->Result<()>{*&*&();self.relocs.push( +DebugReloc{offset:(offset as u32), size,name:(DebugRelocName::Section(section)), +addend:val as i64,kind:object::RelocationKind::Absolute,});;self.write_udata_at( +offset,(((0))),size)}fn write_eh_pointer(&mut self,address:Address,eh_pe:gimli:: +DwEhPe,size:u8)->Result<()>{match address{Address::Constant(val)=>{({});let val= +match eh_pe.application(){gimli::DW_EH_PE_absptr=>val,gimli::DW_EH_PE_pcrel=>{3; +let offset=self.len()as u64;();offset.wrapping_sub(val)}_=>{3;return Err(gimli:: +write::Error::UnsupportedPointerEncoding(eh_pe));;}};self.write_eh_pointer_data( +val,(((((eh_pe.format()))))),size)} Address::Symbol{symbol,addend}=>match eh_pe. +application(){gimli::DW_EH_PE_pcrel=>{({});let size=match eh_pe.format(){gimli:: +DW_EH_PE_sdata4=>(4),gimli::DW_EH_PE_sdata8=>8,_=>return Err(gimli::write::Error +::UnsupportedPointerEncoding(eh_pe)),};;self.relocs.push(DebugReloc{offset:self. +len()as u32,size,name:((( DebugRelocName::Symbol(symbol)))),addend,kind:object:: +RelocationKind::Relative,});;self.write_udata(0,size)}_=>Err(gimli::write::Error +::UnsupportedPointerEncoding(eh_pe)),},}}}//let _=();let _=();let _=();let _=(); diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs index 32b9c824ded2f..e010f3e7fcde6 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs @@ -1,175 +1,60 @@ -//! Line info generation (`.debug_line`) - -use std::ffi::OsStr; -use std::path::{Component, Path}; - -use cranelift_codegen::binemit::CodeOffset; -use cranelift_codegen::MachSrcLoc; -use gimli::write::{AttributeValue, FileId, FileInfo, LineProgram, LineString, LineStringTable}; -use rustc_span::{ - FileName, Pos, SourceFile, SourceFileAndLine, SourceFileHash, SourceFileHashAlgorithm, -}; - -use crate::debuginfo::emit::address_for_func; -use crate::debuginfo::FunctionDebugContext; -use crate::prelude::*; - -// OPTIMIZATION: It is cheaper to do this in one pass than using `.parent()` and `.file_name()`. -fn split_path_dir_and_file(path: &Path) -> (&Path, &OsStr) { - let mut iter = path.components(); - let file_name = match iter.next_back() { - Some(Component::Normal(p)) => p, - component => { - panic!( - "Path component {:?} of path {} is an invalid filename", - component, - path.display() - ); - } - }; - let parent = iter.as_path(); - (parent, file_name) -} - -// OPTIMIZATION: Avoid UTF-8 validation on UNIX. -fn osstr_as_utf8_bytes(path: &OsStr) -> &[u8] { - #[cfg(unix)] - { - use std::os::unix::ffi::OsStrExt; - path.as_bytes() - } - #[cfg(not(unix))] - { - path.to_str().unwrap().as_bytes() - } -} - -const MD5_LEN: usize = 16; - -fn make_file_info(hash: SourceFileHash) -> Option { - if hash.kind == SourceFileHashAlgorithm::Md5 { - let mut buf = [0u8; MD5_LEN]; - buf.copy_from_slice(hash.hash_bytes()); - Some(FileInfo { timestamp: 0, size: 0, md5: buf }) - } else { - None - } -} - -impl DebugContext { - pub(crate) fn get_span_loc( - &mut self, - tcx: TyCtxt<'_>, - function_span: Span, - span: Span, - ) -> (FileId, u64, u64) { - // Based on https://github.com/rust-lang/rust/blob/e369d87b015a84653343032833d65d0545fd3f26/src/librustc_codegen_ssa/mir/mod.rs#L116-L131 - // In order to have a good line stepping behavior in debugger, we overwrite debug - // locations of macro expansions with that of the outermost expansion site (when the macro is - // annotated with `#[collapse_debuginfo]` or when `-Zdebug-macros` is provided). - let span = tcx.collapsed_debuginfo(span, function_span); - match tcx.sess.source_map().lookup_line(span.lo()) { - Ok(SourceFileAndLine { sf: file, line }) => { - let file_id = self.add_source_file(&file); - let line_pos = file.lines()[line]; - let col = file.relative_position(span.lo()) - line_pos; - - (file_id, u64::try_from(line).unwrap() + 1, u64::from(col.to_u32()) + 1) - } - Err(file) => (self.add_source_file(&file), 0, 0), - } - } - - pub(crate) fn add_source_file(&mut self, source_file: &SourceFile) -> FileId { - let cache_key = (source_file.stable_id, source_file.src_hash); - *self.created_files.entry(cache_key).or_insert_with(|| { - let line_program: &mut LineProgram = &mut self.dwarf.unit.line_program; - let line_strings: &mut LineStringTable = &mut self.dwarf.line_strings; - - match &source_file.name { - FileName::Real(path) => { - let (dir_path, file_name) = - split_path_dir_and_file(path.to_path(self.filename_display_preference)); - let dir_name = osstr_as_utf8_bytes(dir_path.as_os_str()); - let file_name = osstr_as_utf8_bytes(file_name); - - let dir_id = if !dir_name.is_empty() { - let dir_name = - LineString::new(dir_name, line_program.encoding(), line_strings); - line_program.add_directory(dir_name) - } else { - line_program.default_directory() - }; - let file_name = - LineString::new(file_name, line_program.encoding(), line_strings); - - let info = make_file_info(source_file.src_hash); - - line_program.file_has_md5 &= info.is_some(); - line_program.add_file(file_name, dir_id, info) - } - filename => { - let dir_id = line_program.default_directory(); - let dummy_file_name = LineString::new( - filename.display(self.filename_display_preference).to_string().into_bytes(), - line_program.encoding(), - line_strings, - ); - line_program.add_file(dummy_file_name, dir_id, None) - } - } - }) - } -} - -impl FunctionDebugContext { - pub(crate) fn add_dbg_loc(&mut self, file_id: FileId, line: u64, column: u64) -> SourceLoc { - let (index, _) = self.source_loc_set.insert_full((file_id, line, column)); - SourceLoc::new(u32::try_from(index).unwrap()) - } - - pub(super) fn create_debug_lines( - &mut self, - debug_context: &mut DebugContext, - func_id: FuncId, - context: &Context, - ) -> CodeOffset { - let create_row_for_span = - |debug_context: &mut DebugContext, source_loc: (FileId, u64, u64)| { - let (file_id, line, col) = source_loc; - - debug_context.dwarf.unit.line_program.row().file = file_id; - debug_context.dwarf.unit.line_program.row().line = line; - debug_context.dwarf.unit.line_program.row().column = col; - debug_context.dwarf.unit.line_program.generate_row(); - }; - - debug_context.dwarf.unit.line_program.begin_sequence(Some(address_for_func(func_id))); - - let mut func_end = 0; - - let mcr = context.compiled_code().unwrap(); - for &MachSrcLoc { start, end, loc } in mcr.buffer.get_srclocs_sorted() { - debug_context.dwarf.unit.line_program.row().address_offset = u64::from(start); - if !loc.is_default() { - let source_loc = self.source_loc_set[loc.bits() as usize]; - create_row_for_span(debug_context, source_loc); - } else { - create_row_for_span(debug_context, self.function_source_loc); - } - func_end = end; - } - - debug_context.dwarf.unit.line_program.end_sequence(u64::from(func_end)); - - let func_end = mcr.buffer.total_size(); - - assert_ne!(func_end, 0); - - let entry = debug_context.dwarf.unit.get_mut(self.entry_id); - entry.set(gimli::DW_AT_low_pc, AttributeValue::Address(address_for_func(func_id))); - entry.set(gimli::DW_AT_high_pc, AttributeValue::Udata(u64::from(func_end))); - - func_end - } -} +use std::ffi::OsStr;use std::path::{Component,Path};use cranelift_codegen:://(); +binemit::CodeOffset;use cranelift_codegen::MachSrcLoc;use gimli::write::{//({}); +AttributeValue,FileId,FileInfo,LineProgram,LineString,LineStringTable};use//{;}; +rustc_span::{FileName,Pos,SourceFile,SourceFileAndLine,SourceFileHash,//((),()); +SourceFileHashAlgorithm,};use crate::debuginfo::emit::address_for_func;use//{;}; +crate::debuginfo::FunctionDebugContext;use crate::prelude::*;fn//*&*&();((),()); +split_path_dir_and_file(path:&Path)->(&Path,&OsStr){if true{};let mut iter=path. +components();;let file_name=match iter.next_back(){Some(Component::Normal(p))=>p +,component=>{{;};panic!("Path component {:?} of path {} is an invalid filename", +component,path.display());;}};;;let parent=iter.as_path();;(parent,file_name)}fn +osstr_as_utf8_bytes(path:&OsStr)->&[u8]{#[cfg(unix)]{();use std::os::unix::ffi:: +OsStrExt;3;path.as_bytes()}#[cfg(not(unix))]{path.to_str().unwrap().as_bytes()}} +const MD5_LEN:usize=16;fn make_file_info(hash:SourceFileHash)->Option +{if hash.kind==SourceFileHashAlgorithm::Md5{3;let mut buf=[0u8;MD5_LEN];3;3;buf. +copy_from_slice(hash.hash_bytes());3;Some(FileInfo{timestamp:0,size:0,md5:buf})} +else{None}}impl DebugContext{pub(crate)fn get_span_loc(&mut self,tcx:TyCtxt<'_> +,function_span:Span,span:Span,)->(FileId,u64,u64){((),());let _=();let span=tcx. +collapsed_debuginfo(span,function_span);;match tcx.sess.source_map().lookup_line +(span.lo()){Ok(SourceFileAndLine{sf:file,line})=>{loop{break;};let file_id=self. +add_source_file(&file);();();let line_pos=file.lines()[line];();();let col=file. +relative_position(span.lo())-line_pos;3;(file_id,u64::try_from(line).unwrap()+1, +u64::from((col.to_u32()))+1)}Err(file)=>(self.add_source_file(&file),0,0),}}pub( +crate)fn add_source_file(&mut self,source_file:&SourceFile)->FileId{let _=();let +cache_key=(source_file.stable_id,source_file.src_hash);({});*self.created_files. +entry(cache_key).or_insert_with(||{;let line_program:&mut LineProgram=&mut self. +dwarf.unit.line_program;;;let line_strings:&mut LineStringTable=&mut self.dwarf. +line_strings;{;};match&source_file.name{FileName::Real(path)=>{{;};let(dir_path, +file_name)=split_path_dir_and_file(path.to_path(self.//loop{break};loop{break;}; +filename_display_preference));{;};{;};let dir_name=osstr_as_utf8_bytes(dir_path. +as_os_str());3;3;let file_name=osstr_as_utf8_bytes(file_name);3;3;let dir_id=if! +dir_name.is_empty(){;let dir_name=LineString::new(dir_name,line_program.encoding +(),line_strings);((),());line_program.add_directory(dir_name)}else{line_program. +default_directory()};();();let file_name=LineString::new(file_name,line_program. +encoding(),line_strings);();3;let info=make_file_info(source_file.src_hash);3;3; +line_program.file_has_md5&=info.is_some();{();};line_program.add_file(file_name, +dir_id,info)}filename=>{();let dir_id=line_program.default_directory();();();let +dummy_file_name=LineString::new(filename.display(self.//loop{break};loop{break}; +filename_display_preference).to_string().into_bytes(),(line_program.encoding()), +line_strings,);({});line_program.add_file(dummy_file_name,dir_id,None)}}})}}impl +FunctionDebugContext{pub(crate)fn add_dbg_loc(& mut self,file_id:FileId,line:u64 +,column:u64)->SourceLoc{3;let(index,_)=self.source_loc_set.insert_full((file_id, +line,column));((),());SourceLoc::new(u32::try_from(index).unwrap())}pub(super)fn +create_debug_lines(&mut self,debug_context:&mut DebugContext,func_id:FuncId,//3; +context:&Context,)->CodeOffset{{();};let create_row_for_span=|debug_context:&mut +DebugContext,source_loc:(FileId,u64,u64)|{3;let(file_id,line,col)=source_loc;3;; +debug_context.dwarf.unit.line_program.row().file=file_id;3;;debug_context.dwarf. +unit.line_program.row().line=line;;;debug_context.dwarf.unit.line_program.row(). +column=col;;debug_context.dwarf.unit.line_program.generate_row();};debug_context +.dwarf.unit.line_program.begin_sequence(Some(address_for_func(func_id)));3;3;let +mut func_end=0;;;let mcr=context.compiled_code().unwrap();;for&MachSrcLoc{start, +end,loc}in mcr.buffer.get_srclocs_sorted(){loop{break};debug_context.dwarf.unit. +line_program.row().address_offset=u64::from(start);();if!loc.is_default(){();let +source_loc=self.source_loc_set[loc.bits()as usize];({});{;};create_row_for_span( +debug_context,source_loc);({});}else{{;};create_row_for_span(debug_context,self. +function_source_loc);3;}3;func_end=end;;};debug_context.dwarf.unit.line_program. +end_sequence(u64::from(func_end));();3;let func_end=mcr.buffer.total_size();3;3; +assert_ne!(func_end,0);;let entry=debug_context.dwarf.unit.get_mut(self.entry_id +);{;};();entry.set(gimli::DW_AT_low_pc,AttributeValue::Address(address_for_func( +func_id)));();();entry.set(gimli::DW_AT_high_pc,AttributeValue::Udata(u64::from( +func_end)));if let _=(){};*&*&();((),());if let _=(){};*&*&();((),());func_end}} diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs index 5d943b5d99657..37dd8c183b25d 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs @@ -1,337 +1,121 @@ -//! Handling of everything related to debuginfo. - -mod emit; -mod line_info; -mod object; -mod types; -mod unwind; - -use cranelift_codegen::ir::Endianness; -use cranelift_codegen::isa::TargetIsa; -use cranelift_module::DataId; -use gimli::write::{ - Address, AttributeValue, DwarfUnit, Expression, FileId, LineProgram, LineString, Range, - RangeList, UnitEntryId, -}; -use gimli::{AArch64, Encoding, Format, LineEncoding, Register, RiscV, RunTimeEndian, X86_64}; -use indexmap::IndexSet; -use rustc_codegen_ssa::debuginfo::type_names; -use rustc_hir::def::DefKind; -use rustc_hir::def_id::DefIdMap; -use rustc_session::Session; -use rustc_span::{SourceFileHash, StableSourceFileId}; -use rustc_target::abi::call::FnAbi; - -pub(crate) use self::emit::{DebugReloc, DebugRelocName}; -pub(crate) use self::types::TypeDebugContext; -pub(crate) use self::unwind::UnwindContext; -use crate::debuginfo::emit::{address_for_data, address_for_func}; -use crate::prelude::*; - -pub(crate) fn producer(sess: &Session) -> String { - format!("rustc version {} with cranelift {}", sess.cfg_version, cranelift_codegen::VERSION) -} - -pub(crate) struct DebugContext { - endian: RunTimeEndian, - - dwarf: DwarfUnit, - unit_range_list: RangeList, - created_files: FxHashMap<(StableSourceFileId, SourceFileHash), FileId>, - stack_pointer_register: Register, - namespace_map: DefIdMap, - array_size_type: UnitEntryId, - - filename_display_preference: FileNameDisplayPreference, -} - -pub(crate) struct FunctionDebugContext { - entry_id: UnitEntryId, - function_source_loc: (FileId, u64, u64), - source_loc_set: IndexSet<(FileId, u64, u64)>, -} - -impl DebugContext { - pub(crate) fn new(tcx: TyCtxt<'_>, isa: &dyn TargetIsa, cgu_name: &str) -> Self { - let encoding = Encoding { - format: Format::Dwarf32, - // FIXME this should be configurable - // macOS doesn't seem to support DWARF > 3 - // 5 version is required for md5 file hash - version: if tcx.sess.target.is_like_osx { - 3 - } else { - // FIXME change to version 5 once the gdb and lldb shipping with the latest debian - // support it. - 4 - }, - address_size: isa.frontend_config().pointer_bytes(), - }; - - let endian = match isa.endianness() { - Endianness::Little => RunTimeEndian::Little, - Endianness::Big => RunTimeEndian::Big, - }; - - let stack_pointer_register = match isa.triple().architecture { - target_lexicon::Architecture::Aarch64(_) => AArch64::SP, - target_lexicon::Architecture::Riscv64(_) => RiscV::SP, - target_lexicon::Architecture::X86_64 | target_lexicon::Architecture::X86_64h => { - X86_64::RSP - } - _ => Register(u16::MAX), - }; - - let mut dwarf = DwarfUnit::new(encoding); - - use rustc_session::config::RemapPathScopeComponents; - - let filename_display_preference = - tcx.sess.filename_display_preference(RemapPathScopeComponents::DEBUGINFO); - - let producer = producer(tcx.sess); - let comp_dir = - tcx.sess.opts.working_dir.to_string_lossy(filename_display_preference).to_string(); - - let (name, file_info) = match tcx.sess.local_crate_source_file() { - Some(path) => { - let name = path.to_string_lossy(filename_display_preference).to_string(); - (name, None) - } - None => (tcx.crate_name(LOCAL_CRATE).to_string(), None), - }; - - let mut line_program = LineProgram::new( - encoding, - LineEncoding::default(), - LineString::new(comp_dir.as_bytes(), encoding, &mut dwarf.line_strings), - LineString::new(name.as_bytes(), encoding, &mut dwarf.line_strings), - file_info, - ); - line_program.file_has_md5 = file_info.is_some(); - - dwarf.unit.line_program = line_program; - - { - let name = dwarf.strings.add(format!("{name}/@/{cgu_name}")); - let comp_dir = dwarf.strings.add(comp_dir); - - let root = dwarf.unit.root(); - let root = dwarf.unit.get_mut(root); - root.set(gimli::DW_AT_producer, AttributeValue::StringRef(dwarf.strings.add(producer))); - root.set(gimli::DW_AT_language, AttributeValue::Language(gimli::DW_LANG_Rust)); - root.set(gimli::DW_AT_name, AttributeValue::StringRef(name)); - - // This will be replaced when emitting the debuginfo. It is only - // defined here to ensure that the order of the attributes matches - // rustc. - root.set(gimli::DW_AT_stmt_list, AttributeValue::Udata(0)); - - root.set(gimli::DW_AT_comp_dir, AttributeValue::StringRef(comp_dir)); - root.set(gimli::DW_AT_low_pc, AttributeValue::Address(Address::Constant(0))); - } - - let array_size_type = dwarf.unit.add(dwarf.unit.root(), gimli::DW_TAG_base_type); - let array_size_type_entry = dwarf.unit.get_mut(array_size_type); - array_size_type_entry.set( - gimli::DW_AT_name, - AttributeValue::StringRef(dwarf.strings.add("__ARRAY_SIZE_TYPE__")), - ); - array_size_type_entry - .set(gimli::DW_AT_encoding, AttributeValue::Encoding(gimli::DW_ATE_unsigned)); - array_size_type_entry.set( - gimli::DW_AT_byte_size, - AttributeValue::Udata(isa.frontend_config().pointer_bytes().into()), - ); - - DebugContext { - endian, - dwarf, - unit_range_list: RangeList(Vec::new()), - created_files: FxHashMap::default(), - stack_pointer_register, - namespace_map: DefIdMap::default(), - array_size_type, - filename_display_preference, - } - } - - fn item_namespace(&mut self, tcx: TyCtxt<'_>, def_id: DefId) -> UnitEntryId { - if let Some(&scope) = self.namespace_map.get(&def_id) { - return scope; - } - - let def_key = tcx.def_key(def_id); - let parent_scope = def_key - .parent - .map(|parent| self.item_namespace(tcx, DefId { krate: def_id.krate, index: parent })) - .unwrap_or(self.dwarf.unit.root()); - - let namespace_name = { - let mut output = String::new(); - type_names::push_item_name(tcx, def_id, false, &mut output); - output - }; - let namespace_name_id = self.dwarf.strings.add(namespace_name); - - let scope = self.dwarf.unit.add(parent_scope, gimli::DW_TAG_namespace); - let scope_entry = self.dwarf.unit.get_mut(scope); - scope_entry.set(gimli::DW_AT_name, AttributeValue::StringRef(namespace_name_id)); - - self.namespace_map.insert(def_id, scope); - scope - } - - pub(crate) fn define_function<'tcx>( - &mut self, - tcx: TyCtxt<'tcx>, - type_dbg: &mut TypeDebugContext<'tcx>, - instance: Instance<'tcx>, - fn_abi: &'tcx FnAbi<'tcx, Ty<'tcx>>, - linkage_name: &str, - function_span: Span, - ) -> FunctionDebugContext { - let (file_id, line, column) = self.get_span_loc(tcx, function_span, function_span); - - let scope = self.item_namespace(tcx, tcx.parent(instance.def_id())); - - let mut name = String::new(); - type_names::push_item_name(tcx, instance.def_id(), false, &mut name); - - // Find the enclosing function, in case this is a closure. - let enclosing_fn_def_id = tcx.typeck_root_def_id(instance.def_id()); - - // We look up the generics of the enclosing function and truncate the args - // to their length in order to cut off extra stuff that might be in there for - // closures or coroutines. - let generics = tcx.generics_of(enclosing_fn_def_id); - let args = instance.args.truncate_to(tcx, generics); - - type_names::push_generic_params( - tcx, - tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), args), - enclosing_fn_def_id, - &mut name, - ); - - let entry_id = self.dwarf.unit.add(scope, gimli::DW_TAG_subprogram); - let entry = self.dwarf.unit.get_mut(entry_id); - let linkage_name_id = - if name != linkage_name { Some(self.dwarf.strings.add(linkage_name)) } else { None }; - let name_id = self.dwarf.strings.add(name); - - // These will be replaced in FunctionDebugContext::finalize. They are - // only defined here to ensure that the order of the attributes matches - // rustc. - entry.set(gimli::DW_AT_low_pc, AttributeValue::Udata(0)); - entry.set(gimli::DW_AT_high_pc, AttributeValue::Udata(0)); - - let mut frame_base_expr = Expression::new(); - frame_base_expr.op_reg(self.stack_pointer_register); - entry.set(gimli::DW_AT_frame_base, AttributeValue::Exprloc(frame_base_expr)); - - if let Some(linkage_name_id) = linkage_name_id { - entry.set(gimli::DW_AT_linkage_name, AttributeValue::StringRef(linkage_name_id)); - } - // Gdb requires DW_AT_name. Otherwise the DW_TAG_subprogram is skipped. - entry.set(gimli::DW_AT_name, AttributeValue::StringRef(name_id)); - - entry.set(gimli::DW_AT_decl_file, AttributeValue::FileIndex(Some(file_id))); - entry.set(gimli::DW_AT_decl_line, AttributeValue::Udata(line)); - - if !fn_abi.ret.is_ignore() { - let return_dw_ty = self.debug_type(tcx, type_dbg, fn_abi.ret.layout.ty); - let entry = self.dwarf.unit.get_mut(entry_id); - entry.set(gimli::DW_AT_type, AttributeValue::UnitRef(return_dw_ty)); - } - - if tcx.is_reachable_non_generic(instance.def_id()) { - let entry = self.dwarf.unit.get_mut(entry_id); - entry.set(gimli::DW_AT_external, AttributeValue::FlagPresent); - } - - FunctionDebugContext { - entry_id, - function_source_loc: (file_id, line, column), - source_loc_set: IndexSet::new(), - } - } - - // Adapted from https://github.com/rust-lang/rust/blob/10a7aa14fed9b528b74b0f098c4899c37c09a9c7/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs#L1288-L1346 - pub(crate) fn define_static<'tcx>( - &mut self, - tcx: TyCtxt<'tcx>, - type_dbg: &mut TypeDebugContext<'tcx>, - def_id: DefId, - data_id: DataId, - ) { - let DefKind::Static { nested, .. } = tcx.def_kind(def_id) else { bug!() }; - if nested { - return; - } - - let scope = self.item_namespace(tcx, tcx.parent(def_id)); - - let span = tcx.def_span(def_id); - let (file_id, line, _column) = self.get_span_loc(tcx, span, span); - - let static_type = Instance::mono(tcx, def_id).ty(tcx, ty::ParamEnv::reveal_all()); - let static_layout = tcx.layout_of(ty::ParamEnv::reveal_all().and(static_type)).unwrap(); - // FIXME use the actual type layout - let type_id = self.debug_type(tcx, type_dbg, static_type); - - let name = tcx.item_name(def_id); - let linkage_name = tcx.symbol_name(Instance::mono(tcx, def_id)).name; - - let entry_id = self.dwarf.unit.add(scope, gimli::DW_TAG_variable); - let entry = self.dwarf.unit.get_mut(entry_id); - let linkage_name_id = if name.as_str() != linkage_name { - Some(self.dwarf.strings.add(linkage_name)) - } else { - None - }; - let name_id = self.dwarf.strings.add(name.as_str()); - - entry.set(gimli::DW_AT_name, AttributeValue::StringRef(name_id)); - entry.set(gimli::DW_AT_type, AttributeValue::UnitRef(type_id)); - - if tcx.is_reachable_non_generic(def_id) { - entry.set(gimli::DW_AT_external, AttributeValue::FlagPresent); - } - - entry.set(gimli::DW_AT_decl_file, AttributeValue::FileIndex(Some(file_id))); - entry.set(gimli::DW_AT_decl_line, AttributeValue::Udata(line)); - - entry.set(gimli::DW_AT_alignment, AttributeValue::Udata(static_layout.align.pref.bytes())); - - let mut expr = Expression::new(); - expr.op_addr(address_for_data(data_id)); - entry.set(gimli::DW_AT_location, AttributeValue::Exprloc(expr)); - - if let Some(linkage_name_id) = linkage_name_id { - entry.set(gimli::DW_AT_linkage_name, AttributeValue::StringRef(linkage_name_id)); - } - } -} - -impl FunctionDebugContext { - pub(crate) fn finalize( - mut self, - debug_context: &mut DebugContext, - func_id: FuncId, - context: &Context, - ) { - let end = self.create_debug_lines(debug_context, func_id, context); - - debug_context - .unit_range_list - .0 - .push(Range::StartLength { begin: address_for_func(func_id), length: u64::from(end) }); - - let func_entry = debug_context.dwarf.unit.get_mut(self.entry_id); - // Gdb requires both DW_AT_low_pc and DW_AT_high_pc. Otherwise the DW_TAG_subprogram is skipped. - func_entry.set(gimli::DW_AT_low_pc, AttributeValue::Address(address_for_func(func_id))); - // Using Udata for DW_AT_high_pc requires at least DWARF4 - func_entry.set(gimli::DW_AT_high_pc, AttributeValue::Udata(u64::from(end))); - } -} +mod emit;mod line_info;mod object;mod types;mod unwind;use cranelift_codegen::// +ir::Endianness;use cranelift_codegen::isa::TargetIsa;use cranelift_module:://(); +DataId;use gimli::write::{Address,AttributeValue,DwarfUnit,Expression,FileId,//; +LineProgram,LineString,Range,RangeList,UnitEntryId,};use gimli::{AArch64,//({}); +Encoding,Format,LineEncoding,Register,RiscV,RunTimeEndian,X86_64};use indexmap// +::IndexSet;use rustc_codegen_ssa::debuginfo::type_names;use rustc_hir::def:://3; +DefKind;use rustc_hir::def_id::DefIdMap;use rustc_session::Session;use//((),()); +rustc_span::{SourceFileHash,StableSourceFileId};use rustc_target::abi::call:://; +FnAbi;pub(crate)use self::emit::{DebugReloc,DebugRelocName};pub(crate)use self// +::types::TypeDebugContext;pub(crate)use self::unwind::UnwindContext;use crate:: +debuginfo::emit::{address_for_data,address_for_func}; use crate::prelude::*;pub( +crate)fn producer(sess:&Session)->String{format!(//if let _=(){};*&*&();((),()); +"rustc version {} with cranelift {}",sess.cfg_version,cranelift_codegen:://({}); +VERSION)}pub(crate)struct DebugContext{endian:RunTimeEndian,dwarf:DwarfUnit,//3; +unit_range_list:RangeList,created_files:FxHashMap<(StableSourceFileId,//((),()); +SourceFileHash),FileId>,stack_pointer_register :Register,namespace_map:DefIdMap< +UnitEntryId>,array_size_type:UnitEntryId,filename_display_preference://let _=(); +FileNameDisplayPreference,}pub(crate)struct FunctionDebugContext{entry_id://{;}; +UnitEntryId,function_source_loc:(FileId,u64,u64),source_loc_set:IndexSet<(//{;}; +FileId,u64,u64)>,}impl DebugContext{pub(crate)fn new(tcx:TyCtxt<'_>,isa:&dyn//3; +TargetIsa,cgu_name:&str)->Self{{;};let encoding=Encoding{format:Format::Dwarf32, +version:if tcx.sess.target.is_like_osx{((((3))))}else{(((4)))},address_size:isa. +frontend_config().pointer_bytes(),};({});({});let endian=match isa.endianness(){ +Endianness::Little=>RunTimeEndian::Little, Endianness::Big=>RunTimeEndian::Big,} +;3;3;let stack_pointer_register=match isa.triple().architecture{target_lexicon:: +Architecture::Aarch64(_)=>AArch64::SP,target_lexicon::Architecture::Riscv64(_)// +=>RiscV::SP,target_lexicon:: Architecture::X86_64|target_lexicon::Architecture:: +X86_64h=>{X86_64::RSP}_=>Register(u16::MAX),};();3;let mut dwarf=DwarfUnit::new( +encoding);{;};{;};use rustc_session::config::RemapPathScopeComponents;{;};();let +filename_display_preference=tcx.sess.filename_display_preference(//loop{break;}; +RemapPathScopeComponents::DEBUGINFO);3;3;let producer=producer(tcx.sess);3;3;let +comp_dir=tcx.sess. opts.working_dir.to_string_lossy(filename_display_preference) +.to_string();;let(name,file_info)=match tcx.sess.local_crate_source_file(){Some( +path)=>{;let name=path.to_string_lossy(filename_display_preference).to_string(); +(name,None)}None=>(tcx.crate_name(LOCAL_CRATE).to_string(),None),};();();let mut +line_program=LineProgram::new(encoding,LineEncoding ::default(),LineString::new( +comp_dir.as_bytes(),encoding,((&mut dwarf .line_strings))),LineString::new(name. +as_bytes(),encoding,&mut dwarf.line_strings),file_info,);({});({});line_program. +file_has_md5=file_info.is_some();;dwarf.unit.line_program=line_program;{let name +=dwarf.strings.add(format!("{name}/@/{cgu_name}"));;;let comp_dir=dwarf.strings. +add(comp_dir);;let root=dwarf.unit.root();let root=dwarf.unit.get_mut(root);root +.set(gimli::DW_AT_producer,AttributeValue:: StringRef(dwarf.strings.add(producer +)));;root.set(gimli::DW_AT_language,AttributeValue::Language(gimli::DW_LANG_Rust +));;root.set(gimli::DW_AT_name,AttributeValue::StringRef(name));root.set(gimli:: +DW_AT_stmt_list,AttributeValue::Udata(0));{;};();root.set(gimli::DW_AT_comp_dir, +AttributeValue::StringRef(comp_dir));*&*&();*&*&();root.set(gimli::DW_AT_low_pc, +AttributeValue::Address(Address::Constant(0)));;}let array_size_type=dwarf.unit. +add(dwarf.unit.root(),gimli::DW_TAG_base_type);;let array_size_type_entry=dwarf. +unit.get_mut(array_size_type);();();array_size_type_entry.set(gimli::DW_AT_name, +AttributeValue::StringRef(dwarf.strings.add("__ARRAY_SIZE_TYPE__")),);({});({}); +array_size_type_entry.set(gimli::DW_AT_encoding,AttributeValue::Encoding(gimli// +::DW_ATE_unsigned));{();};({});array_size_type_entry.set(gimli::DW_AT_byte_size, +AttributeValue::Udata(isa.frontend_config().pointer_bytes().into()),);if true{}; +DebugContext{endian,dwarf,unit_range_list:(RangeList(Vec::new())),created_files: +FxHashMap::default(),stack_pointer_register,namespace_map:(DefIdMap::default()), +array_size_type,filename_display_preference,}}fn item_namespace(&mut self,tcx:// +TyCtxt<'_>,def_id:DefId)->UnitEntryId{if let Some(&scope)=self.namespace_map.//; +get(&def_id){;return scope;;};let def_key=tcx.def_key(def_id);;let parent_scope= +def_key.parent.map(|parent|self.item_namespace(tcx,DefId{krate:def_id.krate,//3; +index:parent})).unwrap_or(self.dwarf.unit.root());;;let namespace_name={;let mut +output=String::new();;;type_names::push_item_name(tcx,def_id,false,&mut output); +output};;let namespace_name_id=self.dwarf.strings.add(namespace_name);let scope= +self.dwarf.unit.add(parent_scope,gimli::DW_TAG_namespace);;let scope_entry=self. +dwarf.unit.get_mut(scope);3;3;scope_entry.set(gimli::DW_AT_name,AttributeValue:: +StringRef(namespace_name_id));;self.namespace_map.insert(def_id,scope);scope}pub +(crate)fn define_function<'tcx>(&mut self,tcx:TyCtxt<'tcx>,type_dbg:&mut//{();}; +TypeDebugContext<'tcx>,instance:Instance<'tcx>,fn_abi:&'tcx FnAbi<'tcx,Ty<'tcx// +>>,linkage_name:&str,function_span:Span,)->FunctionDebugContext{{;};let(file_id, +line,column)=self.get_span_loc(tcx,function_span,function_span);;let scope=self. +item_namespace(tcx,tcx.parent(instance.def_id()));;;let mut name=String::new();; +type_names::push_item_name(tcx,instance.def_id(),false,&mut name);{();};({});let +enclosing_fn_def_id=tcx.typeck_root_def_id(instance.def_id());;let generics=tcx. +generics_of(enclosing_fn_def_id);{;};{;};let args=instance.args.truncate_to(tcx, +generics);;;type_names::push_generic_params(tcx,tcx.normalize_erasing_regions(ty +::ParamEnv::reveal_all(),args),enclosing_fn_def_id,&mut name,);3;3;let entry_id= +self.dwarf.unit.add(scope,gimli::DW_TAG_subprogram);;;let entry=self.dwarf.unit. +get_mut(entry_id);3;3;let linkage_name_id=if name!=linkage_name{Some(self.dwarf. +strings.add(linkage_name))}else{None};;let name_id=self.dwarf.strings.add(name); +entry.set(gimli::DW_AT_low_pc,AttributeValue::Udata(0));{;};();entry.set(gimli:: +DW_AT_high_pc,AttributeValue::Udata(0));;let mut frame_base_expr=Expression::new +();3;3;frame_base_expr.op_reg(self.stack_pointer_register);3;3;entry.set(gimli:: +DW_AT_frame_base,AttributeValue::Exprloc(frame_base_expr));let _=();if let Some( +linkage_name_id)=linkage_name_id{let _=||();entry.set(gimli::DW_AT_linkage_name, +AttributeValue::StringRef(linkage_name_id));{;};}();entry.set(gimli::DW_AT_name, +AttributeValue::StringRef(name_id));{();};({});entry.set(gimli::DW_AT_decl_file, +AttributeValue::FileIndex(Some(file_id)));();3;entry.set(gimli::DW_AT_decl_line, +AttributeValue::Udata(line));3;if!fn_abi.ret.is_ignore(){;let return_dw_ty=self. +debug_type(tcx,type_dbg,fn_abi.ret.layout.ty);;let entry=self.dwarf.unit.get_mut +(entry_id);;entry.set(gimli::DW_AT_type,AttributeValue::UnitRef(return_dw_ty));} +if tcx.is_reachable_non_generic(instance.def_id()){();let entry=self.dwarf.unit. +get_mut(entry_id);;entry.set(gimli::DW_AT_external,AttributeValue::FlagPresent); +}FunctionDebugContext{entry_id,function_source_loc:((( (file_id,line,column)))), +source_loc_set:IndexSet::new(),}}pub( crate)fn define_static<'tcx>(&mut self,tcx +:TyCtxt<'tcx>,type_dbg:&mut TypeDebugContext <'tcx>,def_id:DefId,data_id:DataId, +){3;let DefKind::Static{nested,..}=tcx.def_kind(def_id)else{bug!()};;if nested{; +return;3;};let scope=self.item_namespace(tcx,tcx.parent(def_id));;;let span=tcx. +def_span(def_id);;let(file_id,line,_column)=self.get_span_loc(tcx,span,span);let +static_type=Instance::mono(tcx,def_id).ty(tcx,ty::ParamEnv::reveal_all());3;;let +static_layout=tcx.layout_of(ty::ParamEnv:: reveal_all().and(static_type)).unwrap +();;let type_id=self.debug_type(tcx,type_dbg,static_type);let name=tcx.item_name +(def_id);;;let linkage_name=tcx.symbol_name(Instance::mono(tcx,def_id)).name;let +entry_id=self.dwarf.unit.add(scope,gimli::DW_TAG_variable);;let entry=self.dwarf +.unit.get_mut(entry_id);;let linkage_name_id=if name.as_str()!=linkage_name{Some +(self.dwarf.strings.add(linkage_name))}else{None};{;};();let name_id=self.dwarf. +strings.add(name.as_str());({});{;};entry.set(gimli::DW_AT_name,AttributeValue:: +StringRef(name_id));;entry.set(gimli::DW_AT_type,AttributeValue::UnitRef(type_id +));();if tcx.is_reachable_non_generic(def_id){3;entry.set(gimli::DW_AT_external, +AttributeValue::FlagPresent);;}entry.set(gimli::DW_AT_decl_file,AttributeValue:: +FileIndex(Some(file_id)));();3;entry.set(gimli::DW_AT_decl_line,AttributeValue:: +Udata(line));{();};{();};entry.set(gimli::DW_AT_alignment,AttributeValue::Udata( +static_layout.align.pref.bytes()));;let mut expr=Expression::new();expr.op_addr( +address_for_data(data_id));();3;entry.set(gimli::DW_AT_location,AttributeValue:: +Exprloc(expr));3;if let Some(linkage_name_id)=linkage_name_id{;entry.set(gimli:: +DW_AT_linkage_name,AttributeValue::StringRef(linkage_name_id));if true{};}}}impl +FunctionDebugContext{pub(crate)fn finalize(mut self,debug_context:&mut//((),()); +DebugContext,func_id:FuncId,context:&Context,){;let end=self.create_debug_lines( +debug_context,func_id,context);();3;debug_context.unit_range_list.0.push(Range:: +StartLength{begin:address_for_func(func_id),length:u64::from(end)});({});{;};let +func_entry=debug_context.dwarf.unit.get_mut(self.entry_id);;func_entry.set(gimli +::DW_AT_low_pc,AttributeValue::Address(address_for_func(func_id)));;;func_entry. +set(gimli::DW_AT_high_pc,AttributeValue::Udata(u64::from(end)));if let _=(){};}} diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs index 27eabd8a0a616..a7f9830456ab1 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs @@ -1,83 +1,26 @@ -use cranelift_module::{DataId, FuncId}; -use cranelift_object::ObjectProduct; -use gimli::SectionId; -use object::write::{Relocation, StandardSegment}; -use object::{RelocationEncoding, SectionKind}; -use rustc_data_structures::fx::FxHashMap; - -use crate::debuginfo::{DebugReloc, DebugRelocName}; - -pub(super) trait WriteDebugInfo { - type SectionId: Copy; - - fn add_debug_section(&mut self, name: SectionId, data: Vec) -> Self::SectionId; - fn add_debug_reloc( - &mut self, - section_map: &FxHashMap, - from: &Self::SectionId, - reloc: &DebugReloc, - ); -} - -impl WriteDebugInfo for ObjectProduct { - type SectionId = (object::write::SectionId, object::write::SymbolId); - - fn add_debug_section( - &mut self, - id: SectionId, - data: Vec, - ) -> (object::write::SectionId, object::write::SymbolId) { - let name = if self.object.format() == object::BinaryFormat::MachO { - id.name().replace('.', "__") // machO expects __debug_info instead of .debug_info - } else { - id.name().to_string() - } - .into_bytes(); - - let segment = self.object.segment_name(StandardSegment::Debug).to_vec(); - // FIXME use SHT_X86_64_UNWIND for .eh_frame - let section_id = self.object.add_section( - segment, - name, - if id == SectionId::EhFrame { SectionKind::ReadOnlyData } else { SectionKind::Debug }, - ); - self.object - .section_mut(section_id) - .set_data(data, if id == SectionId::EhFrame { 8 } else { 1 }); - let symbol_id = self.object.section_symbol(section_id); - (section_id, symbol_id) - } - - fn add_debug_reloc( - &mut self, - section_map: &FxHashMap, - from: &Self::SectionId, - reloc: &DebugReloc, - ) { - let (symbol, symbol_offset) = match reloc.name { - DebugRelocName::Section(id) => (section_map.get(&id).unwrap().1, 0), - DebugRelocName::Symbol(id) => { - let id = id.try_into().unwrap(); - let symbol_id = if id & 1 << 31 == 0 { - self.function_symbol(FuncId::from_u32(id)) - } else { - self.data_symbol(DataId::from_u32(id & !(1 << 31))) - }; - self.object.symbol_section_and_offset(symbol_id).unwrap_or((symbol_id, 0)) - } - }; - self.object - .add_relocation( - from.0, - Relocation { - offset: u64::from(reloc.offset), - symbol, - kind: reloc.kind, - encoding: RelocationEncoding::Generic, - size: reloc.size * 8, - addend: i64::try_from(symbol_offset).unwrap() + reloc.addend, - }, - ) - .unwrap(); - } -} +use cranelift_module::{DataId,FuncId};use cranelift_object::ObjectProduct;use//; +gimli::SectionId;use object::write::{Relocation,StandardSegment};use object::{// +RelocationEncoding,SectionKind};use rustc_data_structures::fx::FxHashMap;use//3; +crate::debuginfo::{DebugReloc,DebugRelocName};pub(super)trait WriteDebugInfo{//; +type SectionId:Copy;fn add_debug_section(&mut self,name:SectionId,data:Vec) +->Self::SectionId;fn add_debug_reloc(& mut self,section_map:&FxHashMap,from:&Self::SectionId,reloc:&DebugReloc,);}impl//loop{break;}; +WriteDebugInfo for ObjectProduct{type SectionId=(object::write::SectionId,//{;}; +object::write::SymbolId);fn add_debug_section(&mut self,id:SectionId,data:Vec,)->(object::write::SectionId,object::write::SymbolId){({});let name=if self. +object.format()==object::BinaryFormat::MachO{(id.name().replace('.',"__"))}else{ +id.name().to_string()}.into_bytes();{;};();let segment=self.object.segment_name( +StandardSegment::Debug).to_vec();;let section_id=self.object.add_section(segment +,name,if ((id==SectionId::EhFrame)){SectionKind::ReadOnlyData}else{SectionKind:: +Debug},);3;;self.object.section_mut(section_id).set_data(data,if id==SectionId:: +EhFrame{8}else{1});();3;let symbol_id=self.object.section_symbol(section_id);3;( +section_id,symbol_id)}fn add_debug_reloc(&mut self,section_map:&FxHashMap,from:&Self::SectionId,reloc:&DebugReloc,){;let(symbol +,symbol_offset)=match reloc.name{DebugRelocName::Section (id)=>(section_map.get( +&id).unwrap().1,0),DebugRelocName::Symbol(id)=>{;let id=id.try_into().unwrap();; +let symbol_id=if (id&1<<31== 0){self.function_symbol(FuncId::from_u32(id))}else{ +self.data_symbol(DataId::from_u32(id&!(1<<31)))};let _=();if true{};self.object. +symbol_section_and_offset(symbol_id).unwrap_or((symbol_id,0))}};3;3;self.object. +add_relocation(from.0,Relocation{offset:((u64::from(reloc.offset))),symbol,kind: +reloc.kind,encoding:RelocationEncoding::Generic,size:(reloc.size*8),addend:i64:: +try_from(symbol_offset).unwrap()+reloc.addend,},).unwrap();let _=();if true{};}} diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs index 7baf0a3868d2c..c68b53adb04f5 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs @@ -1,204 +1,73 @@ -// Adapted from https://github.com/rust-lang/rust/blob/10a7aa14fed9b528b74b0f098c4899c37c09a9c7/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs - -use gimli::write::{AttributeValue, UnitEntryId}; -use rustc_codegen_ssa::debuginfo::type_names; -use rustc_data_structures::fx::FxHashMap; -use rustc_middle::ty::layout::LayoutOf; -use rustc_middle::ty::{self, Ty, TyCtxt}; - -use crate::{has_ptr_meta, DebugContext, RevealAllLayoutCx}; - -#[derive(Default)] -pub(crate) struct TypeDebugContext<'tcx> { - type_map: FxHashMap, UnitEntryId>, -} - -/// Returns from the enclosing function if the type debuginfo node with the given -/// unique ID can be found in the type map. -macro_rules! return_if_type_created_in_meantime { - ($type_dbg:expr, $ty:expr) => { - if let Some(&type_id) = $type_dbg.type_map.get(&$ty) { - return type_id; - } - }; -} - -impl DebugContext { - pub(crate) fn debug_type<'tcx>( - &mut self, - tcx: TyCtxt<'tcx>, - type_dbg: &mut TypeDebugContext<'tcx>, - ty: Ty<'tcx>, - ) -> UnitEntryId { - if let Some(&type_id) = type_dbg.type_map.get(&ty) { - return type_id; - } - - let type_id = match ty.kind() { - ty::Never | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => { - self.basic_type(tcx, ty) - } - ty::Tuple(elems) if elems.is_empty() => self.basic_type(tcx, ty), - ty::Array(elem_ty, len) => self.array_type( - tcx, - type_dbg, - ty, - *elem_ty, - len.eval_target_usize(tcx, ty::ParamEnv::reveal_all()), - ), - // ty::Slice(_) | ty::Str - // ty::Dynamic - // ty::Foreign - ty::RawPtr(pointee_type, _) | ty::Ref(_, pointee_type, _) => { - self.pointer_type(tcx, type_dbg, ty, *pointee_type) - } - // ty::Adt(def, args) if def.is_box() && args.get(1).map_or(true, |arg| cx.layout_of(arg.expect_ty()).is_1zst()) - // ty::FnDef(..) | ty::FnPtr(..) - // ty::Closure(..) - // ty::Adt(def, ..) - ty::Tuple(components) => self.tuple_type(tcx, type_dbg, ty, *components), - // ty::Param(_) - // FIXME implement remaining types and add unreachable!() to the fallback branch - _ => self.placeholder_for_type(tcx, type_dbg, ty), - }; - - type_dbg.type_map.insert(ty, type_id); - - type_id - } - - fn basic_type<'tcx>(&mut self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> UnitEntryId { - let (name, encoding) = match ty.kind() { - ty::Never => ("!", gimli::DW_ATE_unsigned), - ty::Tuple(elems) if elems.is_empty() => ("()", gimli::DW_ATE_unsigned), - ty::Bool => ("bool", gimli::DW_ATE_boolean), - ty::Char => ("char", gimli::DW_ATE_UTF), - ty::Int(int_ty) => (int_ty.name_str(), gimli::DW_ATE_signed), - ty::Uint(uint_ty) => (uint_ty.name_str(), gimli::DW_ATE_unsigned), - ty::Float(float_ty) => (float_ty.name_str(), gimli::DW_ATE_float), - _ => unreachable!(), - }; - - let type_id = self.dwarf.unit.add(self.dwarf.unit.root(), gimli::DW_TAG_base_type); - let type_entry = self.dwarf.unit.get_mut(type_id); - type_entry.set(gimli::DW_AT_name, AttributeValue::StringRef(self.dwarf.strings.add(name))); - type_entry.set(gimli::DW_AT_encoding, AttributeValue::Encoding(encoding)); - type_entry.set( - gimli::DW_AT_byte_size, - AttributeValue::Udata(RevealAllLayoutCx(tcx).layout_of(ty).size.bytes()), - ); - - type_id - } - - fn array_type<'tcx>( - &mut self, - tcx: TyCtxt<'tcx>, - type_dbg: &mut TypeDebugContext<'tcx>, - array_ty: Ty<'tcx>, - elem_ty: Ty<'tcx>, - len: u64, - ) -> UnitEntryId { - let elem_dw_ty = self.debug_type(tcx, type_dbg, elem_ty); - - return_if_type_created_in_meantime!(type_dbg, array_ty); - - let array_type_id = self.dwarf.unit.add(self.dwarf.unit.root(), gimli::DW_TAG_array_type); - let array_type_entry = self.dwarf.unit.get_mut(array_type_id); - array_type_entry.set(gimli::DW_AT_type, AttributeValue::UnitRef(elem_dw_ty)); - - let subrange_id = self.dwarf.unit.add(array_type_id, gimli::DW_TAG_subrange_type); - let subrange_entry = self.dwarf.unit.get_mut(subrange_id); - subrange_entry.set(gimli::DW_AT_type, AttributeValue::UnitRef(self.array_size_type)); - subrange_entry.set(gimli::DW_AT_lower_bound, AttributeValue::Udata(0)); - subrange_entry.set(gimli::DW_AT_count, AttributeValue::Udata(len)); - - array_type_id - } - - fn pointer_type<'tcx>( - &mut self, - tcx: TyCtxt<'tcx>, - type_dbg: &mut TypeDebugContext<'tcx>, - ptr_type: Ty<'tcx>, - pointee_type: Ty<'tcx>, - ) -> UnitEntryId { - let pointee_dw_ty = self.debug_type(tcx, type_dbg, pointee_type); - - return_if_type_created_in_meantime!(type_dbg, ptr_type); - - let name = type_names::compute_debuginfo_type_name(tcx, ptr_type, true); - - if !has_ptr_meta(tcx, ptr_type) { - let pointer_type_id = - self.dwarf.unit.add(self.dwarf.unit.root(), gimli::DW_TAG_pointer_type); - let pointer_entry = self.dwarf.unit.get_mut(pointer_type_id); - pointer_entry.set(gimli::DW_AT_type, AttributeValue::UnitRef(pointee_dw_ty)); - pointer_entry - .set(gimli::DW_AT_name, AttributeValue::StringRef(self.dwarf.strings.add(name))); - - pointer_type_id - } else { - // FIXME implement debuginfo for fat pointers - self.placeholder_for_type(tcx, type_dbg, ptr_type) - } - } - - fn tuple_type<'tcx>( - &mut self, - tcx: TyCtxt<'tcx>, - type_dbg: &mut TypeDebugContext<'tcx>, - tuple_type: Ty<'tcx>, - components: &'tcx [Ty<'tcx>], - ) -> UnitEntryId { - let components = components - .into_iter() - .map(|&ty| (ty, self.debug_type(tcx, type_dbg, ty))) - .collect::>(); - - return_if_type_created_in_meantime!(type_dbg, tuple_type); - - let name = type_names::compute_debuginfo_type_name(tcx, tuple_type, false); - let layout = RevealAllLayoutCx(tcx).layout_of(tuple_type); - - let tuple_type_id = - self.dwarf.unit.add(self.dwarf.unit.root(), gimli::DW_TAG_structure_type); - let tuple_entry = self.dwarf.unit.get_mut(tuple_type_id); - tuple_entry.set(gimli::DW_AT_name, AttributeValue::StringRef(self.dwarf.strings.add(name))); - tuple_entry.set(gimli::DW_AT_byte_size, AttributeValue::Udata(layout.size.bytes())); - tuple_entry.set(gimli::DW_AT_alignment, AttributeValue::Udata(layout.align.pref.bytes())); - - for (i, (ty, dw_ty)) in components.into_iter().enumerate() { - let member_id = self.dwarf.unit.add(tuple_type_id, gimli::DW_TAG_member); - let member_entry = self.dwarf.unit.get_mut(member_id); - member_entry.set( - gimli::DW_AT_name, - AttributeValue::StringRef(self.dwarf.strings.add(format!("__{i}"))), - ); - member_entry.set(gimli::DW_AT_type, AttributeValue::UnitRef(dw_ty)); - member_entry.set( - gimli::DW_AT_alignment, - AttributeValue::Udata(RevealAllLayoutCx(tcx).layout_of(ty).align.pref.bytes()), - ); - member_entry.set( - gimli::DW_AT_data_member_location, - AttributeValue::Udata(layout.fields.offset(i).bytes()), - ); - } - - tuple_type_id - } - - fn placeholder_for_type<'tcx>( - &mut self, - tcx: TyCtxt<'tcx>, - type_dbg: &mut TypeDebugContext<'tcx>, - ty: Ty<'tcx>, - ) -> UnitEntryId { - self.debug_type( - tcx, - type_dbg, - Ty::new_array(tcx, tcx.types.u8, RevealAllLayoutCx(tcx).layout_of(ty).size.bytes()), - ) - } -} +use gimli::write::{AttributeValue ,UnitEntryId};use rustc_codegen_ssa::debuginfo +::type_names;use rustc_data_structures::fx::FxHashMap;use rustc_middle::ty:://3; +layout::LayoutOf;use rustc_middle::ty::{self,Ty,TyCtxt};use crate::{//if true{}; +has_ptr_meta,DebugContext,RevealAllLayoutCx};#[ derive(Default)]pub(crate)struct +TypeDebugContext<'tcx>{type_map:FxHashMap,UnitEntryId>,}macro_rules!//; +return_if_type_created_in_meantime{($type_dbg:expr,$ty:expr)=>{if let Some(&//3; +type_id)=$type_dbg.type_map.get(&$ty) {return type_id;}};}impl DebugContext{pub( +crate)fn debug_type<'tcx>(&mut self,tcx:TyCtxt<'tcx>,type_dbg:&mut//loop{break}; +TypeDebugContext<'tcx>,ty:Ty<'tcx>,)->UnitEntryId{if let Some(&type_id)=//{();}; +type_dbg.type_map.get(&ty){3;return type_id;3;};let type_id=match ty.kind(){ty:: +Never|ty::Bool|ty::Char|ty::Int(_)|ty::Uint(_)|ty::Float(_)=>{self.basic_type(// +tcx,ty)}ty::Tuple(elems)if elems.is_empty ()=>self.basic_type(tcx,ty),ty::Array( +elem_ty,len)=>self.array_type(tcx,type_dbg ,ty,(*elem_ty),len.eval_target_usize( +tcx,((((ty::ParamEnv::reveal_all()))))),) ,ty::RawPtr(pointee_type,_)|ty::Ref(_, +pointee_type,_)=>{(self.pointer_type(tcx,type_dbg ,ty,*pointee_type))}ty::Tuple( +components)=>((((self.tuple_type(tcx,type_dbg,ty,(((*components)))))))),_=>self. +placeholder_for_type(tcx,type_dbg,ty),};;;type_dbg.type_map.insert(ty,type_id);; +type_id}fn basic_type<'tcx>(&mut self,tcx:TyCtxt<'tcx>,ty:Ty<'tcx>)->//let _=(); +UnitEntryId{if true{};let(name,encoding)=match ty.kind(){ty::Never=>("!",gimli:: +DW_ATE_unsigned),ty::Tuple(elems)if (((elems .is_empty())))=>(((("()"))),gimli:: +DW_ATE_unsigned),ty::Bool=>((("bool"),gimli::DW_ATE_boolean)),ty::Char=>("char", +gimli::DW_ATE_UTF),ty::Int(int_ty)=>( int_ty.name_str(),gimli::DW_ATE_signed),ty +::Uint(uint_ty)=>(uint_ty.name_str( ),gimli::DW_ATE_unsigned),ty::Float(float_ty +)=>(float_ty.name_str(),gimli::DW_ATE_float),_=>unreachable!(),};3;;let type_id= +self.dwarf.unit.add(self.dwarf.unit.root(),gimli::DW_TAG_base_type);({});{;};let +type_entry=self.dwarf.unit.get_mut(type_id);3;;type_entry.set(gimli::DW_AT_name, +AttributeValue::StringRef(self.dwarf.strings.add(name)));;type_entry.set(gimli:: +DW_AT_encoding,AttributeValue::Encoding(encoding));{;};();type_entry.set(gimli:: +DW_AT_byte_size,AttributeValue::Udata(RevealAllLayoutCx (tcx).layout_of(ty).size +.bytes()),);();type_id}fn array_type<'tcx>(&mut self,tcx:TyCtxt<'tcx>,type_dbg:& +mut TypeDebugContext<'tcx>,array_ty:Ty<'tcx>,elem_ty:Ty<'tcx>,len:u64,)->//({}); +UnitEntryId{({});let elem_dw_ty=self.debug_type(tcx,type_dbg,elem_ty);({});({}); +return_if_type_created_in_meantime!(type_dbg,array_ty);;;let array_type_id=self. +dwarf.unit.add(self.dwarf.unit.root(),gimli::DW_TAG_array_type);*&*&();{();};let +array_type_entry=self.dwarf.unit.get_mut(array_type_id);3;;array_type_entry.set( +gimli::DW_AT_type,AttributeValue::UnitRef(elem_dw_ty));3;3;let subrange_id=self. +dwarf.unit.add(array_type_id,gimli::DW_TAG_subrange_type);3;;let subrange_entry= +self.dwarf.unit.get_mut(subrange_id);();();subrange_entry.set(gimli::DW_AT_type, +AttributeValue::UnitRef(self.array_size_type));{;};();subrange_entry.set(gimli:: +DW_AT_lower_bound,AttributeValue::Udata(0));({});({});subrange_entry.set(gimli:: +DW_AT_count,AttributeValue::Udata(len));();array_type_id}fn pointer_type<'tcx>(& +mut self,tcx:TyCtxt<'tcx>,type_dbg: &mut TypeDebugContext<'tcx>,ptr_type:Ty<'tcx +>,pointee_type:Ty<'tcx>,)->UnitEntryId{();let pointee_dw_ty=self.debug_type(tcx, +type_dbg,pointee_type);;;return_if_type_created_in_meantime!(type_dbg,ptr_type); +let name=type_names::compute_debuginfo_type_name(tcx,ptr_type,true);let _=();if! +has_ptr_meta(tcx,ptr_type){3;let pointer_type_id=self.dwarf.unit.add(self.dwarf. +unit.root(),gimli::DW_TAG_pointer_type);();();let pointer_entry=self.dwarf.unit. +get_mut(pointer_type_id);3;;pointer_entry.set(gimli::DW_AT_type,AttributeValue:: +UnitRef(pointee_dw_ty));3;3;pointer_entry.set(gimli::DW_AT_name,AttributeValue:: +StringRef(self.dwarf.strings.add(name)));loop{break;};pointer_type_id}else{self. +placeholder_for_type(tcx,type_dbg,ptr_type)}}fn tuple_type<'tcx>(&mut self,tcx: +TyCtxt<'tcx>,type_dbg:&mut TypeDebugContext<'tcx>,tuple_type:Ty<'tcx>,//((),()); +components:&'tcx[Ty<'tcx>],)->UnitEntryId{;let components=components.into_iter() +.map(|&ty|(ty,self.debug_type(tcx,type_dbg,ty))).collect::>();{();};({}); +return_if_type_created_in_meantime!(type_dbg,tuple_type);;;let name=type_names:: +compute_debuginfo_type_name(tcx,tuple_type,false);;let layout=RevealAllLayoutCx( +tcx).layout_of(tuple_type);3;3;let tuple_type_id=self.dwarf.unit.add(self.dwarf. +unit.root(),gimli::DW_TAG_structure_type);();();let tuple_entry=self.dwarf.unit. +get_mut(tuple_type_id);{;};();tuple_entry.set(gimli::DW_AT_name,AttributeValue:: +StringRef(self.dwarf.strings.add(name)));;tuple_entry.set(gimli::DW_AT_byte_size +,AttributeValue::Udata(layout.size.bytes()));{();};{();};tuple_entry.set(gimli:: +DW_AT_alignment,AttributeValue::Udata(layout.align.pref.bytes()));{;};for(i,(ty, +dw_ty))in components.into_iter().enumerate(){;let member_id=self.dwarf.unit.add( +tuple_type_id,gimli::DW_TAG_member);3;;let member_entry=self.dwarf.unit.get_mut( +member_id);3;;member_entry.set(gimli::DW_AT_name,AttributeValue::StringRef(self. +dwarf.strings.add(format!("__{i}"))),);();();member_entry.set(gimli::DW_AT_type, +AttributeValue::UnitRef(dw_ty));{;};{;};member_entry.set(gimli::DW_AT_alignment, +AttributeValue::Udata(RevealAllLayoutCx(tcx).layout_of( ty).align.pref.bytes()), +);();3;member_entry.set(gimli::DW_AT_data_member_location,AttributeValue::Udata( +layout.fields.offset(i).bytes()),);;}tuple_type_id}fn placeholder_for_type<'tcx> +(&mut self,tcx:TyCtxt<'tcx>,type_dbg:&mut TypeDebugContext<'tcx>,ty:Ty<'tcx>,)// +->UnitEntryId{self.debug_type(tcx,type_dbg,Ty::new_array(tcx,tcx.types.u8,//{;}; +RevealAllLayoutCx(tcx).layout_of(ty).size.bytes()),)}}//loop{break};loop{break}; diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs index 96ab7a29205bf..a7ce5cfe56a75 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs @@ -1,134 +1,37 @@ -//! Unwind info generation (`.eh_frame`) - -use cranelift_codegen::ir::Endianness; -use cranelift_codegen::isa::{unwind::UnwindInfo, TargetIsa}; -use cranelift_object::ObjectProduct; -use gimli::write::{CieId, EhFrame, FrameTable, Section}; -use gimli::RunTimeEndian; - -use super::emit::address_for_func; -use super::object::WriteDebugInfo; -use crate::prelude::*; - -pub(crate) struct UnwindContext { - endian: RunTimeEndian, - frame_table: FrameTable, - cie_id: Option, -} - -impl UnwindContext { - pub(crate) fn new(isa: &dyn TargetIsa, pic_eh_frame: bool) -> Self { - let endian = match isa.endianness() { - Endianness::Little => RunTimeEndian::Little, - Endianness::Big => RunTimeEndian::Big, - }; - let mut frame_table = FrameTable::default(); - - let cie_id = if let Some(mut cie) = isa.create_systemv_cie() { - if pic_eh_frame { - cie.fde_address_encoding = - gimli::DwEhPe(gimli::DW_EH_PE_pcrel.0 | gimli::DW_EH_PE_sdata4.0); - } - Some(frame_table.add_cie(cie)) - } else { - None - }; - - UnwindContext { endian, frame_table, cie_id } - } - - pub(crate) fn add_function(&mut self, func_id: FuncId, context: &Context, isa: &dyn TargetIsa) { - let unwind_info = if let Some(unwind_info) = - context.compiled_code().unwrap().create_unwind_info(isa).unwrap() - { - unwind_info - } else { - return; - }; - - match unwind_info { - UnwindInfo::SystemV(unwind_info) => { - self.frame_table - .add_fde(self.cie_id.unwrap(), unwind_info.to_fde(address_for_func(func_id))); - } - UnwindInfo::WindowsX64(_) => { - // FIXME implement this - } - unwind_info => unimplemented!("{:?}", unwind_info), - } - } - - pub(crate) fn emit(self, product: &mut ObjectProduct) { - let mut eh_frame = EhFrame::from(super::emit::WriterRelocate::new(self.endian)); - self.frame_table.write_eh_frame(&mut eh_frame).unwrap(); - - if !eh_frame.0.writer.slice().is_empty() { - let id = eh_frame.id(); - let section_id = product.add_debug_section(id, eh_frame.0.writer.into_vec()); - let mut section_map = FxHashMap::default(); - section_map.insert(id, section_id); - - for reloc in &eh_frame.0.relocs { - product.add_debug_reloc(§ion_map, §ion_id, reloc); - } - } - } - - #[cfg(all(feature = "jit", windows))] - pub(crate) unsafe fn register_jit(self, _jit_module: &cranelift_jit::JITModule) {} - - #[cfg(all(feature = "jit", not(windows)))] - pub(crate) unsafe fn register_jit(self, jit_module: &cranelift_jit::JITModule) { - use std::mem::ManuallyDrop; - - let mut eh_frame = EhFrame::from(super::emit::WriterRelocate::new(self.endian)); - self.frame_table.write_eh_frame(&mut eh_frame).unwrap(); - - if eh_frame.0.writer.slice().is_empty() { - return; - } - - let mut eh_frame = eh_frame.0.relocate_for_jit(jit_module); - - // GCC expects a terminating "empty" length, so write a 0 length at the end of the table. - eh_frame.extend(&[0, 0, 0, 0]); - - // FIXME support unregistering unwind tables once cranelift-jit supports deallocating - // individual functions - let eh_frame = ManuallyDrop::new(eh_frame); - - // ======================================================================= - // Everything after this line up to the end of the file is loosely based on - // https://github.com/bytecodealliance/wasmtime/blob/4471a82b0c540ff48960eca6757ccce5b1b5c3e4/crates/jit/src/unwind/systemv.rs - #[cfg(target_os = "macos")] - { - // On macOS, `__register_frame` takes a pointer to a single FDE - let start = eh_frame.as_ptr(); - let end = start.add(eh_frame.len()); - let mut current = start; - - // Walk all of the entries in the frame table and register them - while current < end { - let len = std::ptr::read::(current as *const u32) as usize; - - // Skip over the CIE - if current != start { - __register_frame(current); - } - - // Move to the next table entry (+4 because the length itself is not inclusive) - current = current.add(len + 4); - } - } - #[cfg(not(target_os = "macos"))] - { - // On other platforms, `__register_frame` will walk the FDEs until an entry of length 0 - __register_frame(eh_frame.as_ptr()); - } - } -} - -extern "C" { - // libunwind import - fn __register_frame(fde: *const u8); -} +use cranelift_codegen::ir::Endianness;use cranelift_codegen::isa::{unwind:://(); +UnwindInfo,TargetIsa};use cranelift_object::ObjectProduct;use gimli::write::{//; +CieId,EhFrame,FrameTable,Section};use gimli::RunTimeEndian;use super::emit:://3; +address_for_func;use super::object::WriteDebugInfo;use crate::prelude::*;pub(//; +crate)struct UnwindContext{endian:RunTimeEndian,frame_table:FrameTable,cie_id:// +Option,}impl UnwindContext{pub(crate)fn new(isa:&dyn TargetIsa,//((),()); +pic_eh_frame:bool)->Self{;let endian=match isa.endianness(){Endianness::Little=> +RunTimeEndian::Little,Endianness::Big=>RunTimeEndian::Big,};;let mut frame_table +=FrameTable::default();;let cie_id=if let Some(mut cie)=isa.create_systemv_cie() +{if pic_eh_frame{;cie.fde_address_encoding=gimli::DwEhPe(gimli::DW_EH_PE_pcrel.0 +|gimli::DW_EH_PE_sdata4.0);({});}Some(frame_table.add_cie(cie))}else{None};({}); +UnwindContext{endian,frame_table,cie_id}}pub(crate)fn add_function(&mut self,//; +func_id:FuncId,context:&Context,isa:&dyn TargetIsa){;let unwind_info=if let Some +(unwind_info)=context.compiled_code(). unwrap().create_unwind_info(isa).unwrap() +{unwind_info}else{;return;};match unwind_info{UnwindInfo::SystemV(unwind_info)=> +{if let _=(){};self.frame_table.add_fde(self.cie_id.unwrap(),unwind_info.to_fde( +address_for_func(func_id)));let _=();}UnwindInfo::WindowsX64(_)=>{}unwind_info=> +unimplemented!("{:?}",unwind_info),}}pub(crate)fn emit(self,product:&mut//{();}; +ObjectProduct){;let mut eh_frame=EhFrame::from(super::emit::WriterRelocate::new( +self.endian));();3;self.frame_table.write_eh_frame(&mut eh_frame).unwrap();3;if! +eh_frame.0.writer.slice().is_empty(){();let id=eh_frame.id();3;3;let section_id= +product.add_debug_section(id,eh_frame.0.writer.into_vec());;let mut section_map= +FxHashMap::default();;section_map.insert(id,section_id);for reloc in&eh_frame.0. +relocs{3;product.add_debug_reloc(§ion_map,§ion_id,reloc);3;}}}#[cfg(all( +feature="jit",windows))]pub(crate)unsafe fn register_jit(self,_jit_module:&//(); +cranelift_jit::JITModule){}#[cfg(all(feature="jit",not(windows)))]pub(crate)//3; +unsafe fn register_jit(self,jit_module:&cranelift_jit::JITModule){3;use std::mem +::ManuallyDrop;;let mut eh_frame=EhFrame::from(super::emit::WriterRelocate::new( +self.endian));();3;self.frame_table.write_eh_frame(&mut eh_frame).unwrap();3;if +eh_frame.0.writer.slice().is_empty(){();return;3;}3;let mut eh_frame=eh_frame.0. +relocate_for_jit(jit_module);();();eh_frame.extend(&[0,0,0,0]);3;3;let eh_frame= +ManuallyDrop::new(eh_frame);;#[cfg(target_os="macos")]{let start=eh_frame.as_ptr +();;;let end=start.add(eh_frame.len());;let mut current=start;while current(current as*const u32)as usize;;if current!=start{; +__register_frame(current);3;};current=current.add(len+4);;}}#[cfg(not(target_os= +"macos"))]{let _=();__register_frame(eh_frame.as_ptr());((),());}}}extern "C"{fn +__register_frame(fde:*const u8);}//let _=||();let _=||();let _=||();loop{break}; diff --git a/compiler/rustc_codegen_cranelift/src/discriminant.rs b/compiler/rustc_codegen_cranelift/src/discriminant.rs index 670384663e83f..da91d39095afe 100644 --- a/compiler/rustc_codegen_cranelift/src/discriminant.rs +++ b/compiler/rustc_codegen_cranelift/src/discriminant.rs @@ -1,205 +1,60 @@ -//! Handling of enum discriminants -//! -//! Adapted from -//! () - -use rustc_target::abi::{Int, TagEncoding, Variants}; - -use crate::prelude::*; - -pub(crate) fn codegen_set_discriminant<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - place: CPlace<'tcx>, - variant_index: VariantIdx, -) { - let layout = place.layout(); - if layout.for_variant(fx, variant_index).abi.is_uninhabited() { - return; - } - match layout.variants { - Variants::Single { index } => { - assert_eq!(index, variant_index); - } - Variants::Multiple { - tag: _, - tag_field, - tag_encoding: TagEncoding::Direct, - variants: _, - } => { - let ptr = place.place_field(fx, FieldIdx::new(tag_field)); - let to = layout.ty.discriminant_for_variant(fx.tcx, variant_index).unwrap().val; - let to = if ptr.layout().abi.is_signed() { - ty::ScalarInt::try_from_int( - ptr.layout().size.sign_extend(to) as i128, - ptr.layout().size, - ) - .unwrap() - } else { - ty::ScalarInt::try_from_uint(to, ptr.layout().size).unwrap() - }; - let discr = CValue::const_val(fx, ptr.layout(), to); - ptr.write_cvalue(fx, discr); - } - Variants::Multiple { - tag: _, - tag_field, - tag_encoding: TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start }, - variants: _, - } => { - if variant_index != untagged_variant { - let niche = place.place_field(fx, FieldIdx::new(tag_field)); - let niche_type = fx.clif_type(niche.layout().ty).unwrap(); - let niche_value = variant_index.as_u32() - niche_variants.start().as_u32(); - let niche_value = (niche_value as u128).wrapping_add(niche_start); - let niche_value = match niche_type { - types::I128 => { - let lsb = fx.bcx.ins().iconst(types::I64, niche_value as u64 as i64); - let msb = - fx.bcx.ins().iconst(types::I64, (niche_value >> 64) as u64 as i64); - fx.bcx.ins().iconcat(lsb, msb) - } - ty => fx.bcx.ins().iconst(ty, niche_value as i64), - }; - let niche_llval = CValue::by_val(niche_value, niche.layout()); - niche.write_cvalue(fx, niche_llval); - } - } - } -} - -pub(crate) fn codegen_get_discriminant<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - dest: CPlace<'tcx>, - value: CValue<'tcx>, - dest_layout: TyAndLayout<'tcx>, -) { - let layout = value.layout(); - - if layout.abi.is_uninhabited() { - return; - } - - let (tag_scalar, tag_field, tag_encoding) = match &layout.variants { - Variants::Single { index } => { - let discr_val = layout - .ty - .discriminant_for_variant(fx.tcx, *index) - .map_or(u128::from(index.as_u32()), |discr| discr.val); - let discr_val = if dest_layout.abi.is_signed() { - ty::ScalarInt::try_from_int( - dest_layout.size.sign_extend(discr_val) as i128, - dest_layout.size, - ) - .unwrap() - } else { - ty::ScalarInt::try_from_uint(discr_val, dest_layout.size).unwrap() - }; - let res = CValue::const_val(fx, dest_layout, discr_val); - dest.write_cvalue(fx, res); - return; - } - Variants::Multiple { tag, tag_field, tag_encoding, variants: _ } => { - (tag, *tag_field, tag_encoding) - } - }; - - let cast_to = fx.clif_type(dest_layout.ty).unwrap(); - - // Read the tag/niche-encoded discriminant from memory. - let tag = value.value_field(fx, FieldIdx::new(tag_field)); - let tag = tag.load_scalar(fx); - - // Decode the discriminant (specifically if it's niche-encoded). - match *tag_encoding { - TagEncoding::Direct => { - let signed = match tag_scalar.primitive() { - Int(_, signed) => signed, - _ => false, - }; - let val = clif_intcast(fx, tag, cast_to, signed); - let res = CValue::by_val(val, dest_layout); - dest.write_cvalue(fx, res); - } - TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start } => { - let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32(); - - // We have a subrange `niche_start..=niche_end` inside `range`. - // If the value of the tag is inside this subrange, it's a - // "niche value", an increment of the discriminant. Otherwise it - // indicates the untagged variant. - // A general algorithm to extract the discriminant from the tag - // is: - // relative_tag = tag - niche_start - // is_niche = relative_tag <= (ule) relative_max - // discr = if is_niche { - // cast(relative_tag) + niche_variants.start() - // } else { - // untagged_variant - // } - // However, we will likely be able to emit simpler code. - - let (is_niche, tagged_discr, delta) = if relative_max == 0 { - // Best case scenario: only one tagged variant. This will - // likely become just a comparison and a jump. - // The algorithm is: - // is_niche = tag == niche_start - // discr = if is_niche { - // niche_start - // } else { - // untagged_variant - // } - let is_niche = codegen_icmp_imm(fx, IntCC::Equal, tag, niche_start as i128); - let tagged_discr = - fx.bcx.ins().iconst(cast_to, niche_variants.start().as_u32() as i64); - (is_niche, tagged_discr, 0) - } else { - // The special cases don't apply, so we'll have to go with - // the general algorithm. - let niche_start = match fx.bcx.func.dfg.value_type(tag) { - types::I128 => { - let lsb = fx.bcx.ins().iconst(types::I64, niche_start as u64 as i64); - let msb = - fx.bcx.ins().iconst(types::I64, (niche_start >> 64) as u64 as i64); - fx.bcx.ins().iconcat(lsb, msb) - } - ty => fx.bcx.ins().iconst(ty, niche_start as i64), - }; - let relative_discr = fx.bcx.ins().isub(tag, niche_start); - let cast_tag = clif_intcast(fx, relative_discr, cast_to, false); - let is_niche = crate::common::codegen_icmp_imm( - fx, - IntCC::UnsignedLessThanOrEqual, - relative_discr, - i128::from(relative_max), - ); - (is_niche, cast_tag, niche_variants.start().as_u32() as u128) - }; - - let tagged_discr = if delta == 0 { - tagged_discr - } else { - let delta = match cast_to { - types::I128 => { - let lsb = fx.bcx.ins().iconst(types::I64, delta as u64 as i64); - let msb = fx.bcx.ins().iconst(types::I64, (delta >> 64) as u64 as i64); - fx.bcx.ins().iconcat(lsb, msb) - } - ty => fx.bcx.ins().iconst(ty, delta as i64), - }; - fx.bcx.ins().iadd(tagged_discr, delta) - }; - - let untagged_variant = if cast_to == types::I128 { - let zero = fx.bcx.ins().iconst(types::I64, 0); - let untagged_variant = - fx.bcx.ins().iconst(types::I64, i64::from(untagged_variant.as_u32())); - fx.bcx.ins().iconcat(untagged_variant, zero) - } else { - fx.bcx.ins().iconst(cast_to, i64::from(untagged_variant.as_u32())) - }; - let discr = fx.bcx.ins().select(is_niche, tagged_discr, untagged_variant); - let res = CValue::by_val(discr, dest_layout); - dest.write_cvalue(fx, res); - } - } -} +use rustc_target::abi::{Int,TagEncoding,Variants};use crate::prelude::*;pub(//3; +crate)fn codegen_set_discriminant<'tcx>(fx:&mut FunctionCx<'_,'_,'tcx>,place://; +CPlace<'tcx>,variant_index:VariantIdx,){3;let layout=place.layout();3;if layout. +for_variant(fx,variant_index).abi.is_uninhabited(){{;};return;{;};}match layout. +variants{Variants::Single{index}=>{;assert_eq!(index,variant_index);;}Variants:: +Multiple{tag:_,tag_field,tag_encoding:TagEncoding::Direct,variants:_,}=>{{;};let +ptr=place.place_field(fx,FieldIdx::new(tag_field));{();};{();};let to=layout.ty. +discriminant_for_variant(fx.tcx,variant_index).unwrap().val;();();let to=if ptr. +layout().abi.is_signed(){ty:: ScalarInt::try_from_int(((((ptr.layout())))).size. +sign_extend(to)as i128,((((ptr.layout())))).size,).unwrap()}else{ty::ScalarInt:: +try_from_uint(to,ptr.layout().size).unwrap()};3;;let discr=CValue::const_val(fx, +ptr.layout(),to);;ptr.write_cvalue(fx,discr);}Variants::Multiple{tag:_,tag_field +,tag_encoding:TagEncoding::Niche{untagged_variant,ref niche_variants,//let _=(); +niche_start},variants:_,}=>{if variant_index!=untagged_variant{;let niche=place. +place_field(fx,FieldIdx::new(tag_field));();3;let niche_type=fx.clif_type(niche. +layout().ty).unwrap();3;3;let niche_value=variant_index.as_u32()-niche_variants. +start().as_u32();;let niche_value=(niche_value as u128).wrapping_add(niche_start +);;;let niche_value=match niche_type{types::I128=>{;let lsb=fx.bcx.ins().iconst( +types::I64,niche_value as u64 as i64);;;let msb=fx.bcx.ins().iconst(types::I64,( +niche_value>>64)as u64 as i64);3;fx.bcx.ins().iconcat(lsb,msb)}ty=>fx.bcx.ins(). +iconst(ty,niche_value as i64),};();3;let niche_llval=CValue::by_val(niche_value, +niche.layout());({});{;};niche.write_cvalue(fx,niche_llval);{;};}}}}pub(crate)fn +codegen_get_discriminant<'tcx>(fx:&mut FunctionCx< '_,'_,'tcx>,dest:CPlace<'tcx> +,value:CValue<'tcx>,dest_layout:TyAndLayout<'tcx>,){;let layout=value.layout();; +if layout.abi.is_uninhabited(){;return;;}let(tag_scalar,tag_field,tag_encoding)= +match&layout.variants{Variants::Single{index}=>{((),());let discr_val=layout.ty. +discriminant_for_variant(fx.tcx,(*index)).map_or(( u128::from(index.as_u32())),| +discr|discr.val);3;;let discr_val=if dest_layout.abi.is_signed(){ty::ScalarInt:: +try_from_int(dest_layout.size.sign_extend(discr_val) as i128,dest_layout.size,). +unwrap()}else{ty::ScalarInt:: try_from_uint(discr_val,dest_layout.size).unwrap() +};;let res=CValue::const_val(fx,dest_layout,discr_val);dest.write_cvalue(fx,res) +;3;3;return;;}Variants::Multiple{tag,tag_field,tag_encoding,variants:_}=>{(tag,* +tag_field,tag_encoding)}};;let cast_to=fx.clif_type(dest_layout.ty).unwrap();let +tag=value.value_field(fx,FieldIdx::new(tag_field));;;let tag=tag.load_scalar(fx) +;;match*tag_encoding{TagEncoding::Direct=>{let signed=match tag_scalar.primitive +(){Int(_,signed)=>signed,_=>false,};;let val=clif_intcast(fx,tag,cast_to,signed) +;;let res=CValue::by_val(val,dest_layout);dest.write_cvalue(fx,res);}TagEncoding +::Niche{untagged_variant,ref niche_variants,niche_start}=>{{;};let relative_max= +niche_variants.end().as_u32()-niche_variants.start().as_u32();();3;let(is_niche, +tagged_discr,delta)=if relative_max==0{;let is_niche=codegen_icmp_imm(fx,IntCC:: +Equal,tag,niche_start as i128);3;3;let tagged_discr=fx.bcx.ins().iconst(cast_to, +niche_variants.start().as_u32()as i64);{;};(is_niche,tagged_discr,0)}else{();let +niche_start=match fx.bcx.func.dfg.value_type(tag){types::I128=>{;let lsb=fx.bcx. +ins().iconst(types::I64,niche_start as u64 as i64);;let msb=fx.bcx.ins().iconst( +types::I64,(niche_start>>64)as u64 as i64);;fx.bcx.ins().iconcat(lsb,msb)}ty=>fx +.bcx.ins().iconst(ty,niche_start as i64),};;let relative_discr=fx.bcx.ins().isub +(tag,niche_start);;;let cast_tag=clif_intcast(fx,relative_discr,cast_to,false);; +let is_niche=crate::common ::codegen_icmp_imm(fx,IntCC::UnsignedLessThanOrEqual, +relative_discr,i128::from(relative_max),);{;};(is_niche,cast_tag,niche_variants. +start().as_u32()as u128)};3;;let tagged_discr=if delta==0{tagged_discr}else{;let +delta=match cast_to{types::I128=>{3;let lsb=fx.bcx.ins().iconst(types::I64,delta +as u64 as i64);;let msb=fx.bcx.ins().iconst(types::I64,(delta>>64)as u64 as i64) +;3;fx.bcx.ins().iconcat(lsb,msb)}ty=>fx.bcx.ins().iconst(ty,delta as i64),};;fx. +bcx.ins().iadd(tagged_discr,delta)};3;3;let untagged_variant=if cast_to==types:: +I128{;let zero=fx.bcx.ins().iconst(types::I64,0);let untagged_variant=fx.bcx.ins +().iconst(types::I64,i64::from(untagged_variant.as_u32()));;fx.bcx.ins().iconcat +(untagged_variant,zero)}else{((((((fx.bcx. ins())))))).iconst(cast_to,i64::from( +untagged_variant.as_u32()))};{();};{();};let discr=fx.bcx.ins().select(is_niche, +tagged_discr,untagged_variant);;;let res=CValue::by_val(discr,dest_layout);dest. +write_cvalue(fx,res);if let _=(){};if let _=(){};if let _=(){};if let _=(){};}}} diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 75268341a4fe0..1df492aa18ba1 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -1,694 +1,209 @@ -//! The AOT driver uses [`cranelift_object`] to write object files suitable for linking into a -//! standalone executable. - -use std::fs::{self, File}; -use std::path::{Path, PathBuf}; -use std::sync::Arc; -use std::thread::JoinHandle; - -use cranelift_object::{ObjectBuilder, ObjectModule}; -use rustc_codegen_ssa::assert_module_sources::CguReuse; -use rustc_codegen_ssa::back::link::ensure_removed; -use rustc_codegen_ssa::back::metadata::create_compressed_metadata_file; -use rustc_codegen_ssa::base::determine_cgu_reuse; -use rustc_codegen_ssa::errors as ssa_errors; -use rustc_codegen_ssa::{CodegenResults, CompiledModule, CrateInfo, ModuleKind}; -use rustc_data_structures::profiling::SelfProfilerRef; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_metadata::fs::copy_to_stdout; -use rustc_metadata::EncodedMetadata; -use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; -use rustc_middle::mir::mono::{CodegenUnit, MonoItem}; -use rustc_session::config::{DebugInfo, OutFileName, OutputFilenames, OutputType}; -use rustc_session::Session; - -use crate::concurrency_limiter::{ConcurrencyLimiter, ConcurrencyLimiterToken}; -use crate::debuginfo::TypeDebugContext; -use crate::global_asm::GlobalAsmConfig; -use crate::{prelude::*, BackendConfig}; - -struct ModuleCodegenResult { - module_regular: CompiledModule, - module_global_asm: Option, - existing_work_product: Option<(WorkProductId, WorkProduct)>, -} - -enum OngoingModuleCodegen { - Sync(Result), - Async(JoinHandle>), -} - -impl HashStable for OngoingModuleCodegen { - fn hash_stable(&self, _: &mut HCX, _: &mut StableHasher) { - // do nothing - } -} - -pub(crate) struct OngoingCodegen { - modules: Vec, - allocator_module: Option, - metadata_module: Option, - metadata: EncodedMetadata, - crate_info: CrateInfo, - concurrency_limiter: ConcurrencyLimiter, -} - -impl OngoingCodegen { - pub(crate) fn join( - self, - sess: &Session, - outputs: &OutputFilenames, - backend_config: &BackendConfig, - ) -> (CodegenResults, FxIndexMap) { - let mut work_products = FxIndexMap::default(); - let mut modules = vec![]; - - for module_codegen in self.modules { - let module_codegen_result = match module_codegen { - OngoingModuleCodegen::Sync(module_codegen_result) => module_codegen_result, - OngoingModuleCodegen::Async(join_handle) => match join_handle.join() { - Ok(module_codegen_result) => module_codegen_result, - Err(panic) => std::panic::resume_unwind(panic), - }, - }; - - let module_codegen_result = match module_codegen_result { - Ok(module_codegen_result) => module_codegen_result, - Err(err) => sess.dcx().fatal(err), - }; - let ModuleCodegenResult { module_regular, module_global_asm, existing_work_product } = - module_codegen_result; - - if let Some((work_product_id, work_product)) = existing_work_product { - work_products.insert(work_product_id, work_product); - } else { - let work_product = if backend_config.disable_incr_cache { - None - } else if let Some(module_global_asm) = &module_global_asm { - rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir( - sess, - &module_regular.name, - &[ - ("o", &module_regular.object.as_ref().unwrap()), - ("asm.o", &module_global_asm.object.as_ref().unwrap()), - ], - ) - } else { - rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir( - sess, - &module_regular.name, - &[("o", &module_regular.object.as_ref().unwrap())], - ) - }; - if let Some((work_product_id, work_product)) = work_product { - work_products.insert(work_product_id, work_product); - } - } - - modules.push(module_regular); - if let Some(module_global_asm) = module_global_asm { - modules.push(module_global_asm); - } - } - - self.concurrency_limiter.finished(); - - sess.dcx().abort_if_errors(); - - let codegen_results = CodegenResults { - modules, - allocator_module: self.allocator_module, - metadata_module: self.metadata_module, - metadata: self.metadata, - crate_info: self.crate_info, - }; - - produce_final_output_artifacts(sess, &codegen_results, outputs); - - (codegen_results, work_products) - } -} - -// Adapted from https://github.com/rust-lang/rust/blob/73476d49904751f8d90ce904e16dfbc278083d2c/compiler/rustc_codegen_ssa/src/back/write.rs#L547C1-L706C2 -fn produce_final_output_artifacts( - sess: &Session, - codegen_results: &CodegenResults, - crate_output: &OutputFilenames, -) { - let user_wants_bitcode = false; - let mut user_wants_objects = false; - - // Produce final compile outputs. - let copy_gracefully = |from: &Path, to: &OutFileName| match to { - OutFileName::Stdout => { - if let Err(e) = copy_to_stdout(from) { - sess.dcx().emit_err(ssa_errors::CopyPath::new(from, to.as_path(), e)); - } - } - OutFileName::Real(path) => { - if let Err(e) = fs::copy(from, path) { - sess.dcx().emit_err(ssa_errors::CopyPath::new(from, path, e)); - } - } - }; - - let copy_if_one_unit = |output_type: OutputType, keep_numbered: bool| { - if codegen_results.modules.len() == 1 { - // 1) Only one codegen unit. In this case it's no difficulty - // to copy `foo.0.x` to `foo.x`. - let module_name = Some(&codegen_results.modules[0].name[..]); - let path = crate_output.temp_path(output_type, module_name); - let output = crate_output.path(output_type); - if !output_type.is_text_output() && output.is_tty() { - sess.dcx() - .emit_err(ssa_errors::BinaryOutputToTty { shorthand: output_type.shorthand() }); - } else { - copy_gracefully(&path, &output); - } - if !sess.opts.cg.save_temps && !keep_numbered { - // The user just wants `foo.x`, not `foo.#module-name#.x`. - ensure_removed(sess.dcx(), &path); - } - } else { - let extension = crate_output - .temp_path(output_type, None) - .extension() - .unwrap() - .to_str() - .unwrap() - .to_owned(); - - if crate_output.outputs.contains_explicit_name(&output_type) { - // 2) Multiple codegen units, with `--emit foo=some_name`. We have - // no good solution for this case, so warn the user. - sess.dcx().emit_warn(ssa_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.dcx().emit_warn(ssa_errors::IgnoringOutput { extension }); - } else { - // 4) Multiple codegen units, but no explicit name. We - // just leave the `foo.0.x` files in place. - // (We don't have to do any work in this case.) - } - } - }; - - // Flag to indicate whether the user explicitly requested bitcode. - // Otherwise, we produced it only as a temporary output, and will need - // to get rid of it. - for output_type in crate_output.outputs.keys() { - match *output_type { - OutputType::Bitcode => { - // Cranelift doesn't have bitcode - // user_wants_bitcode = true; - // // Copy to .bc, but always keep the .0.bc. There is a later - // // check to figure out if we should delete .0.bc files, or keep - // // them for making an rlib. - // copy_if_one_unit(OutputType::Bitcode, true); - } - OutputType::LlvmAssembly => { - // Cranelift IR text already emitted during codegen - // copy_if_one_unit(OutputType::LlvmAssembly, false); - } - OutputType::Assembly => { - // Currently no support for emitting raw assembly files - // copy_if_one_unit(OutputType::Assembly, false); - } - OutputType::Object => { - user_wants_objects = true; - copy_if_one_unit(OutputType::Object, true); - } - OutputType::Mir | OutputType::Metadata | OutputType::Exe | OutputType::DepInfo => {} - } - } - - // Clean up unwanted temporary files. - - // We create the following files by default: - // - #crate#.#module-name#.bc - // - #crate#.#module-name#.o - // - #crate#.crate.metadata.bc - // - #crate#.crate.metadata.o - // - #crate#.o (linked from crate.##.o) - // - #crate#.bc (copied from crate.##.bc) - // We may create additional files if requested by the user (through - // `-C save-temps` or `--emit=` flags). - - if !sess.opts.cg.save_temps { - // Remove the temporary .#module-name#.o objects. If the user didn't - // explicitly request bitcode (with --emit=bc), and the bitcode is not - // needed for building an rlib, then we must remove .#module-name#.bc as - // well. - - // Specific rules for keeping .#module-name#.bc: - // - If the user requested bitcode (`user_wants_bitcode`), and - // codegen_units > 1, then keep it. - // - If the user requested bitcode but codegen_units == 1, then we - // can toss .#module-name#.bc because we copied it to .bc earlier. - // - If we're not building an rlib and the user didn't request - // bitcode, then delete .#module-name#.bc. - // If you change how this works, also update back::link::link_rlib, - // where .#module-name#.bc files are (maybe) deleted after making an - // rlib. - let needs_crate_object = crate_output.outputs.contains_key(&OutputType::Exe); - - let keep_numbered_bitcode = user_wants_bitcode && sess.codegen_units().as_usize() > 1; - - let keep_numbered_objects = - needs_crate_object || (user_wants_objects && sess.codegen_units().as_usize() > 1); - - for module in codegen_results.modules.iter() { - if let Some(ref path) = module.object { - if !keep_numbered_objects { - ensure_removed(sess.dcx(), path); - } - } - - if let Some(ref path) = module.dwarf_object { - if !keep_numbered_objects { - ensure_removed(sess.dcx(), path); - } - } - - if let Some(ref path) = module.bytecode { - if !keep_numbered_bitcode { - ensure_removed(sess.dcx(), path); - } - } - } - - if !user_wants_bitcode { - if let Some(ref allocator_module) = codegen_results.allocator_module { - if let Some(ref path) = allocator_module.bytecode { - ensure_removed(sess.dcx(), path); - } - } - } - } - - // We leave the following files around by default: - // - #crate#.o - // - #crate#.crate.metadata.o - // - #crate#.bc - // These are used in linking steps and will be cleaned up afterward. -} - -fn make_module(sess: &Session, backend_config: &BackendConfig, name: String) -> ObjectModule { - let isa = crate::build_isa(sess, backend_config); - - let mut builder = - ObjectBuilder::new(isa, name + ".o", cranelift_module::default_libcall_names()).unwrap(); - // Unlike cg_llvm, cg_clif defaults to disabling -Zfunction-sections. For cg_llvm binary size - // is important, while cg_clif cares more about compilation times. Enabling -Zfunction-sections - // can easily double the amount of time necessary to perform linking. - builder.per_function_section(sess.opts.unstable_opts.function_sections.unwrap_or(false)); - ObjectModule::new(builder) -} - -fn emit_cgu( - output_filenames: &OutputFilenames, - prof: &SelfProfilerRef, - name: String, - module: ObjectModule, - debug: Option, - unwind_context: UnwindContext, - global_asm_object_file: Option, - producer: &str, -) -> Result { - let mut product = module.finish(); - - if let Some(mut debug) = debug { - debug.emit(&mut product); - } - - unwind_context.emit(&mut product); - - let module_regular = emit_module( - output_filenames, - prof, - product.object, - ModuleKind::Regular, - name.clone(), - producer, - )?; - - Ok(ModuleCodegenResult { - module_regular, - module_global_asm: global_asm_object_file.map(|global_asm_object_file| CompiledModule { - name: format!("{name}.asm"), - kind: ModuleKind::Regular, - object: Some(global_asm_object_file), - dwarf_object: None, - bytecode: None, - }), - existing_work_product: None, - }) -} - -fn emit_module( - output_filenames: &OutputFilenames, - prof: &SelfProfilerRef, - mut object: cranelift_object::object::write::Object<'_>, - kind: ModuleKind, - name: String, - producer_str: &str, -) -> Result { - if object.format() == cranelift_object::object::BinaryFormat::Elf { - let comment_section = object.add_section( - Vec::new(), - b".comment".to_vec(), - cranelift_object::object::SectionKind::OtherString, - ); - let mut producer = vec![0]; - producer.extend(producer_str.as_bytes()); - producer.push(0); - object.set_section_data(comment_section, producer, 1); - } - - let tmp_file = output_filenames.temp_path(OutputType::Object, Some(&name)); - let mut file = match File::create(&tmp_file) { - Ok(file) => file, - Err(err) => return Err(format!("error creating object file: {}", err)), - }; - - if let Err(err) = object.write_stream(&mut file) { - return Err(format!("error writing object file: {}", err)); - } - - prof.artifact_size("object_file", &*name, file.metadata().unwrap().len()); - - Ok(CompiledModule { name, kind, object: Some(tmp_file), dwarf_object: None, bytecode: None }) -} - -fn reuse_workproduct_for_cgu( - tcx: TyCtxt<'_>, - cgu: &CodegenUnit<'_>, -) -> Result { - let work_product = cgu.previous_work_product(tcx); - let obj_out_regular = - tcx.output_filenames(()).temp_path(OutputType::Object, Some(cgu.name().as_str())); - let source_file_regular = rustc_incremental::in_incr_comp_dir_sess( - &tcx.sess, - &work_product.saved_files.get("o").expect("no saved object file in work product"), - ); - - if let Err(err) = rustc_fs_util::link_or_copy(&source_file_regular, &obj_out_regular) { - return Err(format!( - "unable to copy {} to {}: {}", - source_file_regular.display(), - obj_out_regular.display(), - err - )); - } - let obj_out_global_asm = - crate::global_asm::add_file_stem_postfix(obj_out_regular.clone(), ".asm"); - let has_global_asm = if let Some(asm_o) = work_product.saved_files.get("asm.o") { - let source_file_global_asm = rustc_incremental::in_incr_comp_dir_sess(&tcx.sess, asm_o); - if let Err(err) = rustc_fs_util::link_or_copy(&source_file_global_asm, &obj_out_global_asm) - { - return Err(format!( - "unable to copy {} to {}: {}", - source_file_regular.display(), - obj_out_regular.display(), - err - )); - } - true - } else { - false - }; - - Ok(ModuleCodegenResult { - module_regular: CompiledModule { - name: cgu.name().to_string(), - kind: ModuleKind::Regular, - object: Some(obj_out_regular), - dwarf_object: None, - bytecode: None, - }, - module_global_asm: has_global_asm.then(|| CompiledModule { - name: cgu.name().to_string(), - kind: ModuleKind::Regular, - object: Some(obj_out_global_asm), - dwarf_object: None, - bytecode: None, - }), - existing_work_product: Some((cgu.work_product_id(), work_product)), - }) -} - -fn module_codegen( - tcx: TyCtxt<'_>, - (backend_config, global_asm_config, cgu_name, token): ( - BackendConfig, - Arc, - rustc_span::Symbol, - ConcurrencyLimiterToken, - ), -) -> OngoingModuleCodegen { - let (cgu_name, mut cx, mut module, codegened_functions) = - tcx.prof.generic_activity_with_arg("codegen cgu", cgu_name.as_str()).run(|| { - let cgu = tcx.codegen_unit(cgu_name); - let mono_items = cgu.items_in_deterministic_order(tcx); - - let mut module = make_module(tcx.sess, &backend_config, cgu_name.as_str().to_string()); - - let mut cx = crate::CodegenCx::new( - tcx, - backend_config.clone(), - module.isa(), - tcx.sess.opts.debuginfo != DebugInfo::None, - cgu_name, - ); - let mut type_dbg = TypeDebugContext::default(); - super::predefine_mono_items(tcx, &mut module, &mono_items); - let mut codegened_functions = vec![]; - for (mono_item, _) in mono_items { - match mono_item { - MonoItem::Fn(inst) => { - let codegened_function = crate::base::codegen_fn( - tcx, - &mut cx, - &mut type_dbg, - Function::new(), - &mut module, - inst, - ); - codegened_functions.push(codegened_function); - } - MonoItem::Static(def_id) => { - let data_id = crate::constant::codegen_static(tcx, &mut module, def_id); - if let Some(debug_context) = &mut cx.debug_context { - debug_context.define_static(tcx, &mut type_dbg, def_id, data_id); - } - } - MonoItem::GlobalAsm(item_id) => { - crate::global_asm::codegen_global_asm_item( - tcx, - &mut cx.global_asm, - item_id, - ); - } - } - } - crate::main_shim::maybe_create_entry_wrapper( - tcx, - &mut module, - &mut cx.unwind_context, - false, - cgu.is_primary(), - ); - - let cgu_name = cgu.name().as_str().to_owned(); - - (cgu_name, cx, module, codegened_functions) - }); - - let producer = crate::debuginfo::producer(tcx.sess); - - OngoingModuleCodegen::Async(std::thread::spawn(move || { - cx.profiler.clone().generic_activity_with_arg("compile functions", &*cgu_name).run(|| { - cranelift_codegen::timing::set_thread_profiler(Box::new(super::MeasuremeProfiler( - cx.profiler.clone(), - ))); - - let mut cached_context = Context::new(); - for codegened_func in codegened_functions { - crate::base::compile_fn(&mut cx, &mut cached_context, &mut module, codegened_func); - } - }); - - let global_asm_object_file = - cx.profiler.generic_activity_with_arg("compile assembly", &*cgu_name).run(|| { - crate::global_asm::compile_global_asm(&global_asm_config, &cgu_name, &cx.global_asm) - })?; - - let codegen_result = - cx.profiler.generic_activity_with_arg("write object file", &*cgu_name).run(|| { - emit_cgu( - &global_asm_config.output_filenames, - &cx.profiler, - cgu_name, - module, - cx.debug_context, - cx.unwind_context, - global_asm_object_file, - &producer, - ) - }); - std::mem::drop(token); - codegen_result - })) -} - -pub(crate) fn run_aot( - tcx: TyCtxt<'_>, - backend_config: BackendConfig, - metadata: EncodedMetadata, - need_metadata_module: bool, -) -> Box { - // FIXME handle `-Ctarget-cpu=native` - let target_cpu = match tcx.sess.opts.cg.target_cpu { - Some(ref name) => name, - None => tcx.sess.target.cpu.as_ref(), - } - .to_owned(); - - let cgus = if tcx.sess.opts.output_types.should_codegen() { - tcx.collect_and_partition_mono_items(()).1 - } else { - // If only `--emit metadata` is used, we shouldn't perform any codegen. - // Also `tcx.collect_and_partition_mono_items` may panic in that case. - return Box::new(OngoingCodegen { - modules: vec![], - allocator_module: None, - metadata_module: None, - metadata, - crate_info: CrateInfo::new(tcx, target_cpu), - concurrency_limiter: ConcurrencyLimiter::new(tcx.sess, 0), - }); - }; - - if tcx.dep_graph.is_fully_enabled() { - for cgu in cgus { - tcx.ensure().codegen_unit(cgu.name()); - } - } - - // Calculate the CGU reuse - let cgu_reuse = tcx.sess.time("find_cgu_reuse", || { - cgus.iter().map(|cgu| determine_cgu_reuse(tcx, &cgu)).collect::>() - }); - - rustc_codegen_ssa::assert_module_sources::assert_module_sources(tcx, &|cgu_reuse_tracker| { - for (i, cgu) in cgus.iter().enumerate() { - let cgu_reuse = cgu_reuse[i]; - cgu_reuse_tracker.set_actual_reuse(cgu.name().as_str(), cgu_reuse); - } - }); - - let global_asm_config = Arc::new(crate::global_asm::GlobalAsmConfig::new(tcx)); - - let mut concurrency_limiter = ConcurrencyLimiter::new(tcx.sess, cgus.len()); - - let modules = tcx.sess.time("codegen mono items", || { - cgus.iter() - .enumerate() - .map(|(i, cgu)| { - let cgu_reuse = - if backend_config.disable_incr_cache { CguReuse::No } else { cgu_reuse[i] }; - match cgu_reuse { - CguReuse::No => { - let dep_node = cgu.codegen_dep_node(tcx); - tcx.dep_graph - .with_task( - dep_node, - tcx, - ( - backend_config.clone(), - global_asm_config.clone(), - cgu.name(), - concurrency_limiter.acquire(tcx.dcx()), - ), - module_codegen, - Some(rustc_middle::dep_graph::hash_result), - ) - .0 - } - CguReuse::PreLto | CguReuse::PostLto => { - concurrency_limiter.job_already_done(); - OngoingModuleCodegen::Sync(reuse_workproduct_for_cgu(tcx, cgu)) - } - } - }) - .collect::>() - }); - - let mut allocator_module = make_module(tcx.sess, &backend_config, "allocator_shim".to_string()); - let mut allocator_unwind_context = UnwindContext::new(allocator_module.isa(), true); - let created_alloc_shim = - crate::allocator::codegen(tcx, &mut allocator_module, &mut allocator_unwind_context); - - let allocator_module = if created_alloc_shim { - let mut product = allocator_module.finish(); - allocator_unwind_context.emit(&mut product); - - match emit_module( - tcx.output_filenames(()), - &tcx.sess.prof, - product.object, - ModuleKind::Allocator, - "allocator_shim".to_owned(), - &crate::debuginfo::producer(tcx.sess), - ) { - Ok(allocator_module) => Some(allocator_module), - Err(err) => tcx.dcx().fatal(err), - } - } else { - None - }; - - let metadata_module = if need_metadata_module { - let (metadata_cgu_name, tmp_file) = tcx.sess.time("write compressed metadata", || { - use rustc_middle::mir::mono::CodegenUnitNameBuilder; - - let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx); - let metadata_cgu_name = cgu_name_builder - .build_cgu_name(LOCAL_CRATE, ["crate"], Some("metadata")) - .as_str() - .to_string(); - - let tmp_file = - tcx.output_filenames(()).temp_path(OutputType::Metadata, Some(&metadata_cgu_name)); - - let symbol_name = rustc_middle::middle::exported_symbols::metadata_symbol_name(tcx); - let obj = create_compressed_metadata_file(tcx.sess, &metadata, &symbol_name); - - if let Err(err) = std::fs::write(&tmp_file, obj) { - tcx.dcx().fatal(format!("error writing metadata object file: {}", err)); - } - - (metadata_cgu_name, tmp_file) - }); - - Some(CompiledModule { - name: metadata_cgu_name, - kind: ModuleKind::Metadata, - object: Some(tmp_file), - dwarf_object: None, - bytecode: None, - }) - } else { - None - }; - - Box::new(OngoingCodegen { - modules, - allocator_module, - metadata_module, - metadata, - crate_info: CrateInfo::new(tcx, target_cpu), - concurrency_limiter, - }) -} +use std::fs::{self,File};use std::path::{Path,PathBuf};use std::sync::Arc;use//; +std::thread::JoinHandle;use cranelift_object::{ObjectBuilder,ObjectModule};use// +rustc_codegen_ssa::assert_module_sources::CguReuse;use rustc_codegen_ssa::back// +::link::ensure_removed;use rustc_codegen_ssa::back::metadata:://((),());((),()); +create_compressed_metadata_file;use rustc_codegen_ssa::base:://((),());let _=(); +determine_cgu_reuse;use rustc_codegen_ssa::errors as ssa_errors;use//let _=||(); +rustc_codegen_ssa::{CodegenResults,CompiledModule,CrateInfo,ModuleKind};use//(); +rustc_data_structures::profiling::SelfProfilerRef;use rustc_data_structures:://; +stable_hasher::{HashStable,StableHasher} ;use rustc_metadata::fs::copy_to_stdout +;use rustc_metadata::EncodedMetadata;use rustc_middle::dep_graph::{WorkProduct, +WorkProductId};use rustc_middle::mir::mono::{CodegenUnit,MonoItem};use//((),()); +rustc_session::config::{DebugInfo,OutFileName,OutputFilenames,OutputType};use//; +rustc_session::Session;use crate::concurrency_limiter::{ConcurrencyLimiter,//(); +ConcurrencyLimiterToken};use crate::debuginfo::TypeDebugContext;use crate:://(); +global_asm::GlobalAsmConfig;use crate::{prelude::*,BackendConfig};struct//{();}; +ModuleCodegenResult{module_regular:CompiledModule,module_global_asm:Option,existing_work_product:Option<( WorkProductId,WorkProduct)>,}enum +OngoingModuleCodegen{Sync(Result),Async(JoinHandle// +>),}implHashStablefor//loop{break}; +OngoingModuleCodegen{fn hash_stable(&self,_:&mut HCX,_:&mut StableHasher){}}pub +(crate)struct OngoingCodegen{ modules:Vec,allocator_module +:Option,metadata_module:Option,metadata://{();}; +EncodedMetadata,crate_info:CrateInfo,concurrency_limiter:ConcurrencyLimiter,}//; +impl OngoingCodegen{pub(crate)fn join(self,sess:&Session,outputs:&//loop{break}; +OutputFilenames,backend_config:&BackendConfig,)->(CodegenResults,FxIndexMap){;let mut work_products=FxIndexMap::default();let mut +modules=vec![];3;for module_codegen in self.modules{3;let module_codegen_result= +match module_codegen{OngoingModuleCodegen::Sync(module_codegen_result)=>//{();}; +module_codegen_result,OngoingModuleCodegen::Async(join_handle)=>match //((),()); +join_handle.join(){Ok(module_codegen_result)=>module_codegen_result,Err(panic)// +=>std::panic::resume_unwind(panic),},};({});({});let module_codegen_result=match +module_codegen_result{Ok(module_codegen_result) =>module_codegen_result,Err(err) +=>sess.dcx().fatal(err),};((),());*&*&();let ModuleCodegenResult{module_regular, +module_global_asm,existing_work_product}=module_codegen_result;{;};if let Some(( +work_product_id,work_product))=existing_work_product{{();};work_products.insert( +work_product_id,work_product);({});}else{{;};let work_product=if backend_config. +disable_incr_cache{None}else if let Some(module_global_asm)=&module_global_asm{ +rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir(sess,&//let _=(); +module_regular.name,&[("o",&module_regular.object. as_ref().unwrap()),("asm.o",& +module_global_asm.object.as_ref().unwrap()),],)}else{rustc_incremental:://{();}; +copy_cgu_workproduct_to_incr_comp_cache_dir(sess,(&module_regular.name),&[("o",& +module_regular.object.as_ref().unwrap())],)};{();};if let Some((work_product_id, +work_product))=work_product{;work_products.insert(work_product_id,work_product); +}};modules.push(module_regular);if let Some(module_global_asm)=module_global_asm +{;modules.push(module_global_asm);}}self.concurrency_limiter.finished();sess.dcx +().abort_if_errors();((),());((),());let codegen_results=CodegenResults{modules, +allocator_module:self.allocator_module,metadata_module:self.metadata_module,//3; +metadata:self.metadata,crate_info:self.crate_info,};if let _=(){};if let _=(){}; +produce_final_output_artifacts(sess,&codegen_results,outputs);;(codegen_results, +work_products)}}fn produce_final_output_artifacts(sess:&Session,codegen_results +:&CodegenResults,crate_output:&OutputFilenames,){;let user_wants_bitcode=false;; +let mut user_wants_objects=false;{();};({});let copy_gracefully=|from:&Path,to:& +OutFileName|match to{OutFileName::Stdout=>{if let Err(e)=copy_to_stdout(from){3; +sess.dcx().emit_err(ssa_errors::CopyPath::new(from,to.as_path(),e));if true{};}} +OutFileName::Real(path)=>{if let Err(e)=fs::copy(from,path){;sess.dcx().emit_err +(ssa_errors::CopyPath::new(from,path,e));;}}};let copy_if_one_unit=|output_type: +OutputType,keep_numbered:bool|{if codegen_results.modules.len()==1{if true{};let +module_name=Some(&codegen_results.modules[0].name[..]);3;;let path=crate_output. +temp_path(output_type,module_name);;let output=crate_output.path(output_type);if +!output_type.is_text_output()&&output.is_tty(){;sess.dcx().emit_err(ssa_errors:: +BinaryOutputToTty{shorthand:output_type.shorthand()});3;}else{;copy_gracefully(& +path,&output);;}if!sess.opts.cg.save_temps&&!keep_numbered{;ensure_removed(sess. +dcx(),&path);();}}else{3;let extension=crate_output.temp_path(output_type,None). +extension().unwrap().to_str().unwrap().to_owned();{();};if crate_output.outputs. +contains_explicit_name(&output_type){if true{};sess.dcx().emit_warn(ssa_errors:: +IgnoringEmitPath{extension});;}else if crate_output.single_output_file.is_some() +{3;sess.dcx().emit_warn(ssa_errors::IgnoringOutput{extension});3;}else{}}};3;for +output_type in ((crate_output.outputs.keys( ))){match(*output_type){OutputType:: +Bitcode=>{}OutputType::LlvmAssembly=>{}OutputType::Assembly=>{}OutputType:://(); +Object=>{;user_wants_objects=true;;;copy_if_one_unit(OutputType::Object,true);;} +OutputType::Mir|OutputType::Metadata|OutputType::Exe|OutputType::DepInfo=>{}}}// +if!sess.opts.cg.save_temps{let _=();let needs_crate_object=crate_output.outputs. +contains_key(&OutputType::Exe);3;;let keep_numbered_bitcode=user_wants_bitcode&& +sess.codegen_units().as_usize()>1;;;let keep_numbered_objects=needs_crate_object +||(user_wants_objects&&sess.codegen_units().as_usize()>1);((),());for module in +codegen_results.modules.iter(){if let Some(ref path)=module.object{if!//((),()); +keep_numbered_objects{;ensure_removed(sess.dcx(),path);;}}if let Some(ref path)= +module.dwarf_object{if!keep_numbered_objects{;ensure_removed(sess.dcx(),path);}} +if let Some(ref path)=module.bytecode{if!keep_numbered_bitcode{3;ensure_removed( +sess.dcx(),path);{;};}}}if!user_wants_bitcode{if let Some(ref allocator_module)= +codegen_results.allocator_module{if let Some(ref path)=allocator_module.//{();}; +bytecode{();ensure_removed(sess.dcx(),path);3;}}}}}fn make_module(sess:&Session, +backend_config:&BackendConfig,name:String)->ObjectModule{((),());let isa=crate:: +build_isa(sess,backend_config);;let mut builder=ObjectBuilder::new(isa,name+".o" +,cranelift_module::default_libcall_names()).unwrap();if true{};let _=();builder. +per_function_section(sess.opts.unstable_opts. function_sections.unwrap_or(false) +);;ObjectModule::new(builder)}fn emit_cgu(output_filenames:&OutputFilenames,prof +:&SelfProfilerRef,name:String,module:ObjectModule,debug:Option,//; +unwind_context:UnwindContext,global_asm_object_file:Option,producer:&// +str,)->Result{3;let mut product=module.finish();3;if +let Some(mut debug)=debug{3;debug.emit(&mut product);;};unwind_context.emit(&mut +product);3;;let module_regular=emit_module(output_filenames,prof,product.object, +ModuleKind::Regular,name.clone(),producer,)?;loop{break};Ok(ModuleCodegenResult{ +module_regular,module_global_asm:global_asm_object_file.map(|//((),());let _=(); +global_asm_object_file|CompiledModule{name:(((((format!("{name}.asm")))))),kind: +ModuleKind::Regular,object:(((Some(global_asm_object_file)))),dwarf_object:None, +bytecode:None,}),existing_work_product: None,})}fn emit_module(output_filenames: +&OutputFilenames,prof:&SelfProfilerRef,mut object:cranelift_object::object:://3; +write::Object<'_>,kind:ModuleKind,name:String,producer_str:&str,)->Result{if (((((object .format())))))==cranelift_object::object:: +BinaryFormat::Elf{;let comment_section=object.add_section(Vec::new(),b".comment" +.to_vec(),cranelift_object::object::SectionKind::OtherString,);;let mut producer +=vec![0];;;producer.extend(producer_str.as_bytes());;;producer.push(0);;;object. +set_section_data(comment_section,producer,1);3;}3;let tmp_file=output_filenames. +temp_path(OutputType::Object,Some(&name));();3;let mut file=match File::create(& +tmp_file){Ok(file)=>file,Err(err)=>return Err(format!(//loop{break};loop{break}; +"error creating object file: {}",err)),};3;if let Err(err)=object.write_stream(& +mut file){();return Err(format!("error writing object file: {}",err));3;}3;prof. +artifact_size("object_file",&*name,file.metadata().unwrap().len());if true{};Ok( +CompiledModule{name,kind,object:Some(tmp_file ),dwarf_object:None,bytecode:None} +)}fn reuse_workproduct_for_cgu(tcx:TyCtxt<'_>,cgu:&CodegenUnit<'_>,)->Result{;let work_product=cgu.previous_work_product(tcx);let +obj_out_regular=(tcx.output_filenames(())).temp_path(OutputType::Object,Some(cgu +.name().as_str()));let _=();let _=();let source_file_regular=rustc_incremental:: +in_incr_comp_dir_sess((&tcx.sess),&(work_product.saved_files.get(("o"))).expect( +"no saved object file in work product"),);*&*&();if let Err(err)=rustc_fs_util:: +link_or_copy(&source_file_regular,&obj_out_regular){let _=();return Err(format!( +"unable to copy {} to {}: {}",source_file_regular.display(),obj_out_regular.//3; +display(),err));let _=||();}if true{};let obj_out_global_asm=crate::global_asm:: +add_file_stem_postfix(obj_out_regular.clone(),".asm");;let has_global_asm=if let +Some(asm_o)=work_product.saved_files.get("asm.o"){();let source_file_global_asm= +rustc_incremental::in_incr_comp_dir_sess(&tcx.sess,asm_o);{();};if let Err(err)= +rustc_fs_util::link_or_copy(&source_file_global_asm,&obj_out_global_asm){;return +Err(format!("unable to copy {} to {}: {}",source_file_regular.display(),//{();}; +obj_out_regular.display(),err));{;};}true}else{false};();Ok(ModuleCodegenResult{ +module_regular:CompiledModule{name:((cgu.name ()).to_string()),kind:ModuleKind:: +Regular,object:((((Some(obj_out_regular))))), dwarf_object:None,bytecode:None,}, +module_global_asm:has_global_asm.then(||CompiledModule {name:((((cgu.name())))). +to_string(),kind:ModuleKind::Regular ,object:(((((Some(obj_out_global_asm)))))), +dwarf_object:None,bytecode:None,}),existing_work_product:Some((cgu.//let _=||(); +work_product_id(),work_product)),})}fn module_codegen(tcx:TyCtxt<'_>,(//((),()); +backend_config,global_asm_config,cgu_name,token):(BackendConfig,Arc,rustc_span::Symbol,ConcurrencyLimiterToken,),)->//loop{break;}; +OngoingModuleCodegen{();let(cgu_name,mut cx,mut module,codegened_functions)=tcx. +prof.generic_activity_with_arg("codegen cgu",cgu_name.as_str()).run(||{;let cgu= +tcx.codegen_unit(cgu_name);;let mono_items=cgu.items_in_deterministic_order(tcx) +;({});{;};let mut module=make_module(tcx.sess,&backend_config,cgu_name.as_str(). +to_string());;let mut cx=crate::CodegenCx::new(tcx,backend_config.clone(),module +.isa(),tcx.sess.opts.debuginfo!=DebugInfo::None,cgu_name,);3;3;let mut type_dbg= +TypeDebugContext::default();{;};();super::predefine_mono_items(tcx,&mut module,& +mono_items);;;let mut codegened_functions=vec![];;for(mono_item,_)in mono_items{ +match mono_item{MonoItem::Fn(inst)=>{*&*&();let codegened_function=crate::base:: +codegen_fn(tcx,&mut cx,&mut type_dbg,Function::new(),&mut module,inst,);{;};{;}; +codegened_functions.push(codegened_function);3;}MonoItem::Static(def_id)=>{3;let +data_id=crate::constant::codegen_static(tcx,&mut module,def_id);{;};if let Some( +debug_context)=&mut cx.debug_context{*&*&();debug_context.define_static(tcx,&mut +type_dbg,def_id,data_id);3;}}MonoItem::GlobalAsm(item_id)=>{;crate::global_asm:: +codegen_global_asm_item(tcx,&mut cx.global_asm,item_id,);;}}};crate::main_shim:: +maybe_create_entry_wrapper(tcx,(&mut module),(&mut cx.unwind_context),false,cgu. +is_primary(),);;let cgu_name=cgu.name().as_str().to_owned();(cgu_name,cx,module, +codegened_functions)});();3;let producer=crate::debuginfo::producer(tcx.sess);3; +OngoingModuleCodegen::Async(std::thread::spawn(move||{{();};cx.profiler.clone(). +generic_activity_with_arg("compile functions",&*cgu_name).run(||{*&*&();((),()); +cranelift_codegen::timing::set_thread_profiler(Box::new(super:://*&*&();((),()); +MeasuremeProfiler(cx.profiler.clone(),)));;let mut cached_context=Context::new() +;;for codegened_func in codegened_functions{crate::base::compile_fn(&mut cx,&mut +cached_context,&mut module,codegened_func);;}});;;let global_asm_object_file=cx. +profiler.generic_activity_with_arg(("compile assembly"),&*cgu_name).run(||{crate +::global_asm::compile_global_asm(&global_asm_config,&cgu_name ,&cx.global_asm)}) +?;;let codegen_result=cx.profiler.generic_activity_with_arg("write object file", +&(*cgu_name)).run(||{ emit_cgu(&global_asm_config.output_filenames,&cx.profiler, +cgu_name,module,cx.debug_context,cx.unwind_context,global_asm_object_file,&//(); +producer,)});;;std::mem::drop(token);codegen_result}))}pub(crate)fn run_aot(tcx: +TyCtxt<'_>,backend_config:BackendConfig,metadata:EncodedMetadata,//loop{break;}; +need_metadata_module:bool,)->Box{;let target_cpu=match tcx.sess. +opts.cg.target_cpu{Some(ref name)=>name,None =>(tcx.sess.target.cpu.as_ref()),}. +to_owned();({});{;};let cgus=if tcx.sess.opts.output_types.should_codegen(){tcx. +collect_and_partition_mono_items(()).1}else{({});return Box::new(OngoingCodegen{ +modules:(vec![]),allocator_module:None,metadata_module:None,metadata,crate_info: +CrateInfo::new(tcx,target_cpu) ,concurrency_limiter:ConcurrencyLimiter::new(tcx. +sess,0),});;};;if tcx.dep_graph.is_fully_enabled(){for cgu in cgus{tcx.ensure(). +codegen_unit(cgu.name());;}}let cgu_reuse=tcx.sess.time("find_cgu_reuse",||{cgus +.iter().map(|cgu|determine_cgu_reuse(tcx,&cgu)).collect::>()});({});({}); +rustc_codegen_ssa::assert_module_sources::assert_module_sources(tcx,&|//((),()); +cgu_reuse_tracker|{for(i,cgu)in cgus.iter().enumerate(){;let cgu_reuse=cgu_reuse +[i];;;cgu_reuse_tracker.set_actual_reuse(cgu.name().as_str(),cgu_reuse);;}});let +global_asm_config=Arc::new(crate::global_asm::GlobalAsmConfig::new(tcx));3;3;let +mut concurrency_limiter=ConcurrencyLimiter::new(tcx.sess,cgus.len());{;};{;};let +modules=tcx.sess.time(("codegen mono items"),||{cgus.iter().enumerate().map(|(i, +cgu)|{({});let cgu_reuse=if backend_config.disable_incr_cache{CguReuse::No}else{ +cgu_reuse[i]};;match cgu_reuse{CguReuse::No=>{let dep_node=cgu.codegen_dep_node( +tcx);if let _=(){};tcx.dep_graph.with_task(dep_node,tcx,(backend_config.clone(), +global_asm_config.clone(),(cgu.name()),concurrency_limiter.acquire(tcx.dcx()),), +module_codegen,Some(rustc_middle::dep_graph::hash_result) ,).0}CguReuse::PreLto| +CguReuse::PostLto=>{;concurrency_limiter.job_already_done();OngoingModuleCodegen +::Sync(reuse_workproduct_for_cgu(tcx,cgu))}}}).collect::>()});3;3;let mut +allocator_module=make_module(tcx.sess, ((&backend_config)),(("allocator_shim")). +to_string());((),());*&*&();let mut allocator_unwind_context=UnwindContext::new( +allocator_module.isa(),true);;;let created_alloc_shim=crate::allocator::codegen( +tcx,&mut allocator_module,&mut allocator_unwind_context);;;let allocator_module= +if created_alloc_shim{{();};let mut product=allocator_module.finish();({});({}); +allocator_unwind_context.emit(&mut product);if let _=(){};match emit_module(tcx. +output_filenames(((()))),(&tcx.sess .prof),product.object,ModuleKind::Allocator, +"allocator_shim".to_owned(),((&((crate::debuginfo ::producer(tcx.sess))))),){Ok( +allocator_module)=>Some(allocator_module),Err(err)=> tcx.dcx().fatal(err),}}else +{None};();3;let metadata_module=if need_metadata_module{3;let(metadata_cgu_name, +tmp_file)=tcx.sess.time("write compressed metadata",||{3;use rustc_middle::mir:: +mono::CodegenUnitNameBuilder;;let cgu_name_builder=&mut CodegenUnitNameBuilder:: +new(tcx);3;3;let metadata_cgu_name=cgu_name_builder.build_cgu_name(LOCAL_CRATE,[ +"crate"],Some("metadata")).as_str().to_string();((),());*&*&();let tmp_file=tcx. +output_filenames(()).temp_path(OutputType::Metadata,Some(&metadata_cgu_name));;; +let symbol_name=rustc_middle::middle::exported_symbols::metadata_symbol_name(//; +tcx);;;let obj=create_compressed_metadata_file(tcx.sess,&metadata,&symbol_name); +if let Err(err)=std::fs::write(&tmp_file,obj){if true{};tcx.dcx().fatal(format!( +"error writing metadata object file: {}",err));;}(metadata_cgu_name,tmp_file)}); +Some(CompiledModule{name:metadata_cgu_name,kind:ModuleKind::Metadata,object://3; +Some(tmp_file),dwarf_object:None,bytecode:None,})}else{None};if true{};Box::new( +OngoingCodegen{modules,allocator_module,metadata_module,metadata,crate_info://3; +CrateInfo::new(tcx,target_cpu),concurrency_limiter,})}//loop{break};loop{break}; diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs index 6dbc3f191278d..f50690687145e 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs @@ -1,415 +1,140 @@ -//! The JIT driver uses [`cranelift_jit`] to JIT execute programs without writing any object -//! files. - -use std::cell::RefCell; -use std::ffi::CString; -use std::os::raw::{c_char, c_int}; -use std::sync::{mpsc, Mutex, OnceLock}; - -use cranelift_jit::{JITBuilder, JITModule}; -use rustc_codegen_ssa::CrateInfo; -use rustc_middle::mir::mono::MonoItem; -use rustc_session::Session; -use rustc_span::Symbol; - -use crate::debuginfo::TypeDebugContext; -use crate::{prelude::*, BackendConfig}; -use crate::{CodegenCx, CodegenMode}; - -struct JitState { - backend_config: BackendConfig, - jit_module: JITModule, -} - -thread_local! { - static LAZY_JIT_STATE: RefCell> = const { RefCell::new(None) }; -} - -/// The Sender owned by the rustc thread -static GLOBAL_MESSAGE_SENDER: OnceLock>> = OnceLock::new(); - -/// A message that is sent from the jitted runtime to the rustc thread. -/// Senders are responsible for upholding `Send` semantics. -enum UnsafeMessage { - /// Request that the specified `Instance` be lazily jitted. - /// - /// Nothing accessible through `instance_ptr` may be moved or mutated by the sender after - /// this message is sent. - JitFn { - instance_ptr: *const Instance<'static>, - trampoline_ptr: *const u8, - tx: mpsc::Sender<*const u8>, - }, -} -unsafe impl Send for UnsafeMessage {} - -impl UnsafeMessage { - /// Send the message. - fn send(self) -> Result<(), mpsc::SendError> { - thread_local! { - /// The Sender owned by the local thread - static LOCAL_MESSAGE_SENDER: mpsc::Sender = - GLOBAL_MESSAGE_SENDER - .get().unwrap() - .lock().unwrap() - .clone(); - } - LOCAL_MESSAGE_SENDER.with(|sender| sender.send(self)) - } -} - -fn create_jit_module( - tcx: TyCtxt<'_>, - backend_config: &BackendConfig, - hotswap: bool, -) -> (JITModule, CodegenCx) { - let crate_info = CrateInfo::new(tcx, "dummy_target_cpu".to_string()); - - 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.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); - - let mut cx = crate::CodegenCx::new( - tcx, - backend_config.clone(), - jit_module.isa(), - false, - Symbol::intern("dummy_cgu_name"), - ); - - crate::allocator::codegen(tcx, &mut jit_module, &mut cx.unwind_context); - crate::main_shim::maybe_create_entry_wrapper( - tcx, - &mut jit_module, - &mut cx.unwind_context, - true, - true, - ); - - (jit_module, cx) -} - -pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! { - if !tcx.sess.opts.output_types.should_codegen() { - tcx.dcx().fatal("JIT mode doesn't work with `cargo check`"); - } - - if !tcx.crate_types().contains(&rustc_session::config::CrateType::Executable) { - tcx.dcx().fatal("can't jit non-executable crate"); - } - - let (mut jit_module, mut cx) = create_jit_module( - tcx, - &backend_config, - matches!(backend_config.codegen_mode, CodegenMode::JitLazy), - ); - let mut cached_context = Context::new(); - - let (_, cgus) = tcx.collect_and_partition_mono_items(()); - let mono_items = cgus - .iter() - .map(|cgu| cgu.items_in_deterministic_order(tcx).into_iter()) - .flatten() - .collect::>() - .into_iter() - .collect::>(); - - tcx.sess.time("codegen mono items", || { - super::predefine_mono_items(tcx, &mut jit_module, &mono_items); - for (mono_item, _) in mono_items { - match mono_item { - MonoItem::Fn(inst) => match backend_config.codegen_mode { - CodegenMode::Aot => unreachable!(), - CodegenMode::Jit => { - codegen_and_compile_fn( - tcx, - &mut cx, - &mut cached_context, - &mut jit_module, - inst, - ); - } - CodegenMode::JitLazy => { - codegen_shim(tcx, &mut cx, &mut cached_context, &mut jit_module, inst) - } - }, - MonoItem::Static(def_id) => { - crate::constant::codegen_static(tcx, &mut jit_module, def_id); - } - MonoItem::GlobalAsm(item_id) => { - let item = tcx.hir().item(item_id); - tcx.dcx().span_fatal(item.span, "Global asm is not supported in JIT mode"); - } - } - } - }); - - if !cx.global_asm.is_empty() { - tcx.dcx().fatal("Inline asm is not supported in JIT mode"); - } - - tcx.dcx().abort_if_errors(); - - jit_module.finalize_definitions().unwrap(); - unsafe { cx.unwind_context.register_jit(&jit_module) }; - - println!( - "Rustc codegen cranelift will JIT run the executable, because -Cllvm-args=mode=jit was passed" - ); - - let args = std::iter::once(&*tcx.crate_name(LOCAL_CRATE).as_str().to_string()) - .chain(backend_config.jit_args.iter().map(|arg| &**arg)) - .map(|arg| CString::new(arg).unwrap()) - .collect::>(); - - let start_sig = Signature { - params: vec![ - AbiParam::new(jit_module.target_config().pointer_type()), - AbiParam::new(jit_module.target_config().pointer_type()), - ], - returns: vec![AbiParam::new(jit_module.target_config().pointer_type() /*isize*/)], - call_conv: jit_module.target_config().default_call_conv, - }; - let start_func_id = jit_module.declare_function("main", Linkage::Import, &start_sig).unwrap(); - let finalized_start: *const u8 = jit_module.get_finalized_function(start_func_id); - - LAZY_JIT_STATE.with(|lazy_jit_state| { - let mut lazy_jit_state = lazy_jit_state.borrow_mut(); - assert!(lazy_jit_state.is_none()); - *lazy_jit_state = Some(JitState { backend_config, jit_module }); - }); - - let f: extern "C" fn(c_int, *const *const c_char) -> c_int = - unsafe { ::std::mem::transmute(finalized_start) }; - - let (tx, rx) = mpsc::channel(); - GLOBAL_MESSAGE_SENDER.set(Mutex::new(tx)).unwrap(); - - // Spawn the jitted runtime in a new thread so that this rustc thread can handle messages - // (eg to lazily JIT further functions as required) - std::thread::spawn(move || { - let mut argv = args.iter().map(|arg| arg.as_ptr()).collect::>(); - - // Push a null pointer as a terminating argument. This is required by POSIX and - // useful as some dynamic linkers use it as a marker to jump over. - argv.push(std::ptr::null()); - - let ret = f(args.len() as c_int, argv.as_ptr()); - std::process::exit(ret); - }); - - // Handle messages - loop { - match rx.recv().unwrap() { - // lazy JIT compilation request - compile requested instance and return pointer to result - UnsafeMessage::JitFn { instance_ptr, trampoline_ptr, tx } => { - tx.send(jit_fn(instance_ptr, trampoline_ptr)) - .expect("jitted runtime hung up before response to lazy JIT request was sent"); - } - } - } -} - -pub(crate) fn codegen_and_compile_fn<'tcx>( - tcx: TyCtxt<'tcx>, - cx: &mut crate::CodegenCx, - cached_context: &mut Context, - module: &mut dyn Module, - instance: Instance<'tcx>, -) { - cranelift_codegen::timing::set_thread_profiler(Box::new(super::MeasuremeProfiler( - cx.profiler.clone(), - ))); - - tcx.prof.generic_activity("codegen and compile fn").run(|| { - let _inst_guard = - crate::PrintOnPanic(|| format!("{:?} {}", instance, tcx.symbol_name(instance).name)); - - let cached_func = std::mem::replace(&mut cached_context.func, Function::new()); - let codegened_func = crate::base::codegen_fn( - tcx, - cx, - &mut TypeDebugContext::default(), - cached_func, - module, - instance, - ); - - crate::base::compile_fn(cx, cached_context, module, codegened_func); - }); -} - -extern "C" fn clif_jit_fn( - instance_ptr: *const Instance<'static>, - trampoline_ptr: *const u8, -) -> *const u8 { - // send the JIT request to the rustc thread, with a channel for the response - let (tx, rx) = mpsc::channel(); - UnsafeMessage::JitFn { instance_ptr, trampoline_ptr, tx } - .send() - .expect("rustc thread hung up before lazy JIT request was sent"); - - // block on JIT compilation result - rx.recv().expect("rustc thread hung up before responding to sent lazy JIT request") -} - -fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) -> *const u8 { - rustc_middle::ty::tls::with(|tcx| { - // lift is used to ensure the correct lifetime for instance. - let instance = tcx.lift(unsafe { *instance_ptr }).unwrap(); - - LAZY_JIT_STATE.with(|lazy_jit_state| { - let mut lazy_jit_state = lazy_jit_state.borrow_mut(); - let lazy_jit_state = lazy_jit_state.as_mut().unwrap(); - let jit_module = &mut lazy_jit_state.jit_module; - let backend_config = lazy_jit_state.backend_config.clone(); - - let name = tcx.symbol_name(instance).name; - let sig = crate::abi::get_function_sig( - tcx, - jit_module.target_config().default_call_conv, - instance, - ); - let func_id = jit_module.declare_function(name, Linkage::Export, &sig).unwrap(); - - let current_ptr = jit_module.read_got_entry(func_id); - - // If the function's GOT entry has already been updated to point at something other - // than the shim trampoline, don't re-jit but just return the new pointer instead. - // This does not need synchronization as this code is executed only by a sole rustc - // thread. - if current_ptr != trampoline_ptr { - return current_ptr; - } - - jit_module.prepare_for_function_redefine(func_id).unwrap(); - - let mut cx = crate::CodegenCx::new( - tcx, - backend_config, - jit_module.isa(), - false, - Symbol::intern("dummy_cgu_name"), - ); - codegen_and_compile_fn(tcx, &mut cx, &mut Context::new(), jit_module, instance); - - assert!(cx.global_asm.is_empty()); - jit_module.finalize_definitions().unwrap(); - unsafe { cx.unwind_context.register_jit(&jit_module) }; - jit_module.get_finalized_function(func_id) - }) - }) -} - -fn dep_symbol_lookup_fn( - sess: &Session, - crate_info: CrateInfo, -) -> Box Option<*const u8>> { - use rustc_middle::middle::dependency_format::Linkage; - - let mut dylib_paths = Vec::new(); - - let data = &crate_info - .dependency_formats - .iter() - .find(|(crate_type, _data)| *crate_type == rustc_session::config::CrateType::Executable) - .unwrap() - .1; - // `used_crates` is in reverse postorder in terms of dependencies. Reverse the order here to - // get a postorder which ensures that all dependencies of a dylib are loaded before the dylib - // itself. This helps the dynamic linker to find dylibs not in the regular dynamic library - // search path. - for &cnum in crate_info.used_crates.iter().rev() { - let src = &crate_info.used_crate_source[&cnum]; - match data[cnum.as_usize() - 1] { - Linkage::NotLinked | Linkage::IncludedFromDylib => {} - Linkage::Static => { - let name = crate_info.crate_name[&cnum]; - let mut diag = sess.dcx().struct_err(format!("Can't load static lib {}", name)); - diag.note("rustc_codegen_cranelift can only load dylibs in JIT mode."); - diag.emit(); - } - Linkage::Dynamic => { - dylib_paths.push(src.dylib.as_ref().unwrap().0.clone()); - } - } - } - - let imported_dylibs = Box::leak( - dylib_paths - .into_iter() - .map(|path| unsafe { libloading::Library::new(&path).unwrap() }) - .collect::>(), - ); - - sess.dcx().abort_if_errors(); - - 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>( - tcx: TyCtxt<'tcx>, - cx: &mut CodegenCx, - cached_context: &mut Context, - module: &mut JITModule, - inst: Instance<'tcx>, -) { - let pointer_type = module.target_config().pointer_type(); - - let name = tcx.symbol_name(inst).name; - let sig = crate::abi::get_function_sig(tcx, module.target_config().default_call_conv, inst); - let func_id = module.declare_function(name, Linkage::Export, &sig).unwrap(); - - let instance_ptr = Box::into_raw(Box::new(inst)); - - let jit_fn = module - .declare_function( - "__clif_jit_fn", - Linkage::Import, - &Signature { - call_conv: module.target_config().default_call_conv, - params: vec![AbiParam::new(pointer_type), AbiParam::new(pointer_type)], - returns: vec![AbiParam::new(pointer_type)], - }, - ) - .unwrap(); - - let context = cached_context; - context.clear(); - let trampoline = &mut context.func; - trampoline.signature = sig.clone(); - - let mut builder_ctx = FunctionBuilderContext::new(); - let mut trampoline_builder = FunctionBuilder::new(trampoline, &mut builder_ctx); - - let trampoline_fn = module.declare_func_in_func(func_id, trampoline_builder.func); - let jit_fn = module.declare_func_in_func(jit_fn, trampoline_builder.func); - let sig_ref = trampoline_builder.func.import_signature(sig); - - let entry_block = trampoline_builder.create_block(); - trampoline_builder.append_block_params_for_function_params(entry_block); - let fn_args = trampoline_builder.func.dfg.block_params(entry_block).to_vec(); - - trampoline_builder.switch_to_block(entry_block); - let instance_ptr = trampoline_builder.ins().iconst(pointer_type, instance_ptr as u64 as i64); - let trampoline_ptr = trampoline_builder.ins().func_addr(pointer_type, trampoline_fn); - let jitted_fn = trampoline_builder.ins().call(jit_fn, &[instance_ptr, trampoline_ptr]); - let jitted_fn = trampoline_builder.func.dfg.inst_results(jitted_fn)[0]; - let call_inst = trampoline_builder.ins().call_indirect(sig_ref, jitted_fn, &fn_args); - let ret_vals = trampoline_builder.func.dfg.inst_results(call_inst).to_vec(); - trampoline_builder.ins().return_(&ret_vals); - - module.define_function(func_id, context).unwrap(); - cx.unwind_context.add_function(func_id, context, module.isa()); -} +use std::cell::RefCell;use std::ffi::CString;use std::os::raw::{c_char,c_int};// +use std::sync::{mpsc,Mutex,OnceLock };use cranelift_jit::{JITBuilder,JITModule}; +use rustc_codegen_ssa::CrateInfo;use rustc_middle::mir::mono::MonoItem;use//{;}; +rustc_session::Session;use rustc_span::Symbol;use crate::debuginfo:://if true{}; +TypeDebugContext;use crate::{prelude::*,BackendConfig};use crate::{CodegenCx,//; +CodegenMode};struct JitState{ backend_config:BackendConfig,jit_module:JITModule, +}thread_local!{static LAZY_JIT_STATE:RefCell>=const{RefCell::// +new(None)};}static GLOBAL_MESSAGE_SENDER:OnceLock>>=(OnceLock::new()) ;enum UnsafeMessage{JitFn{instance_ptr:*const +Instance<'static>,trampoline_ptr:*const u8,tx: mpsc::Sender<*const u8>,},}unsafe +impl Send for UnsafeMessage{}impl UnsafeMessage{fn send(self)->Result<(),mpsc//; +::SendError>{thread_local!{static LOCAL_MESSAGE_SENDER:mpsc:://3; +Sender=GLOBAL_MESSAGE_SENDER.get().unwrap().lock().unwrap().//(); +clone();}(((LOCAL_MESSAGE_SENDER.with(((|sender| ((sender.send(self)))))))))}}fn +create_jit_module(tcx:TyCtxt<'_>,backend_config :&BackendConfig,hotswap:bool,)-> +(JITModule,CodegenCx){({});let crate_info=CrateInfo::new(tcx,"dummy_target_cpu". +to_string());();();let isa=crate::build_isa(tcx.sess,backend_config);3;3;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.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);let mut +cx=crate::CodegenCx::new(tcx,(backend_config.clone( )),(jit_module.isa()),false, +Symbol::intern("dummy_cgu_name"),);{();};({});crate::allocator::codegen(tcx,&mut +jit_module,&mut cx.unwind_context);;crate::main_shim::maybe_create_entry_wrapper +(tcx,&mut jit_module,&mut cx.unwind_context,true,true,);{;};(jit_module,cx)}pub( +crate)fn run_jit(tcx:TyCtxt<'_>,backend_config:BackendConfig)->!{if!tcx.sess.//; +opts.output_types.should_codegen(){if let _=(){};*&*&();((),());tcx.dcx().fatal( +"JIT mode doesn't work with `cargo check`");{;};}if!tcx.crate_types().contains(& +rustc_session::config::CrateType::Executable){let _=();let _=();tcx.dcx().fatal( +"can't jit non-executable crate");;}let(mut jit_module,mut cx)=create_jit_module +(tcx,&backend_config,matches !(backend_config.codegen_mode,CodegenMode::JitLazy) +,);{();};{();};let mut cached_context=Context::new();{();};({});let(_,cgus)=tcx. +collect_and_partition_mono_items(());3;;let mono_items=cgus.iter().map(|cgu|cgu. +items_in_deterministic_order(tcx).into_iter()) .flatten().collect::>().into_iter().collect::>();;tcx.sess.time("codegen mono items",|| +{;super::predefine_mono_items(tcx,&mut jit_module,&mono_items);;for(mono_item,_) +in mono_items{match mono_item{MonoItem::Fn(inst)=>match backend_config.//*&*&(); +codegen_mode{CodegenMode::Aot=>unreachable!(),CodegenMode::Jit=>{*&*&();((),()); +codegen_and_compile_fn(tcx,&mut cx,&mut cached_context,&mut jit_module,inst,);;} +CodegenMode::JitLazy=>{codegen_shim(tcx,((&mut cx)),((&mut cached_context)),&mut +jit_module,inst)}},MonoItem::Static(def_id)=>{3;crate::constant::codegen_static( +tcx,&mut jit_module,def_id);;}MonoItem::GlobalAsm(item_id)=>{let item=tcx.hir(). +item(item_id);let _=();let _=();((),());let _=();tcx.dcx().span_fatal(item.span, +"Global asm is not supported in JIT mode");;}}}});;if!cx.global_asm.is_empty(){; +tcx.dcx().fatal("Inline asm is not supported in JIT mode");({});}({});tcx.dcx(). +abort_if_errors();();3;jit_module.finalize_definitions().unwrap();3;3;unsafe{cx. +unwind_context.register_jit(&jit_module)};*&*&();((),());if let _=(){};println!( +"Rustc codegen cranelift will JIT run the executable, because -Cllvm-args=mode=jit was passed" +);;let args=std::iter::once(&*tcx.crate_name(LOCAL_CRATE).as_str().to_string()). +chain((backend_config.jit_args.iter().map(|arg|&* *arg))).map(|arg|CString::new( +arg).unwrap()).collect::>();;let start_sig=Signature{params:vec![AbiParam +::new(jit_module.target_config().pointer_type()),AbiParam::new(jit_module.//{;}; +target_config().pointer_type()),],returns:vec![AbiParam::new(jit_module.//{();}; +target_config().pointer_type())],call_conv:(((((jit_module.target_config()))))). +default_call_conv,};{;};();let start_func_id=jit_module.declare_function("main", +Linkage::Import,&start_sig).unwrap();;;let finalized_start:*const u8=jit_module. +get_finalized_function(start_func_id);;;LAZY_JIT_STATE.with(|lazy_jit_state|{let +mut lazy_jit_state=lazy_jit_state.borrow_mut();;assert!(lazy_jit_state.is_none() +);;*lazy_jit_state=Some(JitState{backend_config,jit_module});});let f:extern "C" +fn(c_int,*const*const c_char)->c_int=unsafe{::std::mem::transmute(//loop{break}; +finalized_start)};;;let(tx,rx)=mpsc::channel();GLOBAL_MESSAGE_SENDER.set(Mutex:: +new(tx)).unwrap();;;std::thread::spawn(move||{let mut argv=args.iter().map(|arg| +arg.as_ptr()).collect::>();;;argv.push(std::ptr::null());;let ret=f(args. +len()as c_int,argv.as_ptr());;;std::process::exit(ret);;});loop{match rx.recv(). +unwrap(){UnsafeMessage::JitFn{instance_ptr,trampoline_ptr,tx}=>{;tx.send(jit_fn( +instance_ptr,trampoline_ptr)).expect(//if true{};if true{};if true{};let _=||(); +"jitted runtime hung up before response to lazy JIT request was sent");;}}}}pub( +crate)fn codegen_and_compile_fn<'tcx>(tcx:TyCtxt <'tcx>,cx:&mut crate::CodegenCx +,cached_context:&mut Context,module:&mut dyn Module,instance:Instance<'tcx>,){3; +cranelift_codegen::timing::set_thread_profiler(Box::new(super:://*&*&();((),()); +MeasuremeProfiler(cx.profiler.clone(),)));{();};{();};tcx.prof.generic_activity( +"codegen and compile fn").run(||{;let _inst_guard=crate::PrintOnPanic(||format!( +"{:?} {}",instance,tcx.symbol_name(instance).name));;;let cached_func=std::mem:: +replace(&mut cached_context.func,Function::new());3;3;let codegened_func=crate:: +base::codegen_fn(tcx,cx,(&mut (TypeDebugContext::default())),cached_func,module, +instance,);;crate::base::compile_fn(cx,cached_context,module,codegened_func);}); +}extern "C" fn clif_jit_fn(instance_ptr :*const Instance<'static>,trampoline_ptr +:*const u8,)->*const u8{();let(tx,rx)=mpsc::channel();();3;UnsafeMessage::JitFn{ +instance_ptr,trampoline_ptr,tx}.send().expect(//((),());((),());((),());((),()); +"rustc thread hung up before lazy JIT request was sent");{();};rx.recv().expect( +"rustc thread hung up before responding to sent lazy JIT request")}fn jit_fn(//; +instance_ptr:*const Instance<'static>,trampoline_ptr:*const u8)->*const u8{//(); +rustc_middle::ty::tls::with(|tcx|{;let instance=tcx.lift(unsafe{*instance_ptr}). +unwrap();{();};LAZY_JIT_STATE.with(|lazy_jit_state|{({});let mut lazy_jit_state= +lazy_jit_state.borrow_mut();;let lazy_jit_state=lazy_jit_state.as_mut().unwrap() +;{;};{;};let jit_module=&mut lazy_jit_state.jit_module;();();let backend_config= +lazy_jit_state.backend_config.clone();;;let name=tcx.symbol_name(instance).name; +let sig=crate::abi::get_function_sig(tcx,((((((jit_module.target_config())))))). +default_call_conv,instance,);();();let func_id=jit_module.declare_function(name, +Linkage::Export,&sig).unwrap();{;};();let current_ptr=jit_module.read_got_entry( +func_id);();if current_ptr!=trampoline_ptr{3;return current_ptr;3;}3;jit_module. +prepare_for_function_redefine(func_id).unwrap();3;;let mut cx=crate::CodegenCx:: +new(tcx,backend_config,jit_module.isa(), false,Symbol::intern("dummy_cgu_name"), +);;;codegen_and_compile_fn(tcx,&mut cx,&mut Context::new(),jit_module,instance); +assert!(cx.global_asm.is_empty());;;jit_module.finalize_definitions().unwrap();; +unsafe{cx.unwind_context.register_jit(&jit_module)};((),());let _=();jit_module. +get_finalized_function(func_id)})})}fn dep_symbol_lookup_fn(sess:&Session,//{;}; +crate_info:CrateInfo,)->BoxOption<*const u8>>{;use rustc_middle:: +middle::dependency_format::Linkage;;;let mut dylib_paths=Vec::new();;;let data=& +crate_info.dependency_formats.iter().find( |(crate_type,_data)|((*crate_type))== +rustc_session::config::CrateType::Executable).unwrap().1;;for&cnum in crate_info +.used_crates.iter().rev(){3;let src=&crate_info.used_crate_source[&cnum];;match +data[((cnum.as_usize())-(1) )]{Linkage::NotLinked|Linkage::IncludedFromDylib=>{} +Linkage::Static=>{;let name=crate_info.crate_name[&cnum];let mut diag=sess.dcx() +.struct_err(format!("Can't load static lib {}",name));((),());((),());diag.note( +"rustc_codegen_cranelift can only load dylibs in JIT mode.");3;3;diag.emit();3;} +Linkage::Dynamic=>{;dylib_paths.push(src.dylib.as_ref().unwrap().0.clone());;}}} +let imported_dylibs=Box::leak(((((dylib_paths. into_iter())))).map(|path|unsafe{ +libloading::Library::new(&path).unwrap()}).collect::>(),);;;sess.dcx(). +abort_if_errors();3;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>( tcx:TyCtxt<'tcx>,cx:&mut CodegenCx,cached_context +:&mut Context,module:&mut JITModule,inst:Instance<'tcx>,){({});let pointer_type= +module.target_config().pointer_type();;;let name=tcx.symbol_name(inst).name;;let +sig=crate::abi::get_function_sig(tcx,(module.target_config()).default_call_conv, +inst);;;let func_id=module.declare_function(name,Linkage::Export,&sig).unwrap(); +let instance_ptr=Box::into_raw(Box::new(inst));((),());*&*&();let jit_fn=module. +declare_function(("__clif_jit_fn"),Linkage::Import, &Signature{call_conv:module. +target_config().default_call_conv,params:vec![AbiParam::new(pointer_type),//{;}; +AbiParam::new(pointer_type)],returns:((vec![ AbiParam::new(pointer_type)])),},). +unwrap();;let context=cached_context;context.clear();let trampoline=&mut context +.func;{();};({});trampoline.signature=sig.clone();({});({});let mut builder_ctx= +FunctionBuilderContext::new();;;let mut trampoline_builder=FunctionBuilder::new( +trampoline,&mut builder_ctx);();3;let trampoline_fn=module.declare_func_in_func( +func_id,trampoline_builder.func);;let jit_fn=module.declare_func_in_func(jit_fn, +trampoline_builder.func);;;let sig_ref=trampoline_builder.func.import_signature( +sig);3;3;let entry_block=trampoline_builder.create_block();;;trampoline_builder. +append_block_params_for_function_params(entry_block);((),());*&*&();let fn_args= +trampoline_builder.func.dfg.block_params(entry_block).to_vec();let _=();((),()); +trampoline_builder.switch_to_block(entry_block);((),());*&*&();let instance_ptr= +trampoline_builder.ins().iconst(pointer_type,instance_ptr as u64 as i64);3;3;let +trampoline_ptr=trampoline_builder.ins().func_addr(pointer_type,trampoline_fn);;; +let jitted_fn=(((((((trampoline_builder.ins()))))))).call(jit_fn,&[instance_ptr, +trampoline_ptr]);{;};{;};let jitted_fn=trampoline_builder.func.dfg.inst_results( +jitted_fn)[0];();3;let call_inst=trampoline_builder.ins().call_indirect(sig_ref, +jitted_fn,&fn_args);();();let ret_vals=trampoline_builder.func.dfg.inst_results( +call_inst).to_vec();();3;trampoline_builder.ins().return_(&ret_vals);3;3;module. +define_function(func_id,context).unwrap();{;};();cx.unwind_context.add_function( +func_id,context,module.isa());loop{break};loop{break};loop{break};loop{break;};} diff --git a/compiler/rustc_codegen_cranelift/src/driver/mod.rs b/compiler/rustc_codegen_cranelift/src/driver/mod.rs index 12e90b5841034..e30bd6b1d5661 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/mod.rs @@ -1,70 +1,22 @@ -//! Drivers are responsible for calling [`codegen_fn`] or [`codegen_static`] for each mono item and -//! performing any further actions like JIT executing or writing object files. -//! -//! [`codegen_fn`]: crate::base::codegen_fn -//! [`codegen_static`]: crate::constant::codegen_static - -use rustc_data_structures::profiling::SelfProfilerRef; -use rustc_middle::mir::mono::{MonoItem, MonoItemData}; - -use crate::prelude::*; - -pub(crate) mod aot; -#[cfg(feature = "jit")] -pub(crate) mod jit; - -fn predefine_mono_items<'tcx>( - tcx: TyCtxt<'tcx>, - module: &mut dyn Module, - mono_items: &[(MonoItem<'tcx>, MonoItemData)], -) { - tcx.prof.generic_activity("predefine functions").run(|| { - let is_compiler_builtins = tcx.is_compiler_builtins(LOCAL_CRATE); - for &(mono_item, data) in mono_items { - match mono_item { - MonoItem::Fn(instance) => { - let name = tcx.symbol_name(instance).name; - let _inst_guard = crate::PrintOnPanic(|| format!("{:?} {}", instance, name)); - let sig = - get_function_sig(tcx, module.target_config().default_call_conv, instance); - let linkage = crate::linkage::get_clif_linkage( - mono_item, - data.linkage, - data.visibility, - is_compiler_builtins, - ); - module.declare_function(name, linkage, &sig).unwrap(); - } - MonoItem::Static(_) | MonoItem::GlobalAsm(_) => {} - } - } - }); -} - -struct MeasuremeProfiler(SelfProfilerRef); - -struct TimingGuard { - profiler: std::mem::ManuallyDrop, - inner: Option>, -} - -impl Drop for TimingGuard { - fn drop(&mut self) { - self.inner.take(); - unsafe { - std::mem::ManuallyDrop::drop(&mut self.profiler); - } - } -} - -impl cranelift_codegen::timing::Profiler for MeasuremeProfiler { - fn start_pass(&self, pass: cranelift_codegen::timing::Pass) -> Box { - let mut timing_guard = - TimingGuard { profiler: std::mem::ManuallyDrop::new(self.0.clone()), inner: None }; - timing_guard.inner = Some( - unsafe { &*(&*timing_guard.profiler as &SelfProfilerRef as *const SelfProfilerRef) } - .generic_activity(pass.description()), - ); - Box::new(timing_guard) - } -} +use rustc_data_structures::profiling::SelfProfilerRef;use rustc_middle::mir:://; +mono::{MonoItem,MonoItemData};use crate::prelude::*;pub(crate)mod aot;#[cfg(//3; +feature="jit")]pub(crate)mod jit; fn predefine_mono_items<'tcx>(tcx:TyCtxt<'tcx> +,module:&mut dyn Module,mono_items:&[(MonoItem<'tcx>,MonoItemData)],){;tcx.prof. +generic_activity("predefine functions").run(||{{;};let is_compiler_builtins=tcx. +is_compiler_builtins(LOCAL_CRATE);*&*&();for&(mono_item,data)in mono_items{match +mono_item{MonoItem::Fn(instance)=>{;let name=tcx.symbol_name(instance).name;;let +_inst_guard=crate::PrintOnPanic(||format!("{:?} {}",instance,name));3;3;let sig= +get_function_sig(tcx,module.target_config().default_call_conv,instance);();3;let +linkage=crate::linkage::get_clif_linkage( mono_item,data.linkage,data.visibility +,is_compiler_builtins,);;;module.declare_function(name,linkage,&sig).unwrap();;} +MonoItem::Static(_)|MonoItem::GlobalAsm(_)=>{}}}});();}struct MeasuremeProfiler( +SelfProfilerRef);struct TimingGuard{profiler:std::mem::ManuallyDrop,inner:Option>,}impl Drop for TimingGuard{fn drop(&mut self){();self.inner.take();(); +unsafe{let _=();std::mem::ManuallyDrop::drop(&mut self.profiler);((),());}}}impl +cranelift_codegen::timing::Profiler for MeasuremeProfiler{fn start_pass(&self,// +pass:cranelift_codegen::timing::Pass)->Box{let _=||();let mut +timing_guard=TimingGuard{profiler:(std::mem::ManuallyDrop::new(self.0.clone())), +inner:None};{;};();timing_guard.inner=Some(unsafe{&*(&*timing_guard.profiler as& +SelfProfilerRef as*const SelfProfilerRef) }.generic_activity(pass.description()) +,);loop{break;};loop{break;};loop{break;};if let _=(){};Box::new(timing_guard)}} diff --git a/compiler/rustc_codegen_cranelift/src/global_asm.rs b/compiler/rustc_codegen_cranelift/src/global_asm.rs index 5a0cd3990f2a7..3cd8289c3846a 100644 --- a/compiler/rustc_codegen_cranelift/src/global_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/global_asm.rs @@ -1,190 +1,63 @@ -//! The AOT driver uses [`cranelift_object`] to write object files suitable for linking into a -//! standalone executable. - -use std::io::Write; -use std::path::PathBuf; -use std::process::{Command, Stdio}; -use std::sync::Arc; - -use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; -use rustc_hir::{InlineAsmOperand, ItemId}; -use rustc_middle::mir::interpret::ErrorHandled; -use rustc_session::config::{OutputFilenames, OutputType}; -use rustc_target::asm::InlineAsmArch; - -use crate::prelude::*; - -pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String, item_id: ItemId) { - let item = tcx.hir().item(item_id); - if let rustc_hir::ItemKind::GlobalAsm(asm) = item.kind { - let is_x86 = - matches!(tcx.sess.asm_arch.unwrap(), InlineAsmArch::X86 | InlineAsmArch::X86_64); - - if is_x86 { - if !asm.options.contains(InlineAsmOptions::ATT_SYNTAX) { - global_asm.push_str("\n.intel_syntax noprefix\n"); - } else { - global_asm.push_str("\n.att_syntax\n"); - } - } - for piece in asm.template { - match *piece { - InlineAsmTemplatePiece::String(ref s) => global_asm.push_str(s), - InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span: op_sp } => { - match asm.operands[operand_idx].0 { - InlineAsmOperand::Const { ref anon_const } => { - match tcx.const_eval_poly(anon_const.def_id.to_def_id()) { - Ok(const_value) => { - let ty = tcx - .typeck_body(anon_const.body) - .node_type(anon_const.hir_id); - let string = rustc_codegen_ssa::common::asm_const_to_str( - tcx, - op_sp, - const_value, - RevealAllLayoutCx(tcx).layout_of(ty), - ); - global_asm.push_str(&string); - } - Err(ErrorHandled::Reported { .. }) => { - // An error has already been reported and compilation is - // guaranteed to fail if execution hits this path. - } - Err(ErrorHandled::TooGeneric(_)) => { - span_bug!(op_sp, "asm const cannot be resolved; too generic"); - } - } - } - InlineAsmOperand::SymFn { anon_const } => { - if cfg!(not(feature = "inline_asm_sym")) { - tcx.dcx().span_err( - item.span, - "asm! and global_asm! sym operands are not yet supported", - ); - } - - let ty = tcx.typeck_body(anon_const.body).node_type(anon_const.hir_id); - let instance = match ty.kind() { - &ty::FnDef(def_id, args) => Instance::new(def_id, args), - _ => span_bug!(op_sp, "asm sym is not a function"), - }; - let symbol = tcx.symbol_name(instance); - // FIXME handle the case where the function was made private to the - // current codegen unit - global_asm.push_str(symbol.name); - } - InlineAsmOperand::SymStatic { path: _, def_id } => { - if cfg!(not(feature = "inline_asm_sym")) { - tcx.dcx().span_err( - item.span, - "asm! and global_asm! sym operands are not yet supported", - ); - } - - let instance = Instance::mono(tcx, def_id).polymorphize(tcx); - let symbol = tcx.symbol_name(instance); - global_asm.push_str(symbol.name); - } - InlineAsmOperand::In { .. } - | InlineAsmOperand::Out { .. } - | InlineAsmOperand::InOut { .. } - | InlineAsmOperand::SplitInOut { .. } - | InlineAsmOperand::Label { .. } => { - span_bug!(op_sp, "invalid operand type for global_asm!") - } - } - } - } - } - - global_asm.push('\n'); - if is_x86 { - global_asm.push_str(".att_syntax\n\n"); - } - } else { - bug!("Expected GlobalAsm found {:?}", item); - } -} - -#[derive(Debug)] -pub(crate) struct GlobalAsmConfig { - assembler: PathBuf, - target: String, - pub(crate) output_filenames: Arc, -} - -impl GlobalAsmConfig { - pub(crate) fn new(tcx: TyCtxt<'_>) -> Self { - GlobalAsmConfig { - assembler: crate::toolchain::get_toolchain_binary(tcx.sess, "as"), - target: match &tcx.sess.opts.target_triple { - rustc_target::spec::TargetTriple::TargetTriple(triple) => triple.clone(), - rustc_target::spec::TargetTriple::TargetJson { path_for_rustdoc, .. } => { - path_for_rustdoc.to_str().unwrap().to_owned() - } - }, - output_filenames: tcx.output_filenames(()).clone(), - } - } -} - -pub(crate) fn compile_global_asm( - config: &GlobalAsmConfig, - cgu_name: &str, - global_asm: &str, -) -> Result, String> { - if global_asm.is_empty() { - return Ok(None); - } - - // Remove all LLVM style comments - let mut global_asm = global_asm - .lines() - .map(|line| if let Some(index) = line.find("//") { &line[0..index] } else { line }) - .collect::>() - .join("\n"); - global_asm.push('\n'); - - let global_asm_object_file = add_file_stem_postfix( - config.output_filenames.temp_path(OutputType::Object, Some(cgu_name)), - ".asm", - ); - - // Assemble `global_asm` - if option_env!("CG_CLIF_FORCE_GNU_AS").is_some() { - let mut child = Command::new(&config.assembler) - .arg("-o") - .arg(&global_asm_object_file) - .stdin(Stdio::piped()) - .spawn() - .expect("Failed to spawn `as`."); - child.stdin.take().unwrap().write_all(global_asm.as_bytes()).unwrap(); - let status = child.wait().expect("Failed to wait for `as`."); - if !status.success() { - return Err(format!("Failed to assemble `{}`", global_asm)); - } - } else { - let mut child = Command::new(std::env::current_exe().unwrap()) - // Avoid a warning about the jobserver fd not being passed - .env_remove("CARGO_MAKEFLAGS") - .arg("--target") - .arg(&config.target) - .arg("--crate-type") - .arg("staticlib") - .arg("--emit") - .arg("obj") - .arg("-o") - .arg(&global_asm_object_file) - .arg("-") - .arg("-Abad_asm_style") - .arg("-Zcodegen-backend=llvm") - .stdin(Stdio::piped()) - .spawn() - .expect("Failed to spawn `as`."); - let mut stdin = child.stdin.take().unwrap(); - stdin - .write_all( - br####" +use std::io::Write;use std::path:: PathBuf;use std::process::{Command,Stdio};use +std::sync::Arc;use rustc_ast::{InlineAsmOptions,InlineAsmTemplatePiece};use//(); +rustc_hir::{InlineAsmOperand,ItemId};use rustc_middle::mir::interpret:://*&*&(); +ErrorHandled;use rustc_session::config::{OutputFilenames,OutputType};use//{();}; +rustc_target::asm::InlineAsmArch;use crate::prelude::*;pub(crate)fn//let _=||(); +codegen_global_asm_item(tcx:TyCtxt<'_>,global_asm:&mut String,item_id:ItemId){3; +let item=tcx.hir().item(item_id);{;};if let rustc_hir::ItemKind::GlobalAsm(asm)= +item.kind{{;};let is_x86=matches!(tcx.sess.asm_arch.unwrap(),InlineAsmArch::X86| +InlineAsmArch::X86_64);({});if is_x86{if!asm.options.contains(InlineAsmOptions:: +ATT_SYNTAX){;global_asm.push_str("\n.intel_syntax noprefix\n");}else{global_asm. +push_str("\n.att_syntax\n");loop{break};}}for piece in asm.template{match*piece{ +InlineAsmTemplatePiece::String(ref s)=>(((((((((global_asm.push_str(s)))))))))), +InlineAsmTemplatePiece::Placeholder{operand_idx,modifier:_ ,span:op_sp}=>{match +asm.operands[operand_idx].0{InlineAsmOperand:: Const{ref anon_const}=>{match tcx +.const_eval_poly(anon_const.def_id.to_def_id()){Ok(const_value)=>{();let ty=tcx. +typeck_body(anon_const.body).node_type(anon_const.hir_id);{();};({});let string= +rustc_codegen_ssa::common::asm_const_to_str(tcx,op_sp,const_value,//loop{break}; +RevealAllLayoutCx(tcx).layout_of(ty),);();3;global_asm.push_str(&string);3;}Err( +ErrorHandled::Reported{..})=>{}Err(ErrorHandled::TooGeneric(_))=>{{;};span_bug!( +op_sp,"asm const cannot be resolved; too generic");3;}}}InlineAsmOperand::SymFn{ +anon_const}=>{if cfg!(not(feature="inline_asm_sym")){();tcx.dcx().span_err(item. +span,"asm! and global_asm! sym operands are not yet supported",);3;};let ty=tcx. +typeck_body(anon_const.body).node_type(anon_const.hir_id);;let instance=match ty +.kind(){&ty::FnDef(def_id,args)=> Instance::new(def_id,args),_=>span_bug!(op_sp, +"asm sym is not a function"),};;let symbol=tcx.symbol_name(instance);global_asm. +push_str(symbol.name);;}InlineAsmOperand::SymStatic{path:_,def_id}=>{if cfg!(not +(feature="inline_asm_sym")){let _=||();loop{break};tcx.dcx().span_err(item.span, +"asm! and global_asm! sym operands are not yet supported",);();}();let instance= +Instance::mono(tcx,def_id).polymorphize(tcx);{;};{;};let symbol=tcx.symbol_name( +instance);{;};{;};global_asm.push_str(symbol.name);();}InlineAsmOperand::In{..}| +InlineAsmOperand::Out{..}|InlineAsmOperand::InOut{..}|InlineAsmOperand:://{();}; +SplitInOut{..}|InlineAsmOperand::Label{..}=>{span_bug!(op_sp,//((),());let _=(); +"invalid operand type for global_asm!")}}}}}3;global_asm.push('\n');;if is_x86{; +global_asm.push_str(".att_syntax\n\n");*&*&();((),());}}else{if let _=(){};bug!( +"Expected GlobalAsm found {:?}",item);((),());}}#[derive(Debug)]pub(crate)struct +GlobalAsmConfig{assembler:PathBuf,target:String ,pub(crate)output_filenames:Arc< +OutputFilenames>,}impl GlobalAsmConfig{pub(crate)fn new(tcx:TyCtxt<'_>)->Self{// +GlobalAsmConfig{assembler:crate::toolchain::get_toolchain_binary (tcx.sess,"as") +,target:match((&tcx.sess.opts.target_triple)){rustc_target::spec::TargetTriple:: +TargetTriple(triple)=>((((triple.clone ())))),rustc_target::spec::TargetTriple:: +TargetJson{path_for_rustdoc,..}=>{path_for_rustdoc. to_str().unwrap().to_owned() +}},output_filenames:((((tcx.output_filenames(((()))))).clone())),}}}pub(crate)fn +compile_global_asm(config:&GlobalAsmConfig,cgu_name:&str,global_asm:&str,)->//3; +Result,String>{if global_asm.is_empty(){3;return Ok(None);;};let +mut global_asm=global_asm.lines().map(|line| if let Some(index)=line.find("//"){ +&line[0..index]}else{line}).collect::>().join("\n");;global_asm.push('\n' +);();3;let global_asm_object_file=add_file_stem_postfix(config.output_filenames. +temp_path(OutputType::Object,Some(cgu_name)),".asm",);let _=||();if option_env!( +"CG_CLIF_FORCE_GNU_AS").is_some(){;let mut child=Command::new(&config.assembler) +.arg(("-o")).arg(&global_asm_object_file).stdin (Stdio::piped()).spawn().expect( +"Failed to spawn `as`.");();();child.stdin.take().unwrap().write_all(global_asm. +as_bytes()).unwrap();;let status=child.wait().expect("Failed to wait for `as`.") +;;if!status.success(){return Err(format!("Failed to assemble `{}`",global_asm)); +}}else{;let mut child=Command::new(std::env::current_exe().unwrap()).env_remove( +"CARGO_MAKEFLAGS").arg("--target").arg(& config.target).arg("--crate-type").arg( +"staticlib").arg(("--emit")).arg("obj") .arg("-o").arg(&global_asm_object_file). +arg(("-")).arg(("-Abad_asm_style")) .arg("-Zcodegen-backend=llvm").stdin(Stdio:: +piped()).spawn().expect("Failed to spawn `as`.");;let mut stdin=child.stdin.take +().unwrap();loop{break;};loop{break;};loop{break;};loop{break;};stdin.write_all( +br####" #![feature(decl_macro, no_core, rustc_attrs)] #![allow(internal_features)] #![no_core] @@ -192,34 +65,15 @@ pub(crate) fn compile_global_asm( #[rustc_macro_transparency = "semitransparent"] macro global_asm() { /* compiler built-in */ } global_asm!(r###" - "####, - ) - .unwrap(); - stdin.write_all(global_asm.as_bytes()).unwrap(); - stdin - .write_all( - br####" + "#### +,).unwrap();;;stdin.write_all(global_asm.as_bytes()).unwrap();;;stdin.write_all( +br####" "###); - "####, - ) - .unwrap(); - std::mem::drop(stdin); - let status = child.wait().expect("Failed to wait for `as`."); - if !status.success() { - return Err(format!("Failed to assemble `{}`", global_asm)); - } - } - - Ok(Some(global_asm_object_file)) -} - -pub(crate) fn add_file_stem_postfix(mut path: PathBuf, postfix: &str) -> PathBuf { - let mut new_filename = path.file_stem().unwrap().to_owned(); - new_filename.push(postfix); - if let Some(extension) = path.extension() { - new_filename.push("."); - new_filename.push(extension); - } - path.set_file_name(new_filename); - path -} + "####,).unwrap();;std::mem::drop( +stdin);3;;let status=child.wait().expect("Failed to wait for `as`.");;if!status. +success(){;return Err(format!("Failed to assemble `{}`",global_asm));;}}Ok(Some( +global_asm_object_file))}pub(crate)fn add_file_stem_postfix(mut path:PathBuf,//; +postfix:&str)->PathBuf{;let mut new_filename=path.file_stem().unwrap().to_owned( +);();();new_filename.push(postfix);();if let Some(extension)=path.extension(){3; +new_filename.push(".");3;3;new_filename.push(extension);3;}3;path.set_file_name( +new_filename);*&*&();((),());*&*&();((),());*&*&();((),());((),());((),());path} diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs index 171ee88a11c75..40d3b8219733b 100644 --- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs @@ -1,799 +1,236 @@ -//! Codegen of `asm!` invocations. - -use std::fmt::Write; - -use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece}; -use rustc_span::sym; -use rustc_target::asm::*; -use target_lexicon::BinaryFormat; - -use crate::prelude::*; - -pub(crate) enum CInlineAsmOperand<'tcx> { - In { - reg: InlineAsmRegOrRegClass, - value: Value, - }, - Out { - reg: InlineAsmRegOrRegClass, - late: bool, - place: Option>, - }, - InOut { - reg: InlineAsmRegOrRegClass, - _late: bool, - in_value: Value, - out_place: Option>, - }, - Const { - value: String, - }, - Symbol { - symbol: String, - }, -} - -pub(crate) fn codegen_inline_asm_terminator<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - span: Span, - template: &[InlineAsmTemplatePiece], - operands: &[InlineAsmOperand<'tcx>], - options: InlineAsmOptions, - destination: Option, -) { - // Used by panic_abort on Windows, but uses a syntax which only happens to work with - // asm!() by accident and breaks with the GNU assembler as well as global_asm!() for - // the LLVM backend. - if template.len() == 1 - && template[0] == InlineAsmTemplatePiece::String("int $$0x29".to_string()) - { - fx.bcx.ins().trap(TrapCode::User(1)); - return; - } - - let operands = operands - .iter() - .map(|operand| match *operand { - InlineAsmOperand::In { reg, ref value } => CInlineAsmOperand::In { - reg, - value: crate::base::codegen_operand(fx, value).load_scalar(fx), - }, - InlineAsmOperand::Out { reg, late, ref place } => CInlineAsmOperand::Out { - reg, - late, - place: place.map(|place| crate::base::codegen_place(fx, place)), - }, - InlineAsmOperand::InOut { reg, late, ref in_value, ref out_place } => { - CInlineAsmOperand::InOut { - reg, - _late: late, - in_value: crate::base::codegen_operand(fx, in_value).load_scalar(fx), - out_place: out_place.map(|place| crate::base::codegen_place(fx, place)), - } - } - InlineAsmOperand::Const { ref value } => { - let (const_value, ty) = crate::constant::eval_mir_constant(fx, value); - let value = rustc_codegen_ssa::common::asm_const_to_str( - fx.tcx, - span, - const_value, - fx.layout_of(ty), - ); - CInlineAsmOperand::Const { value } - } - InlineAsmOperand::SymFn { ref value } => { - if cfg!(not(feature = "inline_asm_sym")) { - fx.tcx - .dcx() - .span_err(span, "asm! and global_asm! sym operands are not yet supported"); - } - - let const_ = fx.monomorphize(value.const_); - if let ty::FnDef(def_id, args) = *const_.ty().kind() { - let instance = ty::Instance::resolve_for_fn_ptr( - fx.tcx, - ty::ParamEnv::reveal_all(), - def_id, - args, - ) - .unwrap(); - let symbol = fx.tcx.symbol_name(instance); - - // Pass a wrapper rather than the function itself as the function itself may not - // be exported from the main codegen unit and may thus be unreachable from the - // object file created by an external assembler. - let inline_asm_index = fx.cx.inline_asm_index.get(); - fx.cx.inline_asm_index.set(inline_asm_index + 1); - let wrapper_name = format!( - "__inline_asm_{}_wrapper_n{}", - fx.cx.cgu_name.as_str().replace('.', "__").replace('-', "_"), - inline_asm_index - ); - let sig = - get_function_sig(fx.tcx, fx.target_config.default_call_conv, instance); - create_wrapper_function( - fx.module, - &mut fx.cx.unwind_context, - sig, - &wrapper_name, - symbol.name, - ); - - CInlineAsmOperand::Symbol { symbol: wrapper_name } - } else { - span_bug!(span, "invalid type for asm sym (fn)"); - } - } - InlineAsmOperand::SymStatic { def_id } => { - assert!(fx.tcx.is_static(def_id)); - let instance = Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx); - CInlineAsmOperand::Symbol { symbol: fx.tcx.symbol_name(instance).name.to_owned() } - } - InlineAsmOperand::Label { .. } => { - span_bug!(span, "asm! label operands are not yet supported"); - } - }) - .collect::>(); - - codegen_inline_asm_inner(fx, template, &operands, options); - - match destination { - Some(destination) => { - let destination_block = fx.get_block(destination); - fx.bcx.ins().jump(destination_block, &[]); - } - None => { - fx.bcx.ins().trap(TrapCode::UnreachableCodeReached); - } - } -} - -pub(crate) fn codegen_inline_asm_inner<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - template: &[InlineAsmTemplatePiece], - operands: &[CInlineAsmOperand<'tcx>], - options: InlineAsmOptions, -) { - // FIXME add .eh_frame unwind info directives - - let mut asm_gen = InlineAssemblyGenerator { - tcx: fx.tcx, - arch: fx.tcx.sess.asm_arch.unwrap(), - enclosing_def_id: fx.instance.def_id(), - template, - operands, - options, - registers: Vec::new(), - stack_slots_clobber: Vec::new(), - stack_slots_input: Vec::new(), - stack_slots_output: Vec::new(), - stack_slot_size: Size::from_bytes(0), - }; - asm_gen.allocate_registers(); - asm_gen.allocate_stack_slots(); - - let inline_asm_index = fx.cx.inline_asm_index.get(); - fx.cx.inline_asm_index.set(inline_asm_index + 1); - let asm_name = format!( - "__inline_asm_{}_n{}", - fx.cx.cgu_name.as_str().replace('.', "__").replace('-', "_"), - inline_asm_index - ); - - let generated_asm = asm_gen.generate_asm_wrapper(&asm_name); - fx.cx.global_asm.push_str(&generated_asm); - - let mut inputs = Vec::new(); - let mut outputs = Vec::new(); - for (i, operand) in operands.iter().enumerate() { - match operand { - CInlineAsmOperand::In { reg: _, value } => { - inputs.push((asm_gen.stack_slots_input[i].unwrap(), *value)); - } - CInlineAsmOperand::Out { reg: _, late: _, place } => { - if let Some(place) = place { - outputs.push((asm_gen.stack_slots_output[i].unwrap(), *place)); - } - } - CInlineAsmOperand::InOut { reg: _, _late: _, in_value, out_place } => { - inputs.push((asm_gen.stack_slots_input[i].unwrap(), *in_value)); - if let Some(out_place) = out_place { - outputs.push((asm_gen.stack_slots_output[i].unwrap(), *out_place)); - } - } - CInlineAsmOperand::Const { value: _ } | CInlineAsmOperand::Symbol { symbol: _ } => {} - } - } - - call_inline_asm(fx, &asm_name, asm_gen.stack_slot_size, inputs, outputs); -} - -struct InlineAssemblyGenerator<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - arch: InlineAsmArch, - enclosing_def_id: DefId, - template: &'a [InlineAsmTemplatePiece], - operands: &'a [CInlineAsmOperand<'tcx>], - options: InlineAsmOptions, - registers: Vec>, - stack_slots_clobber: Vec>, - stack_slots_input: Vec>, - stack_slots_output: Vec>, - stack_slot_size: Size, -} - -impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { - fn allocate_registers(&mut self) { - let sess = self.tcx.sess; - let map = allocatable_registers( - self.arch, - sess.relocation_model(), - self.tcx.asm_target_features(self.enclosing_def_id), - &sess.target, - ); - let mut allocated = FxHashMap::<_, (bool, bool)>::default(); - let mut regs = vec![None; self.operands.len()]; - - // Add explicit registers to the allocated set. - for (i, operand) in self.operands.iter().enumerate() { - match *operand { - CInlineAsmOperand::In { reg: InlineAsmRegOrRegClass::Reg(reg), .. } => { - regs[i] = Some(reg); - allocated.entry(reg).or_default().0 = true; - } - CInlineAsmOperand::Out { - reg: InlineAsmRegOrRegClass::Reg(reg), - late: true, - .. - } => { - regs[i] = Some(reg); - allocated.entry(reg).or_default().1 = true; - } - CInlineAsmOperand::Out { reg: InlineAsmRegOrRegClass::Reg(reg), .. } - | CInlineAsmOperand::InOut { reg: InlineAsmRegOrRegClass::Reg(reg), .. } => { - regs[i] = Some(reg); - allocated.insert(reg, (true, true)); - } - _ => (), - } - } - - // Allocate out/inout/inlateout registers first because they are more constrained. - for (i, operand) in self.operands.iter().enumerate() { - match *operand { - CInlineAsmOperand::Out { - reg: InlineAsmRegOrRegClass::RegClass(class), - late: false, - .. - } - | CInlineAsmOperand::InOut { - reg: InlineAsmRegOrRegClass::RegClass(class), .. - } => { - let mut alloc_reg = None; - for ® in &map[&class] { - let mut used = false; - reg.overlapping_regs(|r| { - if allocated.contains_key(&r) { - used = true; - } - }); - - if !used { - alloc_reg = Some(reg); - break; - } - } - - let reg = alloc_reg.expect("cannot allocate registers"); - regs[i] = Some(reg); - allocated.insert(reg, (true, true)); - } - _ => (), - } - } - - // Allocate in/lateout. - for (i, operand) in self.operands.iter().enumerate() { - match *operand { - CInlineAsmOperand::In { reg: InlineAsmRegOrRegClass::RegClass(class), .. } => { - let mut alloc_reg = None; - for ® in &map[&class] { - let mut used = false; - reg.overlapping_regs(|r| { - if allocated.get(&r).copied().unwrap_or_default().0 { - used = true; - } - }); - - if !used { - alloc_reg = Some(reg); - break; - } - } - - let reg = alloc_reg.expect("cannot allocate registers"); - regs[i] = Some(reg); - allocated.entry(reg).or_default().0 = true; - } - CInlineAsmOperand::Out { - reg: InlineAsmRegOrRegClass::RegClass(class), - late: true, - .. - } => { - let mut alloc_reg = None; - for ® in &map[&class] { - let mut used = false; - reg.overlapping_regs(|r| { - if allocated.get(&r).copied().unwrap_or_default().1 { - used = true; - } - }); - - if !used { - alloc_reg = Some(reg); - break; - } - } - - let reg = alloc_reg.expect("cannot allocate registers"); - regs[i] = Some(reg); - allocated.entry(reg).or_default().1 = true; - } - _ => (), - } - } - - self.registers = regs; - } - - fn allocate_stack_slots(&mut self) { - let mut slot_size = Size::from_bytes(0); - let mut slots_clobber = vec![None; self.operands.len()]; - let mut slots_input = vec![None; self.operands.len()]; - let mut slots_output = vec![None; self.operands.len()]; - - let new_slot_fn = |slot_size: &mut Size, reg_class: InlineAsmRegClass| { - let reg_size = - reg_class.supported_types(self.arch).iter().map(|(ty, _)| ty.size()).max().unwrap(); - let align = rustc_target::abi::Align::from_bytes(reg_size.bytes()).unwrap(); - let offset = slot_size.align_to(align); - *slot_size = offset + reg_size; - offset - }; - let mut new_slot = |x| new_slot_fn(&mut slot_size, x); - - // Allocate stack slots for saving clobbered registers - let abi_clobber = InlineAsmClobberAbi::parse(self.arch, &self.tcx.sess.target, sym::C) - .unwrap() - .clobbered_regs(); - for (i, reg) in self.registers.iter().enumerate().filter_map(|(i, r)| r.map(|r| (i, r))) { - let mut need_save = true; - // If the register overlaps with a register clobbered by function call, then - // we don't need to save it. - for r in abi_clobber { - r.overlapping_regs(|r| { - if r == reg { - need_save = false; - } - }); - - if !need_save { - break; - } - } - - if need_save { - slots_clobber[i] = Some(new_slot(reg.reg_class())); - } - } - - // Allocate stack slots for inout - for (i, operand) in self.operands.iter().enumerate() { - match *operand { - CInlineAsmOperand::InOut { reg, out_place: Some(_), .. } => { - let slot = new_slot(reg.reg_class()); - slots_input[i] = Some(slot); - slots_output[i] = Some(slot); - } - _ => (), - } - } - - let slot_size_before_input = slot_size; - let mut new_slot = |x| new_slot_fn(&mut slot_size, x); - - // Allocate stack slots for input - for (i, operand) in self.operands.iter().enumerate() { - match *operand { - CInlineAsmOperand::In { reg, .. } - | CInlineAsmOperand::InOut { reg, out_place: None, .. } => { - slots_input[i] = Some(new_slot(reg.reg_class())); - } - _ => (), - } - } - - // Reset slot size to before input so that input and output operands can overlap - // and save some memory. - let slot_size_after_input = slot_size; - slot_size = slot_size_before_input; - let mut new_slot = |x| new_slot_fn(&mut slot_size, x); - - // Allocate stack slots for output - for (i, operand) in self.operands.iter().enumerate() { - match *operand { - CInlineAsmOperand::Out { reg, place: Some(_), .. } => { - slots_output[i] = Some(new_slot(reg.reg_class())); - } - _ => (), - } - } - - slot_size = slot_size.max(slot_size_after_input); - - self.stack_slots_clobber = slots_clobber; - self.stack_slots_input = slots_input; - self.stack_slots_output = slots_output; - self.stack_slot_size = slot_size; - } - - fn generate_asm_wrapper(&self, asm_name: &str) -> String { - let binary_format = crate::target_triple(self.tcx.sess).binary_format; - - let mut generated_asm = String::new(); - match binary_format { - BinaryFormat::Elf => { - writeln!(generated_asm, ".globl {}", asm_name).unwrap(); - writeln!(generated_asm, ".type {},@function", asm_name).unwrap(); - writeln!(generated_asm, ".section .text.{},\"ax\",@progbits", asm_name).unwrap(); - writeln!(generated_asm, "{}:", asm_name).unwrap(); - } - BinaryFormat::Macho => { - writeln!(generated_asm, ".globl _{}", asm_name).unwrap(); - writeln!(generated_asm, "_{}:", asm_name).unwrap(); - } - BinaryFormat::Coff => { - writeln!(generated_asm, ".globl {}", asm_name).unwrap(); - writeln!(generated_asm, "{}:", asm_name).unwrap(); - } - _ => self - .tcx - .dcx() - .fatal(format!("Unsupported binary format for inline asm: {binary_format:?}")), - } - - let is_x86 = matches!(self.arch, InlineAsmArch::X86 | InlineAsmArch::X86_64); - - if is_x86 { - generated_asm.push_str(".intel_syntax noprefix\n"); - } - Self::prologue(&mut generated_asm, self.arch); - - // Save clobbered registers - if !self.options.contains(InlineAsmOptions::NORETURN) { - for (reg, slot) in self - .registers - .iter() - .zip(self.stack_slots_clobber.iter().copied()) - .filter_map(|(r, s)| r.zip(s)) - { - Self::save_register(&mut generated_asm, self.arch, reg, slot); - } - } - - // Write input registers - for (reg, slot) in self - .registers - .iter() - .zip(self.stack_slots_input.iter().copied()) - .filter_map(|(r, s)| r.zip(s)) - { - Self::restore_register(&mut generated_asm, self.arch, reg, slot); - } - - if is_x86 && self.options.contains(InlineAsmOptions::ATT_SYNTAX) { - generated_asm.push_str(".att_syntax\n"); - } - - // The actual inline asm - for piece in self.template { - match piece { - InlineAsmTemplatePiece::String(s) => { - generated_asm.push_str(s); - } - InlineAsmTemplatePiece::Placeholder { operand_idx, modifier, span: _ } => { - match self.operands[*operand_idx] { - CInlineAsmOperand::In { .. } - | CInlineAsmOperand::Out { .. } - | CInlineAsmOperand::InOut { .. } => { - if self.options.contains(InlineAsmOptions::ATT_SYNTAX) { - generated_asm.push('%'); - } - - let reg = self.registers[*operand_idx].unwrap(); - match self.arch { - InlineAsmArch::X86_64 => match reg { - InlineAsmReg::X86(reg) - if reg as u32 >= X86InlineAsmReg::xmm0 as u32 - && reg as u32 <= X86InlineAsmReg::xmm15 as u32 => - { - // rustc emits x0 rather than xmm0 - let class = match *modifier { - None | Some('x') => "xmm", - Some('y') => "ymm", - Some('z') => "zmm", - _ => unreachable!(), - }; - write!( - generated_asm, - "{class}{}", - reg as u32 - X86InlineAsmReg::xmm0 as u32 - ) - .unwrap(); - } - _ => reg - .emit(&mut generated_asm, InlineAsmArch::X86_64, *modifier) - .unwrap(), - }, - _ => reg.emit(&mut generated_asm, self.arch, *modifier).unwrap(), - } - } - CInlineAsmOperand::Const { ref value } => { - generated_asm.push_str(value); - } - CInlineAsmOperand::Symbol { ref symbol } => generated_asm.push_str(symbol), - } - } - } - } - generated_asm.push('\n'); - - if is_x86 && self.options.contains(InlineAsmOptions::ATT_SYNTAX) { - generated_asm.push_str(".intel_syntax noprefix\n"); - } - - if !self.options.contains(InlineAsmOptions::NORETURN) { - // Read output registers - for (reg, slot) in self - .registers - .iter() - .zip(self.stack_slots_output.iter().copied()) - .filter_map(|(r, s)| r.zip(s)) - { - Self::save_register(&mut generated_asm, self.arch, reg, slot); - } - - // Restore clobbered registers - for (reg, slot) in self - .registers - .iter() - .zip(self.stack_slots_clobber.iter().copied()) - .filter_map(|(r, s)| r.zip(s)) - { - Self::restore_register(&mut generated_asm, self.arch, reg, slot); - } - - Self::epilogue(&mut generated_asm, self.arch); - } else { - Self::epilogue_noreturn(&mut generated_asm, self.arch); - } - - if is_x86 { - generated_asm.push_str(".att_syntax\n"); - } - - match binary_format { - BinaryFormat::Elf => { - writeln!(generated_asm, ".size {name}, .-{name}", name = asm_name).unwrap(); - generated_asm.push_str(".text\n"); - } - BinaryFormat::Macho | BinaryFormat::Coff => {} - _ => self - .tcx - .dcx() - .fatal(format!("Unsupported binary format for inline asm: {binary_format:?}")), - } - - generated_asm.push_str("\n\n"); - - generated_asm - } - - fn prologue(generated_asm: &mut String, arch: InlineAsmArch) { - match arch { - InlineAsmArch::X86_64 => { - generated_asm.push_str(" push rbp\n"); - generated_asm.push_str(" mov rbp,rsp\n"); - generated_asm.push_str(" push rbx\n"); // rbx is callee saved - // rbx is reserved by LLVM for the "base pointer", so rustc doesn't allow using it - generated_asm.push_str(" mov rbx,rdi\n"); - } - InlineAsmArch::AArch64 => { - generated_asm.push_str(" stp fp, lr, [sp, #-32]!\n"); - generated_asm.push_str(" mov fp, sp\n"); - generated_asm.push_str(" str x19, [sp, #24]\n"); // x19 is callee saved - // x19 is reserved by LLVM for the "base pointer", so rustc doesn't allow using it - generated_asm.push_str(" mov x19, x0\n"); - } - InlineAsmArch::RiscV64 => { - generated_asm.push_str(" addi sp, sp, -16\n"); - generated_asm.push_str(" sd ra, 8(sp)\n"); - generated_asm.push_str(" sd s1, 0(sp)\n"); // s1 is callee saved - // s1/x9 is reserved by LLVM for the "base pointer", so rustc doesn't allow using it - generated_asm.push_str(" mv s1, a0\n"); - } - _ => unimplemented!("prologue for {:?}", arch), - } - } - - fn epilogue(generated_asm: &mut String, arch: InlineAsmArch) { - match arch { - InlineAsmArch::X86_64 => { - generated_asm.push_str(" pop rbx\n"); - generated_asm.push_str(" pop rbp\n"); - generated_asm.push_str(" ret\n"); - } - InlineAsmArch::AArch64 => { - generated_asm.push_str(" ldr x19, [sp, #24]\n"); - generated_asm.push_str(" ldp fp, lr, [sp], #32\n"); - generated_asm.push_str(" ret\n"); - } - InlineAsmArch::RiscV64 => { - generated_asm.push_str(" ld s1, 0(sp)\n"); - generated_asm.push_str(" ld ra, 8(sp)\n"); - generated_asm.push_str(" addi sp, sp, 16\n"); - generated_asm.push_str(" ret\n"); - } - _ => unimplemented!("epilogue for {:?}", arch), - } - } - - fn epilogue_noreturn(generated_asm: &mut String, arch: InlineAsmArch) { - match arch { - InlineAsmArch::X86_64 => { - generated_asm.push_str(" ud2\n"); - } - InlineAsmArch::AArch64 => { - generated_asm.push_str(" brk #0x1\n"); - } - InlineAsmArch::RiscV64 => { - generated_asm.push_str(" ebreak\n"); - } - _ => unimplemented!("epilogue_noreturn for {:?}", arch), - } - } - - fn save_register( - generated_asm: &mut String, - arch: InlineAsmArch, - reg: InlineAsmReg, - offset: Size, - ) { - match arch { - InlineAsmArch::X86_64 => { - match reg { - InlineAsmReg::X86(reg) - if reg as u32 >= X86InlineAsmReg::xmm0 as u32 - && reg as u32 <= X86InlineAsmReg::xmm15 as u32 => - { - // rustc emits x0 rather than xmm0 - write!(generated_asm, " movups [rbx+0x{:x}], ", offset.bytes()).unwrap(); - write!(generated_asm, "xmm{}", reg as u32 - X86InlineAsmReg::xmm0 as u32) - .unwrap(); - } - _ => { - write!(generated_asm, " mov [rbx+0x{:x}], ", offset.bytes()).unwrap(); - reg.emit(generated_asm, InlineAsmArch::X86_64, None).unwrap(); - } - } - generated_asm.push('\n'); - } - InlineAsmArch::AArch64 => { - generated_asm.push_str(" str "); - reg.emit(generated_asm, InlineAsmArch::AArch64, None).unwrap(); - writeln!(generated_asm, ", [x19, 0x{:x}]", offset.bytes()).unwrap(); - } - InlineAsmArch::RiscV64 => { - generated_asm.push_str(" sd "); - reg.emit(generated_asm, InlineAsmArch::RiscV64, None).unwrap(); - writeln!(generated_asm, ", 0x{:x}(s1)", offset.bytes()).unwrap(); - } - _ => unimplemented!("save_register for {:?}", arch), - } - } - - fn restore_register( - generated_asm: &mut String, - arch: InlineAsmArch, - reg: InlineAsmReg, - offset: Size, - ) { - match arch { - InlineAsmArch::X86_64 => { - match reg { - InlineAsmReg::X86(reg) - if reg as u32 >= X86InlineAsmReg::xmm0 as u32 - && reg as u32 <= X86InlineAsmReg::xmm15 as u32 => - { - // rustc emits x0 rather than xmm0 - write!( - generated_asm, - " movups xmm{}", - reg as u32 - X86InlineAsmReg::xmm0 as u32 - ) - .unwrap(); - } - _ => { - generated_asm.push_str(" mov "); - reg.emit(generated_asm, InlineAsmArch::X86_64, None).unwrap() - } - } - writeln!(generated_asm, ", [rbx+0x{:x}]", offset.bytes()).unwrap(); - } - InlineAsmArch::AArch64 => { - generated_asm.push_str(" ldr "); - reg.emit(generated_asm, InlineAsmArch::AArch64, None).unwrap(); - writeln!(generated_asm, ", [x19, 0x{:x}]", offset.bytes()).unwrap(); - } - InlineAsmArch::RiscV64 => { - generated_asm.push_str(" ld "); - reg.emit(generated_asm, InlineAsmArch::RiscV64, None).unwrap(); - writeln!(generated_asm, ", 0x{:x}(s1)", offset.bytes()).unwrap(); - } - _ => unimplemented!("restore_register for {:?}", arch), - } - } -} - -fn call_inline_asm<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - asm_name: &str, - slot_size: Size, - inputs: Vec<(Size, Value)>, - outputs: Vec<(Size, CPlace<'tcx>)>, -) { - let stack_slot = fx.create_stack_slot(u32::try_from(slot_size.bytes()).unwrap(), 16); - - let inline_asm_func = fx - .module - .declare_function( - asm_name, - Linkage::Import, - &Signature { - call_conv: CallConv::SystemV, - params: vec![AbiParam::new(fx.pointer_type)], - returns: vec![], - }, - ) - .unwrap(); - let inline_asm_func = fx.module.declare_func_in_func(inline_asm_func, fx.bcx.func); - if fx.clif_comments.enabled() { - fx.add_comment(inline_asm_func, asm_name); - } - - for (offset, value) in inputs { - stack_slot.offset(fx, i32::try_from(offset.bytes()).unwrap().into()).store( - fx, - value, - MemFlags::trusted(), - ); - } - - let stack_slot_addr = stack_slot.get_addr(fx); - fx.bcx.ins().call(inline_asm_func, &[stack_slot_addr]); - - for (offset, place) in outputs { - let ty = if place.layout().ty.is_simd() { - let (lane_count, lane_type) = place.layout().ty.simd_size_and_type(fx.tcx); - fx.clif_type(lane_type).unwrap().by(lane_count.try_into().unwrap()).unwrap() - } else { - fx.clif_type(place.layout().ty).unwrap() - }; - let value = stack_slot.offset(fx, i32::try_from(offset.bytes()).unwrap().into()).load( - fx, - ty, - MemFlags::trusted(), - ); - place.write_cvalue(fx, CValue::by_val(value, place.layout())); - } -} +use std::fmt::Write;use rustc_ast::ast::{InlineAsmOptions,//if true{};if true{}; +InlineAsmTemplatePiece};use rustc_span::sym;use rustc_target::asm::*;use//{();}; +target_lexicon::BinaryFormat;use crate::prelude::*;pub(crate)enum//loop{break;}; +CInlineAsmOperand<'tcx>{In{reg:InlineAsmRegOrRegClass,value:Value,},Out{reg://3; +InlineAsmRegOrRegClass,late:bool,place:Option>,},InOut{reg://{();}; +InlineAsmRegOrRegClass,_late:bool,in_value:Value ,out_place:Option> +,},Const{value:String,},Symbol{symbol:String,},}pub(crate)fn//let _=();let _=(); +codegen_inline_asm_terminator<'tcx>(fx:&mut FunctionCx<'_,'_,'tcx>,span:Span,//; +template:&[InlineAsmTemplatePiece],operands:&[InlineAsmOperand<'tcx>],options:// +InlineAsmOptions,destination:Option,){if (template.len()==1)&& +template[0]==InlineAsmTemplatePiece::String("int $$0x29".to_string()){();fx.bcx. +ins().trap(TrapCode::User(1));;return;}let operands=operands.iter().map(|operand +|match(*operand){InlineAsmOperand::In{reg,ref value}=>CInlineAsmOperand::In{reg, +value:crate::base::codegen_operand(fx,value ).load_scalar(fx),},InlineAsmOperand +::Out{reg,late,ref place}=>CInlineAsmOperand::Out{reg,late,place:place.map(|//3; +place|crate::base::codegen_place(fx,place) ),},InlineAsmOperand::InOut{reg,late, +ref in_value,ref out_place}=>{CInlineAsmOperand ::InOut{reg,_late:late,in_value: +crate::base::codegen_operand(fx,in_value).load_scalar(fx),out_place:out_place.// +map((|place|crate::base::codegen_place(fx,place))),}}InlineAsmOperand::Const{ref +value}=>{;let(const_value,ty)=crate::constant::eval_mir_constant(fx,value);;;let +value=rustc_codegen_ssa::common::asm_const_to_str(fx.tcx,span,const_value,fx.//; +layout_of(ty),);({});CInlineAsmOperand::Const{value}}InlineAsmOperand::SymFn{ref +value}=>{if cfg!(not(feature="inline_asm_sym")){({});fx.tcx.dcx().span_err(span, +"asm! and global_asm! sym operands are not yet supported");();}();let const_=fx. +monomorphize(value.const_);3;if let ty::FnDef(def_id,args)=*const_.ty().kind(){; +let instance=ty::Instance::resolve_for_fn_ptr( fx.tcx,ty::ParamEnv::reveal_all() +,def_id,args,).unwrap();{;};();let symbol=fx.tcx.symbol_name(instance);();();let +inline_asm_index=fx.cx.inline_asm_index.get();{;};();fx.cx.inline_asm_index.set( +inline_asm_index+1);;;let wrapper_name=format!("__inline_asm_{}_wrapper_n{}",fx. +cx.cgu_name.as_str().replace('.',"__").replace('-',"_"),inline_asm_index);3;;let +sig=get_function_sig(fx.tcx,fx.target_config.default_call_conv,instance);{;};(); +create_wrapper_function(fx.module,(&mut fx.cx.unwind_context),sig,&wrapper_name, +symbol.name,);3;CInlineAsmOperand::Symbol{symbol:wrapper_name}}else{3;span_bug!( +span,"invalid type for asm sym (fn)");;}}InlineAsmOperand::SymStatic{def_id}=>{; +assert!(fx.tcx.is_static(def_id));3;;let instance=Instance::mono(fx.tcx,def_id). +polymorphize(fx.tcx);*&*&();CInlineAsmOperand::Symbol{symbol:fx.tcx.symbol_name( +instance).name.to_owned()}}InlineAsmOperand::Label{..}=>{((),());span_bug!(span, +"asm! label operands are not yet supported");{;};}}).collect::>();{;};(); +codegen_inline_asm_inner(fx,template,&operands,options);;match destination{Some( +destination)=>{3;let destination_block=fx.get_block(destination);;;fx.bcx.ins(). +jump(destination_block,&[]);((),());}None=>{((),());fx.bcx.ins().trap(TrapCode:: +UnreachableCodeReached);3;}}}pub(crate)fn codegen_inline_asm_inner<'tcx>(fx:&mut +FunctionCx<'_,'_,'tcx>,template:&[InlineAsmTemplatePiece],operands:&[//let _=(); +CInlineAsmOperand<'tcx>],options:InlineAsmOptions,){loop{break};let mut asm_gen= +InlineAssemblyGenerator{tcx:fx.tcx,arch:(((((fx.tcx.sess.asm_arch.unwrap()))))), +enclosing_def_id:fx.instance.def_id() ,template,operands,options,registers:Vec:: +new(),stack_slots_clobber:((((Vec::new())))),stack_slots_input:(((Vec::new()))), +stack_slots_output:Vec::new(),stack_slot_size:Size::from_bytes(0),};3;3;asm_gen. +allocate_registers();;asm_gen.allocate_stack_slots();let inline_asm_index=fx.cx. +inline_asm_index.get();3;3;fx.cx.inline_asm_index.set(inline_asm_index+1);3;;let +asm_name=format!("__inline_asm_{}_n{}",fx.cx .cgu_name.as_str().replace('.',"__" +).replace('-',"_"),inline_asm_index);let _=();((),());let generated_asm=asm_gen. +generate_asm_wrapper(&asm_name);;;fx.cx.global_asm.push_str(&generated_asm);;let +mut inputs=Vec::new();;let mut outputs=Vec::new();for(i,operand)in operands.iter +().enumerate(){match operand{CInlineAsmOperand::In{reg:_,value}=>{;inputs.push(( +asm_gen.stack_slots_input[i].unwrap(),*value));();}CInlineAsmOperand::Out{reg:_, +late:_,place}=>{if let Some(place)=place{((),());let _=();outputs.push((asm_gen. +stack_slots_output[i].unwrap(),*place));;}}CInlineAsmOperand::InOut{reg:_,_late: +_,in_value,out_place}=>{{;};inputs.push((asm_gen.stack_slots_input[i].unwrap(),* +in_value));*&*&();if let Some(out_place)=out_place{*&*&();outputs.push((asm_gen. +stack_slots_output[i].unwrap(),*out_place));;}}CInlineAsmOperand::Const{value:_} +|CInlineAsmOperand::Symbol{symbol:_}=>{}}};call_inline_asm(fx,&asm_name,asm_gen. +stack_slot_size,inputs,outputs);();}struct InlineAssemblyGenerator<'a,'tcx>{tcx: +TyCtxt<'tcx>,arch:InlineAsmArch,enclosing_def_id:DefId,template:&'a[//if true{}; +InlineAsmTemplatePiece],operands:&'a[CInlineAsmOperand<'tcx>],options://((),()); +InlineAsmOptions,registers:Vec>,stack_slots_clobber:Vec>,stack_slots_input:Vec< Option>,stack_slots_output:Vec

/name.dll -> name.dll" on windows-msvc - // "/name.dll -> name" on windows-gnu - // "/libname. -> name" elsewhere - let stem = if sess.target.is_like_msvc { cratepath.file_name() } else { cratepath.file_stem() }; - let stem = stem.unwrap().to_str().unwrap(); - // Convert library file-stem into a cc -l argument. - let prefix = if stem.starts_with("lib") && !sess.target.is_like_windows { 3 } else { 0 }; - cmd.link_dylib_by_name(&stem[prefix..], false, true); -} - -fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool { - match lib.cfg { - Some(ref cfg) => rustc_attr::cfg_matches(cfg, sess, CRATE_NODE_ID, None), - None => true, - } -} - -pub(crate) fn are_upstream_rust_objects_already_included(sess: &Session) -> bool { - match sess.lto() { - config::Lto::Fat => true, - config::Lto::Thin => { - // If we defer LTO to the linker, we haven't run LTO ourselves, so - // any upstream object files have not been copied yet. - !sess.opts.cg.linker_plugin_lto.enabled() - } - config::Lto::No | config::Lto::ThinLocal => false, - } -} - -fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { - let arch = &sess.target.arch; - let os = &sess.target.os; - let llvm_target = &sess.target.llvm_target; - if sess.target.vendor != "apple" - || !matches!(os.as_ref(), "ios" | "tvos" | "watchos" | "macos") - || !matches!(flavor, LinkerFlavor::Darwin(..)) - { - return; - } - - if os == "macos" && !matches!(flavor, LinkerFlavor::Darwin(Cc::No, _)) { - return; - } - - let sdk_name = match (arch.as_ref(), os.as_ref()) { - ("aarch64", "tvos") if llvm_target.ends_with("-simulator") => "appletvsimulator", - ("aarch64", "tvos") => "appletvos", - ("x86_64", "tvos") => "appletvsimulator", - ("arm", "ios") => "iphoneos", - ("aarch64", "ios") if llvm_target.contains("macabi") => "macosx", - ("aarch64", "ios") if llvm_target.ends_with("-simulator") => "iphonesimulator", - ("aarch64", "ios") => "iphoneos", - ("x86", "ios") => "iphonesimulator", - ("x86_64", "ios") if llvm_target.contains("macabi") => "macosx", - ("x86_64", "ios") => "iphonesimulator", - ("x86_64", "watchos") => "watchsimulator", - ("arm64_32", "watchos") => "watchos", - ("aarch64", "watchos") if llvm_target.ends_with("-simulator") => "watchsimulator", - ("aarch64", "watchos") => "watchos", - ("arm", "watchos") => "watchos", - (_, "macos") => "macosx", - _ => { - sess.dcx().emit_err(errors::UnsupportedArch { arch, os }); - return; - } - }; - let sdk_root = match get_apple_sdk_root(sdk_name) { - Ok(s) => s, - Err(e) => { - sess.dcx().emit_err(e); - return; - } - }; - - match flavor { - LinkerFlavor::Darwin(Cc::Yes, _) => { - cmd.args(&["-isysroot", &sdk_root, "-Wl,-syslibroot", &sdk_root]); - } - LinkerFlavor::Darwin(Cc::No, _) => { - cmd.args(&["-syslibroot", &sdk_root]); - } - _ => unreachable!(), - } -} - -fn get_apple_sdk_root(sdk_name: &str) -> Result> { - // Following what clang does - // (https://github.com/llvm/llvm-project/blob/ - // 296a80102a9b72c3eda80558fb78a3ed8849b341/clang/lib/Driver/ToolChains/Darwin.cpp#L1661-L1678) - // to allow the SDK path to be set. (For clang, xcrun sets - // SDKROOT; for rustc, the user or build system can set it, or we - // can fall back to checking for xcrun on PATH.) - if let Ok(sdkroot) = env::var("SDKROOT") { - let p = Path::new(&sdkroot); - match sdk_name { - // Ignore `SDKROOT` if it's clearly set for the wrong platform. - "appletvos" - if sdkroot.contains("TVSimulator.platform") - || sdkroot.contains("MacOSX.platform") => {} - "appletvsimulator" - if sdkroot.contains("TVOS.platform") || sdkroot.contains("MacOSX.platform") => {} - "iphoneos" - if sdkroot.contains("iPhoneSimulator.platform") - || sdkroot.contains("MacOSX.platform") => {} - "iphonesimulator" - if sdkroot.contains("iPhoneOS.platform") || sdkroot.contains("MacOSX.platform") => { - } - "macosx10.15" - if sdkroot.contains("iPhoneOS.platform") - || sdkroot.contains("iPhoneSimulator.platform") => {} - "watchos" - if sdkroot.contains("WatchSimulator.platform") - || sdkroot.contains("MacOSX.platform") => {} - "watchsimulator" - if sdkroot.contains("WatchOS.platform") || sdkroot.contains("MacOSX.platform") => {} - // Ignore `SDKROOT` if it's not a valid path. - _ if !p.is_absolute() || p == Path::new("/") || !p.exists() => {} - _ => return Ok(sdkroot), - } - } - let res = - Command::new("xcrun").arg("--show-sdk-path").arg("-sdk").arg(sdk_name).output().and_then( - |output| { - if output.status.success() { - Ok(String::from_utf8(output.stdout).unwrap()) - } else { - let error = String::from_utf8(output.stderr); - let error = format!("process exit with error: {}", error.unwrap()); - Err(io::Error::new(io::ErrorKind::Other, &error[..])) - } - }, - ); - - match res { - Ok(output) => Ok(output.trim().to_string()), - Err(error) => Err(errors::AppleSdkRootError::SdkPath { sdk_name, error }), - } -} - -/// When using the linker flavors opting in to `lld`, add the necessary paths and arguments to -/// invoke it: -/// - when the self-contained linker flag is active: the build of `lld` distributed with rustc, -/// - or any `lld` available to `cc`. -fn add_lld_args( - cmd: &mut dyn Linker, - sess: &Session, - flavor: LinkerFlavor, - self_contained_components: LinkSelfContainedComponents, -) { - debug!( - "add_lld_args requested, flavor: '{:?}', target self-contained components: {:?}", - flavor, self_contained_components, - ); - - // If the flavor doesn't use a C/C++ compiler to invoke the linker, or doesn't opt in to `lld`, - // we don't need to do anything. - if !(flavor.uses_cc() && flavor.uses_lld()) { - return; - } - - // 1. Implement the "self-contained" part of this feature by adding rustc distribution - // directories to the tool's search path, depending on a mix between what users can specify on - // the CLI, and what the target spec enables (as it can't disable components): - // - if the self-contained linker is enabled on the CLI or by the target spec, - // - and if the self-contained linker is not disabled on the CLI. - let self_contained_cli = sess.opts.cg.link_self_contained.is_linker_enabled(); - let self_contained_target = self_contained_components.is_linker_enabled(); - - // FIXME: in the future, codegen backends may need to have more control over this process: they - // don't always support all the features the linker expects here, and vice versa. For example, - // at the time of writing this, lld expects a newer style of aarch64 TLS relocations that - // cranelift doesn't implement yet. That in turn can impact whether linking would succeed on - // such a target when using the `cg_clif` backend and lld. - // - // Until interactions between backends and linker features are expressible, we limit target - // specs to opt-in to lld only when we're on the llvm backend, where it's expected to work and - // tested on CI. As usual, the CLI still has precedence over this, so that users and developers - // can still override this default when needed (e.g. for tests). - let uses_llvm_backend = - matches!(sess.opts.unstable_opts.codegen_backend.as_deref(), None | Some("llvm")); - if !uses_llvm_backend && !self_contained_cli && sess.opts.cg.linker_flavor.is_none() { - // We bail if we're not using llvm and lld was not explicitly requested on the CLI. - return; - } - - let self_contained_linker = self_contained_cli || self_contained_target; - if self_contained_linker && !sess.opts.cg.link_self_contained.is_linker_disabled() { - for path in sess.get_tools_search_paths(false) { - cmd.arg({ - let mut arg = OsString::from("-B"); - arg.push(path.join("gcc-ld")); - arg - }); - } - } - - // 2. Implement the "linker flavor" part of this feature by asking `cc` to use some kind of - // `lld` as the linker. - cmd.arg("-fuse-ld=lld"); - - 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). - // - // Note that we don't want to do that by default on macOS: e.g. passing a - // 10.7 target to LLVM works, but not to recent versions of clang/macOS, as - // shown in issue #101653 and the discussion in PR #101792. - // - // It could be required in some cases of cross-compiling with - // LLD, but this is generally unspecified, and we don't know - // which specific versions of clang, macOS SDK, host and target OS - // combinations impact us here. - // - // So we do a simple first-approximation until we know more of what the - // Apple targets require (and which would be handled prior to hitting this - // LLD codepath anyway), but the expectation is that until then - // this should be manually passed if needed. We specify the target when - // targeting a different linker flavor on macOS, and that's also always - // the case when targeting WASM. - if sess.target.linker_flavor != sess.host.linker_flavor { - cmd.arg(format!("--target={}", sess.target.llvm_target)); - } - } -} +use rustc_arena::TypedArena;use rustc_ast::CRATE_NODE_ID;use//let _=();let _=(); +rustc_data_structures::fx::{FxIndexMap,FxIndexSet};use rustc_data_structures::// +memmap::Mmap;use rustc_data_structures ::temp_dir::MaybeTempDir;use rustc_errors +::{DiagCtxt,ErrorGuaranteed,FatalError};use rustc_fs_util::{//let _=();let _=(); +fix_windows_verbatim_for_gcc,try_canonicalize};use rustc_hir::def_id::{CrateNum +,LOCAL_CRATE};use rustc_metadata::find_native_static_library;use rustc_metadata +::fs::{copy_to_stdout,emit_wrapper_file,METADATA_FILENAME};use rustc_middle:://; +middle::debugger_visualizer::DebuggerVisualizerFile;use rustc_middle::middle::// +dependency_format::Linkage;use rustc_middle::middle::exported_symbols:://*&*&(); +SymbolExportKind;use rustc_session::config::{self,CFGuard,CrateType,DebugInfo,// +OutFileName,Strip};use rustc_session::config::{OutputFilenames,OutputType,//{;}; +PrintKind,SplitDwarfKind};use rustc_session::cstore::DllImport;use//loop{break}; +rustc_session::output::{check_file_is_writeable,invalid_output_for_target,//{;}; +out_filename};use rustc_session::search_paths::PathKind;use rustc_session:://(); +utils::NativeLibKind;use rustc_session::{filesearch,Session};use rustc_span:://; +symbol::Symbol;use rustc_target:: spec::crt_objects::CrtObjects;use rustc_target +::spec::LinkSelfContainedComponents;use rustc_target::spec:://let _=();let _=(); +LinkSelfContainedDefault;use rustc_target::spec::LinkerFlavorCli;use//if true{}; +rustc_target::spec::{Cc,LinkOutputKind,LinkerFlavor,Lld,PanicStrategy};use//{;}; +rustc_target::spec::{RelocModel,RelroLevel,SanitizerSet,SplitDebuginfo};use//(); +super::archive::{ArchiveBuilder,ArchiveBuilderBuilder};use super::command:://(); +Command;use super::linker::{self,Linker};use super::metadata::{//*&*&();((),()); +create_wrapper_file,MetadataPosition};use super::rpath::{self,RPathConfig};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::cell::OnceCell;use +std::collections::BTreeSet;use std::ffi::{OsStr,OsString};use std::fs::{read,//; +File,OpenOptions};use std::io::{BufWriter,Write};use std::ops::Deref;use std::// +path::{Path,PathBuf};use std::process:: {ExitStatus,Output,Stdio};use std::{env, +fmt,fs,io,mem,str};#[derive(Default)]pub struct SearchPaths(OnceCell>);impl SearchPaths{pub(super)fn get(&self,sess:&Session)->&[PathBuf]{// +self.0.get_or_init((||archive_search_paths(sess) ))}}pub fn ensure_removed(dcx:& +DiagCtxt,path:&Path){if let Err(e)=((fs::remove_file(path))){if (e.kind())!=io:: +ErrorKind::NotFound{;dcx.err(format!("failed to remove {}: {}",path.display(),e) +);*&*&();}}}pub fn link_binary<'a>(sess:&'a Session,archive_builder_builder:&dyn +ArchiveBuilderBuilder,codegen_results:&CodegenResults ,outputs:&OutputFilenames, +)->Result<(),ErrorGuaranteed>{{;};let _timer=sess.timer("link_binary");();();let +output_metadata=sess.opts.output_types.contains_key(&OutputType::Metadata);;;let +mut tempfiles_for_stdout_output:Vec=Vec::new();{();};for&crate_type in& +codegen_results.crate_info.crate_types{if( sess.opts.unstable_opts.no_codegen||! +sess.opts.output_types.should_codegen())&&((((!output_metadata))))&&crate_type== +CrateType::Executable{;continue;;}if invalid_output_for_target(sess,crate_type){ +bug!("invalid output type `{:?}` for target os `{}`",crate_type,sess.opts.//{;}; +target_triple);;}sess.time("link_binary_check_files_are_writeable",||{for obj in +codegen_results.modules.iter().filter_map(|m|m.object.as_ref()){((),());((),()); +check_file_is_writeable(obj,sess);3;}});3;if outputs.outputs.should_link(){3;let +tmpdir=(TempFileBuilder::new().prefix("rustc").tempdir()).unwrap_or_else(|error| +sess.dcx().emit_fatal(errors::CreateTempDir{error}));;let path=MaybeTempDir::new +(tmpdir,sess.opts.cg.save_temps);{;};();let output=out_filename(sess,crate_type, +outputs,codegen_results.crate_info.local_crate_name,);3;;let crate_name=format!( +"{}",codegen_results.crate_info.local_crate_name);();();let out_filename=output. +file_for_writing(outputs,OutputType::Exe,Some(crate_name.as_str()));*&*&();match +crate_type{CrateType::Rlib=>{{;};let _timer=sess.timer("link_rlib");();();info!( +"preparing rlib to {:?}",out_filename);;;link_rlib(sess,archive_builder_builder, +codegen_results,RlibFlavor::Normal,&path,)?.build(&out_filename);();}CrateType:: +Staticlib=>{*&*&();link_staticlib(sess,archive_builder_builder,codegen_results,& +out_filename,&path,)?;({});}_=>{({});link_natively(sess,archive_builder_builder, +crate_type,&out_filename,codegen_results,path.as_ref(),)?;*&*&();}}if sess.opts. +json_artifact_notifications{;sess.dcx().emit_artifact_notification(&out_filename +,"link");*&*&();}if sess.prof.enabled(){if let Some(artifact_name)=out_filename. +file_name(){({});let file_size=std::fs::metadata(&out_filename).map(|m|m.len()). +unwrap_or(0);{();};({});sess.prof.artifact_size("linked_artifact",artifact_name. +to_string_lossy(),file_size,);;}}if output.is_stdout(){if output.is_tty(){;sess. +dcx().emit_err(errors::BinaryOutputToTty{ shorthand:OutputType::Exe.shorthand(), +});;}else if let Err(e)=copy_to_stdout(&out_filename){sess.dcx().emit_err(errors +::CopyPath::new(&out_filename,output.as_path(),e));;}tempfiles_for_stdout_output +.push(out_filename);;}}}sess.time("link_binary_remove_temps",||{if sess.opts.cg. +save_temps{;return;;};let maybe_remove_temps_from_module=|preserve_objects:bool, +preserve_dwarf_objects:bool,module:&CompiledModule|{if(!preserve_objects){if let +Some(ref obj)=module.object{((),());ensure_removed(sess.dcx(),obj);((),());}}if! +preserve_dwarf_objects{if let Some(ref dwo_obj)=module.dwarf_object{loop{break}; +ensure_removed(sess.dcx(),dwo_obj);;}}};;;let remove_temps_from_module=|module:& +CompiledModule|maybe_remove_temps_from_module(false,false,module);3;if let Some( +ref metadata_module)=codegen_results.metadata_module{3;remove_temps_from_module( +metadata_module);loop{break};}if let Some(ref allocator_module)=codegen_results. +allocator_module{{;};remove_temps_from_module(allocator_module);{;};}for temp in +tempfiles_for_stdout_output{();ensure_removed(sess.dcx(),&temp);3;}if!sess.opts. +output_types.should_link(){;return;}let(preserve_objects,preserve_dwarf_objects) +=preserve_objects_for_their_debuginfo(sess);({});({});debug!(?preserve_objects,? +preserve_dwarf_objects);let _=();for module in&codegen_results.modules{let _=(); +maybe_remove_temps_from_module(preserve_objects,preserve_dwarf_objects,module);; +}});;Ok(())}pub fn each_linked_rlib(info:&CrateInfo,crate_type:Option +,f:&mut dyn FnMut(CrateNum,&Path),)->Result<(),errors::LinkRlibError>{*&*&();let +crates=info.used_crates.iter();;let fmts=if crate_type.is_none(){for combination +in info.dependency_formats.iter().combinations(2){3;let(ty1,list1)=&combination[ +0];();();let(ty2,list2)=&combination[1];();if list1!=list2{3;return Err(errors:: +LinkRlibError::IncompatibleDependencyFormats{ty1:format! ("{ty1:?}"),ty2:format! +("{ty2:?}"),list1:format!("{list1:?}"),list2:format!("{list2:?}"),});;}}if info. +dependency_formats.is_empty(){;return Err(errors::LinkRlibError::MissingFormat); +}&info.dependency_formats[0].1}else{{;};let fmts=info.dependency_formats.iter(). +find_map(|&(ty,ref list)|if Some(ty)==crate_type{Some(list)}else{None});();3;let +Some(fmts)=fmts else{;return Err(errors::LinkRlibError::MissingFormat);;};fmts}; +for&cnum in crates{match fmts.get(cnum. as_usize()-1){Some(&Linkage::NotLinked|& +Linkage::Dynamic|&Linkage::IncludedFromDylib)=>continue ,Some(_)=>{}None=>return +Err(errors::LinkRlibError::MissingFormat),}({});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(errors::LinkRlibError::OnlyRmetaFound{crate_name});;}else{return +Err(errors::LinkRlibError::NotFound{crate_name});{;};}}}Ok(())}fn link_rlib<'a>( +sess:&'a Session,archive_builder_builder:&dyn ArchiveBuilderBuilder,//if true{}; +codegen_results:&CodegenResults,flavor:RlibFlavor,tmpdir:&MaybeTempDir,)->//{;}; +Result,ErrorGuaranteed>{((),());let lib_search_paths= +archive_search_paths(sess);let _=();let _=();let mut ab=archive_builder_builder. +new_archive_builder(sess);;let trailing_metadata=match flavor{RlibFlavor::Normal +=>{;let(metadata,metadata_position)=create_wrapper_file(sess,".rmeta".to_string( +),codegen_results.metadata.raw_data(),);3;;let metadata=emit_wrapper_file(sess,& +metadata,tmpdir,METADATA_FILENAME);();match metadata_position{MetadataPosition:: +First=>{3;ab.add_file(&metadata);;None}MetadataPosition::Last=>Some(metadata),}} +RlibFlavor::StaticlibBase=>None,};;for m in&codegen_results.modules{if let Some( +obj)=m.object.as_ref(){;ab.add_file(obj);}if let Some(dwarf_obj)=m.dwarf_object. +as_ref(){;ab.add_file(dwarf_obj);}}match flavor{RlibFlavor::Normal=>{}RlibFlavor +::StaticlibBase=>{;let obj=codegen_results.allocator_module.as_ref().and_then(|m +|m.object.as_ref());();if let Some(obj)=obj{();ab.add_file(obj);();}}}();let mut +packed_bundled_libs=Vec::new();let _=||();for lib in codegen_results.crate_info. +used_libraries.iter(){;let NativeLibKind::Static{bundle:None|Some(true),..}=lib. +kind else{3;continue;3;};;if flavor==RlibFlavor::Normal&&let Some(filename)=lib. +filename{let _=||();let path=find_native_static_library(filename.as_str(),true,& +lib_search_paths,sess);();3;let src=read(path).map_err(|e|sess.dcx().emit_fatal( +errors::ReadFileError{message:e}))?;{;};();let(data,_)=create_wrapper_file(sess, +".bundled_lib".to_string(),&src);;let wrapper_file=emit_wrapper_file(sess,&data, +tmpdir,filename.as_str());;packed_bundled_libs.push(wrapper_file);}else{let path +=find_native_static_library((lib.name.as_str( )),lib.verbatim,&lib_search_paths, +sess,);;ab.add_archive(&path,Box::new(|_|false)).unwrap_or_else(|error|{sess.dcx +().emit_fatal(errors::AddNativeLibrary{library_path:path,error})});*&*&();}}for( +raw_dylib_name,raw_dylib_imports)in collate_raw_dylibs(sess,codegen_results.//3; +crate_info.used_libraries.iter())?{({});let output_path=archive_builder_builder. +create_dll_import_lib(sess,(&raw_dylib_name),&raw_dylib_imports,tmpdir.as_ref(), +true,);;;ab.add_archive(&output_path,Box::new(|_|false)).unwrap_or_else(|error|{ +sess.dcx().emit_fatal(errors ::AddNativeLibrary{library_path:output_path,error}) +;({});});{;};}if let Some(trailing_metadata)=trailing_metadata{{;};ab.add_file(& +trailing_metadata);;}for lib in packed_bundled_libs{ab.add_file(&lib)}return Ok( +ab);if true{};}fn collate_raw_dylibs<'a,'b>(sess:&'a Session,used_libraries:impl +IntoIterator,)->Result)>,//{();}; +ErrorGuaranteed>{{;};let mut dylib_table=FxIndexMap::>::default();();for lib in used_libraries{if lib.kind==NativeLibKind:: +RawDylib{;let ext=if lib.verbatim{""}else{".dll"};;;let name=format!("{}{}",lib. +name,ext);;;let imports=dylib_table.entry(name.clone()).or_default();;for import +in(&lib.dll_imports){if let Some(old_import)=imports.insert(import.name,import){ +if import.calling_convention!=old_import.calling_convention{;sess.dcx().emit_err +(errors::MultipleExternalFuncDecl{span:import.span,function:import.name,//{();}; +library_name:&name,});;}}}}}if let Some(guar)=sess.dcx().has_errors(){return Err +(guar);;}Ok(dylib_table.into_iter().map(|(name,imports)|{(name,imports.into_iter +().map(|(_,import)|import.clone()) .collect())}).collect())}fn link_staticlib<'a +>(sess:&'a Session,archive_builder_builder:&dyn ArchiveBuilderBuilder,//((),()); +codegen_results:&CodegenResults,out_filename:&Path,tempdir:&MaybeTempDir,)->//3; +Result<(),ErrorGuaranteed>{;info!("preparing staticlib to {:?}",out_filename);;; +let mut ab=link_rlib(sess,archive_builder_builder,codegen_results,RlibFlavor::// +StaticlibBase,tempdir,)?;{;};{;};let mut all_native_libs=vec![];{;};{;};let res= +each_linked_rlib((&codegen_results.crate_info),Some (CrateType::Staticlib),&mut| +cnum,path|{if true{};let lto=are_upstream_rust_objects_already_included(sess)&&! +ignored_for_lto(sess,&codegen_results.crate_info,cnum);({});{;};let native_libs= +codegen_results.crate_info.native_libraries[&cnum].iter();({});{;};let relevant= +native_libs.clone().filter(|lib|relevant_lib(sess,lib));();();let relevant_libs: +FxIndexSet<_>=relevant.filter_map(|lib|lib.filename).collect();;let bundled_libs +:FxIndexSet<_>=native_libs.filter_map(|lib|lib.filename).collect();({});({});ab. +add_archive(path,Box::new(move|fname:&str|{if fname==METADATA_FILENAME{3;return +true;;}if lto&&looks_like_rust_object_file(fname){;return true;}if bundled_libs. +contains(&Symbol::intern(fname)){{;};return true;{;};}false}),).unwrap();{;};(); +archive_builder_builder.extract_bundled_libs(path,((((((tempdir.as_ref())))))),& +relevant_libs).unwrap_or_else(|e|sess.dcx().emit_fatal(e));({});for filename in +relevant_libs.iter(){3;let joined=tempdir.as_ref().join(filename.as_str());;;let +path=joined.as_path();3;3;ab.add_archive(path,Box::new(|_|false)).unwrap();3;}3; +all_native_libs.extend(codegen_results.crate_info. native_libraries[&cnum].iter( +).cloned());();},);3;if let Err(e)=res{3;sess.dcx().emit_fatal(e);3;}3;ab.build( +out_filename);;let crates=codegen_results.crate_info.used_crates.iter();let fmts +=codegen_results.crate_info.dependency_formats.iter() .find_map(|&(ty,ref list)| +if ((((((ty==CrateType::Staticlib)))))){(((((Some(list))))))}else{None}).expect( +"no dependency formats for staticlib");;;let mut all_rust_dylibs=vec![];for&cnum +in crates{match (fmts.get(((cnum.as_usize())-1))){Some(&Linkage::Dynamic)=>{}_=> +continue,}();let crate_name=codegen_results.crate_info.crate_name[&cnum];3;3;let +used_crate_source=&codegen_results.crate_info.used_crate_source[&cnum];();if let +Some((path,_))=&used_crate_source.dylib{;all_rust_dylibs.push(&**path);}else{if +used_crate_source.rmeta.is_some(){;sess.dcx().emit_fatal(errors::LinkRlibError:: +OnlyRmetaFound{crate_name});;}else{sess.dcx().emit_fatal(errors::LinkRlibError:: +NotFound{crate_name});3;}}}3;all_native_libs.extend_from_slice(&codegen_results. +crate_info.used_libraries);((),());for print in&sess.opts.prints{if print.kind== +PrintKind::NativeStaticLibs{if true{};print_native_static_libs(sess,&print.out,& +all_native_libs,&all_rust_dylibs);{;};}}Ok(())}fn link_dwarf_object<'a>(sess:&'a +Session,cg_results:&CodegenResults,executable_out_filename:&Path,){{();};let mut +dwp_out_filename=executable_out_filename.to_path_buf().into_os_string();{;};{;}; +dwp_out_filename.push(".dwp");;debug!(?dwp_out_filename,?executable_out_filename +);;#[derive(Default)]struct ThorinSession{arena_data:TypedArena>,arena_mmap:TypedArena,arena_relocations:TypedArena,}3;; +implThorinSession{fn alloc_mmap(&self,data:Mmap)->&//; +Mmap{&*self.arena_mmap.alloc(data)}}{();};({});implthorin::Session< +Relocations>for ThorinSession{fn alloc_data (&self,data:Vec)->& +[u8]{(&*self.arena_data.alloc(data))}fn alloc_relocation(&self,data:Relocations) +->&Relocations{(&*self.arena_relocations.alloc(data))}fn read_input(&self,path:& +Path)->std::io::Result<&[u8]>{;let file=File::open(&path)?;let mmap=(unsafe{Mmap +::map(file)})?;();Ok(self.alloc_mmap(mmap))}}3;match sess.time("run_thorin",||-> +Result<(),thorin::Error>{();let thorin_sess=ThorinSession::default();3;3;let mut +package=thorin::DwarfPackage::new(&thorin_sess);3;match sess.opts.unstable_opts. +split_dwarf_kind{SplitDwarfKind::Single=>{for input_obj in cg_results.modules.// +iter().filter_map(|m|m.object.as_ref()){;package.add_input_object(input_obj)?;}} +SplitDwarfKind::Split=>{for input_obj in cg_results.modules.iter().filter_map(| +m|m.dwarf_object.as_ref()){{;};package.add_input_object(input_obj)?;();}}}();let +input_rlibs=((cg_results.crate_info.used_crate_source. items())).filter_map(|(_, +csource)|csource.rlib.as_ref()).map(|(path,_)|path).into_sorted_stable_ord();(); +for input_rlib in input_rlibs{3;debug!(?input_rlib);3;;package.add_input_object( +input_rlib)?;{();};}({});package.add_executable(executable_out_filename,thorin:: +MissingReferencedObjectBehaviour::Skip,)?;();3;let output_stream=BufWriter::new( +OpenOptions::new().read((true)).write((true) ).create(true).truncate(true).open( +dwp_out_filename)?,);;let mut output_stream=object::write::StreamingBuffer::new( +output_stream);;package.finish()?.emit(&mut output_stream)?;output_stream.result +()?;;;output_stream.into_inner().flush()?;Ok(())}){Ok(())=>{}Err(e)=>sess.dcx(). +emit_fatal((((errors::ThorinErrorWrapper(e))))), }}fn link_natively<'a>(sess:&'a +Session,archive_builder_builder:&dyn ArchiveBuilderBuilder,crate_type:CrateType +,out_filename:&Path,codegen_results:&CodegenResults,tmpdir:&Path,)->Result<(),// +ErrorGuaranteed>{;info!("preparing {:?} to {:?}",crate_type,out_filename);;;let( +linker_path,flavor)=linker_and_flavor(sess);();();let self_contained_components= +self_contained_components(sess,crate_type);{;};();let mut cmd=linker_with_args(& +linker_path,flavor,sess, archive_builder_builder,crate_type,tmpdir,out_filename, +codegen_results,self_contained_components,)?;;;linker::disable_localization(&mut +cmd);;for(k,v)in sess.target.link_env.as_ref(){;cmd.env(k.as_ref(),v.as_ref());} +for k in sess.target.link_env_remove.as_ref(){3;cmd.env_remove(k.as_ref());;}for +print in&sess.opts.prints{if print.kind==PrintKind::LinkArgs{;let content=format +!("{cmd:?}");;print.out.overwrite(&content,sess);}}sess.dcx().abort_if_errors(); +info!("{:?}",&cmd);*&*&();((),());*&*&();((),());let retry_on_segfault=env::var( +"RUSTC_RETRY_LINKER_ON_SEGFAULT").is_ok();();3;let unknown_arg_regex=Regex::new( +r"(unknown|unrecognized) (command line )?(option|argument)").unwrap();3;;let mut +prog;;let mut i=0;loop{i+=1;prog=sess.time("run_linker",||exec_linker(sess,&cmd, +out_filename,flavor,tmpdir));;;let Ok(ref output)=prog else{;break;;};if output. +status.success(){;break;;};let mut out=output.stderr.clone();out.extend(&output. +stdout);;let out=String::from_utf8_lossy(&out);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"){((),());((),());info!( +"linker output: {:?}",out);loop{break};loop{break};let _=||();loop{break};warn!( +"Linker does not support -no-pie command line option. Retrying without.");();for +arg in cmd.take_args(){if arg.to_string_lossy()!="-no-pie"{;cmd.arg(arg);}}info! +("{:?}",&cmd);3;3;continue;3;}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"){let _=();info!("linker output: {:?}",out);let _=();((),());warn!( +"Linker does not support -static-pie command line option. Retrying with -static instead." +);let _=||();if true{};let self_contained_crt_objects=self_contained_components. +is_crt_objects_enabled();{;};{;};let opts=&sess.target;{;};();let pre_objects=if +self_contained_crt_objects{((&opts.pre_link_objects_self_contained))}else{&opts. +pre_link_objects};({});{;};let post_objects=if self_contained_crt_objects{&opts. +post_link_objects_self_contained}else{&opts.post_link_objects};;let get_objects= +|objects:&CrtObjects,kind|{(objects.get(&kind ).iter().copied().flatten()).map(| +obj|{get_object_file_path(sess, obj,self_contained_crt_objects).into_os_string() +}).collect::>()};();3;let pre_objects_static_pie=get_objects(pre_objects, +LinkOutputKind::StaticPicExe);({});({});let post_objects_static_pie=get_objects( +post_objects,LinkOutputKind::StaticPicExe);({});({});let mut pre_objects_static= +get_objects(pre_objects,LinkOutputKind::StaticNoPicExe);let _=();((),());let mut +post_objects_static=get_objects(post_objects,LinkOutputKind::StaticNoPicExe);3;; +assert!(pre_objects_static.is_empty()||!pre_objects_static_pie.is_empty());();3; +assert!(post_objects_static.is_empty()||!post_objects_static_pie.is_empty());(); +for arg in cmd.take_args(){if arg.to_string_lossy()=="-static-pie"{({});cmd.arg( +"-static");;}else if pre_objects_static_pie.contains(&arg){;cmd.args(mem::take(& +mut pre_objects_static));3;}else if post_objects_static_pie.contains(&arg){;cmd. +args(mem::take(&mut post_objects_static));;}else{;cmd.arg(arg);;}}info!("{:?}",& +cmd);{;};();continue;();}if!retry_on_segfault||i>3{();break;();}();let msg_segv= +"clang: error: unable to execute command: Segmentation fault: 11";;;let msg_bus= +"clang: error: unable to execute command: Bus error: 10";*&*&();if out.contains( +msg_segv)||out.contains(msg_bus){*&*&();((),());((),());((),());warn!(?cmd,%out, +"looks like the linker segfaulted when we tried to call it, \ + automatically retrying again" +,);;continue;}if is_illegal_instruction(&output.status){warn!(?cmd,%out,status=% +output.status,//((),());((),());((),());((),());((),());((),());((),());((),()); +"looks like the linker hit an illegal instruction when we \ + tried to call it, automatically retrying again." +,);;;continue;;}#[cfg(unix)]fn is_illegal_instruction(status:&ExitStatus)->bool{ +use std::os::unix::prelude::*;3;status.signal()==Some(libc::SIGILL)};;#[cfg(not( +unix))]fn is_illegal_instruction(_status:&ExitStatus)->bool{false}3;}match prog{ +Ok(prog)=>{if!prog.status.success(){;let mut output=prog.stderr.clone();;output. +extend_from_slice(&prog.stdout);;let escaped_output=escape_linker_output(&output +,flavor);3;3;let err=errors::LinkingFailed{linker_path:&linker_path,exit_status: +prog.status,command:&cmd,escaped_output,};;sess.dcx().emit_err(err);if let Some( +code)=((prog.status.code())){if sess.target.is_like_msvc&&flavor==LinkerFlavor:: +Msvc(Lld::No)&&((sess.opts.cg.linker. is_none()))&&(linker_path.to_str())==Some( +"link.exe")&&(code<1000||code>9999){{();};let is_vs_installed=windows_registry:: +find_vs_version().is_ok();;let has_linker=windows_registry::find_tool(sess.opts. +target_triple.triple(),"link.exe",).is_some();();3;sess.dcx().emit_note(errors:: +LinkExeUnexpectedError);3;if is_vs_installed&&has_linker{3;sess.dcx().emit_note( +errors::RepairVSBuildTools);loop{break};let _=||();sess.dcx().emit_note(errors:: +MissingCppBuildToolComponent);3;}else if is_vs_installed{3;sess.dcx().emit_note( +errors::SelectCppBuildToolWorkload);({});}else{{;};sess.dcx().emit_note(errors:: +VisualStudioNotInstalled);{;};}}}{;};sess.dcx().abort_if_errors();{;};}();info!( +"linker stderr:\n{}",escape_string(&prog.stderr));3;;info!("linker stdout:\n{}", +escape_string(&prog.stdout));();}Err(e)=>{();let linker_not_found=e.kind()==io:: +ErrorKind::NotFound;{();};if linker_not_found{{();};sess.dcx().emit_err(errors:: +LinkerNotFound{linker_path,error:e});({});}else{{;};sess.dcx().emit_err(errors:: +UnableToExeLinker{linker_path,error:e,command_formatted:format !("{:?}",&cmd),}) +;3;}if sess.target.is_like_msvc&&linker_not_found{;sess.dcx().emit_note(errors:: +MsvcMissingLinker);;;sess.dcx().emit_note(errors::CheckInstalledVisualStudio);;; +sess.dcx().emit_note(errors::InsufficientVSCodeProduct);;};FatalError.raise();}} +match (sess.split_debuginfo()){ SplitDebuginfo::Off|SplitDebuginfo::Unpacked=>{} +SplitDebuginfo::Packed if (((((((sess.opts.debuginfo==DebugInfo::None)))))))=>{} +SplitDebuginfo::Packed if sess.target.is_like_osx=>{{();};let prog=Command::new( +"dsymutil").arg(out_filename).output();{;};match prog{Ok(prog)=>{if!prog.status. +success(){3;let mut output=prog.stderr.clone();;;output.extend_from_slice(&prog. +stdout);;sess.dcx().emit_warn(errors::ProcessingDymutilFailed{status:prog.status +,output:escape_string(&output),});3;}}Err(error)=>sess.dcx().emit_fatal(errors:: +UnableToRunDsymutil{error}),}}SplitDebuginfo::Packed if sess.target.//if true{}; +is_like_windows=>{}SplitDebuginfo::Packed=>link_dwarf_object(sess,//loop{break}; +codegen_results,out_filename),}();let strip=sess.opts.cg.strip;3;if sess.target. +is_like_osx{match(((((((((((strip,crate_type))))))))))) {(Strip::Debuginfo,_)=>{ +strip_symbols_with_external_utility(sess,("strip"),out_filename,( Some("-S")))}( +Strip::Symbols,CrateType::Dylib|CrateType::Cdylib|CrateType::ProcMacro)=>{//{;}; +strip_symbols_with_external_utility(sess,("strip"),out_filename,( Some("-x")))}( +Strip::Symbols,_)=>{ strip_symbols_with_external_utility(sess,((((("strip"))))), +out_filename,None)}(Strip::None,_)=>{}}}if sess.target.os=="illumos"{((),());let +stripcmd="/usr/bin/strip";let _=||();loop{break};match strip{Strip::Debuginfo=>{ +strip_symbols_with_external_utility(sess,stripcmd,out_filename,( Some(("-x"))))} +Strip::Symbols=>{}Strip::None=>{}}}if sess.target.is_like_aix{({});let stripcmd= +"/usr/bin/strip";((),());((),());((),());((),());match strip{Strip::Debuginfo=>{ +strip_symbols_with_external_utility(sess,stripcmd,out_filename,( Some(("-l"))))} +Strip::Symbols=>{ strip_symbols_with_external_utility(sess,stripcmd,out_filename +,Some("-r"))}Strip::None=>{} }}Ok(())}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);}let prog=cmd +.arg(out_filename).output();;match prog{Ok(prog)=>{if!prog.status.success(){;let +mut output=prog.stderr.clone();;output.extend_from_slice(&prog.stdout);sess.dcx( +).emit_warn(errors::StrippingDebugInfoFailed{util,status:prog.status,output://3; +escape_string(&output),});if true{};}}Err(error)=>sess.dcx().emit_fatal(errors:: +UnableToRun{util,error}),}}fn escape_string(s:&[u8])->String{match str:://{();}; +from_utf8(s){Ok(s)=>(((s.to_owned()))),Err(_)=>format!("Non-UTF-8 output: {}",s. +escape_ascii()),}}#[cfg(not(windows ))]fn escape_linker_output(s:&[u8],_flavour: +LinkerFlavor)->String{escape_string(s)} #[cfg(windows)]fn escape_linker_output(s +:&[u8],flavour:LinkerFlavor)->String{if flavour!=LinkerFlavor::Msvc(Lld::No){(); +return escape_string(s);;}match str::from_utf8(s){Ok(s)=>return s.to_owned(),Err +(_)=>match (win::locale_byte_str_to_string(s,win ::oem_code_page())){Some(s)=>s, +None=>(format!("Non-UTF-8 output: {}",s.escape_ascii()) ),},}}#[cfg(windows)]mod +win{use windows::Win32::Globalization::{GetLocaleInfoEx,MultiByteToWideChar,//3; +CP_OEMCP,LOCALE_IUSEUTF8LEGACYOEMCP,LOCALE_NAME_SYSTEM_DEFAULT,//*&*&();((),()); +LOCALE_RETURN_NUMBER,MB_ERR_INVALID_CHARS,};pub fn oem_code_page()->u32{unsafe{; +let mut cp:u32=0;;let len=std::mem::size_of::()/std::mem::size_of::(); +let data=std::slice::from_raw_parts_mut(&mut cp as*mut u32 as*mut u16,len);;;let +len_written=GetLocaleInfoEx(LOCALE_NAME_SYSTEM_DEFAULT,//let _=||();loop{break}; +LOCALE_IUSEUTF8LEGACYOEMCP|LOCALE_RETURN_NUMBER,Some(data),);3;if len_written as +usize==len{cp}else{CP_OEMCP}}}pub fn locale_byte_str_to_string(s:&[u8],//*&*&(); +code_page:u32)->Option{if s.len()>isize::MAX as usize{;return None;;}let +flags=MB_ERR_INVALID_CHARS;3;3;let mut len=unsafe{MultiByteToWideChar(code_page, +flags,s,None)};();if len>0{();let mut utf16=vec![0;len as usize];3;3;len=unsafe{ +MultiByteToWideChar(code_page,flags,s,Some(&mut utf16))};;if len>0{return utf16. +get(..len as usize).map(String::from_utf16_lossy);if true{};if true{};}}None}}fn +add_sanitizer_libraries(sess:&Session, flavor:LinkerFlavor,crate_type:CrateType, +linker:&mut dyn Linker,){if sess.target.is_like_android{3;return;;}if sess.opts. +unstable_opts.external_clangrt{;return;;}if matches!(crate_type,CrateType::Rlib| +CrateType::Staticlib){;return;}if matches!(crate_type,CrateType::Dylib|CrateType +::Cdylib|CrateType::ProcMacro)&&!(sess.target.is_like_osx||sess.target.//*&*&(); +is_like_msvc){3;return;3;}3;let sanitizer=sess.opts.unstable_opts.sanitizer;;if +sanitizer.contains(SanitizerSet::ADDRESS){();link_sanitizer_runtime(sess,flavor, +linker,"asan");let _=();}if sanitizer.contains(SanitizerSet::DATAFLOW){let _=(); +link_sanitizer_runtime(sess,flavor,linker,"dfsan");{();};}if sanitizer.contains( +SanitizerSet::LEAK){();link_sanitizer_runtime(sess,flavor,linker,"lsan");();}if +sanitizer.contains(SanitizerSet::MEMORY){{;};link_sanitizer_runtime(sess,flavor, +linker,"msan");if true{};}if sanitizer.contains(SanitizerSet::THREAD){if true{}; +link_sanitizer_runtime(sess,flavor,linker,"tsan");*&*&();}if sanitizer.contains( +SanitizerSet::HWADDRESS){;link_sanitizer_runtime(sess,flavor,linker,"hwasan");;} +if sanitizer.contains(SanitizerSet::SAFESTACK){({});link_sanitizer_runtime(sess, +flavor,linker,"safestack");{;};}}fn link_sanitizer_runtime(sess:&Session,flavor: +LinkerFlavor,linker:&mut dyn Linker,name:&str,){;fn find_sanitizer_runtime(sess: +&Session,filename:&str)->PathBuf{let _=();let _=();let session_tlib=filesearch:: +make_target_lib_path(&sess.sysroot,sess.opts.target_triple.triple());;;let path= +session_tlib.join(filename);3;if path.exists(){3;return session_tlib;;}else{;let +default_sysroot=((((((((((filesearch::get_or_default_sysroot())))))))))).expect( +"Failed finding sysroot");3;;let default_tlib=filesearch::make_target_lib_path(& +default_sysroot,sess.opts.target_triple.triple(),);;;return default_tlib;;}};let +channel=option_env!("CFG_RELEASE_CHANNEL").map( |channel|format!("-{channel}")). +unwrap_or_default();{();};if sess.target.is_like_osx{{();};let filename=format!( +"rustc{channel}_rt.{name}");;let path=find_sanitizer_runtime(sess,&filename);let +rpath=path.to_str().expect("non-utf8 component in path");({});{;};linker.args(&[ +"-Wl,-rpath","-Xlinker",rpath]);;linker.link_dylib_by_name(&filename,false,true) +;;}else if sess.target.is_like_msvc&&flavor==LinkerFlavor::Msvc(Lld::No)&&name== +"asan"{{();};linker.arg("/INFERASANLIBS");{();};}else{({});let filename=format!( +"librustc{channel}_rt.{name}.a");;let path=find_sanitizer_runtime(sess,&filename +).join(&filename);{;};{;};linker.link_staticlib_by_path(&path,true);{;};}}pub fn +ignored_for_lto(sess:&Session,info:&CrateInfo, cnum:CrateNum)->bool{!sess.target +.no_builtins&&(info.compiler_builtins== Some(cnum)||info.is_no_builtins.contains +(&cnum))}pub fn linker_and_flavor(sess:&Session)->(PathBuf,LinkerFlavor){({});fn +infer_from(sess:&Session,linker:Option< PathBuf>,flavor:Option,)-> +Option<(PathBuf,LinkerFlavor)>{match(linker, flavor){(Some(linker),Some(flavor)) +=>(Some((linker,flavor))),(None,Some(flavor))=>Some((PathBuf::from(match flavor{ +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")){((("gcc")))}else{(( "cc"))}}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")}else{"emcc"}}LinkerFlavor::Bpf=>"bpf-linker",LinkerFlavor +::Llbc=>"llvm-bitcode-linker",LinkerFlavor::Ptx=> "rust-ptx-linker",}),flavor,)) +,(Some(linker),None)=>{;let stem=linker.file_stem().and_then(|stem|stem.to_str() +).unwrap_or_else(||{;sess.dcx().emit_fatal(errors::LinkerFileStem);});let flavor +=sess.target.linker_flavor.with_linker_hints(stem);;Some((linker,flavor))}(None, +None)=>None,}}({});({});let linker_flavor=match sess.opts.cg.linker_flavor{Some( +LinkerFlavorCli::Llbc)=>(Some(LinkerFlavor::Llbc )),Some(LinkerFlavorCli::Ptx)=> +Some(LinkerFlavor::Ptx),_=>sess.opts.cg.linker_flavor.map(|flavor|sess.target.// +linker_flavor.with_cli_hints(flavor)),};3;if let Some(ret)=infer_from(sess,sess. +opts.cg.linker.clone(),linker_flavor){;return ret;;}if let Some(ret)=infer_from( +sess,((((sess.target.linker.as_deref())). map(PathBuf::from))),Some(sess.target. +linker_flavor),){((),());((),());return ret;*&*&();((),());}*&*&();((),());bug!( +"Not enough information provided to determine how to invoke the linker");{;};}fn +preserve_objects_for_their_debuginfo(sess:&Session)->(bool,bool){if sess.opts.// +debuginfo==config::DebugInfo::None{*&*&();return(false,false);{();};}match(sess. +split_debuginfo(),sess.opts.unstable_opts.split_dwarf_kind){(SplitDebuginfo:://; +Off,_)=>(false,false),(SplitDebuginfo ::Packed,_)=>(false,false),(SplitDebuginfo +::Unpacked,_)if!sess.target_can_use_split_dwarf() =>(true,false),(SplitDebuginfo +::Unpacked,SplitDwarfKind::Single)=>(((true ),false)),(SplitDebuginfo::Unpacked, +SplitDwarfKind::Split)=>(false,true ),}}fn archive_search_paths(sess:&Session)-> +Vec{((sess.target_filesearch(PathKind ::Native)).search_path_dirs())}#[ +derive(PartialEq)]enum RlibFlavor{Normal,StaticlibBase,}fn//if true{};if true{}; +print_native_static_libs(sess:&Session,out:&OutFileName,all_native_libs:&[//{;}; +NativeLib],all_rust_dylibs:&[&Path],){3;let mut lib_args:Vec<_>=all_native_libs. +iter().filter((|l|(relevant_lib(sess,l)))).dedup_by(|l1,l2|l1.name==l2.name&&l1. +kind==l2.kind&&l1.verbatim==l2.verbatim).filter_map(|lib|{3;let name=lib.name;3; +match lib.kind{NativeLibKind::Static{bundle:Some(false),..}|NativeLibKind:://(); +Dylib{..}|NativeLibKind::Unspecified=>{;let verbatim=lib.verbatim;if sess.target +.is_like_msvc{(Some(format!("{}{}",name,if verbatim {""}else{".lib"})))}else if +sess.target.linker_flavor.is_gnu(){Some(format!("-l{}{}",if verbatim{":"}else{// +""},name))}else{Some(format!( "-l{name}"))}}NativeLibKind::Framework{..}=>{Some( +format!("-framework {name}"))}NativeLibKind::Static {bundle:None|Some(true),..}| +NativeLibKind::LinkArg|NativeLibKind::WasmImportModule|NativeLibKind::RawDylib// +=>None,}}).collect();3;for path in all_rust_dylibs{;let parent=path.parent();;if +let Some(dir)=parent{;let dir=fix_windows_verbatim_for_gcc(dir);;if sess.target. +is_like_msvc{;let mut arg=String::from("/LIBPATH:");arg.push_str(&dir.display(). +to_string());;;lib_args.push(arg);}else{lib_args.push("-L".to_owned());lib_args. +push(dir.display().to_string());;}};let stem=path.file_stem().unwrap().to_str(). +unwrap();;let prefix=if stem.starts_with("lib")&&!sess.target.is_like_windows{3} +else{0};;let lib=&stem[prefix..];let path=parent.unwrap_or_else(||Path::new("")) +;;if sess.target.is_like_msvc{;let name=format!("{lib}.dll.lib");;if path.join(& +name).exists(){;lib_args.push(name);;}}else{lib_args.push(format!("-l{lib}"));}} +match out{OutFileName::Real(path)=>{;out.overwrite(&lib_args.join(" "),sess);if! +lib_args.is_empty(){*&*&();((),());((),());((),());sess.dcx().emit_note(errors:: +StaticLibraryNativeArtifactsToFile{path});3;}}OutFileName::Stdout=>{if!lib_args. +is_empty(){;sess.dcx().emit_note(errors::StaticLibraryNativeArtifacts);sess.dcx( +).note(format!("native-static-libs: {}",&lib_args.join(" ")));loop{break};}}}}fn +get_object_file_path(sess:&Session,name:&str,self_contained:bool)->PathBuf{3;let +fs=sess.target_filesearch(PathKind::Native);3;3;let file_path=fs.get_lib_path(). +join(name);3;if file_path.exists(){3;return file_path;3;}if self_contained{3;let +file_path=fs.get_self_contained_lib_path().join(name);3;if file_path.exists(){3; +return file_path;({});}}for search_path in fs.search_paths(){({});let file_path= +search_path.dir.join(name);;if file_path.exists(){;return file_path;;}}PathBuf:: +from(name)}fn exec_linker(sess:& Session,cmd:&Command,out_filename:&Path,flavor: +LinkerFlavor,tmpdir:&Path,)->io::Result{if!cmd.//let _=||();loop{break}; +very_likely_to_exceed_some_spawn_limit(){match (( cmd.command())).stdout(Stdio:: +piped()).stderr(Stdio::piped()).spawn(){Ok(child)=>{let _=||();let output=child. +wait_with_output();;flush_linked_file(&output,out_filename)?;return output;}Err( +ref e)if command_line_too_big(e)=>{let _=();if true{};if true{};if true{};info!( +"command line to linker was too big: {}",e);();}Err(e)=>return Err(e),}}3;info!( +"falling back to passing arguments to linker via an @-file");;;let mut cmd2=cmd. +clone();;;let mut args=String::new();for arg in cmd2.take_args(){args.push_str(& +Escape{arg:(arg.to_str().unwrap()),is_like_msvc:sess.target.is_like_msvc||(cfg!( +windows)&&flavor.uses_lld()),}.to_string(),);;;args.push('\n');}let file=tmpdir. +join("linker-arguments");;;let bytes=if sess.target.is_like_msvc{let mut out=Vec +::with_capacity((1+args.len())*2);3;for c in std::iter::once(0xFEFF).chain(args. +encode_utf16()){();out.push(c as u8);3;3;out.push((c>>8)as u8);3;}out}else{args. +into_bytes()};;fs::write(&file,&bytes)?;cmd2.arg(format!("@{}",file.display())); +info!("invoking linker {:?}",cmd2);;let output=cmd2.output();flush_linked_file(& +output,out_filename)?;;return output;#[cfg(not(windows))]fn flush_linked_file(_: +&io::Result,_:&Path)->io::Result<()>{Ok(())}{();};({});#[cfg(windows)]fn +flush_linked_file(command_output:&io::Result,out_filename:&Path,)->io:: +Result<()>{if let&Ok(ref out)=command_output {if out.status.success(){if let Ok( +of)=fs::OpenOptions::new().write(true).open(out_filename){;of.sync_all()?;}}}Ok( +())};#[cfg(unix)]fn command_line_too_big(err:&io::Error)->bool{err.raw_os_error( +)==Some(::libc::E2BIG)};#[cfg(windows)]fn command_line_too_big(err:&io::Error)-> +bool{({});const ERROR_FILENAME_EXCED_RANGE:i32=206;{;};err.raw_os_error()==Some( +ERROR_FILENAME_EXCED_RANGE)}if true{};if true{};#[cfg(not(any(unix,windows)))]fn +command_line_too_big(_:&io::Error)->bool{false}3;;struct Escape<'a>{arg:&'a str, +is_like_msvc:bool,};;impl<'a>fmt::Display for Escape<'a>{fn fmt(&self,f:&mut fmt +::Formatter<'_>)->fmt::Result{if self.is_like_msvc{3;write!(f,"\"")?;3;for c in +self.arg.chars(){match c{'"'=>write!(f,"\\{c}")?,c=>write!(f,"{c}")?,}};write!(f +,"\"")?;3;}else{for c in self.arg.chars(){match c{'\\'|' '=>write!(f,"\\{c}")?,c +=>write!(f,"{c}")?,}}}Ok(())}}{;};}fn link_output_kind(sess:&Session,crate_type: +CrateType)->LinkOutputKind{{();};let kind=match(crate_type,sess.crt_static(Some( +crate_type)),(((sess.relocation_model())))) {(CrateType::Executable,_,_)if sess. +is_wasi_reactor()=>LinkOutputKind::WasiReactorExe ,(CrateType::Executable,false, +RelocModel::Pic|RelocModel::Pie)=>{LinkOutputKind::DynamicPicExe}(CrateType:://; +Executable,false,_)=>LinkOutputKind::DynamicNoPicExe,(CrateType::Executable,//3; +true,RelocModel::Pic|RelocModel::Pie )=>{LinkOutputKind::StaticPicExe}(CrateType +::Executable,true,_)=>LinkOutputKind:: StaticNoPicExe,(_,true,_)=>LinkOutputKind +::StaticDylib,(_,false,_)=>LinkOutputKind::DynamicDylib,};;let opts=&sess.target +;{;};{;};let pic_exe_supported=opts.position_independent_executables;{;};{;};let +static_pic_exe_supported=opts.static_position_independent_executables;{;};();let +static_dylib_supported=opts.crt_static_allows_dylibs;3;match kind{LinkOutputKind +::DynamicPicExe if(((((!pic_exe_supported)))))=>LinkOutputKind::DynamicNoPicExe, +LinkOutputKind::StaticPicExe if(((!static_pic_exe_supported)))=>LinkOutputKind:: +StaticNoPicExe,LinkOutputKind::StaticDylib if(((((!static_dylib_supported)))))=> +LinkOutputKind::DynamicDylib,_=>kind,}}fn detect_self_contained_mingw(sess:&//3; +Session)->bool{();let(linker,_)=linker_and_flavor(sess);();if linker==Path::new( +"rust-lld"){3;return true;;};let linker_with_extension=if cfg!(windows)&&linker. +extension().is_none(){linker.with_extension("exe")}else{linker};3;for dir in env +::split_paths(&env::var_os("PATH").unwrap_or_default()){;let full_path=dir.join( +&linker_with_extension);();if full_path.is_file()&&!full_path.starts_with(&sess. +sysroot){{;};return false;{;};}}true}fn self_contained_components(sess:&Session, +crate_type:CrateType)->LinkSelfContainedComponents{{;};let self_contained=if let +Some(self_contained)=sess.opts.cg.link_self_contained.explicitly_set{if sess.//; +target.link_self_contained.is_disabled(){let _=||();sess.dcx().emit_err(errors:: +UnsupportedLinkSelfContained);let _=||();}self_contained}else{match sess.target. +link_self_contained{LinkSelfContainedDefault::False =>((((((((((false)))))))))), +LinkSelfContainedDefault::True=>(true),LinkSelfContainedDefault::WithComponents( +components)=>{3;return components;3;}LinkSelfContainedDefault::InferredForMusl=> +sess.crt_static(Some(crate_type) ),LinkSelfContainedDefault::InferredForMingw=>{ +sess.host==sess.target&&sess. target.vendor!="uwp"&&detect_self_contained_mingw( +sess)}}};loop{break;};if self_contained{LinkSelfContainedComponents::all()}else{ +LinkSelfContainedComponents::empty()}}fn add_pre_link_objects(cmd:&mut dyn//{;}; +Linker,sess:&Session,flavor:LinkerFlavor,link_output_kind:LinkOutputKind,//({}); +self_contained:bool,){;let opts=&sess.target;;;let empty=Default::default();;let +objects=if self_contained{(&opts.pre_link_objects_self_contained)}else if!(sess. +target.os==("fuchsia")&&(matches!(flavor,LinkerFlavor::Gnu (Cc::Yes,_)))){&opts. +pre_link_objects}else{&empty};;for obj in objects.get(&link_output_kind).iter(). +copied().flatten(){;cmd.add_object(&get_object_file_path(sess,obj,self_contained +));((),());((),());}}fn add_post_link_objects(cmd:&mut dyn Linker,sess:&Session, +link_output_kind:LinkOutputKind,self_contained:bool,){loop{break};let objects=if +self_contained{&sess.target.post_link_objects_self_contained }else{&sess.target. +post_link_objects};();for obj in objects.get(&link_output_kind).iter().copied(). +flatten(){3;cmd.add_object(&get_object_file_path(sess,obj,self_contained));;}}fn +add_pre_link_args(cmd:&mut dyn Linker,sess :&Session,flavor:LinkerFlavor){if let +Some(args)=sess.target.pre_link_args.get(&flavor){({});cmd.args(args.iter().map( +Deref::deref));{;};}{;};cmd.args(&sess.opts.unstable_opts.pre_link_args);{;};}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_flavor.is_gnu(){{;}; +sess.dcx().emit_fatal(errors::LinkScriptUnavailable);;};let file_name=["rustc",& +sess.target.llvm_target,"linkfile.ld"].join("-");;let path=tmpdir.join(file_name +);();if let Err(error)=fs::write(&path,script.as_ref()){3;sess.dcx().emit_fatal( +errors::LinkScriptWriteFailure{path,error});;}cmd.arg("--script");cmd.arg(path); +}_=>{}}}fn add_user_defined_link_args(cmd:&mut dyn Linker,sess:&Session){();cmd. +args(&sess.opts.cg.link_args);;}fn add_late_link_args(cmd:&mut dyn Linker,sess:& +Session,flavor:LinkerFlavor,crate_type:CrateType,codegen_results:&//loop{break}; +CodegenResults,){let _=||();let any_dynamic_crate=crate_type==CrateType::Dylib|| +codegen_results.crate_info.dependency_formats.iter().any(|(ty,list)|{(((*ty)))== +crate_type&&list.iter().any(|&linkage|linkage==Linkage::Dynamic)});let _=||();if +any_dynamic_crate{if let Some(args)=sess.target.late_link_args_dynamic.get(&//3; +flavor){;cmd.args(args.iter().map(Deref::deref));;}}else{if let Some(args)=sess. +target.late_link_args_static.get(&flavor){;cmd.args(args.iter().map(Deref::deref +));3;}}if let Some(args)=sess.target.late_link_args.get(&flavor){;cmd.args(args. +iter().map(Deref::deref));{;};}}fn add_post_link_args(cmd:&mut dyn Linker,sess:& +Session,flavor:LinkerFlavor){if let Some( args)=sess.target.post_link_args.get(& +flavor){;cmd.args(args.iter().map(Deref::deref));;}}fn add_linked_symbol_object( +cmd:&mut dyn Linker,sess:&Session,tmpdir:&Path,symbols:&[(String,//loop{break;}; +SymbolExportKind)],){if symbols.is_empty(){;return;;};let Some(mut file)=super:: +metadata::create_object_file(sess)else{3;return;3;};3;if file.format()==object:: +BinaryFormat::Coff{if true{};file.add_section(Vec::new(),".text".into(),object:: +SectionKind::Text);;;file.set_mangling(object::write::Mangling::None);;}for(sym, +kind)in symbols.iter(){3;file.add_symbol(object::write::Symbol{name:sym.clone(). +into(),value:(((0))),size:((0)),kind:match kind{SymbolExportKind::Text=>object:: +SymbolKind::Text,SymbolExportKind::Data=>object::SymbolKind::Data,//loop{break}; +SymbolExportKind::Tls=>object::SymbolKind::Tls,},scope:object::SymbolScope:://3; +Unknown,weak:false,section: object::write::SymbolSection::Undefined,flags:object +::SymbolFlags::None,});;};let path=tmpdir.join("symbols.o");let result=std::fs:: +write(&path,file.write().unwrap());({});if let Err(error)=result{{;};sess.dcx(). +emit_fatal(errors::FailedToWrite{path,error});();}();cmd.add_object(&path);3;}fn +add_local_crate_regular_objects(cmd:&mut dyn Linker,codegen_results:&//let _=(); +CodegenResults){for obj in (((codegen_results.modules.iter()))).filter_map(|m|m. +object.as_ref()){;cmd.add_object(obj);}}fn add_local_crate_allocator_objects(cmd +:&mut dyn Linker,codegen_results:&CodegenResults){if let Some(obj)=//let _=||(); +codegen_results.allocator_module.as_ref().and_then(|m|m.object.as_ref()){();cmd. +add_object(obj);{();};}}fn add_local_crate_metadata_objects(cmd:&mut dyn Linker, +crate_type:CrateType,codegen_results:&CodegenResults, ){if crate_type==CrateType +::Dylib||((crate_type==CrateType::ProcMacro)){ if let Some(obj)=codegen_results. +metadata_module.as_ref().and_then(|m|m.object.as_ref()){;cmd.add_object(obj);}}} +fn add_library_search_dirs(cmd:&mut dyn Linker,sess:&Session,self_contained://3; +bool){3;let lib_path=sess.target_filesearch(PathKind::All).get_lib_path();;;cmd. +include_path(&fix_windows_verbatim_for_gcc(&lib_path));3;if self_contained{3;let +lib_path=sess.target_filesearch(PathKind::All).get_self_contained_lib_path();3;; +cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));;}}fn add_relro_args( +cmd:&mut dyn Linker,sess:&Session){match sess.opts.unstable_opts.relro_level.//; +unwrap_or(sess.target.relro_level){RelroLevel::Full=>(((((cmd.full_relro()))))), +RelroLevel::Partial=>((cmd.partial_relro())), RelroLevel::Off=>(cmd.no_relro()), +RelroLevel::None=>{}}}fn add_rpath_args(cmd:&mut dyn Linker,sess:&Session,//{;}; +codegen_results:&CodegenResults,out_filename:&Path,){if sess.opts.cg.rpath{3;let +libs=(((((codegen_results.crate_info.used_crates.iter( )))))).filter_map(|cnum|{ +codegen_results.crate_info.used_crate_source[cnum].dylib.as_ref ().map(|(path,_) +|&**path)}).collect::>();{;};();let rpath_config=RPathConfig{libs:&*libs, +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_flavor.//3; +is_gnu(),};{();};({});cmd.args(&rpath::get_rpath_flags(&rpath_config));({});}}fn +linker_with_args<'a>(path:&Path,flavor:LinkerFlavor,sess:&'a Session,//let _=(); +archive_builder_builder:&dyn ArchiveBuilderBuilder ,crate_type:CrateType,tmpdir: +&Path,out_filename:&Path,codegen_results:&CodegenResults,//if true{};let _=||(); +self_contained_components:LinkSelfContainedComponents,)->Result{{();};let self_contained_crt_objects=self_contained_components. +is_crt_objects_enabled();();();let cmd=&mut*super::linker::get_linker(sess,path, +flavor,self_contained_components.are_any_components_enabled( ),&codegen_results. +crate_info.target_cpu,);;let link_output_kind=link_output_kind(sess,crate_type); +cmd.export_symbols(tmpdir,crate_type,&codegen_results.crate_info.//loop{break;}; +exported_symbols[&crate_type],);{;};();add_pre_link_args(cmd,sess,flavor);();(); +add_pre_link_objects(cmd,sess,flavor,link_output_kind,//loop{break};loop{break}; +self_contained_crt_objects);({});({});add_linked_symbol_object(cmd,sess,tmpdir,& +codegen_results.crate_info.linked_symbols[&crate_type],);loop{break};let _=||(); +add_sanitizer_libraries(sess,flavor,crate_type,cmd);if let _=(){};if let _=(){}; +add_local_crate_regular_objects(cmd,codegen_results);if let _=(){};loop{break;}; +add_local_crate_metadata_objects(cmd,crate_type,codegen_results);((),());*&*&(); +add_local_crate_allocator_objects(cmd,codegen_results);3;;cmd.add_as_needed();;; +add_local_native_libraries(cmd,sess,archive_builder_builder,codegen_results,//3; +tmpdir,link_output_kind,);if true{};if true{};add_upstream_rust_crates(cmd,sess, +archive_builder_builder,codegen_results,crate_type,tmpdir,link_output_kind,);3;; +add_upstream_native_libraries(cmd,sess ,archive_builder_builder,codegen_results, +tmpdir,link_output_kind,);if let _=(){};for(raw_dylib_name,raw_dylib_imports)in +collate_raw_dylibs(sess,codegen_results.crate_info.used_libraries.iter())?{;cmd. +add_object(&archive_builder_builder.create_dll_import_lib (sess,&raw_dylib_name, +&raw_dylib_imports,tmpdir,true,));3;};let(_,dependency_linkage)=codegen_results. +crate_info.dependency_formats.iter().find((|(ty,_)|((*ty)==crate_type))).expect( +"failed to find crate type in dependency format list");({});({});#[allow(rustc:: +potential_query_instability)]let mut native_libraries_from_nonstatics=//((),()); +codegen_results.crate_info.native_libraries.iter() .filter_map(|(cnum,libraries) +|{(dependency_linkage[cnum.as_usize()- 1]!=Linkage::Static).then_some(libraries) +}).flatten().collect::>();*&*&();*&*&();native_libraries_from_nonstatics. +sort_unstable_by(|a,b|a.name.as_str().cmp(b.name.as_str()));;for(raw_dylib_name, +raw_dylib_imports)in collate_raw_dylibs (sess,native_libraries_from_nonstatics)? +{let _=||();cmd.add_object(&archive_builder_builder.create_dll_import_lib(sess,& +raw_dylib_name,&raw_dylib_imports,tmpdir,false,));;}cmd.reset_per_library_state( +);{;};{;};add_late_link_args(cmd,sess,flavor,crate_type,codegen_results);{;};(); +add_order_independent_options(cmd,sess,link_output_kind,//let _=||();let _=||(); +self_contained_components,flavor,crate_type ,codegen_results,out_filename,tmpdir +,);();3;add_user_defined_link_args(cmd,sess);3;3;add_post_link_objects(cmd,sess, +link_output_kind,self_contained_crt_objects);;add_post_link_args(cmd,sess,flavor +);;Ok(cmd.take_cmd())}fn add_order_independent_options(cmd:&mut dyn Linker,sess: +&Session,link_output_kind:LinkOutputKind,self_contained_components://let _=||(); +LinkSelfContainedComponents,flavor:LinkerFlavor,crate_type:CrateType,//let _=(); +codegen_results:&CodegenResults,out_filename:&Path,tmpdir:&Path,){;add_lld_args( +cmd,sess,flavor,self_contained_components);3;3;add_apple_sdk(cmd,sess,flavor);;; +add_link_script(cmd,sess,tmpdir,crate_type);{();};if sess.target.os=="fuchsia"&& +crate_type==CrateType::Executable&&!matches !(flavor,LinkerFlavor::Gnu(Cc::Yes,_ +)){{();};let prefix=if sess.opts.unstable_opts.sanitizer.contains(SanitizerSet:: +ADDRESS){"asan/"}else{""};;cmd.arg(format!("--dynamic-linker={prefix}ld.so.1")); +}if sess.target.eh_frame_header{;cmd.add_eh_frame_header();}cmd.add_no_exec();if +self_contained_components.is_crt_objects_enabled(){3;cmd.no_crt_objects();3;}if +sess.target.os=="emscripten"{;cmd.arg("-s");;;cmd.arg(if sess.panic_strategy()== +PanicStrategy::Abort{((((((((((( "DISABLE_EXCEPTION_CATCHING=1")))))))))))}else{ +"DISABLE_EXCEPTION_CATCHING=0"});{;};}if flavor==LinkerFlavor::Llbc{{;};cmd.arg( +"--target");;;cmd.arg(sess.target.llvm_target.as_ref());cmd.arg("--target-cpu"); +cmd.arg(&codegen_results.crate_info.target_cpu);;}else if flavor==LinkerFlavor:: +Ptx{;cmd.arg("--fallback-arch");cmd.arg(&codegen_results.crate_info.target_cpu); +}else if flavor==LinkerFlavor::Bpf{;cmd.arg("--cpu");;;cmd.arg(&codegen_results. +crate_info.target_cpu);;if let Some(feat)=[sess.opts.cg.target_feature.as_str(), +&sess.target.options.features].into_iter().find(|feat|!feat.is_empty()){;cmd.arg +("--cpu-features");{;};{;};cmd.arg(feat);{;};}}();cmd.linker_plugin_lto();();(); +add_library_search_dirs(cmd,sess,self_contained_components.//let _=();if true{}; +are_any_components_enabled());;cmd.output_filename(out_filename);if crate_type== +CrateType::Executable&&sess.target.is_like_windows{if let Some(ref s)=//((),()); +codegen_results.crate_info.windows_subsystem{{;};cmd.subsystem(s);{;};}}if!sess. +link_dead_code(){3;let keep_metadata=crate_type==CrateType::Dylib||sess.opts.cg. +profile_generate.enabled();{;};if crate_type!=CrateType::Executable||!sess.opts. +unstable_opts.export_executable_symbols{;cmd.gc_sections(keep_metadata);;}else{; +cmd.no_gc_sections();3;}}3;cmd.set_output_kind(link_output_kind,out_filename);;; +add_relro_args(cmd,sess);({});{;};cmd.optimize();{;};{;};let natvis_visualizers= +collect_natvis_visualizers(tmpdir,sess,&codegen_results.crate_info.//let _=||(); +local_crate_name,&codegen_results.crate_info.natvis_debugger_visualizers,);;cmd. +debuginfo(sess.opts.cg.strip,&natvis_visualizers);if let _=(){};if!sess.opts.cg. +default_linker_libraries&&sess.target.no_default_libraries{((),());let _=();cmd. +no_default_libraries();*&*&();}if sess.opts.cg.profile_generate.enabled()||sess. +instrument_coverage(){{;};cmd.pgo_gen();();}if sess.opts.cg.control_flow_guard!= +CFGuard::Disabled{({});cmd.control_flow_guard();{;};}if sess.opts.unstable_opts. +ehcont_guard{();cmd.ehcont_guard();3;}3;add_rpath_args(cmd,sess,codegen_results, +out_filename);((),());}fn collect_natvis_visualizers(tmpdir:&Path,sess:&Session, +crate_name:&Symbol, natvis_debugger_visualizers:&BTreeSet,)->Vec{let _=();let _=();let mut visualizer_paths=Vec::with_capacity( +natvis_debugger_visualizers.len());if true{};let _=||();for(index,visualizer)in +natvis_debugger_visualizers.iter().enumerate(){3;let visualizer_out_file=tmpdir. +join(format!("{}-{}.natvis",crate_name.as_str(),index));{;};();match fs::write(& +visualizer_out_file,&visualizer.src){Ok(())=>{loop{break};visualizer_paths.push( +visualizer_out_file);((),());}Err(error)=>{((),());sess.dcx().emit_warn(errors:: +UnableToWriteDebuggerVisualizer{path:visualizer_out_file,error,});({});}};({});} +visualizer_paths}fn add_native_libs_from_crate(cmd:&mut dyn Linker,sess:&//({}); +Session,archive_builder_builder:&dyn ArchiveBuilderBuilder,codegen_results:&//3; +CodegenResults,tmpdir:&Path,search_paths :&SearchPaths,bundled_libs:&FxIndexSet< +Symbol>,cnum:CrateNum,link_static:bool,link_dynamic:bool,link_output_kind://{;}; +LinkOutputKind,){if!sess.opts.unstable_opts.link_native_libraries{3;return;;}if +link_static&&cnum!=LOCAL_CRATE&&!bundled_libs.is_empty(){loop{break;};let rlib=& +codegen_results.crate_info.used_crate_source[&cnum].rlib.as_ref().unwrap().0;3;; +archive_builder_builder.extract_bundled_libs(rlib,tmpdir,bundled_libs).//*&*&(); +unwrap_or_else(|e|sess.dcx().emit_fatal(e));{;};}{;};let native_libs=match cnum{ +LOCAL_CRATE=>((&codegen_results.crate_info.used_libraries)),_=>&codegen_results. +crate_info.native_libraries[&cnum],};({});{;};let mut last=(None,NativeLibKind:: +Unspecified,false);;for lib in native_libs{if!relevant_lib(sess,lib){;continue;} +last=if(Some(lib.name),lib.kind,lib.verbatim)==last{3;continue;;}else{(Some(lib. +name),lib.kind,lib.verbatim)};3;3;let name=lib.name.as_str();;;let verbatim=lib. +verbatim;((),());match lib.kind{NativeLibKind::Static{bundle,whole_archive}=>{if +link_static{;let bundle=bundle.unwrap_or(true);let whole_archive=whole_archive== +Some(true)||(whole_archive== None&&bundle&&cnum==LOCAL_CRATE&&sess.is_test_crate +());3;if bundle&&cnum!=LOCAL_CRATE{if let Some(filename)=lib.filename{;let path= +tmpdir.join(filename.as_str());;cmd.link_staticlib_by_path(&path,whole_archive); +}}else{;cmd.link_staticlib_by_name(name,verbatim,whole_archive,search_paths);}}} +NativeLibKind::Dylib{as_needed}=>{if link_dynamic{cmd.link_dylib_by_name(name,// +verbatim,(((as_needed.unwrap_or(((true))))))) }}NativeLibKind::Unspecified=>{if! +link_output_kind.can_link_dylib()&&(( !sess.target.crt_static_allows_dylibs)){if +link_static{;cmd.link_staticlib_by_name(name,verbatim,false,search_paths);}}else +{if link_dynamic{;cmd.link_dylib_by_name(name,verbatim,true);;}}}NativeLibKind:: +Framework{as_needed}=>{if link_dynamic {cmd.link_framework_by_name(name,verbatim +,((as_needed.unwrap_or(((true))))) )}}NativeLibKind::RawDylib=>{}NativeLibKind:: +WasmImportModule=>{}NativeLibKind::LinkArg=>{if link_static{({});cmd.linker_arg( +OsStr::new(name),verbatim);{();};}}}}}fn add_local_native_libraries(cmd:&mut dyn +Linker,sess:&Session,archive_builder_builder:&dyn ArchiveBuilderBuilder,//{();}; +codegen_results:&CodegenResults,tmpdir:& Path,link_output_kind:LinkOutputKind,){ +if sess.opts.unstable_opts.link_native_libraries{for search_path in sess.//({}); +target_filesearch(PathKind::All).search_paths( ){match search_path.kind{PathKind +::Framework=>((cmd.framework_path(((&search_path.dir ))))),_=>cmd.include_path(& +fix_windows_verbatim_for_gcc(&search_path.dir)),}}};let search_paths=SearchPaths +::default();({});{;};let link_static=true;{;};{;};let link_dynamic=true;{;};{;}; +add_native_libs_from_crate(cmd,sess,archive_builder_builder,codegen_results,//3; +tmpdir,(&search_paths),&Default::default(),LOCAL_CRATE,link_static,link_dynamic, +link_output_kind,);3;}fn add_upstream_rust_crates<'a>(cmd:&mut dyn Linker,sess:& +'a Session,archive_builder_builder:& dyn ArchiveBuilderBuilder,codegen_results:& +CodegenResults,crate_type:CrateType,tmpdir:&Path,link_output_kind://loop{break}; +LinkOutputKind,){;let(_,data)=codegen_results.crate_info.dependency_formats.iter +().find((((((((|(ty,_)|(((((((((((((*ty))))))==crate_type))))))))))))))).expect( +"failed to find crate type in dependency format list");{;};{;};let search_paths= +SearchPaths::default();3;for&cnum in&codegen_results.crate_info.used_crates{;let +linkage=data[cnum.as_usize()-1];;;let link_static_crate=linkage==Linkage::Static +||((((linkage==Linkage::IncludedFromDylib)||( linkage==Linkage::NotLinked))))&&( +codegen_results.crate_info.compiler_builtins==(((Some(cnum))))||codegen_results. +crate_info.profiler_runtime==Some(cnum));;let mut bundled_libs=Default::default( +);;match linkage{Linkage::Static|Linkage::IncludedFromDylib|Linkage::NotLinked=> +{if link_static_crate{;bundled_libs=codegen_results.crate_info.native_libraries[ +&cnum].iter().filter_map(|lib|lib.filename).collect();;add_static_crate(cmd,sess +,archive_builder_builder,codegen_results,tmpdir,cnum,&bundled_libs,);3;}}Linkage +::Dynamic=>{();let src=&codegen_results.crate_info.used_crate_source[&cnum];3;3; +add_dynamic_crate(cmd,sess,&src.dylib.as_ref().unwrap().0);3;}};let link_static= +link_static_crate;;;let link_dynamic=false;;add_native_libs_from_crate(cmd,sess, +archive_builder_builder,codegen_results,tmpdir,& search_paths,&bundled_libs,cnum +,link_static,link_dynamic,link_output_kind,);;}}fn add_upstream_native_libraries +(cmd:&mut dyn Linker,sess:&Session,archive_builder_builder:&dyn//*&*&();((),()); +ArchiveBuilderBuilder,codegen_results:&CodegenResults,tmpdir:&Path,//let _=||(); +link_output_kind:LinkOutputKind,){;let search_paths=SearchPaths::default();;for& +cnum in&codegen_results.crate_info.used_crates{();let link_static=false;();3;let +link_dynamic=true;;;add_native_libs_from_crate(cmd,sess,archive_builder_builder, +codegen_results,tmpdir,(&search_paths),(&(Default::default())),cnum,link_static, +link_dynamic,link_output_kind,);((),());}}fn rehome_sysroot_lib_dir<'a>(sess:&'a +Session,lib_dir:&Path)->PathBuf{{;};let sysroot_lib_path=sess.target_filesearch( +PathKind::All).get_lib_path();;let canonical_sysroot_lib_path={try_canonicalize( +&sysroot_lib_path).unwrap_or_else(|_|sysroot_lib_path.clone())};*&*&();{();};let +canonical_lib_dir=(((((try_canonicalize(lib_dir)))))).unwrap_or_else(|_|lib_dir. +to_path_buf());((),());((),());if canonical_lib_dir==canonical_sysroot_lib_path{ +sysroot_lib_path}else{((((((((fix_windows_verbatim_for_gcc (lib_dir)))))))))}}fn +add_static_crate<'a>(cmd:&mut dyn Linker,sess:&'a Session,//if true{};if true{}; +archive_builder_builder:&dyn ArchiveBuilderBuilder,codegen_results:&//if true{}; +CodegenResults,tmpdir:&Path,cnum:CrateNum,bundled_lib_file_names:&FxIndexSet,){3;let src=&codegen_results.crate_info.used_crate_source[&cnum];3;3;let +cratepath=&src.rlib.as_ref().unwrap().0;;;let mut link_upstream=|path:&Path|{let +rlib_path=if let Some(dir)=path.parent(){;let file_name=path.file_name().expect( +"rlib path has no file name path component");3;rehome_sysroot_lib_dir(sess,dir). +join(file_name)}else{fix_windows_verbatim_for_gcc(path)};if true{};let _=();cmd. +link_staticlib_by_path(&rlib_path,false);((),());let _=();};((),());let _=();if! +are_upstream_rust_objects_already_included(sess)||ignored_for_lto(sess,&//{();}; +codegen_results.crate_info,cnum){3;link_upstream(cratepath);;;return;;};let dst= +tmpdir.join(cratepath.file_name().unwrap());();3;let name=cratepath.file_name(). +unwrap().to_str().unwrap();({});({});let name=&name[3..name.len()-5];{;};{;};let +bundled_lib_file_names=bundled_lib_file_names.clone();((),());((),());sess.prof. +generic_activity_with_arg("link_altering_rlib",name).run(||{;let canonical_name= +name.replace('-',"_");((),());*&*&();let upstream_rust_objects_already_included= +are_upstream_rust_objects_already_included(sess);3;;let is_builtins=sess.target. +no_builtins||!codegen_results.crate_info.is_no_builtins.contains(&cnum);;let mut +archive=archive_builder_builder.new_archive_builder(sess);{;};if let Err(error)= +archive.add_archive(cratepath,Box::new(move|f|{if f==METADATA_FILENAME{3;return +true;;}let canonical=f.replace('-',"_");let is_rust_object=canonical.starts_with +(&canonical_name)&&looks_like_rust_object_file(f);loop{break;};if let _=(){};if +upstream_rust_objects_already_included&&is_rust_object&&is_builtins{;return true +;;}if bundled_lib_file_names.contains(&Symbol::intern(f)){return true;}false}),) +{();sess.dcx().emit_fatal(errors::RlibArchiveBuildFailure{error});3;}if archive. +build(&dst){;link_upstream(&dst);;}});}fn add_dynamic_crate(cmd:&mut dyn Linker, +sess:&Session,cratepath:&Path){3;let parent=cratepath.parent();3;if sess.target. +is_like_msvc&&!cratepath.with_extension("dll.lib").exists(){;return;}if let Some +(dir)=parent{;cmd.include_path(&rehome_sysroot_lib_dir(sess,dir));;};let stem=if +sess.target.is_like_msvc{cratepath.file_name()}else{cratepath.file_stem()};;;let +stem=stem.unwrap().to_str().unwrap();3;;let prefix=if stem.starts_with("lib")&&! +sess.target.is_like_windows{3}else{0};3;;cmd.link_dylib_by_name(&stem[prefix..], +false,true);;}fn relevant_lib(sess:&Session,lib:&NativeLib)->bool{match lib.cfg{ +Some(ref cfg)=>rustc_attr::cfg_matches(cfg, sess,CRATE_NODE_ID,None),None=>true, +}}pub(crate)fn are_upstream_rust_objects_already_included (sess:&Session)->bool{ +match ((sess.lto())){config::Lto::Fat=>(true),config::Lto::Thin=>{!sess.opts.cg. +linker_plugin_lto.enabled()}config::Lto::No|config::Lto::ThinLocal=>(false),}}fn +add_apple_sdk(cmd:&mut dyn Linker,sess:&Session,flavor:LinkerFlavor){;let arch=& +sess.target.arch;();();let os=&sess.target.os;();3;let llvm_target=&sess.target. +llvm_target;;if sess.target.vendor!="apple"||!matches!(os.as_ref(),"ios"|"tvos"| +"watchos"|"macos")||!matches!(flavor,LinkerFlavor::Darwin(..)){;return;;}if os== +"macos"&&!matches!(flavor,LinkerFlavor::Darwin(Cc::No,_)){;return;}let sdk_name= +match(((arch.as_ref()),os.as_ref())){("aarch64","tvos")if llvm_target.ends_with( +"-simulator")=>("appletvsimulator"),("aarch64","tvos")=>("appletvos"),("x86_64", +"tvos")=>(("appletvsimulator")),("arm","ios")=>("iphoneos"),("aarch64","ios")if +llvm_target.contains((("macabi")))=>("macosx" ),("aarch64","ios")if llvm_target. +ends_with("-simulator")=>"iphonesimulator", ("aarch64","ios")=>"iphoneos",("x86" +,"ios")=>("iphonesimulator"),("x86_64","ios")if llvm_target.contains("macabi")=> +"macosx",("x86_64","ios")=>(((((( "iphonesimulator")))))),("x86_64","watchos")=> +"watchsimulator",("arm64_32","watchos")=>(( "watchos")),("aarch64","watchos")if +llvm_target.ends_with(("-simulator"))=> "watchsimulator",("aarch64","watchos")=> +"watchos",("arm","watchos")=>"watchos",(_,"macos")=>"macosx",_=>{{;};sess.dcx(). +emit_err(errors::UnsupportedArch{arch,os});3;3;return;3;}};;;let sdk_root=match +get_apple_sdk_root(sdk_name){Ok(s)=>s,Err(e)=>{;sess.dcx().emit_err(e);return;}} +;{;};match flavor{LinkerFlavor::Darwin(Cc::Yes,_)=>{{;};cmd.args(&["-isysroot",& +sdk_root,"-Wl,-syslibroot",&sdk_root]);3;}LinkerFlavor::Darwin(Cc::No,_)=>{;cmd. +args(&["-syslibroot",&sdk_root]);{;};}_=>unreachable!(),}}fn get_apple_sdk_root( +sdk_name:&str)->Result>{if let Ok(sdkroot) +=env::var("SDKROOT"){3;let p=Path::new(&sdkroot);;match sdk_name{"appletvos" if +sdkroot.contains("TVSimulator.platform")|| sdkroot.contains("MacOSX.platform")=> +{}"appletvsimulator" if (sdkroot.contains(("TVOS.platform")))||sdkroot.contains( +"MacOSX.platform")=>{}"iphoneos" if sdkroot.contains("iPhoneSimulator.platform" +)||sdkroot.contains("MacOSX.platform") =>{}"iphonesimulator" if sdkroot.contains +("iPhoneOS.platform")||sdkroot.contains( "MacOSX.platform")=>{}"macosx10.15" if +sdkroot.contains((((((((((((("iPhoneOS.platform")))))))))))))||sdkroot.contains( +"iPhoneSimulator.platform")=>{}"watchos" if sdkroot.contains(//((),());let _=(); +"WatchSimulator.platform")||(((sdkroot.contains (((("MacOSX.platform")))))))=>{} +"watchsimulator" if (sdkroot.contains(( "WatchOS.platform")))||sdkroot.contains( +"MacOSX.platform")=>{}_ if!p.is_absolute()||p== Path::new("/")||!p.exists()=>{}_ +=>return Ok(sdkroot),}};let res=Command::new("xcrun").arg("--show-sdk-path").arg +("-sdk").arg(sdk_name).output().and_then (|output|{if output.status.success(){Ok +(String::from_utf8(output.stdout).unwrap())}else{();let error=String::from_utf8( +output.stderr);;let error=format!("process exit with error: {}",error.unwrap()); +Err(io::Error::new(io::ErrorKind::Other,&error[..]))}},);;match res{Ok(output)=> +Ok((((output.trim()).to_string())) ),Err(error)=>Err(errors::AppleSdkRootError:: +SdkPath{sdk_name,error}),}}fn add_lld_args(cmd:&mut dyn Linker,sess:&Session,//; +flavor:LinkerFlavor,self_contained_components:LinkSelfContainedComponents,){{;}; +debug!(//((),());let _=();let _=();let _=();let _=();let _=();let _=();let _=(); +"add_lld_args requested, flavor: '{:?}', target self-contained components: {:?}" +,flavor,self_contained_components,);3;if!(flavor.uses_cc()&&flavor.uses_lld()){; +return;((),());}((),());let self_contained_cli=sess.opts.cg.link_self_contained. +is_linker_enabled();{;};{;};let self_contained_target=self_contained_components. +is_linker_enabled();();3;let uses_llvm_backend=matches!(sess.opts.unstable_opts. +codegen_backend.as_deref(),None|Some("llvm"));let _=||();if!uses_llvm_backend&&! +self_contained_cli&&sess.opts.cg.linker_flavor.is_none(){{;};return;{;};}{;};let +self_contained_linker=self_contained_cli||self_contained_target;loop{break;};if +self_contained_linker&&(!sess.opts.cg.link_self_contained.is_linker_disabled()){ +for path in sess.get_tools_search_paths(false){;cmd.arg({;let mut arg=OsString:: +from("-B");;;arg.push(path.join("gcc-ld"));;arg});;}}cmd.arg("-fuse-ld=lld");if! +flavor.is_gnu(){if sess.target.linker_flavor!=sess.host.linker_flavor{3;cmd.arg( +format!("--target={}",sess.target.llvm_target));if let _=(){};*&*&();((),());}}} diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index f5640ea26bc8c..e7d449781abfd 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1,2063 +1,495 @@ -use super::command::Command; -use super::symbol_export; -use crate::back::link::SearchPaths; -use crate::errors; -use rustc_span::symbol::sym; - -use std::ffi::{OsStr, OsString}; -use std::fs::{self, File}; -use std::io::prelude::*; -use std::io::{self, BufWriter}; -use std::path::{Path, PathBuf}; -use std::{env, mem, str}; - -use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; -use rustc_metadata::find_native_static_library; -use rustc_middle::middle::dependency_format::Linkage; -use rustc_middle::middle::exported_symbols; -use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, SymbolExportKind}; -use rustc_middle::ty::TyCtxt; -use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip}; -use rustc_session::Session; -use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, Lld}; - -use cc::windows_registry; - -/// Disables non-English messages from localized linkers. -/// Such messages may cause issues with text encoding on Windows (#35785) -/// and prevent inspection of linker output in case of errors, which we occasionally do. -/// This should be acceptable because other messages from rustc are in English anyway, -/// and may also be desirable to improve searchability of the linker diagnostics. -pub fn disable_localization(linker: &mut Command) { - // No harm in setting both env vars simultaneously. - // Unix-style linkers. - linker.env("LC_ALL", "C"); - // MSVC's `link.exe`. - linker.env("VSLANG", "1033"); -} - -/// The third parameter is for env vars, used on windows to set up the -/// path for MSVC to find its DLLs, and gcc to find its bundled -/// toolchain -pub fn get_linker<'a>( - sess: &'a Session, - linker: &Path, - flavor: LinkerFlavor, - self_contained: bool, - target_cpu: &'a str, -) -> Box { - let msvc_tool = windows_registry::find_tool(sess.opts.target_triple.triple(), "link.exe"); - - // If our linker looks like a batch script on Windows then to execute this - // we'll need to spawn `cmd` explicitly. This is primarily done to handle - // emscripten where the linker is `emcc.bat` and needs to be spawned as - // `cmd /c emcc.bat ...`. - // - // This worked historically but is needed manually since #42436 (regression - // was tagged as #42791) and some more info can be found on #44443 for - // emscripten itself. - let mut cmd = match linker.to_str() { - Some(linker) if cfg!(windows) && linker.ends_with(".bat") => Command::bat_script(linker), - _ => match flavor { - 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), - }, - }; - - // UWP apps have API restrictions enforced during Store submissions. - // 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 matches!(flavor, LinkerFlavor::Msvc(..)) && t.vendor == "uwp" { - if let Some(ref tool) = msvc_tool { - let original_path = tool.path(); - if let Some(root_lib_path) = original_path.ancestors().nth(4) { - let arch = match t.arch.as_ref() { - "x86_64" => Some("x64"), - "x86" => Some("x86"), - "aarch64" => Some("arm64"), - "arm" => Some("arm"), - _ => None, - }; - if let Some(ref a) = arch { - // FIXME: Move this to `fn linker_with_args`. - let mut arg = OsString::from("/LIBPATH:"); - arg.push(format!("{}\\lib\\{}\\store", root_lib_path.display(), a)); - cmd.arg(&arg); - } else { - warn!("arch is not supported"); - } - } else { - warn!("MSVC root path lib location not found"); - } - } else { - warn!("link.exe not found"); - } - } - - // The compiler's sysroot often has some bundled tools, so add it to the - // PATH for the child. - let mut new_path = sess.get_tools_search_paths(self_contained); - let mut msvc_changed_path = false; - if sess.target.is_like_msvc { - if let Some(ref tool) = msvc_tool { - cmd.args(tool.args()); - for (k, v) in tool.env() { - if k == "PATH" { - new_path.extend(env::split_paths(v)); - msvc_changed_path = true; - } else { - cmd.env(k, v); - } - } - } - } - - if !msvc_changed_path { - if let Some(path) = env::var_os("PATH") { - new_path.extend(env::split_paths(&path)); - } - } - cmd.env("PATH", env::join_paths(new_path).unwrap()); - - // FIXME: Move `/LIBPATH` addition for uwp targets from the linker construction - // to the linker args construction. - assert!(cmd.get_args().is_empty() || sess.target.vendor == "uwp"); - match flavor { - LinkerFlavor::Unix(Cc::No) if sess.target.os == "l4re" => { - Box::new(L4Bender::new(cmd, sess)) as Box - } - LinkerFlavor::Unix(Cc::No) if sess.target.os == "aix" => { - Box::new(AixLinker::new(cmd, sess)) as Box - } - LinkerFlavor::WasmLld(Cc::No) => Box::new(WasmLd::new(cmd, sess)) as Box, - LinkerFlavor::Gnu(cc, _) - | LinkerFlavor::Darwin(cc, _) - | LinkerFlavor::WasmLld(cc) - | LinkerFlavor::Unix(cc) => Box::new(GccLinker { - cmd, - sess, - target_cpu, - hinted_static: None, - is_ld: cc == Cc::No, - is_gnu: flavor.is_gnu(), - }) as Box, - LinkerFlavor::Msvc(..) => Box::new(MsvcLinker { cmd, sess }) as Box, - LinkerFlavor::EmCc => Box::new(EmLinker { cmd, sess }) as Box, - LinkerFlavor::Bpf => Box::new(BpfLinker { cmd, sess }) as Box, - LinkerFlavor::Llbc => Box::new(LlbcLinker { cmd, sess }) as Box, - LinkerFlavor::Ptx => Box::new(PtxLinker { cmd, sess }) as Box, - } -} - -/// Linker abstraction used by `back::link` to build up the command to invoke a -/// linker. -/// -/// This trait is the total list of requirements needed by `back::link` and -/// represents the meaning of each option being passed down. This trait is then -/// used to dispatch on whether a GNU-like linker (generally `ld.exe`) or an -/// MSVC linker (e.g., `link.exe`) is being used. -pub trait Linker { - fn cmd(&mut self) -> &mut Command; - fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path); - fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, as_needed: bool); - fn link_framework_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { - bug!("framework linked with unsupported linker") - } - fn link_staticlib_by_name( - &mut self, - name: &str, - verbatim: bool, - whole_archive: bool, - search_paths: &SearchPaths, - ); - fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool); - fn include_path(&mut self, path: &Path); - fn framework_path(&mut self, path: &Path); - fn output_filename(&mut self, path: &Path); - fn add_object(&mut self, path: &Path); - fn gc_sections(&mut self, keep_metadata: bool); - fn no_gc_sections(&mut self); - fn full_relro(&mut self); - fn partial_relro(&mut self); - fn no_relro(&mut self); - fn optimize(&mut self); - fn pgo_gen(&mut self); - fn control_flow_guard(&mut self); - fn ehcont_guard(&mut self); - fn debuginfo(&mut self, strip: Strip, natvis_debugger_visualizers: &[PathBuf]); - fn no_crt_objects(&mut self); - fn no_default_libraries(&mut self); - fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]); - fn subsystem(&mut self, subsystem: &str); - fn linker_plugin_lto(&mut self); - fn add_eh_frame_header(&mut self) {} - fn add_no_exec(&mut self) {} - fn add_as_needed(&mut self) {} - fn reset_per_library_state(&mut self) {} - fn linker_arg(&mut self, arg: &OsStr, verbatim: bool) { - self.linker_args(&[arg], verbatim); - } - fn linker_args(&mut self, args: &[&OsStr], _verbatim: bool) { - args.into_iter().for_each(|a| { - self.cmd().arg(a); - }); - } -} - -impl dyn Linker + '_ { - pub fn arg(&mut self, arg: impl AsRef) { - self.cmd().arg(arg); - } - - pub fn args(&mut self, args: impl IntoIterator>) { - self.cmd().args(args); - } - - pub fn take_cmd(&mut self) -> Command { - mem::replace(self.cmd(), Command::new("")) - } -} - -pub struct GccLinker<'a> { - cmd: Command, - sess: &'a Session, - target_cpu: &'a str, - hinted_static: Option, // Keeps track of the current hinting mode. - // Link as ld - is_ld: bool, - is_gnu: bool, -} - -impl<'a> GccLinker<'a> { - fn linker_arg(&mut self, arg: impl AsRef) { - Linker::linker_arg(self, arg.as_ref(), false); - } - fn linker_args(&mut self, args: &[impl AsRef]) { - let args_vec: Vec<&OsStr> = args.iter().map(|x| x.as_ref()).collect(); - Linker::linker_args(self, &args_vec, false); - } - - fn takes_hints(&self) -> bool { - // Really this function only returns true if the underlying linker - // configured for a compiler is binutils `ld.bfd` and `ld.gold`. We - // don't really have a foolproof way to detect that, so rule out some - // platforms where currently this is guaranteed to *not* be the case: - // - // * On OSX they have their own linker, not binutils' - // * For WebAssembly the only functional linker is LLD, which doesn't - // support hint flags - !self.sess.target.is_like_osx && !self.sess.target.is_like_wasm - } - - // Some platforms take hints about whether a library is static or dynamic. - // For those that support this, we ensure we pass the option if the library - // was flagged "static" (most defaults are dynamic) to ensure that if - // libfoo.a and libfoo.so both exist that the right one is chosen. - fn hint_static(&mut self) { - if !self.takes_hints() { - return; - } - if self.hinted_static != Some(true) { - self.linker_arg("-Bstatic"); - self.hinted_static = Some(true); - } - } - - fn hint_dynamic(&mut self) { - if !self.takes_hints() { - return; - } - if self.hinted_static != Some(false) { - self.linker_arg("-Bdynamic"); - self.hinted_static = Some(false); - } - } - - fn push_linker_plugin_lto_args(&mut self, plugin_path: Option<&OsStr>) { - if let Some(plugin_path) = plugin_path { - let mut arg = OsString::from("-plugin="); - arg.push(plugin_path); - self.linker_arg(&arg); - } - - let opt_level = match self.sess.opts.optimize { - config::OptLevel::No => "O0", - config::OptLevel::Less => "O1", - config::OptLevel::Default | config::OptLevel::Size | config::OptLevel::SizeMin => "O2", - config::OptLevel::Aggressive => "O3", - }; - - if let Some(path) = &self.sess.opts.unstable_opts.profile_sample_use { - self.linker_arg(&format!("-plugin-opt=sample-profile={}", path.display())); - }; - self.linker_args(&[ - &format!("-plugin-opt={opt_level}"), - &format!("-plugin-opt=mcpu={}", self.target_cpu), - ]); - } - - fn build_dylib(&mut self, out_filename: &Path) { - // On mac we need to tell the linker to let this library be rpathed - if self.sess.target.is_like_osx { - if !self.is_ld { - self.cmd.arg("-dynamiclib"); - } - - self.linker_arg("-dylib"); - - // Note that the `osx_rpath_install_name` option here is a hack - // purely to support rustbuild right now, we should get a more - // principled solution at some point to force the compiler to pass - // the right `-Wl,-install_name` with an `@rpath` in it. - if self.sess.opts.cg.rpath || self.sess.opts.unstable_opts.osx_rpath_install_name { - let mut rpath = OsString::from("@rpath/"); - rpath.push(out_filename.file_name().unwrap()); - self.linker_args(&[OsString::from("-install_name"), rpath]); - } - } else { - self.cmd.arg("-shared"); - if self.sess.target.is_like_windows { - // The output filename already contains `dll_suffix` so - // the resulting import library will have a name in the - // form of libfoo.dll.a - let implib_name = - out_filename.file_name().and_then(|file| file.to_str()).map(|file| { - format!( - "{}{}{}", - self.sess.target.staticlib_prefix, - file, - self.sess.target.staticlib_suffix - ) - }); - if let Some(implib_name) = implib_name { - let implib = out_filename.parent().map(|dir| dir.join(&implib_name)); - if let Some(implib) = implib { - self.linker_arg(&format!("--out-implib={}", (*implib).to_str().unwrap())); - } - } - } - } - } -} - -impl<'a> Linker for GccLinker<'a> { - /// Passes a series of arguments directly to the linker. - /// - /// When the linker is ld-like, the arguments are simply appended to the command. When the - /// linker is not ld-like such as when using a compiler as a linker, the arguments are joined by - /// commas to form an argument that is then prepended with `-Wl`. In this situation, only a - /// single argument is appended to the command to ensure that the order of the arguments is - /// preserved by the compiler. - fn linker_args(&mut self, args: &[&OsStr], verbatim: bool) { - if self.is_ld || verbatim { - args.into_iter().for_each(|a| { - self.cmd.arg(a); - }); - } else { - if !args.is_empty() { - let mut s = OsString::from("-Wl"); - for a in args { - s.push(","); - s.push(a); - } - self.cmd.arg(s); - } - } - } - - fn cmd(&mut self) -> &mut Command { - &mut self.cmd - } - - fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) { - match output_kind { - LinkOutputKind::DynamicNoPicExe => { - if !self.is_ld && self.is_gnu { - self.cmd.arg("-no-pie"); - } - } - LinkOutputKind::DynamicPicExe => { - // noop on windows w/ gcc & ld, error w/ lld - if !self.sess.target.is_like_windows { - // `-pie` works for both gcc wrapper and ld. - self.cmd.arg("-pie"); - } - } - LinkOutputKind::StaticNoPicExe => { - // `-static` works for both gcc wrapper and ld. - self.cmd.arg("-static"); - if !self.is_ld && self.is_gnu { - self.cmd.arg("-no-pie"); - } - } - LinkOutputKind::StaticPicExe => { - if !self.is_ld { - // Note that combination `-static -pie` doesn't work as expected - // for the gcc wrapper, `-static` in that case suppresses `-pie`. - self.cmd.arg("-static-pie"); - } else { - // `--no-dynamic-linker` and `-z text` are not strictly necessary for producing - // a static pie, but currently passed because gcc and clang pass them. - // The former suppresses the `INTERP` ELF header specifying dynamic linker, - // which is otherwise implicitly injected by ld (but not lld). - // The latter doesn't change anything, only ensures that everything is pic. - self.cmd.args(&["-static", "-pie", "--no-dynamic-linker", "-z", "text"]); - } - } - LinkOutputKind::DynamicDylib => self.build_dylib(out_filename), - LinkOutputKind::StaticDylib => { - self.cmd.arg("-static"); - self.build_dylib(out_filename); - } - LinkOutputKind::WasiReactorExe => { - self.linker_args(&["--entry", "_initialize"]); - } - } - // VxWorks compiler driver introduced `--static-crt` flag specifically for rustc, - // it switches linking for libc and similar system libraries to static without using - // any `#[link]` attributes in the `libc` crate, see #72782 for details. - // FIXME: Switch to using `#[link]` attributes in the `libc` crate - // similarly to other targets. - if self.sess.target.os == "vxworks" - && matches!( - output_kind, - LinkOutputKind::StaticNoPicExe - | LinkOutputKind::StaticPicExe - | LinkOutputKind::StaticDylib - ) - { - self.cmd.arg("--static-crt"); - } - } - - fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, as_needed: bool) { - if self.sess.target.os == "illumos" && name == "c" { - // libc will be added via late_link_args on illumos so that it will - // appear last in the library search order. - // FIXME: This should be replaced by a more complete and generic - // mechanism for controlling the order of library arguments passed - // to the linker. - return; - } - if !as_needed { - if self.sess.target.is_like_osx { - // 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.dcx().emit_warn(errors::Ld64UnimplementedModifier); - } else if self.is_gnu && !self.sess.target.is_like_windows { - self.linker_arg("--no-as-needed"); - } else { - self.sess.dcx().emit_warn(errors::LinkerUnsupportedModifier); - } - } - self.hint_dynamic(); - self.cmd.arg(format!("-l{}{name}", if verbatim && self.is_gnu { ":" } else { "" },)); - if !as_needed { - if self.sess.target.is_like_osx { - // See above FIXME comment - } else if self.is_gnu && !self.sess.target.is_like_windows { - self.linker_arg("--as-needed"); - } - } - } - - fn link_framework_by_name(&mut self, name: &str, _verbatim: bool, as_needed: bool) { - self.hint_dynamic(); - if !as_needed { - // 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(name); - self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier); - } - self.cmd.arg("-framework").arg(name); - } - - fn link_staticlib_by_name( - &mut self, - name: &str, - verbatim: bool, - whole_archive: bool, - search_paths: &SearchPaths, - ) { - self.hint_static(); - let colon = if verbatim && self.is_gnu { ":" } else { "" }; - if !whole_archive { - self.cmd.arg(format!("-l{colon}{name}")); - } else if self.sess.target.is_like_osx { - // -force_load is the macOS equivalent of --whole-archive, but it - // involves passing the full path to the library to link. - self.linker_arg("-force_load"); - let search_paths = search_paths.get(self.sess); - self.linker_arg(find_native_static_library(name, verbatim, search_paths, self.sess)); - } else { - self.linker_arg("--whole-archive"); - self.cmd.arg(format!("-l{colon}{name}")); - self.linker_arg("--no-whole-archive"); - } - } - - fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) { - self.hint_static(); - if !whole_archive { - self.cmd.arg(path); - } else if self.sess.target.is_like_osx { - self.linker_arg("-force_load"); - self.linker_arg(path); - } else { - self.linker_arg("--whole-archive"); - self.linker_arg(path); - self.linker_arg("--no-whole-archive"); - } - } - - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); - } - fn framework_path(&mut self, path: &Path) { - self.cmd.arg("-F").arg(path); - } - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); - } - fn add_object(&mut self, path: &Path) { - self.cmd.arg(path); - } - fn full_relro(&mut self) { - self.linker_args(&["-z", "relro", "-z", "now"]); - } - fn partial_relro(&mut self) { - self.linker_args(&["-z", "relro"]); - } - fn no_relro(&mut self) { - self.linker_args(&["-z", "norelro"]); - } - - fn gc_sections(&mut self, keep_metadata: bool) { - // The dead_strip option to the linker specifies that functions and data - // unreachable by the entry point will be removed. This is quite useful - // with Rust's compilation model of compiling libraries at a time into - // one object file. For example, this brings hello world from 1.7MB to - // 458K. - // - // Note that this is done for both executables and dynamic libraries. We - // won't get much benefit from dylibs because LLVM will have already - // stripped away as much as it could. This has not been seen to impact - // link times negatively. - // - // -dead_strip can't be part of the pre_link_args because it's also used - // for partial linking when using multiple codegen units (-r). So we - // insert it here. - if self.sess.target.is_like_osx { - self.linker_arg("-dead_strip"); - - // If we're building a dylib, we don't use --gc-sections because LLVM - // has already done the best it can do, and we also don't want to - // 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.is_gnu || self.sess.target.is_like_wasm) && !keep_metadata { - self.linker_arg("--gc-sections"); - } - } - - fn no_gc_sections(&mut self) { - if self.is_gnu || self.sess.target.is_like_wasm { - self.linker_arg("--no-gc-sections"); - } - } - - fn optimize(&mut self) { - if !self.is_gnu && !self.sess.target.is_like_wasm { - return; - } - - // GNU-style linkers support optimization with -O. GNU ld doesn't - // need a numeric argument, but other linkers do. - if self.sess.opts.optimize == config::OptLevel::Default - || self.sess.opts.optimize == config::OptLevel::Aggressive - { - self.linker_arg("-O1"); - } - } - - fn pgo_gen(&mut self) { - if !self.is_gnu { - return; - } - - // If we're doing PGO generation stuff and on a GNU-like linker, use the - // "-u" flag to properly pull in the profiler runtime bits. - // - // This is because LLVM otherwise won't add the needed initialization - // for us on Linux (though the extra flag should be harmless if it - // does). - // - // See https://reviews.llvm.org/D14033 and https://reviews.llvm.org/D14030. - // - // Though it may be worth to try to revert those changes upstream, since - // the overhead of the initialization should be minor. - self.cmd.arg("-u"); - self.cmd.arg("__llvm_profile_runtime"); - } - - fn control_flow_guard(&mut self) {} - - fn ehcont_guard(&mut self) {} - - fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) { - // MacOS linker doesn't support stripping symbols directly anymore. - if self.sess.target.is_like_osx { - return; - } - - match strip { - Strip::None => {} - Strip::Debuginfo => { - // 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.is_like_solaris { - self.linker_arg("--strip-debug"); - } - } - Strip::Symbols => { - self.linker_arg("--strip-all"); - } - } - match self.sess.opts.unstable_opts.debuginfo_compression { - config::DebugInfoCompression::None => {} - config::DebugInfoCompression::Zlib => { - self.linker_arg("--compress-debug-sections=zlib"); - } - config::DebugInfoCompression::Zstd => { - self.linker_arg("--compress-debug-sections=zstd"); - } - } - } - - fn no_crt_objects(&mut self) { - if !self.is_ld { - self.cmd.arg("-nostartfiles"); - } - } - - fn no_default_libraries(&mut self) { - if !self.is_ld { - self.cmd.arg("-nodefaultlibs"); - } - } - - fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) { - // Symbol visibility in object files typically takes care of this. - if crate_type == CrateType::Executable { - let should_export_executable_symbols = - self.sess.opts.unstable_opts.export_executable_symbols; - if self.sess.target.override_export_symbols.is_none() - && !should_export_executable_symbols - { - return; - } - } - - // We manually create a list of exported symbols to ensure we don't expose any more. - // The object files have far more public symbols than we actually want to export, - // so we hide them all here. - - if !self.sess.target.limit_rdylib_exports { - return; - } - - let is_windows = self.sess.target.is_like_windows; - let path = tmpdir.join(if is_windows { "list.def" } else { "list" }); - - debug!("EXPORTED SYMBOLS:"); - - if self.sess.target.is_like_osx { - // Write a plain, newline-separated list of symbols - let res: io::Result<()> = try { - let mut f = BufWriter::new(File::create(&path)?); - for sym in symbols { - debug!(" _{sym}"); - writeln!(f, "_{sym}")?; - } - }; - if let Err(error) = res { - self.sess.dcx().emit_fatal(errors::LibDefWriteFailure { error }); - } - } else if is_windows { - let res: io::Result<()> = try { - let mut f = BufWriter::new(File::create(&path)?); - - // .def file similar to MSVC one but without LIBRARY section - // because LD doesn't like when it's empty - writeln!(f, "EXPORTS")?; - for symbol in symbols { - debug!(" _{symbol}"); - writeln!(f, " {symbol}")?; - } - }; - if let Err(error) = res { - self.sess.dcx().emit_fatal(errors::LibDefWriteFailure { error }); - } - } else { - // Write an LD version script - let res: io::Result<()> = try { - let mut f = BufWriter::new(File::create(&path)?); - writeln!(f, "{{")?; - if !symbols.is_empty() { - writeln!(f, " global:")?; - for sym in symbols { - debug!(" {sym};"); - writeln!(f, " {sym};")?; - } - } - writeln!(f, "\n local:\n *;\n}};")?; - }; - if let Err(error) = res { - self.sess.dcx().emit_fatal(errors::VersionScriptWriteFailure { error }); - } - } - - if self.sess.target.is_like_osx { - self.linker_args(&[OsString::from("-exported_symbols_list"), path.into()]); - } else if self.sess.target.is_like_solaris { - self.linker_args(&[OsString::from("-M"), path.into()]); - } else { - if is_windows { - self.linker_arg(path); - } else { - let mut arg = OsString::from("--version-script="); - arg.push(path); - self.linker_arg(arg); - self.linker_arg("--no-undefined-version"); - } - } - } - - fn subsystem(&mut self, subsystem: &str) { - self.linker_arg("--subsystem"); - self.linker_arg(&subsystem); - } - - fn reset_per_library_state(&mut self) { - self.hint_dynamic(); // Reset to default before returning the composed command line. - } - - fn linker_plugin_lto(&mut self) { - match self.sess.opts.cg.linker_plugin_lto { - LinkerPluginLto::Disabled => { - // Nothing to do - } - LinkerPluginLto::LinkerPluginAuto => { - self.push_linker_plugin_lto_args(None); - } - LinkerPluginLto::LinkerPlugin(ref path) => { - self.push_linker_plugin_lto_args(Some(path.as_os_str())); - } - } - } - - // Add the `GNU_EH_FRAME` program header which is required to locate unwinding information. - // Some versions of `gcc` add it implicitly, some (e.g. `musl-gcc`) don't, - // so we just always add it. - fn add_eh_frame_header(&mut self) { - self.linker_arg("--eh-frame-hdr"); - } - - fn add_no_exec(&mut self) { - if self.sess.target.is_like_windows { - self.linker_arg("--nxcompat"); - } else if self.is_gnu { - self.linker_args(&["-z", "noexecstack"]); - } - } - - fn add_as_needed(&mut self) { - 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 - self.linker_args(&["-z", "ignore"]); - } - } -} - -pub struct MsvcLinker<'a> { - cmd: Command, - sess: &'a Session, -} - -impl<'a> Linker for MsvcLinker<'a> { - fn cmd(&mut self) -> &mut Command { - &mut self.cmd - } - - fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) { - match output_kind { - LinkOutputKind::DynamicNoPicExe - | LinkOutputKind::DynamicPicExe - | LinkOutputKind::StaticNoPicExe - | LinkOutputKind::StaticPicExe => {} - LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => { - self.cmd.arg("/DLL"); - let mut arg: OsString = "/IMPLIB:".into(); - arg.push(out_filename.with_extension("dll.lib")); - self.cmd.arg(arg); - } - LinkOutputKind::WasiReactorExe => { - panic!("can't link as reactor on non-wasi target"); - } - } - } - - fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) { - self.cmd.arg(format!("{}{}", name, if verbatim { "" } else { ".lib" })); - } - - fn link_staticlib_by_name( - &mut self, - name: &str, - verbatim: bool, - whole_archive: bool, - _search_paths: &SearchPaths, - ) { - let prefix = if whole_archive { "/WHOLEARCHIVE:" } else { "" }; - let suffix = if verbatim { "" } else { ".lib" }; - self.cmd.arg(format!("{prefix}{name}{suffix}")); - } - - fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) { - if !whole_archive { - self.cmd.arg(path); - } else { - let mut arg = OsString::from("/WHOLEARCHIVE:"); - arg.push(path); - self.cmd.arg(arg); - } - } - - fn add_object(&mut self, path: &Path) { - self.cmd.arg(path); - } - - fn gc_sections(&mut self, _keep_metadata: bool) { - // MSVC's ICF (Identical COMDAT Folding) link optimization is - // slow for Rust and thus we disable it by default when not in - // optimization build. - if self.sess.opts.optimize != config::OptLevel::No { - self.cmd.arg("/OPT:REF,ICF"); - } else { - // It is necessary to specify NOICF here, because /OPT:REF - // implies ICF by default. - self.cmd.arg("/OPT:REF,NOICF"); - } - } - - fn no_gc_sections(&mut self) { - self.cmd.arg("/OPT:NOREF,NOICF"); - } - - fn full_relro(&mut self) { - // noop - } - - fn partial_relro(&mut self) { - // noop - } - - fn no_relro(&mut self) { - // noop - } - - fn no_crt_objects(&mut self) { - // noop - } - - fn no_default_libraries(&mut self) { - self.cmd.arg("/NODEFAULTLIB"); - } - - fn include_path(&mut self, path: &Path) { - let mut arg = OsString::from("/LIBPATH:"); - arg.push(path); - self.cmd.arg(&arg); - } - - fn output_filename(&mut self, path: &Path) { - let mut arg = OsString::from("/OUT:"); - arg.push(path); - self.cmd.arg(&arg); - } - - fn framework_path(&mut self, _path: &Path) { - bug!("frameworks are not supported on windows") - } - - fn optimize(&mut self) { - // Needs more investigation of `/OPT` arguments - } - - fn pgo_gen(&mut self) { - // Nothing needed here. - } - - fn control_flow_guard(&mut self) { - self.cmd.arg("/guard:cf"); - } - - fn ehcont_guard(&mut self) { - if self.sess.target.pointer_width == 64 { - self.cmd.arg("/guard:ehcont"); - } - } - - fn debuginfo(&mut self, strip: Strip, natvis_debugger_visualizers: &[PathBuf]) { - match strip { - Strip::None => { - // This will cause the Microsoft linker to generate a PDB file - // from the CodeView line tables in the object files. - self.cmd.arg("/DEBUG"); - - // Default to emitting only the file name of the PDB file into - // the binary instead of the full path. Emitting the full path - // may leak private information (such as user names). - // See https://github.com/rust-lang/rust/issues/87825. - // - // This default behavior can be overridden by explicitly passing - // `-Clink-arg=/PDBALTPATH:...` to rustc. - self.cmd.arg("/PDBALTPATH:%_PDB%"); - - // This will cause the Microsoft linker to embed .natvis info into the PDB file - let natvis_dir_path = self.sess.sysroot.join("lib\\rustlib\\etc"); - if let Ok(natvis_dir) = fs::read_dir(&natvis_dir_path) { - for entry in natvis_dir { - match entry { - Ok(entry) => { - let path = entry.path(); - if path.extension() == Some("natvis".as_ref()) { - let mut arg = OsString::from("/NATVIS:"); - arg.push(path); - self.cmd.arg(arg); - } - } - Err(error) => { - self.sess.dcx().emit_warn(errors::NoNatvisDirectory { error }); - } - } - } - } - - // This will cause the Microsoft linker to embed .natvis info for all crates into the PDB file - for path in natvis_debugger_visualizers { - let mut arg = OsString::from("/NATVIS:"); - arg.push(path); - self.cmd.arg(arg); - } - } - Strip::Debuginfo | Strip::Symbols => { - self.cmd.arg("/DEBUG:NONE"); - } - } - } - - // Currently the compiler doesn't use `dllexport` (an LLVM attribute) to - // export symbols from a dynamic library. When building a dynamic library, - // however, we're going to want some symbols exported, so this function - // generates a DEF file which lists all the symbols. - // - // The linker will read this `*.def` file and export all the symbols from - // the dynamic library. Note that this is not as simple as just exporting - // all the symbols in the current crate (as specified by `codegen.reachable`) - // but rather we also need to possibly export the symbols of upstream - // crates. Upstream rlibs may be linked statically to this dynamic library, - // in which case they may continue to transitively be used and hence need - // their symbols exported. - fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) { - // Symbol visibility takes care of this typically - if crate_type == CrateType::Executable { - let should_export_executable_symbols = - self.sess.opts.unstable_opts.export_executable_symbols; - if !should_export_executable_symbols { - return; - } - } - - let path = tmpdir.join("lib.def"); - let res: io::Result<()> = try { - let mut f = BufWriter::new(File::create(&path)?); - - // Start off with the standard module name header and then go - // straight to exports. - writeln!(f, "LIBRARY")?; - writeln!(f, "EXPORTS")?; - for symbol in symbols { - debug!(" _{symbol}"); - writeln!(f, " {symbol}")?; - } - }; - if let Err(error) = res { - self.sess.dcx().emit_fatal(errors::LibDefWriteFailure { error }); - } - let mut arg = OsString::from("/DEF:"); - arg.push(path); - self.cmd.arg(&arg); - } - - fn subsystem(&mut self, subsystem: &str) { - // Note that previous passes of the compiler validated this subsystem, - // so we just blindly pass it to the linker. - self.cmd.arg(&format!("/SUBSYSTEM:{subsystem}")); - - // Windows has two subsystems we're interested in right now, the console - // and windows subsystems. These both implicitly have different entry - // points (starting symbols). The console entry point starts with - // `mainCRTStartup` and the windows entry point starts with - // `WinMainCRTStartup`. These entry points, defined in system libraries, - // will then later probe for either `main` or `WinMain`, respectively to - // start the application. - // - // In Rust we just always generate a `main` function so we want control - // to always start there, so we force the entry point on the windows - // subsystem to be `mainCRTStartup` to get everything booted up - // correctly. - // - // For more information see RFC #1665 - if subsystem == "windows" { - self.cmd.arg("/ENTRY:mainCRTStartup"); - } - } - - fn linker_plugin_lto(&mut self) { - // Do nothing - } - - fn add_no_exec(&mut self) { - self.cmd.arg("/NXCOMPAT"); - } -} - -pub struct EmLinker<'a> { - cmd: Command, - sess: &'a Session, -} - -impl<'a> Linker for EmLinker<'a> { - fn cmd(&mut self) -> &mut Command { - &mut self.cmd - } - - fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} - - fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) { - // Emscripten always links statically - self.cmd.arg("-l").arg(name); - } - - fn link_staticlib_by_name( - &mut self, - name: &str, - _verbatim: bool, - _whole_archive: bool, - _search_paths: &SearchPaths, - ) { - self.cmd.arg("-l").arg(name); - } - - fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) { - self.cmd.arg(path); - } - - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); - } - - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); - } - - fn add_object(&mut self, path: &Path) { - self.cmd.arg(path); - } - - fn full_relro(&mut self) { - // noop - } - - fn partial_relro(&mut self) { - // noop - } - - fn no_relro(&mut self) { - // noop - } - - fn framework_path(&mut self, _path: &Path) { - bug!("frameworks are not supported on Emscripten") - } - - fn gc_sections(&mut self, _keep_metadata: bool) { - // noop - } - - fn no_gc_sections(&mut self) { - // noop - } - - fn optimize(&mut self) { - // Emscripten performs own optimizations - self.cmd.arg(match self.sess.opts.optimize { - OptLevel::No => "-O0", - OptLevel::Less => "-O1", - OptLevel::Default => "-O2", - OptLevel::Aggressive => "-O3", - OptLevel::Size => "-Os", - OptLevel::SizeMin => "-Oz", - }); - } - - fn pgo_gen(&mut self) { - // noop, but maybe we need something like the gnu linker? - } - - fn control_flow_guard(&mut self) {} - - fn ehcont_guard(&mut self) {} - - fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) { - // Preserve names or generate source maps depending on debug info - // For more information see https://emscripten.org/docs/tools_reference/emcc.html#emcc-g - self.cmd.arg(match self.sess.opts.debuginfo { - DebugInfo::None => "-g0", - DebugInfo::Limited | DebugInfo::LineTablesOnly | DebugInfo::LineDirectivesOnly => { - "--profiling-funcs" - } - DebugInfo::Full => "-g", - }); - } - - fn no_crt_objects(&mut self) {} - - fn no_default_libraries(&mut self) { - self.cmd.arg("-nodefaultlibs"); - } - - fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { - debug!("EXPORTED SYMBOLS:"); - - self.cmd.arg("-s"); - - let mut arg = OsString::from("EXPORTED_FUNCTIONS="); - let encoded = serde_json::to_string( - &symbols.iter().map(|sym| "_".to_owned() + sym).collect::>(), - ) - .unwrap(); - debug!("{encoded}"); - - arg.push(encoded); - - self.cmd.arg(arg); - } - - fn subsystem(&mut self, _subsystem: &str) { - // noop - } - - fn linker_plugin_lto(&mut self) { - // Do nothing - } -} - -pub struct WasmLd<'a> { - cmd: Command, - sess: &'a Session, -} - -impl<'a> WasmLd<'a> { - fn new(mut cmd: Command, sess: &'a Session) -> WasmLd<'a> { - // If the atomics feature is enabled for wasm then we need a whole bunch - // of flags: - // - // * `--shared-memory` - the link won't even succeed without this, flags - // the one linear memory as `shared` - // - // * `--max-memory=1G` - when specifying a shared memory this must also - // be specified. We conservatively choose 1GB but users should be able - // to override this with `-C link-arg`. - // - // * `--import-memory` - it doesn't make much sense for memory to be - // exported in a threaded module because typically you're - // sharing memory and instantiating the module multiple times. As a - // result if it were exported then we'd just have no sharing. - // - // 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"); - 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 } - } -} - -impl<'a> Linker for WasmLd<'a> { - fn cmd(&mut self) -> &mut Command { - &mut self.cmd - } - - fn set_output_kind(&mut self, output_kind: LinkOutputKind, _out_filename: &Path) { - match output_kind { - LinkOutputKind::DynamicNoPicExe - | LinkOutputKind::DynamicPicExe - | LinkOutputKind::StaticNoPicExe - | LinkOutputKind::StaticPicExe => {} - LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => { - self.cmd.arg("--no-entry"); - } - LinkOutputKind::WasiReactorExe => { - self.cmd.arg("--entry"); - self.cmd.arg("_initialize"); - } - } - } - - fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) { - self.cmd.arg("-l").arg(name); - } - - fn link_staticlib_by_name( - &mut self, - name: &str, - _verbatim: bool, - whole_archive: bool, - _search_paths: &SearchPaths, - ) { - if !whole_archive { - self.cmd.arg("-l").arg(name); - } else { - self.cmd.arg("--whole-archive").arg("-l").arg(name).arg("--no-whole-archive"); - } - } - - fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) { - if !whole_archive { - self.cmd.arg(path); - } else { - self.cmd.arg("--whole-archive").arg(path).arg("--no-whole-archive"); - } - } - - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); - } - - fn framework_path(&mut self, _path: &Path) { - panic!("frameworks not supported") - } - - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); - } - - fn add_object(&mut self, path: &Path) { - self.cmd.arg(path); - } - - fn full_relro(&mut self) {} - - fn partial_relro(&mut self) {} - - fn no_relro(&mut self) {} - - fn gc_sections(&mut self, _keep_metadata: bool) { - self.cmd.arg("--gc-sections"); - } - - fn no_gc_sections(&mut self) { - self.cmd.arg("--no-gc-sections"); - } - - fn optimize(&mut self) { - // The -O flag is, as of late 2023, only used for merging of strings and debuginfo, and - // only differentiates -O0 and -O1. It does not apply to LTO. - self.cmd.arg(match self.sess.opts.optimize { - OptLevel::No => "-O0", - OptLevel::Less => "-O1", - OptLevel::Default => "-O2", - OptLevel::Aggressive => "-O3", - // Currently LLD doesn't support `Os` and `Oz`, so pass through `O2` - // instead. - OptLevel::Size => "-O2", - OptLevel::SizeMin => "-O2", - }); - } - - fn pgo_gen(&mut self) {} - - fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) { - match strip { - Strip::None => {} - Strip::Debuginfo => { - self.cmd.arg("--strip-debug"); - } - Strip::Symbols => { - self.cmd.arg("--strip-all"); - } - } - } - - fn control_flow_guard(&mut self) {} - - fn ehcont_guard(&mut self) {} - - fn no_crt_objects(&mut self) {} - - fn no_default_libraries(&mut self) {} - - fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { - for sym in symbols { - self.cmd.arg("--export").arg(&sym); - } - - // 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 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) {} - - fn linker_plugin_lto(&mut self) { - match self.sess.opts.cg.linker_plugin_lto { - LinkerPluginLto::Disabled => { - // Nothing to do - } - LinkerPluginLto::LinkerPluginAuto => { - self.push_linker_plugin_lto_args(); - } - LinkerPluginLto::LinkerPlugin(_) => { - self.push_linker_plugin_lto_args(); - } - } - } -} - -impl<'a> WasmLd<'a> { - fn push_linker_plugin_lto_args(&mut self) { - let opt_level = match self.sess.opts.optimize { - config::OptLevel::No => "O0", - config::OptLevel::Less => "O1", - config::OptLevel::Default => "O2", - config::OptLevel::Aggressive => "O3", - // wasm-ld only handles integer LTO opt levels. Use O2 - config::OptLevel::Size | config::OptLevel::SizeMin => "O2", - }; - self.cmd.arg(&format!("--lto-{opt_level}")); - } -} - -/// Linker shepherd script for L4Re (Fiasco) -pub struct L4Bender<'a> { - cmd: Command, - sess: &'a Session, - hinted_static: bool, -} - -impl<'a> Linker for L4Bender<'a> { - fn cmd(&mut self) -> &mut Command { - &mut self.cmd - } - - fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} - - fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { - bug!("dylibs are not supported on L4Re"); - } - - fn link_staticlib_by_name( - &mut self, - name: &str, - _verbatim: bool, - whole_archive: bool, - _search_paths: &SearchPaths, - ) { - self.hint_static(); - if !whole_archive { - self.cmd.arg(format!("-PC{name}")); - } else { - self.cmd.arg("--whole-archive").arg(format!("-l{name}")).arg("--no-whole-archive"); - } - } - - fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) { - self.hint_static(); - if !whole_archive { - self.cmd.arg(path); - } else { - self.cmd.arg("--whole-archive").arg(path).arg("--no-whole-archive"); - } - } - - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); - } - fn framework_path(&mut self, _: &Path) { - bug!("frameworks are not supported on L4Re"); - } - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); - } - - fn add_object(&mut self, path: &Path) { - self.cmd.arg(path); - } - - fn full_relro(&mut self) { - self.cmd.arg("-z").arg("relro"); - self.cmd.arg("-z").arg("now"); - } - - fn partial_relro(&mut self) { - self.cmd.arg("-z").arg("relro"); - } - - fn no_relro(&mut self) { - self.cmd.arg("-z").arg("norelro"); - } - - fn gc_sections(&mut self, keep_metadata: bool) { - if !keep_metadata { - self.cmd.arg("--gc-sections"); - } - } - - fn no_gc_sections(&mut self) { - self.cmd.arg("--no-gc-sections"); - } - - fn optimize(&mut self) { - // GNU-style linkers support optimization with -O. GNU ld doesn't - // need a numeric argument, but other linkers do. - if self.sess.opts.optimize == config::OptLevel::Default - || self.sess.opts.optimize == config::OptLevel::Aggressive - { - self.cmd.arg("-O1"); - } - } - - fn pgo_gen(&mut self) {} - - fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) { - match strip { - Strip::None => {} - Strip::Debuginfo => { - self.cmd().arg("--strip-debug"); - } - Strip::Symbols => { - self.cmd().arg("--strip-all"); - } - } - } - - fn no_default_libraries(&mut self) { - self.cmd.arg("-nostdlib"); - } - - fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[String]) { - // ToDo, not implemented, copy from GCC - self.sess.dcx().emit_warn(errors::L4BenderExportingSymbolsUnimplemented); - return; - } - - fn subsystem(&mut self, subsystem: &str) { - self.cmd.arg(&format!("--subsystem {subsystem}")); - } - - fn reset_per_library_state(&mut self) { - self.hint_static(); // Reset to default before returning the composed command line. - } - - fn linker_plugin_lto(&mut self) {} - - fn control_flow_guard(&mut self) {} - - fn ehcont_guard(&mut self) {} - - fn no_crt_objects(&mut self) {} -} - -impl<'a> L4Bender<'a> { - pub fn new(cmd: Command, sess: &'a Session) -> L4Bender<'a> { - L4Bender { cmd: cmd, sess: sess, hinted_static: false } - } - - fn hint_static(&mut self) { - if !self.hinted_static { - self.cmd.arg("-static"); - self.hinted_static = true; - } - } -} - -/// Linker for AIX. -pub struct AixLinker<'a> { - cmd: Command, - sess: &'a Session, - hinted_static: Option, -} - -impl<'a> AixLinker<'a> { - pub fn new(cmd: Command, sess: &'a Session) -> AixLinker<'a> { - AixLinker { cmd: cmd, sess: sess, hinted_static: None } - } - - fn hint_static(&mut self) { - if self.hinted_static != Some(true) { - self.cmd.arg("-bstatic"); - self.hinted_static = Some(true); - } - } - - fn hint_dynamic(&mut self) { - if self.hinted_static != Some(false) { - self.cmd.arg("-bdynamic"); - self.hinted_static = Some(false); - } - } - - fn build_dylib(&mut self, _out_filename: &Path) { - self.cmd.arg("-bM:SRE"); - self.cmd.arg("-bnoentry"); - // FIXME: Use CreateExportList utility to create export list - // and remove -bexpfull. - self.cmd.arg("-bexpfull"); - } -} - -impl<'a> Linker for AixLinker<'a> { - fn cmd(&mut self) -> &mut Command { - &mut self.cmd - } - - fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) { - match output_kind { - LinkOutputKind::DynamicDylib => { - self.hint_dynamic(); - self.build_dylib(out_filename); - } - LinkOutputKind::StaticDylib => { - self.hint_static(); - self.build_dylib(out_filename); - } - _ => {} - } - } - - fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) { - self.hint_dynamic(); - self.cmd.arg(format!("-l{name}")); - } - - fn link_staticlib_by_name( - &mut self, - name: &str, - verbatim: bool, - whole_archive: bool, - search_paths: &SearchPaths, - ) { - self.hint_static(); - if !whole_archive { - self.cmd.arg(format!("-l{name}")); - } else { - let mut arg = OsString::from("-bkeepfile:"); - let search_path = search_paths.get(self.sess); - arg.push(find_native_static_library(name, verbatim, search_path, self.sess)); - self.cmd.arg(arg); - } - } - - fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) { - self.hint_static(); - if !whole_archive { - self.cmd.arg(path); - } else { - let mut arg = OsString::from("-bkeepfile:"); - arg.push(path); - self.cmd.arg(arg); - } - } - - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); - } - - fn framework_path(&mut self, _: &Path) { - bug!("frameworks are not supported on AIX"); - } - - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); - } - - fn add_object(&mut self, path: &Path) { - self.cmd.arg(path); - } - - fn full_relro(&mut self) {} - - fn partial_relro(&mut self) {} - - fn no_relro(&mut self) {} - - fn gc_sections(&mut self, _keep_metadata: bool) { - self.cmd.arg("-bgc"); - } - - fn no_gc_sections(&mut self) { - self.cmd.arg("-bnogc"); - } - - fn optimize(&mut self) {} - - fn pgo_gen(&mut self) { - self.cmd.arg("-bdbg:namedsects:ss"); - } - - fn control_flow_guard(&mut self) {} - - fn ehcont_guard(&mut self) {} - - fn debuginfo(&mut self, _: Strip, _: &[PathBuf]) {} - - fn no_crt_objects(&mut self) {} - - fn no_default_libraries(&mut self) {} - - fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { - let path = tmpdir.join("list.exp"); - let res: io::Result<()> = try { - let mut f = BufWriter::new(File::create(&path)?); - // FIXME: use llvm-nm to generate export list. - for symbol in symbols { - debug!(" _{symbol}"); - writeln!(f, " {symbol}")?; - } - }; - if let Err(e) = res { - self.sess.dcx().fatal(format!("failed to write export file: {e}")); - } - self.cmd.arg(format!("-bE:{}", path.to_str().unwrap())); - } - - fn subsystem(&mut self, _subsystem: &str) {} - - fn reset_per_library_state(&mut self) { - self.hint_dynamic(); - } - - fn linker_plugin_lto(&mut self) {} - - fn add_eh_frame_header(&mut self) {} - - fn add_no_exec(&mut self) {} - - fn add_as_needed(&mut self) {} -} - -fn for_each_exported_symbols_include_dep<'tcx>( - tcx: TyCtxt<'tcx>, - crate_type: CrateType, - mut callback: impl FnMut(ExportedSymbol<'tcx>, SymbolExportInfo, CrateNum), -) { - for &(symbol, info) in tcx.exported_symbols(LOCAL_CRATE).iter() { - callback(symbol, info, LOCAL_CRATE); - } - - let formats = tcx.dependency_formats(()); - let deps = formats.iter().find_map(|(t, list)| (*t == crate_type).then_some(list)).unwrap(); - - for (index, dep_format) in deps.iter().enumerate() { - let cnum = CrateNum::new(index + 1); - // For each dependency that we are linking to statically ... - if *dep_format == Linkage::Static { - for &(symbol, info) in tcx.exported_symbols(cnum).iter() { - callback(symbol, info, cnum); - } - } - } -} - -pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec { - if let Some(ref exports) = tcx.sess.target.override_export_symbols { - return exports.iter().map(ToString::to_string).collect(); - } - - if let CrateType::ProcMacro = crate_type { - exported_symbols_for_proc_macro_crate(tcx) - } else { - exported_symbols_for_non_proc_macro(tcx, crate_type) - } -} - -fn exported_symbols_for_non_proc_macro(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec { - let mut symbols = Vec::new(); - let export_threshold = symbol_export::crates_export_threshold(&[crate_type]); - for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| { - if info.level.is_below_threshold(export_threshold) { - symbols.push(symbol_export::exporting_symbol_name_for_instance_in_crate( - tcx, symbol, cnum, - )); - } - }); - - symbols -} - -fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec { - // `exported_symbols` will be empty when !should_codegen. - if !tcx.sess.opts.output_types.should_codegen() { - return Vec::new(); - } - - let stable_crate_id = tcx.stable_crate_id(LOCAL_CRATE); - let proc_macro_decls_name = tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id); - let metadata_symbol_name = exported_symbols::metadata_symbol_name(tcx); - - vec![proc_macro_decls_name, metadata_symbol_name] -} - -pub(crate) fn linked_symbols( - tcx: TyCtxt<'_>, - crate_type: CrateType, -) -> Vec<(String, SymbolExportKind)> { - match crate_type { - CrateType::Executable | CrateType::Cdylib | CrateType::Dylib => (), - CrateType::Staticlib | CrateType::ProcMacro | CrateType::Rlib => { - return Vec::new(); - } - } - - let mut symbols = Vec::new(); - - let export_threshold = symbol_export::crates_export_threshold(&[crate_type]); - for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| { - if info.level.is_below_threshold(export_threshold) || info.used { - symbols.push(( - symbol_export::linking_symbol_name_for_instance_in_crate(tcx, symbol, cnum), - info.kind, - )); - } - }); - - symbols -} - -/// Much simplified and explicit CLI for the NVPTX linker. The linker operates -/// with bitcode and uses LLVM backend to generate a PTX assembly. -pub struct PtxLinker<'a> { - cmd: Command, - sess: &'a Session, -} - -impl<'a> Linker for PtxLinker<'a> { - fn cmd(&mut self) -> &mut Command { - &mut self.cmd - } - - fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} - - fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { - panic!("external dylibs not supported") - } - - fn link_staticlib_by_name( - &mut self, - _name: &str, - _verbatim: bool, - _whole_archive: bool, - _search_paths: &SearchPaths, - ) { - panic!("staticlibs not supported") - } - - fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) { - self.cmd.arg("--rlib").arg(path); - } - - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); - } - - fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) { - self.cmd.arg("--debug"); - } - - fn add_object(&mut self, path: &Path) { - self.cmd.arg("--bitcode").arg(path); - } - - fn optimize(&mut self) { - match self.sess.lto() { - Lto::Thin | Lto::Fat | Lto::ThinLocal => { - self.cmd.arg("-Olto"); - } - - Lto::No => {} - } - } - - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); - } - - fn framework_path(&mut self, _path: &Path) { - panic!("frameworks not supported") - } - - fn full_relro(&mut self) {} - - fn partial_relro(&mut self) {} - - fn no_relro(&mut self) {} - - fn gc_sections(&mut self, _keep_metadata: bool) {} - - fn no_gc_sections(&mut self) {} - - fn pgo_gen(&mut self) {} - - fn no_crt_objects(&mut self) {} - - fn no_default_libraries(&mut self) {} - - fn control_flow_guard(&mut self) {} - - fn ehcont_guard(&mut self) {} - - fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, _symbols: &[String]) {} - - fn subsystem(&mut self, _subsystem: &str) {} - - fn linker_plugin_lto(&mut self) {} -} - -/// The `self-contained` LLVM bitcode linker -pub struct LlbcLinker<'a> { - cmd: Command, - sess: &'a Session, -} - -impl<'a> Linker for LlbcLinker<'a> { - fn cmd(&mut self) -> &mut Command { - &mut self.cmd - } - - fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} - - fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { - panic!("external dylibs not supported") - } - - fn link_staticlib_by_name( - &mut self, - _name: &str, - _verbatim: bool, - _whole_archive: bool, - _search_paths: &SearchPaths, - ) { - panic!("staticlibs not supported") - } - - fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) { - self.cmd.arg(path); - } - - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); - } - - fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) { - self.cmd.arg("--debug"); - } - - fn add_object(&mut self, path: &Path) { - self.cmd.arg(path); - } - - fn optimize(&mut self) { - match self.sess.opts.optimize { - OptLevel::No => "-O0", - OptLevel::Less => "-O1", - OptLevel::Default => "-O2", - OptLevel::Aggressive => "-O3", - OptLevel::Size => "-Os", - OptLevel::SizeMin => "-Oz", - }; - } - - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); - } - - fn framework_path(&mut self, _path: &Path) { - panic!("frameworks not supported") - } - - fn full_relro(&mut self) {} - - fn partial_relro(&mut self) {} - - fn no_relro(&mut self) {} - - fn gc_sections(&mut self, _keep_metadata: bool) {} - - fn no_gc_sections(&mut self) {} - - fn pgo_gen(&mut self) {} - - fn no_crt_objects(&mut self) {} - - fn no_default_libraries(&mut self) {} - - fn control_flow_guard(&mut self) {} - - fn ehcont_guard(&mut self) {} - - fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { - match _crate_type { - CrateType::Cdylib => { - for sym in symbols { - self.cmd.arg("--export-symbol").arg(sym); - } - } - _ => (), - } - } - - fn subsystem(&mut self, _subsystem: &str) {} - - fn linker_plugin_lto(&mut self) {} -} - -pub struct BpfLinker<'a> { - cmd: Command, - sess: &'a Session, -} - -impl<'a> Linker for BpfLinker<'a> { - fn cmd(&mut self) -> &mut Command { - &mut self.cmd - } - - fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} - - fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { - panic!("external dylibs not supported") - } - - fn link_staticlib_by_name( - &mut self, - _name: &str, - _verbatim: bool, - _whole_archive: bool, - _search_paths: &SearchPaths, - ) { - panic!("staticlibs not supported") - } - - fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) { - self.cmd.arg(path); - } - - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); - } - - fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) { - self.cmd.arg("--debug"); - } - - fn add_object(&mut self, path: &Path) { - self.cmd.arg(path); - } - - fn optimize(&mut self) { - self.cmd.arg(match self.sess.opts.optimize { - OptLevel::No => "-O0", - OptLevel::Less => "-O1", - OptLevel::Default => "-O2", - OptLevel::Aggressive => "-O3", - OptLevel::Size => "-Os", - OptLevel::SizeMin => "-Oz", - }); - } - - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); - } - - fn framework_path(&mut self, _path: &Path) { - panic!("frameworks not supported") - } - - fn full_relro(&mut self) {} - - fn partial_relro(&mut self) {} - - fn no_relro(&mut self) {} - - fn gc_sections(&mut self, _keep_metadata: bool) {} - - fn no_gc_sections(&mut self) {} - - fn pgo_gen(&mut self) {} - - fn no_crt_objects(&mut self) {} - - fn no_default_libraries(&mut self) {} - - fn control_flow_guard(&mut self) {} - - fn ehcont_guard(&mut self) {} - - fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { - let path = tmpdir.join("symbols"); - let res: io::Result<()> = try { - let mut f = BufWriter::new(File::create(&path)?); - for sym in symbols { - writeln!(f, "{sym}")?; - } - }; - if let Err(error) = res { - self.sess.dcx().emit_fatal(errors::SymbolFileWriteFailure { error }); - } else { - self.cmd.arg("--export-symbols").arg(&path); - } - } - - fn subsystem(&mut self, _subsystem: &str) {} - - fn linker_plugin_lto(&mut self) {} -} +use super::command::Command;use super::symbol_export;use crate::back::link:://3; +SearchPaths;use crate::errors;use rustc_span:: symbol::sym;use std::ffi::{OsStr, +OsString};use std::fs::{self,File};use std::io::prelude::*;use std::io::{self,// +BufWriter};use std::path::{Path,PathBuf}; use std::{env,mem,str};use rustc_hir:: +def_id::{CrateNum,LOCAL_CRATE};use rustc_metadata::find_native_static_library;// +use rustc_middle::middle::dependency_format:: Linkage;use rustc_middle::middle:: +exported_symbols;use rustc_middle::middle::exported_symbols::{ExportedSymbol,//; +SymbolExportInfo,SymbolExportKind};use rustc_middle::ty::TyCtxt;use//let _=||(); +rustc_session::config::{self,CrateType,DebugInfo,LinkerPluginLto,Lto,OptLevel,// +Strip};use rustc_session::Session;use rustc_target::spec::{Cc,LinkOutputKind,//; +LinkerFlavor,Lld};use cc::windows_registry ;pub fn disable_localization(linker:& +mut Command){3;linker.env("LC_ALL","C");3;3;linker.env("VSLANG","1033");;}pub fn +get_linker<'a>(sess:&'a Session ,linker:&Path,flavor:LinkerFlavor,self_contained +:bool,target_cpu:&'a str,)->Box{;let msvc_tool=windows_registry:: +find_tool(sess.opts.target_triple.triple(),"link.exe");;let mut cmd=match linker +.to_str(){Some(linker)if ((cfg!(windows ))&&linker.ends_with(".bat"))=>Command:: +bat_script(linker),_=>match flavor{LinkerFlavor::Gnu(Cc::No,Lld::Yes)|//((),()); +LinkerFlavor::Darwin(Cc::No,Lld::Yes)|LinkerFlavor::WasmLld(Cc::No)|//if true{}; +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),},};;;let t=&sess.target;;if matches!(flavor,LinkerFlavor:: +Msvc(..))&&t.vendor=="uwp"{if let Some(ref tool)=msvc_tool{();let original_path= +tool.path();();if let Some(root_lib_path)=original_path.ancestors().nth(4){3;let +arch=match t.arch.as_ref(){"x86_64"=>Some( "x64"),"x86"=>Some("x86"),"aarch64"=> +Some("arm64"),"arm"=>Some("arm"),_=>None,};;if let Some(ref a)=arch{let mut arg= +OsString::from("/LIBPATH:");;arg.push(format!("{}\\lib\\{}\\store",root_lib_path +.display(),a));;cmd.arg(&arg);}else{warn!("arch is not supported");}}else{warn!( +"MSVC root path lib location not found");;}}else{;warn!("link.exe not found");}} +let mut new_path=sess.get_tools_search_paths(self_contained);{();};{();};let mut +msvc_changed_path=false;{();};if sess.target.is_like_msvc{if let Some(ref tool)= +msvc_tool{3;cmd.args(tool.args());;for(k,v)in tool.env(){if k=="PATH"{;new_path. +extend(env::split_paths(v));;;msvc_changed_path=true;;}else{cmd.env(k,v);}}}}if! +msvc_changed_path{if let Some(path)=env::var_os("PATH"){();new_path.extend(env:: +split_paths(&path));;}}cmd.env("PATH",env::join_paths(new_path).unwrap());assert +!(cmd.get_args().is_empty()||sess.target.vendor=="uwp");let _=||();match flavor{ +LinkerFlavor::Unix(Cc::No)if (sess.target.os== "l4re")=>{Box::new(L4Bender::new( +cmd,sess))as Box}LinkerFlavor:: Unix(Cc::No)if sess.target.os=="aix" +=>{(Box::new(AixLinker::new(cmd,sess))as Box)}LinkerFlavor::WasmLld( +Cc::No)=>Box::new(WasmLd::new(cmd,sess ))as Box,LinkerFlavor::Gnu(cc +,_)|LinkerFlavor::Darwin(cc,_)| LinkerFlavor::WasmLld(cc)|LinkerFlavor::Unix(cc) +=>Box::new(GccLinker{cmd,sess,target_cpu ,hinted_static:None,is_ld:(cc==Cc::No), +is_gnu:(flavor.is_gnu()),})as Box,LinkerFlavor::Msvc(..)=>Box::new( +MsvcLinker{cmd,sess})as Box,LinkerFlavor::EmCc=>Box::new(EmLinker{// +cmd,sess})as Box,LinkerFlavor:: Bpf=>Box::new(BpfLinker{cmd,sess})as +Box,LinkerFlavor::Llbc=>(Box::new((LlbcLinker{cmd,sess})))as Box,LinkerFlavor::Ptx=>(Box::new(PtxLinker{cmd ,sess})as Box),}} +pub trait Linker{fn cmd(&mut self)->&mut Command;fn set_output_kind(&mut self,// +output_kind:LinkOutputKind,out_filename:&Path) ;fn link_dylib_by_name(&mut self, +name:&str,verbatim:bool,as_needed:bool);fn link_framework_by_name(&mut self,//3; +_name:&str,_verbatim:bool,_as_needed:bool){bug!(//*&*&();((),());*&*&();((),()); +"framework linked with unsupported linker")}fn link_staticlib_by_name(&mut self +,name:&str,verbatim:bool,whole_archive:bool,search_paths:&SearchPaths,);fn//{;}; +link_staticlib_by_path(&mut self,path:& Path,whole_archive:bool);fn include_path +(&mut self,path:&Path);fn framework_path(&mut self,path:&Path);fn//loop{break;}; +output_filename(&mut self,path:&Path);fn add_object(&mut self,path:&Path);fn//3; +gc_sections(&mut self,keep_metadata:bool);fn no_gc_sections(&mut self);fn//({}); +full_relro(&mut self);fn partial_relro(&mut self);fn no_relro(&mut self);fn//(); +optimize(&mut self);fn pgo_gen(&mut self);fn control_flow_guard(&mut self);fn//; +ehcont_guard(&mut self);fn debuginfo(&mut self,strip:Strip,//let _=();if true{}; +natvis_debugger_visualizers:&[PathBuf]);fn no_crt_objects(&mut self);fn//*&*&(); +no_default_libraries(&mut self);fn export_symbols(&mut self,tmpdir:&Path,//({}); +crate_type:CrateType,symbols:&[String]);fn subsystem(&mut self,subsystem:&str); +fn linker_plugin_lto(&mut self);fn add_eh_frame_header(&mut self){}fn//let _=(); +add_no_exec(&mut self){}fn add_as_needed(&mut self){}fn reset_per_library_state +(&mut self){}fn linker_arg(&mut self,arg:&OsStr,verbatim:bool){;self.linker_args +(&[arg],verbatim);;}fn linker_args(&mut self,args:&[&OsStr],_verbatim:bool){args +.into_iter().for_each(|a|{;self.cmd().arg(a);});}}impl dyn Linker+'_{pub fn arg( +&mut self,arg:impl AsRef){3;self.cmd().arg(arg);3;}pub fn args(&mut self, +args:impl IntoIterator>){{;};self.cmd().args(args);{;};}pub fn +take_cmd(&mut self)->Command{(mem::replace((self.cmd ()),Command::new("")))}}pub +struct GccLinker<'a>{cmd:Command,sess:&'a Session,target_cpu:&'a str,//let _=(); +hinted_static:Option,is_ld:bool,is_gnu:bool,}impl<'a>GccLinker<'a>{fn//(); +linker_arg(&mut self,arg:impl AsRef){;Linker::linker_arg(self,arg.as_ref( +),false);;}fn linker_args(&mut self,args:&[impl AsRef]){let args_vec:Vec< +&OsStr>=args.iter().map(|x|x.as_ref()).collect();();3;Linker::linker_args(self,& +args_vec,false);();}fn takes_hints(&self)->bool{!self.sess.target.is_like_osx&&! +self.sess.target.is_like_wasm}fn hint_static(&mut self){if!self.takes_hints(){3; +return;3;}if self.hinted_static!=Some(true){;self.linker_arg("-Bstatic");;;self. +hinted_static=Some(true);3;}}fn hint_dynamic(&mut self){if!self.takes_hints(){3; +return;;}if self.hinted_static!=Some(false){;self.linker_arg("-Bdynamic");;self. +hinted_static=Some(false);let _=||();}}fn push_linker_plugin_lto_args(&mut self, +plugin_path:Option<&OsStr>){if let Some(plugin_path)=plugin_path{();let mut arg= +OsString::from("-plugin=");;;arg.push(plugin_path);;;self.linker_arg(&arg);;}let +opt_level=match self.sess.opts.optimize{ config::OptLevel::No=>(("O0")),config:: +OptLevel::Less=>("O1"),config::OptLevel::Default|config::OptLevel::Size|config:: +OptLevel::SizeMin=>"O2",config::OptLevel::Aggressive=>"O3",};;if let Some(path)= +&self.sess.opts.unstable_opts.profile_sample_use{{();};self.linker_arg(&format!( +"-plugin-opt=sample-profile={}",path.display()));;};self.linker_args(&[&format!( +"-plugin-opt={opt_level}"),&format!("-plugin-opt=mcpu={}",self.target_cpu),]);;} +fn build_dylib(&mut self,out_filename:&Path ){if self.sess.target.is_like_osx{if +!self.is_ld{;self.cmd.arg("-dynamiclib");}self.linker_arg("-dylib");if self.sess +.opts.cg.rpath||self.sess.opts.unstable_opts.osx_rpath_install_name{({});let mut +rpath=OsString::from("@rpath/");;;rpath.push(out_filename.file_name().unwrap()); +self.linker_args(&[OsString::from("-install_name"),rpath]);;}}else{self.cmd.arg( +"-shared");3;if self.sess.target.is_like_windows{3;let implib_name=out_filename. +file_name().and_then(|file|file.to_str() ).map(|file|{format!("{}{}{}",self.sess +.target.staticlib_prefix,file,self.sess.target.staticlib_suffix)});;if let Some( +implib_name)=implib_name{();let implib=out_filename.parent().map(|dir|dir.join(& +implib_name));*&*&();if let Some(implib)=implib{*&*&();self.linker_arg(&format!( +"--out-implib={}",(*implib).to_str().unwrap()));((),());}}}}}}impl<'a>Linker for +GccLinker<'a>{fn linker_args(&mut self,args:&[&OsStr],verbatim:bool){if self.//; +is_ld||verbatim{;args.into_iter().for_each(|a|{self.cmd.arg(a);});}else{if!args. +is_empty(){;let mut s=OsString::from("-Wl");for a in args{s.push(",");s.push(a); +}{();};self.cmd.arg(s);{();};}}}fn cmd(&mut self)->&mut Command{&mut self.cmd}fn +set_output_kind(&mut self,output_kind:LinkOutputKind,out_filename:&Path){match// +output_kind{LinkOutputKind::DynamicNoPicExe=>{if!self.is_ld&&self.is_gnu{3;self. +cmd.arg("-no-pie");*&*&();}}LinkOutputKind::DynamicPicExe=>{if!self.sess.target. +is_like_windows{;self.cmd.arg("-pie");;}}LinkOutputKind::StaticNoPicExe=>{;self. +cmd.arg("-static");();if!self.is_ld&&self.is_gnu{();self.cmd.arg("-no-pie");3;}} +LinkOutputKind::StaticPicExe=>{if!self.is_ld{;self.cmd.arg("-static-pie");}else{ +self.cmd.args(&["-static","-pie","--no-dynamic-linker","-z","text"]);let _=();}} +LinkOutputKind::DynamicDylib=>(self. build_dylib(out_filename)),LinkOutputKind:: +StaticDylib=>{();self.cmd.arg("-static");();3;self.build_dylib(out_filename);3;} +LinkOutputKind::WasiReactorExe=>{;self.linker_args(&["--entry","_initialize"]);} +}if ((self.sess.target.os== ("vxworks")))&&matches!(output_kind,LinkOutputKind:: +StaticNoPicExe|LinkOutputKind::StaticPicExe|LinkOutputKind::StaticDylib){3;self. +cmd.arg("--static-crt");();}}fn link_dylib_by_name(&mut self,name:&str,verbatim: +bool,as_needed:bool){if self.sess.target.os=="illumos"&&name=="c"{3;return;;}if! +as_needed{if self.sess.target.is_like_osx{{;};self.sess.dcx().emit_warn(errors:: +Ld64UnimplementedModifier);loop{break;};}else if self.is_gnu&&!self.sess.target. +is_like_windows{();self.linker_arg("--no-as-needed");();}else{3;self.sess.dcx(). +emit_warn(errors::LinkerUnsupportedModifier);;}}self.hint_dynamic();self.cmd.arg +(format!("-l{}{name}",if verbatim&&self.is_gnu{":"}else{""},));3;if!as_needed{if +self.sess.target.is_like_osx{}else if self.is_gnu&&!self.sess.target.//let _=(); +is_like_windows{3;self.linker_arg("--as-needed");;}}}fn link_framework_by_name(& +mut self,name:&str,_verbatim:bool,as_needed:bool){{;};self.hint_dynamic();();if! +as_needed{;self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier);;};self. +cmd.arg("-framework").arg(name);;}fn link_staticlib_by_name(&mut self,name:&str, +verbatim:bool,whole_archive:bool,search_paths:&SearchPaths,){;self.hint_static() +;;let colon=if verbatim&&self.is_gnu{":"}else{""};if!whole_archive{self.cmd.arg( +format!("-l{colon}{name}"));({});}else if self.sess.target.is_like_osx{{;};self. +linker_arg("-force_load");;;let search_paths=search_paths.get(self.sess);;;self. +linker_arg(find_native_static_library(name,verbatim,search_paths,self.sess));3;} +else{;self.linker_arg("--whole-archive");self.cmd.arg(format!("-l{colon}{name}") +);;;self.linker_arg("--no-whole-archive");}}fn link_staticlib_by_path(&mut self, +path:&Path,whole_archive:bool){;self.hint_static();if!whole_archive{self.cmd.arg +(path);;}else if self.sess.target.is_like_osx{;self.linker_arg("-force_load");;; +self.linker_arg(path);;}else{self.linker_arg("--whole-archive");self.linker_arg( +path);;;self.linker_arg("--no-whole-archive");}}fn include_path(&mut self,path:& +Path){3;self.cmd.arg("-L").arg(path);;}fn framework_path(&mut self,path:&Path){; +self.cmd.arg("-F").arg(path);;}fn output_filename(&mut self,path:&Path){self.cmd +.arg("-o").arg(path);;}fn add_object(&mut self,path:&Path){;self.cmd.arg(path);} +fn full_relro(&mut self){{;};self.linker_args(&["-z","relro","-z","now"]);();}fn +partial_relro(&mut self){3;self.linker_args(&["-z","relro"]);3;}fn no_relro(&mut +self){{();};self.linker_args(&["-z","norelro"]);{();};}fn gc_sections(&mut self, +keep_metadata:bool){if self.sess.target.is_like_osx{loop{break};self.linker_arg( +"-dead_strip");if true{};}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.is_gnu||self.sess.target.is_like_wasm{let _=();let _=();self.linker_arg( +"--no-gc-sections");;}}fn optimize(&mut self){if!self.is_gnu&&!self.sess.target. +is_like_wasm{3;return;3;}if self.sess.opts.optimize==config::OptLevel::Default|| +self.sess.opts.optimize==config::OptLevel::Aggressive{;self.linker_arg("-O1");}} +fn pgo_gen(&mut self){if!self.is_gnu{;return;;};self.cmd.arg("-u");self.cmd.arg( +"__llvm_profile_runtime");3;}fn control_flow_guard(&mut self){}fn ehcont_guard(& +mut self){}fn debuginfo(&mut self,strip: Strip,_:&[PathBuf]){if self.sess.target +.is_like_osx{;return;}match strip{Strip::None=>{}Strip::Debuginfo=>{if!self.sess +.target.is_like_solaris{3;self.linker_arg("--strip-debug");;}}Strip::Symbols=>{; +self.linker_arg("--strip-all");loop{break};}}match self.sess.opts.unstable_opts. +debuginfo_compression{config::DebugInfoCompression::None=>{}config:://if true{}; +DebugInfoCompression::Zlib=>{;self.linker_arg("--compress-debug-sections=zlib"); +}config::DebugInfoCompression::Zstd=>{loop{break;};loop{break;};self.linker_arg( +"--compress-debug-sections=zstd");;}}}fn no_crt_objects(&mut self){if!self.is_ld +{3;self.cmd.arg("-nostartfiles");3;}}fn no_default_libraries(&mut self){if!self. +is_ld{;self.cmd.arg("-nodefaultlibs");}}fn export_symbols(&mut self,tmpdir:&Path +,crate_type:CrateType,symbols:&[String]){if crate_type==CrateType::Executable{3; +let should_export_executable_symbols=self.sess.opts.unstable_opts.//loop{break}; +export_executable_symbols;;if self.sess.target.override_export_symbols.is_none() +&&!should_export_executable_symbols{((),());return;*&*&();}}if!self.sess.target. +limit_rdylib_exports{;return;;};let is_windows=self.sess.target.is_like_windows; +let path=tmpdir.join(if is_windows{"list.def"}else{"list"});*&*&();{();};debug!( +"EXPORTED SYMBOLS:");;if self.sess.target.is_like_osx{let res:io::Result<()>=try +{3;let mut f=BufWriter::new(File::create(&path)?);3;for sym in symbols{3;debug!( +" _{sym}");;;writeln!(f,"_{sym}")?;;}};;if let Err(error)=res{;self.sess.dcx(). +emit_fatal(errors::LibDefWriteFailure{error});;}}else if is_windows{let res:io:: +Result<()>=try{();let mut f=BufWriter::new(File::create(&path)?);3;3;writeln!(f, +"EXPORTS")?;;for symbol in symbols{debug!(" _{symbol}");writeln!(f," {symbol}" +)?;{();};}};{();};if let Err(error)=res{({});self.sess.dcx().emit_fatal(errors:: +LibDefWriteFailure{error});();}}else{();let res:io::Result<()>=try{();let mut f= +BufWriter::new(File::create(&path)?);;;writeln!(f,"{{")?;;if!symbols.is_empty(){ +writeln!(f," global:")?;;for sym in symbols{;debug!(" {sym};");;;writeln!(f, +" {sym};")?;;}}writeln!(f,"\n local:\n *;\n}};")?;};if let Err(error)=res +{;self.sess.dcx().emit_fatal(errors::VersionScriptWriteFailure{error});}}if self +.sess.target.is_like_osx{if true{};let _=||();self.linker_args(&[OsString::from( +"-exported_symbols_list"),path.into()]);if let _=(){};}else if self.sess.target. +is_like_solaris{;self.linker_args(&[OsString::from("-M"),path.into()]);;}else{if +is_windows{({});self.linker_arg(path);({});}else{{;};let mut arg=OsString::from( +"--version-script=");3;;arg.push(path);;;self.linker_arg(arg);;;self.linker_arg( +"--no-undefined-version");{;};}}}fn subsystem(&mut self,subsystem:&str){();self. +linker_arg("--subsystem");((),());((),());self.linker_arg(&subsystem);*&*&();}fn +reset_per_library_state(&mut self){;self.hint_dynamic();;}fn linker_plugin_lto(& +mut self){match self.sess .opts.cg.linker_plugin_lto{LinkerPluginLto::Disabled=> +{}LinkerPluginLto::LinkerPluginAuto=>{;self.push_linker_plugin_lto_args(None);;} +LinkerPluginLto::LinkerPlugin(ref path)=>{;self.push_linker_plugin_lto_args(Some +(path.as_os_str()));{;};}}}fn add_eh_frame_header(&mut self){();self.linker_arg( +"--eh-frame-hdr");*&*&();((),());}fn add_no_exec(&mut self){if self.sess.target. +is_like_windows{();self.linker_arg("--nxcompat");();}else if self.is_gnu{3;self. +linker_args(&["-z","noexecstack"]);;}}fn add_as_needed(&mut self){if self.is_gnu +&&!self.sess.target.is_like_windows{();self.linker_arg("--as-needed");3;}else if +self.sess.target.is_like_solaris{();self.linker_args(&["-z","ignore"]);();}}}pub +struct MsvcLinker<'a>{cmd:Command,sess:&'a Session,}impl<'a>Linker for//((),()); +MsvcLinker<'a>{fn cmd(&mut self)->& mut Command{&mut self.cmd}fn set_output_kind +(&mut self,output_kind:LinkOutputKind,out_filename:&Path){match output_kind{//3; +LinkOutputKind::DynamicNoPicExe|LinkOutputKind::DynamicPicExe|LinkOutputKind::// +StaticNoPicExe|LinkOutputKind::StaticPicExe=>{}LinkOutputKind::DynamicDylib|//3; +LinkOutputKind::StaticDylib=>{();self.cmd.arg("/DLL");();3;let mut arg:OsString= +"/IMPLIB:".into();;arg.push(out_filename.with_extension("dll.lib"));self.cmd.arg +(arg);((),());let _=();}LinkOutputKind::WasiReactorExe=>{((),());((),());panic!( +"can't link as reactor on non-wasi target");;}}}fn link_dylib_by_name(&mut self, +name:&str,verbatim:bool,_as_needed:bool){{;};self.cmd.arg(format!("{}{}",name,if +verbatim{""}else{".lib"}));{();};}fn link_staticlib_by_name(&mut self,name:&str, +verbatim:bool,whole_archive:bool,_search_paths:&SearchPaths,){({});let prefix=if +whole_archive{"/WHOLEARCHIVE:"}else{""};;let suffix=if verbatim{""}else{".lib"}; +self.cmd.arg(format!("{prefix}{name}{suffix}"));;}fn link_staticlib_by_path(&mut +self,path:&Path,whole_archive:bool){if!whole_archive{;self.cmd.arg(path);;}else{ +let mut arg=OsString::from("/WHOLEARCHIVE:");;arg.push(path);self.cmd.arg(arg);} +}fn add_object(&mut self,path:&Path){3;self.cmd.arg(path);3;}fn gc_sections(&mut +self,_keep_metadata:bool){if self.sess.opts.optimize!=config::OptLevel::No{;self +.cmd.arg("/OPT:REF,ICF");({});}else{({});self.cmd.arg("/OPT:REF,NOICF");{;};}}fn +no_gc_sections(&mut self){;self.cmd.arg("/OPT:NOREF,NOICF");;}fn full_relro(&mut +self){}fn partial_relro(&mut self){} fn no_relro(&mut self){}fn no_crt_objects(& +mut self){}fn no_default_libraries(&mut self){;self.cmd.arg("/NODEFAULTLIB");}fn +include_path(&mut self,path:&Path){;let mut arg=OsString::from("/LIBPATH:");;arg +.push(path);;;self.cmd.arg(&arg);;}fn output_filename(&mut self,path:&Path){;let +mut arg=OsString::from("/OUT:");();3;arg.push(path);3;3;self.cmd.arg(&arg);3;}fn +framework_path(&mut self,_path:&Path){bug!(//((),());let _=();let _=();let _=(); +"frameworks are not supported on windows")}fn optimize(&mut self){}fn pgo_gen(& +mut self){}fn control_flow_guard(&mut self){{;};self.cmd.arg("/guard:cf");();}fn +ehcont_guard(&mut self){if self.sess.target.pointer_width==64{({});self.cmd.arg( +"/guard:ehcont");loop{break;};loop{break;};}}fn debuginfo(&mut self,strip:Strip, +natvis_debugger_visualizers:&[PathBuf]){match strip{Strip::None=>{;self.cmd.arg( +"/DEBUG");3;;self.cmd.arg("/PDBALTPATH:%_PDB%");;;let natvis_dir_path=self.sess. +sysroot.join("lib\\rustlib\\etc");if true{};if let Ok(natvis_dir)=fs::read_dir(& +natvis_dir_path){for entry in natvis_dir{match entry{Ok(entry)=>{;let path=entry +.path();;if path.extension()==Some("natvis".as_ref()){let mut arg=OsString::from +("/NATVIS:");;;arg.push(path);;self.cmd.arg(arg);}}Err(error)=>{self.sess.dcx(). +emit_warn(errors::NoNatvisDirectory{error});if true{};let _=||();}}}}for path in +natvis_debugger_visualizers{3;let mut arg=OsString::from("/NATVIS:");;;arg.push( +path);3;3;self.cmd.arg(arg);3;}}Strip::Debuginfo|Strip::Symbols=>{;self.cmd.arg( +"/DEBUG:NONE");;}}}fn export_symbols(&mut self,tmpdir:&Path,crate_type:CrateType +,symbols:&[String]){if crate_type==CrateType::Executable{if true{};if true{};let +should_export_executable_symbols=self.sess.opts.unstable_opts.//((),());((),()); +export_executable_symbols;;if!should_export_executable_symbols{return;}}let path +=tmpdir.join("lib.def");3;;let res:io::Result<()>=try{;let mut f=BufWriter::new( +File::create(&path)?);;;writeln!(f,"LIBRARY")?;writeln!(f,"EXPORTS")?;for symbol +in symbols{;debug!(" _{symbol}");writeln!(f," {symbol}")?;}};if let Err(error) +=res{;self.sess.dcx().emit_fatal(errors::LibDefWriteFailure{error});}let mut arg +=OsString::from("/DEF:");;;arg.push(path);;self.cmd.arg(&arg);}fn subsystem(&mut +self,subsystem:&str){{;};self.cmd.arg(&format!("/SUBSYSTEM:{subsystem}"));();if +subsystem=="windows"{let _=();self.cmd.arg("/ENTRY:mainCRTStartup");((),());}}fn +linker_plugin_lto(&mut self){}fn add_no_exec(&mut self){let _=||();self.cmd.arg( +"/NXCOMPAT");();}}pub struct EmLinker<'a>{cmd:Command,sess:&'a Session,}impl<'a> +Linker for EmLinker<'a>{fn cmd(&mut self)->&mut Command{((((&mut self.cmd))))}fn +set_output_kind(&mut self,_output_kind:LinkOutputKind,_out_filename:&Path){}fn// +link_dylib_by_name(&mut self,name:&str,_verbatim:bool,_as_needed:bool){;self.cmd +.arg("-l").arg(name);3;}fn link_staticlib_by_name(&mut self,name:&str,_verbatim: +bool,_whole_archive:bool,_search_paths:&SearchPaths,){();self.cmd.arg("-l").arg( +name);;}fn link_staticlib_by_path(&mut self,path:&Path,_whole_archive:bool){self +.cmd.arg(path);3;}fn include_path(&mut self,path:&Path){;self.cmd.arg("-L").arg( +path);;}fn output_filename(&mut self,path:&Path){;self.cmd.arg("-o").arg(path);} +fn add_object(&mut self,path:&Path){;self.cmd.arg(path);}fn full_relro(&mut self +){}fn partial_relro(&mut self){}fn no_relro(&mut self){}fn framework_path(&mut// +self,_path:&Path){ ((((bug!("frameworks are not supported on Emscripten")))))}fn +gc_sections(&mut self,_keep_metadata:bool){}fn no_gc_sections(&mut self){}fn//3; +optimize(&mut self){();self.cmd.arg(match self.sess.opts.optimize{OptLevel::No=> +"-O0",OptLevel::Less=>("-O1"),OptLevel ::Default=>("-O2"),OptLevel::Aggressive=> +"-O3",OptLevel::Size=>"-Os",OptLevel::SizeMin=>"-Oz",});;}fn pgo_gen(&mut self){ +}fn control_flow_guard(&mut self){}fn ehcont_guard(&mut self){}fn debuginfo(&//; +mut self,_strip:Strip,_:&[PathBuf]){;self.cmd.arg(match self.sess.opts.debuginfo +{DebugInfo::None=>("-g0"),DebugInfo::Limited|DebugInfo::LineTablesOnly|DebugInfo +::LineDirectivesOnly=>{"--profiling-funcs"}DebugInfo::Full=>"-g",});let _=();}fn +no_crt_objects(&mut self){}fn no_default_libraries(&mut self){({});self.cmd.arg( +"-nodefaultlibs");*&*&();}fn export_symbols(&mut self,_tmpdir:&Path,_crate_type: +CrateType,symbols:&[String]){;debug!("EXPORTED SYMBOLS:");self.cmd.arg("-s");let +mut arg=OsString::from("EXPORTED_FUNCTIONS=");({});({});let encoded=serde_json:: +to_string((&symbols.iter().map(|sym|"_". to_owned()+sym).collect::>()),). +unwrap();;debug!("{encoded}");arg.push(encoded);self.cmd.arg(arg);}fn subsystem( +&mut self,_subsystem:&str){}fn linker_plugin_lto(&mut self){}}pub struct WasmLd +<'a>{cmd:Command,sess:&'a Session,}impl<'a>WasmLd<'a>{fn new(mut cmd:Command,//; +sess:&'a Session)->WasmLd<'a>{if sess.target_features.contains(&sym::atomics){3; +cmd.arg("--shared-memory");();();cmd.arg("--max-memory=1073741824");3;3;cmd.arg( +"--import-memory");loop{break};if sess.target.os=="unknown"{loop{break};cmd.arg( +"--export=__wasm_init_tls");{;};();cmd.arg("--export=__tls_size");();();cmd.arg( +"--export=__tls_align");;cmd.arg("--export=__tls_base");}}WasmLd{cmd,sess}}}impl +<'a>Linker for WasmLd<'a>{fn cmd(&mut self)->&mut Command{(((&mut self.cmd)))}fn +set_output_kind(&mut self,output_kind: LinkOutputKind,_out_filename:&Path){match +output_kind{LinkOutputKind::DynamicNoPicExe|LinkOutputKind::DynamicPicExe|//{;}; +LinkOutputKind::StaticNoPicExe|LinkOutputKind:: StaticPicExe=>{}LinkOutputKind:: +DynamicDylib|LinkOutputKind::StaticDylib=>{({});self.cmd.arg("--no-entry");{;};} +LinkOutputKind::WasiReactorExe=>{{;};self.cmd.arg("--entry");();();self.cmd.arg( +"_initialize");({});}}}fn link_dylib_by_name(&mut self,name:&str,_verbatim:bool, +_as_needed:bool){3;self.cmd.arg("-l").arg(name);;}fn link_staticlib_by_name(&mut +self,name:&str,_verbatim:bool,whole_archive:bool,_search_paths:&SearchPaths,){// +if!whole_archive{({});self.cmd.arg("-l").arg(name);({});}else{({});self.cmd.arg( +"--whole-archive").arg("-l").arg(name).arg("--no-whole-archive");let _=||();}}fn +link_staticlib_by_path(&mut self,path:&Path,whole_archive:bool){if!//let _=||(); +whole_archive{;self.cmd.arg(path);}else{self.cmd.arg("--whole-archive").arg(path +).arg("--no-whole-archive");3;}}fn include_path(&mut self,path:&Path){;self.cmd. +arg("-L").arg(path);let _=||();}fn framework_path(&mut self,_path:&Path){panic!( +"frameworks not supported")}fn output_filename(&mut self,path:&Path){3;self.cmd. +arg("-o").arg(path);;}fn add_object(&mut self,path:&Path){self.cmd.arg(path);}fn +full_relro(&mut self){}fn partial_relro(&mut self){}fn no_relro(&mut self){}fn// +gc_sections(&mut self,_keep_metadata:bool){3;self.cmd.arg("--gc-sections");3;}fn +no_gc_sections(&mut self){3;self.cmd.arg("--no-gc-sections");3;}fn optimize(&mut +self){;self.cmd.arg(match self.sess.opts.optimize{OptLevel::No=>"-O0",OptLevel:: +Less=>"-O1",OptLevel::Default=>"-O2" ,OptLevel::Aggressive=>"-O3",OptLevel::Size +=>"-O2",OptLevel::SizeMin=>"-O2",});();}fn pgo_gen(&mut self){}fn debuginfo(&mut +self,strip:Strip,_:&[PathBuf]){match strip{Strip::None=>{}Strip::Debuginfo=>{(); +self.cmd.arg("--strip-debug");;}Strip::Symbols=>{self.cmd.arg("--strip-all");}}} +fn control_flow_guard(&mut self){}fn ehcont_guard(&mut self){}fn no_crt_objects +(&mut self){}fn no_default_libraries(&mut self){}fn export_symbols(&mut self,//; +_tmpdir:&Path,_crate_type:CrateType,symbols:&[String]){for sym in symbols{;self. +cmd.arg("--export").arg(&sym);;}if self.sess.target.os=="unknown"{;self.cmd.arg( +"--export=__heap_base");;self.cmd.arg("--export=__data_end");}}fn subsystem(&mut +self,_subsystem:&str){}fn linker_plugin_lto(&mut self){match self.sess.opts.cg// +.linker_plugin_lto{LinkerPluginLto::Disabled=>{}LinkerPluginLto:://loop{break;}; +LinkerPluginAuto=>{{;};self.push_linker_plugin_lto_args();{;};}LinkerPluginLto:: +LinkerPlugin(_)=>{;self.push_linker_plugin_lto_args();;}}}}impl<'a>WasmLd<'a>{fn +push_linker_plugin_lto_args(&mut self){{();};let opt_level=match self.sess.opts. +optimize{config::OptLevel::No=>(("O0")), config::OptLevel::Less=>("O1"),config:: +OptLevel::Default=>("O2"),config::OptLevel ::Aggressive=>"O3",config::OptLevel:: +Size|config::OptLevel::SizeMin=>"O2",};if true{};let _=();self.cmd.arg(&format!( +"--lto-{opt_level}"));();}}pub struct L4Bender<'a>{cmd:Command,sess:&'a Session, +hinted_static:bool,}impl<'a>Linker for L4Bender<'a>{fn cmd(&mut self)->&mut//(); +Command{&mut self.cmd}fn set_output_kind(&mut self,_output_kind:LinkOutputKind, +_out_filename:&Path){}fn link_dylib_by_name(& mut self,_name:&str,_verbatim:bool +,_as_needed:bool){let _=();bug!("dylibs are not supported on L4Re");let _=();}fn +link_staticlib_by_name(&mut self,name:&str,_verbatim:bool,whole_archive:bool,//; +_search_paths:&SearchPaths,){;self.hint_static();;if!whole_archive{self.cmd.arg( +format!("-PC{name}"));{;};}else{{;};self.cmd.arg("--whole-archive").arg(format!( +"-l{name}")).arg("--no-whole-archive");();}}fn link_staticlib_by_path(&mut self, +path:&Path,whole_archive:bool){;self.hint_static();if!whole_archive{self.cmd.arg +(path);;}else{self.cmd.arg("--whole-archive").arg(path).arg("--no-whole-archive" +);3;}}fn include_path(&mut self,path:&Path){3;self.cmd.arg("-L").arg(path);3;}fn +framework_path(&mut self,_:&Path){;bug!("frameworks are not supported on L4Re"); +}fn output_filename(&mut self,path:&Path){();self.cmd.arg("-o").arg(path);();}fn +add_object(&mut self,path:&Path){;self.cmd.arg(path);;}fn full_relro(&mut self){ +self.cmd.arg("-z").arg("relro");;self.cmd.arg("-z").arg("now");}fn partial_relro +(&mut self){;self.cmd.arg("-z").arg("relro");;}fn no_relro(&mut self){;self.cmd. +arg("-z").arg("norelro");{();};}fn gc_sections(&mut self,keep_metadata:bool){if! +keep_metadata{;self.cmd.arg("--gc-sections");}}fn no_gc_sections(&mut self){self +.cmd.arg("--no-gc-sections");;}fn optimize(&mut self){if self.sess.opts.optimize +==config::OptLevel::Default||self.sess.opts.optimize==config::OptLevel:://{();}; +Aggressive{;self.cmd.arg("-O1");}}fn pgo_gen(&mut self){}fn debuginfo(&mut self, +strip:Strip,_:&[PathBuf]){match strip{Strip::None=>{}Strip::Debuginfo=>{();self. +cmd().arg("--strip-debug");;}Strip::Symbols=>{;self.cmd().arg("--strip-all");}}} +fn no_default_libraries(&mut self){;self.cmd.arg("-nostdlib");}fn export_symbols +(&mut self,_:&Path,_:CrateType,_:&[String]){3;self.sess.dcx().emit_warn(errors:: +L4BenderExportingSymbolsUnimplemented);;return;}fn subsystem(&mut self,subsystem +:&str){if true{};self.cmd.arg(&format!("--subsystem {subsystem}"));if true{};}fn +reset_per_library_state(&mut self){3;self.hint_static();;}fn linker_plugin_lto(& +mut self){}fn control_flow_guard(&mut self){}fn ehcont_guard(&mut self){}fn//(); +no_crt_objects(&mut self){}}impl<'a>L4Bender<'a>{pub fn new(cmd:Command,sess:&// +'a Session)->L4Bender<'a>{(L4Bender{cmd:cmd,sess:sess,hinted_static:(false)})}fn +hint_static(&mut self){if!self.hinted_static{3;self.cmd.arg("-static");3;3;self. +hinted_static=true;{;};}}}pub struct AixLinker<'a>{cmd:Command,sess:&'a Session, +hinted_static:Option,}impl<'a>AixLinker<'a >{pub fn new(cmd:Command,sess:& +'a Session)->AixLinker<'a>{(AixLinker{cmd :cmd,sess:sess,hinted_static:None})}fn +hint_static(&mut self){if self.hinted_static!=Some(true){if true{};self.cmd.arg( +"-bstatic");;self.hinted_static=Some(true);}}fn hint_dynamic(&mut self){if self. +hinted_static!=Some(false){;self.cmd.arg("-bdynamic");;;self.hinted_static=Some( +false);;}}fn build_dylib(&mut self,_out_filename:&Path){self.cmd.arg("-bM:SRE"); +self.cmd.arg("-bnoentry");();();self.cmd.arg("-bexpfull");3;}}impl<'a>Linker for +AixLinker<'a>{fn cmd(&mut self)->& mut Command{&mut self.cmd}fn set_output_kind( +&mut self,output_kind:LinkOutputKind,out_filename:&Path){match output_kind{//(); +LinkOutputKind::DynamicDylib=>{{;};self.hint_dynamic();{;};{;};self.build_dylib( +out_filename);();}LinkOutputKind::StaticDylib=>{();self.hint_static();();3;self. +build_dylib(out_filename);{;};}_=>{}}}fn link_dylib_by_name(&mut self,name:&str, +_verbatim:bool,_as_needed:bool){();self.hint_dynamic();3;3;self.cmd.arg(format!( +"-l{name}"));{();};}fn link_staticlib_by_name(&mut self,name:&str,verbatim:bool, +whole_archive:bool,search_paths:&SearchPaths,){{();};self.hint_static();({});if! +whole_archive{3;self.cmd.arg(format!("-l{name}"));;}else{;let mut arg=OsString:: +from("-bkeepfile:");3;3;let search_path=search_paths.get(self.sess);3;;arg.push( +find_native_static_library(name,verbatim,search_path,self.sess));;;self.cmd.arg( +arg);;}}fn link_staticlib_by_path(&mut self,path:&Path,whole_archive:bool){self. +hint_static();;if!whole_archive{;self.cmd.arg(path);}else{let mut arg=OsString:: +from("-bkeepfile:");;;arg.push(path);;;self.cmd.arg(arg);;}}fn include_path(&mut +self,path:&Path){;self.cmd.arg("-L").arg(path);;}fn framework_path(&mut self,_:& +Path){;bug!("frameworks are not supported on AIX");}fn output_filename(&mut self +,path:&Path){;self.cmd.arg("-o").arg(path);}fn add_object(&mut self,path:&Path){ +self.cmd.arg(path);();}fn full_relro(&mut self){}fn partial_relro(&mut self){}fn +no_relro(&mut self){}fn gc_sections(&mut self,_keep_metadata:bool){;self.cmd.arg +("-bgc");;}fn no_gc_sections(&mut self){self.cmd.arg("-bnogc");}fn optimize(&mut +self){}fn pgo_gen(&mut self){{();};self.cmd.arg("-bdbg:namedsects:ss");{();};}fn +control_flow_guard(&mut self){}fn ehcont_guard(&mut self){}fn debuginfo(&mut//3; +self,_:Strip,_:&[PathBuf]){}fn no_crt_objects(&mut self){}fn//let _=();let _=(); +no_default_libraries(&mut self){}fn export_symbols(&mut self,tmpdir:&Path,//{;}; +_crate_type:CrateType,symbols:&[String]){;let path=tmpdir.join("list.exp");;;let +res:io::Result<()>=try{{;};let mut f=BufWriter::new(File::create(&path)?);();for +symbol in symbols{;debug!(" _{symbol}");writeln!(f," {symbol}")?;}};if let Err +(e)=res{3;self.sess.dcx().fatal(format!("failed to write export file: {e}"));;}; +self.cmd.arg(format!("-bE:{}",path.to_str().unwrap()));;}fn subsystem(&mut self, +_subsystem:&str){}fn reset_per_library_state(&mut self){;self.hint_dynamic();}fn +linker_plugin_lto(&mut self){}fn add_eh_frame_header(&mut self){}fn//let _=||(); +add_no_exec(&mut self){}fn add_as_needed(&mut self){}}fn//let _=||();let _=||(); +for_each_exported_symbols_include_dep<'tcx>(tcx:TyCtxt<'tcx>,crate_type://{();}; +CrateType,mut callback:impl FnMut(ExportedSymbol<'tcx>,SymbolExportInfo,//{();}; +CrateNum),){for&(symbol,info)in tcx.exported_symbols(LOCAL_CRATE).iter(){*&*&(); +callback(symbol,info,LOCAL_CRATE);;};let formats=tcx.dependency_formats(());;let +deps=formats.iter().find_map(|(t,list)| (*t==crate_type).then_some(list)).unwrap +();;for(index,dep_format)in deps.iter().enumerate(){let cnum=CrateNum::new(index ++1);{;};if*dep_format==Linkage::Static{for&(symbol,info)in tcx.exported_symbols( +cnum).iter(){;callback(symbol,info,cnum);;}}}}pub(crate)fn exported_symbols(tcx: +TyCtxt<'_>,crate_type:CrateType)->Vec {if let Some(ref exports)=tcx.sess +.target.override_export_symbols{;return exports.iter().map(ToString::to_string). +collect();*&*&();((),());*&*&();((),());}if let CrateType::ProcMacro=crate_type{ +exported_symbols_for_proc_macro_crate(tcx)}else{//*&*&();((),());*&*&();((),()); +exported_symbols_for_non_proc_macro(tcx,crate_type)}}fn//let _=||();loop{break}; +exported_symbols_for_non_proc_macro(tcx:TyCtxt<'_>,crate_type:CrateType)->Vec{();let mut symbols=Vec::new();();();let export_threshold=symbol_export:: +crates_export_threshold(&[crate_type]);3;;for_each_exported_symbols_include_dep( +tcx,crate_type,|symbol,info,cnum|{if info.level.is_below_threshold(//let _=||(); +export_threshold){((),());let _=();((),());let _=();symbols.push(symbol_export:: +exporting_symbol_name_for_instance_in_crate(tcx,symbol,cnum,));3;}});;symbols}fn +exported_symbols_for_proc_macro_crate(tcx:TyCtxt<'_>)->Vec {if!tcx.sess. +opts.output_types.should_codegen(){;return Vec::new();;}let stable_crate_id=tcx. +stable_crate_id(LOCAL_CRATE);((),());((),());let proc_macro_decls_name=tcx.sess. +generate_proc_macro_decls_symbol(stable_crate_id);();3;let metadata_symbol_name= +exported_symbols::metadata_symbol_name(tcx);let _=();vec![proc_macro_decls_name, +metadata_symbol_name]}pub(crate)fn linked_symbols(tcx:TyCtxt<'_>,crate_type://3; +CrateType,)->Vec<(String,SymbolExportKind)>{match crate_type{CrateType:://{();}; +Executable|CrateType::Cdylib|CrateType::Dylib =>((((())))),CrateType::Staticlib| +CrateType::ProcMacro|CrateType::Rlib=>{;return Vec::new();;}}let mut symbols=Vec +::new();({});({});let export_threshold=symbol_export::crates_export_threshold(&[ +crate_type]);;for_each_exported_symbols_include_dep(tcx,crate_type,|symbol,info, +cnum|{if info.level.is_below_threshold(export_threshold)||info.used{{;};symbols. +push((symbol_export::linking_symbol_name_for_instance_in_crate (tcx,symbol,cnum) +,info.kind,));;}});symbols}pub struct PtxLinker<'a>{cmd:Command,sess:&'a Session +,}impl<'a>Linker for PtxLinker<'a>{fn cmd(&mut self)->&mut Command{&mut self.//; +cmd}fn set_output_kind(&mut self,_output_kind:LinkOutputKind,_out_filename:&//3; +Path){}fn link_dylib_by_name(&mut self,_name:&str,_verbatim:bool,_as_needed://3; +bool){((panic!("external dylibs not supported")))}fn link_staticlib_by_name(&mut +self,_name:&str,_verbatim:bool ,_whole_archive:bool,_search_paths:&SearchPaths,) +{(panic!("staticlibs not supported"))}fn link_staticlib_by_path(&mut self,path:& +Path,_whole_archive:bool){3;self.cmd.arg("--rlib").arg(path);;}fn include_path(& +mut self,path:&Path){();self.cmd.arg("-L").arg(path);();}fn debuginfo(&mut self, +_strip:Strip,_:&[PathBuf]){3;self.cmd.arg("--debug");3;}fn add_object(&mut self, +path:&Path){;self.cmd.arg("--bitcode").arg(path);;}fn optimize(&mut self){match +self.sess.lto(){Lto::Thin|Lto::Fat|Lto::ThinLocal=>{;self.cmd.arg("-Olto");;}Lto +::No=>{}}}fn output_filename(&mut self,path:&Path){;self.cmd.arg("-o").arg(path) +;3;}fn framework_path(&mut self,_path:&Path){panic!("frameworks not supported")} +fn full_relro(&mut self){}fn partial_relro(& mut self){}fn no_relro(&mut self){} +fn gc_sections(&mut self,_keep_metadata:bool) {}fn no_gc_sections(&mut self){}fn +pgo_gen(&mut self){}fn no_crt_objects(&mut self){}fn no_default_libraries(&mut// +self){}fn control_flow_guard(&mut self){}fn ehcont_guard(&mut self){}fn//*&*&(); +export_symbols(&mut self,_tmpdir:&Path ,_crate_type:CrateType,_symbols:&[String] +){}fn subsystem(&mut self,_subsystem:&str){}fn linker_plugin_lto(&mut self){}}// +pub struct LlbcLinker<'a>{cmd:Command,sess:&'a Session,}impl<'a>Linker for//{;}; +LlbcLinker<'a>{fn cmd(&mut self)->& mut Command{&mut self.cmd}fn set_output_kind +(&mut self,_output_kind:LinkOutputKind,_out_filename:&Path){}fn//*&*&();((),()); +link_dylib_by_name(&mut self,_name:&str, _verbatim:bool,_as_needed:bool){panic!( +"external dylibs not supported")}fn link_staticlib_by_name( &mut self,_name:&str +,_verbatim:bool,_whole_archive:bool,_search_paths:&SearchPaths,){panic!(//{();}; +"staticlibs not supported")}fn link_staticlib_by_path(&mut self,path:&Path,//(); +_whole_archive:bool){;self.cmd.arg(path);}fn include_path(&mut self,path:&Path){ +self.cmd.arg("-L").arg(path);;}fn debuginfo(&mut self,_strip:Strip,_:&[PathBuf]) +{;self.cmd.arg("--debug");}fn add_object(&mut self,path:&Path){self.cmd.arg(path +);3;}fn optimize(&mut self){3;match self.sess.opts.optimize{OptLevel::No=>"-O0", +OptLevel::Less=>("-O1"),OptLevel::Default=> ("-O2"),OptLevel::Aggressive=>"-O3", +OptLevel::Size=>"-Os",OptLevel::SizeMin=>"-Oz",};;}fn output_filename(&mut self, +path:&Path){3;self.cmd.arg("-o").arg(path);;}fn framework_path(&mut self,_path:& +Path){(((((panic!("frameworks not supported"))))))} fn full_relro(&mut self){}fn +partial_relro(&mut self){}fn no_relro(&mut self){}fn gc_sections(&mut self,//(); +_keep_metadata:bool){}fn no_gc_sections(&mut self){}fn pgo_gen(&mut self){}fn//; +no_crt_objects(&mut self){}fn no_default_libraries(&mut self){}fn//loop{break;}; +control_flow_guard(&mut self){}fn ehcont_guard(&mut self){}fn export_symbols(&// +mut self,_tmpdir:&Path,_crate_type:CrateType,symbols:&[String]){match//let _=(); +_crate_type{CrateType::Cdylib=>{for sym in symbols{((),());((),());self.cmd.arg( +"--export-symbol").arg(sym);;}}_=>(),}}fn subsystem(&mut self,_subsystem:&str){} +fn linker_plugin_lto(&mut self){}}pub struct BpfLinker<'a>{cmd:Command,sess:&'a +Session,}impl<'a>Linker for BpfLinker<'a>{fn cmd(&mut self)->&mut Command{&mut// +self.cmd}fn set_output_kind(&mut self,_output_kind:LinkOutputKind,//loop{break}; +_out_filename:&Path){}fn link_dylib_by_name(& mut self,_name:&str,_verbatim:bool +,_as_needed:bool){((((((((((panic!("external dylibs not supported")))))))))))}fn +link_staticlib_by_name(&mut self,_name:& str,_verbatim:bool,_whole_archive:bool, +_search_paths:&SearchPaths,){(((((((panic!("staticlibs not supported"))))))))}fn +link_staticlib_by_path(&mut self,path:&Path,_whole_archive:bool){3;self.cmd.arg( +path);;}fn include_path(&mut self,path:&Path){;self.cmd.arg("-L").arg(path);;}fn +debuginfo(&mut self,_strip:Strip,_:&[PathBuf]){();self.cmd.arg("--debug");();}fn +add_object(&mut self,path:&Path){3;self.cmd.arg(path);;}fn optimize(&mut self){; +self.cmd.arg(match self.sess.opts. optimize{OptLevel::No=>"-O0",OptLevel::Less=> +"-O1",OptLevel::Default=>("-O2"),OptLevel ::Aggressive=>("-O3"),OptLevel::Size=> +"-Os",OptLevel::SizeMin=>"-Oz",});3;}fn output_filename(&mut self,path:&Path){3; +self.cmd.arg("-o").arg(path);3;}fn framework_path(&mut self,_path:&Path){panic!( +"frameworks not supported")}fn full_relro(&mut self){}fn partial_relro(&mut//(); +self){}fn no_relro(&mut self){}fn gc_sections(&mut self,_keep_metadata:bool){}// +fn no_gc_sections(&mut self){}fn pgo_gen(&mut self){}fn no_crt_objects(&mut//(); +self){}fn no_default_libraries(&mut self) {}fn control_flow_guard(&mut self){}fn +ehcont_guard(&mut self){}fn export_symbols(&mut self,tmpdir:&Path,_crate_type:// +CrateType,symbols:&[String]){;let path=tmpdir.join("symbols");let res:io::Result +<()>=try{3;let mut f=BufWriter::new(File::create(&path)?);3;for sym in symbols{; +writeln!(f,"{sym}")?;;}};if let Err(error)=res{self.sess.dcx().emit_fatal(errors +::SymbolFileWriteFailure{error});3;}else{;self.cmd.arg("--export-symbols").arg(& +path);;}}fn subsystem(&mut self,_subsystem:&str){}fn linker_plugin_lto(&mut self +){}}//let _=();let _=();let _=();if true{};let _=();let _=();let _=();if true{}; diff --git a/compiler/rustc_codegen_ssa/src/back/lto.rs b/compiler/rustc_codegen_ssa/src/back/lto.rs index cb6244050df24..6ff9f6c858490 100644 --- a/compiler/rustc_codegen_ssa/src/back/lto.rs +++ b/compiler/rustc_codegen_ssa/src/back/lto.rs @@ -1,104 +1,25 @@ -use super::write::CodegenContext; -use crate::traits::*; -use crate::ModuleCodegen; - -use rustc_data_structures::memmap::Mmap; -use rustc_errors::FatalError; - -use std::ffi::CString; -use std::sync::Arc; - -pub struct ThinModule { - pub shared: Arc>, - pub idx: usize, -} - -impl ThinModule { - pub fn name(&self) -> &str { - self.shared.module_names[self.idx].to_str().unwrap() - } - - pub fn cost(&self) -> u64 { - // Yes, that's correct, we're using the size of the bytecode as an - // indicator for how costly this codegen unit is. - self.data().len() as u64 - } - - pub fn data(&self) -> &[u8] { - let a = self.shared.thin_buffers.get(self.idx).map(|b| b.data()); - a.unwrap_or_else(|| { - let len = self.shared.thin_buffers.len(); - self.shared.serialized_modules[self.idx - len].data() - }) - } -} - -pub struct ThinShared { - pub data: B::ThinData, - pub thin_buffers: Vec, - pub serialized_modules: Vec>, - pub module_names: Vec, -} - -pub enum LtoModuleCodegen { - Fat { - module: ModuleCodegen, - _serialized_bitcode: Vec>, - }, - - Thin(ThinModule), -} - -impl LtoModuleCodegen { - pub fn name(&self) -> &str { - match *self { - LtoModuleCodegen::Fat { .. } => "everything", - LtoModuleCodegen::Thin(ref m) => m.name(), - } - } - - /// Optimize this module within the given codegen context. - /// - /// This function is unsafe as it'll return a `ModuleCodegen` still - /// points to LLVM data structures owned by this `LtoModuleCodegen`. - /// It's intended that the module returned is immediately code generated and - /// dropped, and then this LTO module is dropped. - pub unsafe fn optimize( - self, - cgcx: &CodegenContext, - ) -> Result, FatalError> { - match self { - LtoModuleCodegen::Fat { mut module, .. } => { - B::optimize_fat(cgcx, &mut module)?; - Ok(module) - } - LtoModuleCodegen::Thin(thin) => B::optimize_thin(cgcx, thin), - } - } - - /// A "gauge" of how costly it is to optimize this module, used to sort - /// biggest modules first. - pub fn cost(&self) -> u64 { - match *self { - // Only one module with fat LTO, so the cost doesn't matter. - LtoModuleCodegen::Fat { .. } => 0, - LtoModuleCodegen::Thin(ref m) => m.cost(), - } - } -} - -pub enum SerializedModule { - Local(M), - FromRlib(Vec), - FromUncompressedFile(Mmap), -} - -impl SerializedModule { - pub fn data(&self) -> &[u8] { - match *self { - SerializedModule::Local(ref m) => m.data(), - SerializedModule::FromRlib(ref m) => m, - SerializedModule::FromUncompressedFile(ref m) => m, - } - } -} +use super::write::CodegenContext;use crate ::traits::*;use crate::ModuleCodegen; +use rustc_data_structures::memmap::Mmap;use rustc_errors::FatalError;use std::// +ffi::CString;use std::sync::Arc;pub struct ThinModule{//; +pub shared:Arc>,pub idx:usize,}impl//{();}; +ThinModule{pub fn name(&self)->&str{(((self.shared.module_names[self.idx]))). +to_str().unwrap()}pub fn cost(&self)->u64{ self.data().len()as u64}pub fn data(& +self)->&[u8]{3;let a=self.shared.thin_buffers.get(self.idx).map(|b|b.data());;a. +unwrap_or_else(||{{();};let len=self.shared.thin_buffers.len();({});self.shared. +serialized_modules[((((((self.idx-len))))))].data() })}}pub struct ThinShared{pub data:B::ThinData,pub thin_buffers:Vec,// +pub serialized_modules:Vec>,pub module_names: +Vec,}pub enum LtoModuleCodegen{Fat{module://{;}; +ModuleCodegen,_serialized_bitcode:Vec>,},Thin(ThinModule),}impl//loop{break;}; +LtoModuleCodegen{pub fn name(&self)->&str{match(*self){LtoModuleCodegen::Fat{ +..}=>(("everything")),LtoModuleCodegen::Thin(ref m) =>(m.name()),}}pub unsafe fn +optimize(self,cgcx:&CodegenContext,)->Result,//({}); +FatalError>{match self{LtoModuleCodegen::Fat{mut module,..}=>{3;B::optimize_fat( +cgcx,&mut module)?;();Ok(module)}LtoModuleCodegen::Thin(thin)=>B::optimize_thin( +cgcx,thin),}}pub fn cost(&self)-> u64{match(*self){LtoModuleCodegen::Fat{..}=>0, +LtoModuleCodegen::Thin(ref m)=>((((m.cost( ))))),}}}pub enum SerializedModule{Local(M),FromRlib(Vec),FromUncompressedFile(Mmap),}//3; +implSerializedModule{pub fn data(&self)->&[u8]{match* +self{SerializedModule::Local(ref m)=>m .data(),SerializedModule::FromRlib(ref m) +=>m,SerializedModule::FromUncompressedFile(ref m)=>m,}}}//let _=||();let _=||(); diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index ab1bc0b6cd2eb..4e07e4793ab76 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -1,671 +1,188 @@ -//! Reading of the rustc metadata for rlibs and dylibs - -use std::borrow::Cow; -use std::fs::File; -use std::io::Write; -use std::path::Path; - -use object::write::{self, StandardSegment, Symbol, SymbolSection}; -use object::{ - elf, pe, xcoff, Architecture, BinaryFormat, Endianness, FileFlags, Object, ObjectSection, - ObjectSymbol, SectionFlags, SectionKind, SubArchitecture, SymbolFlags, SymbolKind, SymbolScope, -}; - -use rustc_data_structures::memmap::Mmap; -use rustc_data_structures::owned_slice::{try_slice_owned, OwnedSlice}; -use rustc_metadata::creader::MetadataLoader; -use rustc_metadata::fs::METADATA_FILENAME; -use rustc_metadata::EncodedMetadata; -use rustc_session::Session; -use rustc_span::sym; -use rustc_target::abi::Endian; -use rustc_target::spec::{ef_avr_arch, RelocModel, Target}; - -/// The default metadata loader. This is used by cg_llvm and cg_clif. -/// -/// # Metadata location -/// -///
-///
rlib
-///
The metadata can be found in the `lib.rmeta` file inside of the ar archive.
-///
dylib
-///
The metadata can be found in the `.rustc` section of the shared library.
-///
-#[derive(Debug)] -pub struct DefaultMetadataLoader; - -static AIX_METADATA_SYMBOL_NAME: &'static str = "__aix_rust_metadata"; - -fn load_metadata_with( - path: &Path, - f: impl for<'a> FnOnce(&'a [u8]) -> Result<&'a [u8], String>, -) -> Result { - let file = - File::open(path).map_err(|e| format!("failed to open file '{}': {}", path.display(), e))?; - - unsafe { Mmap::map(file) } - .map_err(|e| format!("failed to mmap file '{}': {}", path.display(), e)) - .and_then(|mmap| try_slice_owned(mmap, |mmap| f(mmap))) -} - -impl MetadataLoader for DefaultMetadataLoader { - fn get_rlib_metadata(&self, target: &Target, path: &Path) -> Result { - load_metadata_with(path, |data| { - let archive = object::read::archive::ArchiveFile::parse(&*data) - .map_err(|e| format!("failed to parse rlib '{}': {}", path.display(), e))?; - - for entry_result in archive.members() { - let entry = entry_result - .map_err(|e| format!("failed to parse rlib '{}': {}", path.display(), e))?; - if entry.name() == METADATA_FILENAME.as_bytes() { - let data = entry - .data(data) - .map_err(|e| format!("failed to parse rlib '{}': {}", path.display(), e))?; - if target.is_like_aix { - return get_metadata_xcoff(path, data); - } else { - return search_for_section(path, data, ".rmeta"); - } - } - } - - Err(format!("metadata not found in rlib '{}'", path.display())) - }) - } - - fn get_dylib_metadata(&self, target: &Target, path: &Path) -> Result { - if target.is_like_aix { - load_metadata_with(path, |data| get_metadata_xcoff(path, data)) - } else { - load_metadata_with(path, |data| search_for_section(path, data, ".rustc")) - } - } -} - -pub(super) fn search_for_section<'a>( - path: &Path, - bytes: &'a [u8], - section: &str, -) -> Result<&'a [u8], String> { - let Ok(file) = object::File::parse(bytes) else { - // The parse above could fail for odd reasons like corruption, but for - // now we just interpret it as this target doesn't support metadata - // emission in object files so the entire byte slice itself is probably - // a metadata file. Ideally though if necessary we could at least check - // the prefix of bytes to see if it's an actual metadata object and if - // not forward the error along here. - return Ok(bytes); - }; - file.section_by_name(section) - .ok_or_else(|| format!("no `{}` section in '{}'", section, path.display()))? - .data() - .map_err(|e| format!("failed to read {} section in '{}': {}", section, path.display(), e)) -} - -fn add_gnu_property_note( - file: &mut write::Object<'static>, - architecture: Architecture, - binary_format: BinaryFormat, - endianness: Endianness, -) { - // check bti protection - if binary_format != BinaryFormat::Elf - || !matches!(architecture, Architecture::X86_64 | Architecture::Aarch64) - { - return; - } - - let section = file.add_section( - file.segment_name(StandardSegment::Data).to_vec(), - b".note.gnu.property".to_vec(), - SectionKind::Note, - ); - let mut data: Vec = Vec::new(); - let n_namsz: u32 = 4; // Size of the n_name field - let n_descsz: u32 = 16; // Size of the n_desc field - let n_type: u32 = object::elf::NT_GNU_PROPERTY_TYPE_0; // Type of note descriptor - let header_values = [n_namsz, n_descsz, n_type]; - header_values.iter().for_each(|v| { - data.extend_from_slice(&match endianness { - Endianness::Little => v.to_le_bytes(), - Endianness::Big => v.to_be_bytes(), - }) - }); - data.extend_from_slice(b"GNU\0"); // Owner of the program property note - let pr_type: u32 = match architecture { - Architecture::X86_64 => object::elf::GNU_PROPERTY_X86_FEATURE_1_AND, - Architecture::Aarch64 => object::elf::GNU_PROPERTY_AARCH64_FEATURE_1_AND, - _ => unreachable!(), - }; - let pr_datasz: u32 = 4; //size of the pr_data field - let pr_data: u32 = 3; //program property descriptor - let pr_padding: u32 = 0; - let property_values = [pr_type, pr_datasz, pr_data, pr_padding]; - property_values.iter().for_each(|v| { - data.extend_from_slice(&match endianness { - Endianness::Little => v.to_le_bytes(), - Endianness::Big => v.to_be_bytes(), - }) - }); - file.append_section_data(section, &data, 8); -} - -pub(super) fn get_metadata_xcoff<'a>(path: &Path, data: &'a [u8]) -> Result<&'a [u8], String> { - let Ok(file) = object::File::parse(data) else { - return Ok(data); - }; - let info_data = search_for_section(path, data, ".info")?; - if let Some(metadata_symbol) = - file.symbols().find(|sym| sym.name() == Ok(AIX_METADATA_SYMBOL_NAME)) - { - let offset = metadata_symbol.address() as usize; - // The offset specifies the location of rustc metadata in the .info section of XCOFF. - // Each string stored in .info section of XCOFF is preceded by a 4-byte length field. - if offset < 4 { - return Err(format!("Invalid metadata symbol offset: {offset}")); - } - // XCOFF format uses big-endian byte order. - let len = u32::from_be_bytes(info_data[(offset - 4)..offset].try_into().unwrap()) as usize; - if offset + len > (info_data.len() as usize) { - return Err(format!( - "Metadata at offset {offset} with size {len} is beyond .info section" - )); - } - return Ok(&info_data[offset..(offset + len)]); - } else { - return Err(format!("Unable to find symbol {AIX_METADATA_SYMBOL_NAME}")); - }; -} - -pub(crate) fn create_object_file(sess: &Session) -> Option> { - let endianness = match sess.target.options.endian { - Endian::Little => Endianness::Little, - Endian::Big => Endianness::Big, - }; - let (architecture, sub_architecture) = match &sess.target.arch[..] { - "arm" => (Architecture::Arm, None), - "aarch64" => ( - if sess.target.pointer_width == 32 { - Architecture::Aarch64_Ilp32 - } else { - Architecture::Aarch64 - }, - None, - ), - "x86" => (Architecture::I386, None), - "s390x" => (Architecture::S390x, None), - "mips" | "mips32r6" => (Architecture::Mips, None), - "mips64" | "mips64r6" => (Architecture::Mips64, None), - "x86_64" => ( - if sess.target.pointer_width == 32 { - Architecture::X86_64_X32 - } else { - Architecture::X86_64 - }, - None, - ), - "powerpc" => (Architecture::PowerPc, None), - "powerpc64" => (Architecture::PowerPc64, None), - "riscv32" => (Architecture::Riscv32, None), - "riscv64" => (Architecture::Riscv64, None), - "sparc64" => (Architecture::Sparc64, None), - "avr" => (Architecture::Avr, None), - "msp430" => (Architecture::Msp430, None), - "hexagon" => (Architecture::Hexagon, None), - "bpf" => (Architecture::Bpf, None), - "loongarch64" => (Architecture::LoongArch64, None), - "csky" => (Architecture::Csky, None), - "arm64ec" => (Architecture::Aarch64, Some(SubArchitecture::Arm64EC)), - // Unsupported architecture. - _ => return None, - }; - let binary_format = if sess.target.is_like_osx { - BinaryFormat::MachO - } else if sess.target.is_like_windows { - BinaryFormat::Coff - } else if sess.target.is_like_aix { - BinaryFormat::Xcoff - } else { - BinaryFormat::Elf - }; - - let mut file = write::Object::new(binary_format, architecture, endianness); - file.set_sub_architecture(sub_architecture); - if sess.target.is_like_osx { - if macho_is_arm64e(&sess.target) { - file.set_macho_cpu_subtype(object::macho::CPU_SUBTYPE_ARM64E); - } - - file.set_macho_build_version(macho_object_build_version_for_target(&sess.target)) - } - if binary_format == BinaryFormat::Coff { - // Disable the default mangler to avoid mangling the special "@feat.00" symbol name. - let original_mangling = file.mangling(); - file.set_mangling(object::write::Mangling::None); - - let mut feature = 0; - - if file.architecture() == object::Architecture::I386 { - // When linking with /SAFESEH on x86, lld requires that all linker inputs be marked as - // safe exception handling compatible. Metadata files masquerade as regular COFF - // objects and are treated as linker inputs, despite containing no actual code. Thus, - // they still need to be marked as safe exception handling compatible. See #96498. - // Reference: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format - feature |= 1; - } - - file.add_symbol(object::write::Symbol { - name: "@feat.00".into(), - value: feature, - size: 0, - kind: object::SymbolKind::Data, - scope: object::SymbolScope::Compilation, - weak: false, - section: object::write::SymbolSection::Absolute, - flags: object::SymbolFlags::None, - }); - - file.set_mangling(original_mangling); - } - let e_flags = match architecture { - Architecture::Mips => { - let arch = match sess.target.options.cpu.as_ref() { - "mips1" => elf::EF_MIPS_ARCH_1, - "mips2" => elf::EF_MIPS_ARCH_2, - "mips3" => elf::EF_MIPS_ARCH_3, - "mips4" => elf::EF_MIPS_ARCH_4, - "mips5" => elf::EF_MIPS_ARCH_5, - s if s.contains("r6") => elf::EF_MIPS_ARCH_32R6, - _ => elf::EF_MIPS_ARCH_32R2, - }; - - let mut e_flags = elf::EF_MIPS_CPIC | arch; - - // If the ABI is explicitly given, use it or default to O32. - match sess.target.options.llvm_abiname.to_lowercase().as_str() { - "n32" => e_flags |= elf::EF_MIPS_ABI2, - "o32" => e_flags |= elf::EF_MIPS_ABI_O32, - _ => e_flags |= elf::EF_MIPS_ABI_O32, - }; - - if sess.target.options.relocation_model != RelocModel::Static { - e_flags |= elf::EF_MIPS_PIC; - } - if sess.target.options.cpu.contains("r6") { - e_flags |= elf::EF_MIPS_NAN2008; - } - e_flags - } - Architecture::Mips64 => { - // copied from `mips64el-linux-gnuabi64-gcc foo.c -c` - let e_flags = elf::EF_MIPS_CPIC - | elf::EF_MIPS_PIC - | if sess.target.options.cpu.contains("r6") { - elf::EF_MIPS_ARCH_64R6 | elf::EF_MIPS_NAN2008 - } else { - elf::EF_MIPS_ARCH_64R2 - }; - e_flags - } - Architecture::Riscv32 | Architecture::Riscv64 => { - // Source: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/079772828bd10933d34121117a222b4cc0ee2200/riscv-elf.adoc - let mut e_flags: u32 = 0x0; - - // Check if compressed is enabled - // `unstable_target_features` is used here because "c" is gated behind riscv_target_feature. - if sess.unstable_target_features.contains(&sym::c) { - e_flags |= elf::EF_RISCV_RVC; - } - - // Set the appropriate flag based on ABI - // This needs to match LLVM `RISCVELFStreamer.cpp` - match &*sess.target.llvm_abiname { - "" | "ilp32" | "lp64" => (), - "ilp32f" | "lp64f" => e_flags |= elf::EF_RISCV_FLOAT_ABI_SINGLE, - "ilp32d" | "lp64d" => e_flags |= elf::EF_RISCV_FLOAT_ABI_DOUBLE, - "ilp32e" => e_flags |= elf::EF_RISCV_RVE, - _ => bug!("unknown RISC-V ABI name"), - } - - e_flags - } - Architecture::LoongArch64 => { - // Source: https://github.com/loongson/la-abi-specs/blob/release/laelf.adoc#e_flags-identifies-abi-type-and-version - let mut e_flags: u32 = elf::EF_LARCH_OBJABI_V1; - - // Set the appropriate flag based on ABI - // This needs to match LLVM `LoongArchELFStreamer.cpp` - match &*sess.target.llvm_abiname { - "ilp32s" | "lp64s" => e_flags |= elf::EF_LARCH_ABI_SOFT_FLOAT, - "ilp32f" | "lp64f" => e_flags |= elf::EF_LARCH_ABI_SINGLE_FLOAT, - "ilp32d" | "lp64d" => e_flags |= elf::EF_LARCH_ABI_DOUBLE_FLOAT, - _ => bug!("unknown LoongArch ABI name"), - } - - e_flags - } - Architecture::Avr => { - // Resolve the ISA revision and set - // the appropriate EF_AVR_ARCH flag. - ef_avr_arch(&sess.target.options.cpu) - } - Architecture::Csky => { - let e_flags = match sess.target.options.abi.as_ref() { - "abiv2" => elf::EF_CSKY_ABIV2, - _ => elf::EF_CSKY_ABIV1, - }; - e_flags - } - _ => 0, - }; - // adapted from LLVM's `MCELFObjectTargetWriter::getOSABI` - let os_abi = match sess.target.options.os.as_ref() { - "hermit" => elf::ELFOSABI_STANDALONE, - "freebsd" => elf::ELFOSABI_FREEBSD, - "solaris" => elf::ELFOSABI_SOLARIS, - _ => elf::ELFOSABI_NONE, - }; - let abi_version = 0; - add_gnu_property_note(&mut file, architecture, binary_format, endianness); - file.flags = FileFlags::Elf { os_abi, abi_version, e_flags }; - Some(file) -} - -/// Since Xcode 15 Apple's LD requires object files to contain information about what they were -/// built for (LC_BUILD_VERSION): the platform (macOS/watchOS etc), minimum OS version, and SDK -/// version. This returns a `MachOBuildVersion` for the target. -fn macho_object_build_version_for_target(target: &Target) -> object::write::MachOBuildVersion { - /// The `object` crate demands "X.Y.Z encoded in nibbles as xxxx.yy.zz" - /// e.g. minOS 14.0 = 0x000E0000, or SDK 16.2 = 0x00100200 - fn pack_version((major, minor): (u32, u32)) -> u32 { - (major << 16) | (minor << 8) - } - - let platform = - rustc_target::spec::current_apple_platform(target).expect("unknown Apple target OS"); - let min_os = rustc_target::spec::current_apple_deployment_target(target) - .expect("unknown Apple target OS"); - let sdk = - rustc_target::spec::current_apple_sdk_version(platform).expect("unknown Apple target OS"); - - let mut build_version = object::write::MachOBuildVersion::default(); - build_version.platform = platform; - build_version.minos = pack_version(min_os); - build_version.sdk = pack_version(sdk); - build_version -} - -/// Is Apple's CPU subtype `arm64e`s -fn macho_is_arm64e(target: &Target) -> bool { - return target.llvm_target.starts_with("arm64e"); -} - -pub enum MetadataPosition { - First, - Last, -} - -/// For rlibs we "pack" rustc metadata into a dummy object file. -/// -/// Historically it was needed because rustc linked rlibs as whole-archive in some cases. -/// In that case linkers try to include all files located in an archive, so if metadata is stored -/// in an archive then it needs to be of a form that the linker is able to process. -/// Now it's not clear whether metadata still needs to be wrapped into an object file or not. -/// -/// Note, though, that we don't actually want this metadata to show up in any -/// final output of the compiler. Instead this is purely for rustc's own -/// metadata tracking purposes. -/// -/// With the above in mind, each "flavor" of object format gets special -/// handling here depending on the target: -/// -/// * MachO - macos-like targets will insert the metadata into a section that -/// is sort of fake dwarf debug info. Inspecting the source of the macos -/// linker this causes these sections to be skipped automatically because -/// it's not in an allowlist of otherwise well known dwarf section names to -/// go into the final artifact. -/// -/// * WebAssembly - this uses wasm files themselves as the object file format -/// so an empty file with no linking metadata but a single custom section is -/// created holding our metadata. -/// -/// * COFF - Windows-like targets create an object with a section that has -/// the `IMAGE_SCN_LNK_REMOVE` flag set which ensures that if the linker -/// ever sees the section it doesn't process it and it's removed. -/// -/// * ELF - All other targets are similar to Windows in that there's a -/// `SHF_EXCLUDE` flag we can set on sections in an object file to get -/// automatically removed from the final output. -pub fn create_wrapper_file( - sess: &Session, - section_name: String, - data: &[u8], -) -> (Vec, MetadataPosition) { - let Some(mut file) = create_object_file(sess) else { - if sess.target.is_like_wasm { - return ( - create_metadata_file_for_wasm(sess, data, §ion_name), - MetadataPosition::First, - ); - } - - // Targets using this branch don't have support implemented here yet or - // they're not yet implemented in the `object` crate and will likely - // fill out this module over time. - return (data.to_vec(), MetadataPosition::Last); - }; - let section = if file.format() == BinaryFormat::Xcoff { - file.add_section(Vec::new(), b".info".to_vec(), SectionKind::Debug) - } else { - file.add_section( - file.segment_name(StandardSegment::Debug).to_vec(), - section_name.into_bytes(), - SectionKind::Debug, - ) - }; - match file.format() { - BinaryFormat::Coff => { - file.section_mut(section).flags = - SectionFlags::Coff { characteristics: pe::IMAGE_SCN_LNK_REMOVE }; - } - BinaryFormat::Elf => { - file.section_mut(section).flags = - SectionFlags::Elf { sh_flags: elf::SHF_EXCLUDE as u64 }; - } - BinaryFormat::Xcoff => { - // AIX system linker may aborts if it meets a valid XCOFF file in archive with no .text, no .data and no .bss. - file.add_section(Vec::new(), b".text".to_vec(), SectionKind::Text); - file.section_mut(section).flags = - SectionFlags::Xcoff { s_flags: xcoff::STYP_INFO as u32 }; - // Encode string stored in .info section of XCOFF. - // FIXME: The length of data here is not guaranteed to fit in a u32. - // We may have to split the data into multiple pieces in order to - // store in .info section. - let len: u32 = data.len().try_into().unwrap(); - let offset = file.append_section_data(section, &len.to_be_bytes(), 1); - // Add a symbol referring to the data in .info section. - file.add_symbol(Symbol { - name: AIX_METADATA_SYMBOL_NAME.into(), - value: offset + 4, - size: 0, - kind: SymbolKind::Unknown, - scope: SymbolScope::Compilation, - weak: false, - section: SymbolSection::Section(section), - flags: SymbolFlags::Xcoff { - n_sclass: xcoff::C_INFO, - x_smtyp: xcoff::C_HIDEXT, - x_smclas: xcoff::C_HIDEXT, - containing_csect: None, - }, - }); - } - _ => {} - }; - file.append_section_data(section, data, 1); - (file.write().unwrap(), MetadataPosition::First) -} - -// Historical note: -// -// When using link.exe it was seen that the section name `.note.rustc` -// was getting shortened to `.note.ru`, and according to the PE and COFF -// specification: -// -// > Executable images do not use a string table and do not support -// > section names longer than 8 characters -// -// https://docs.microsoft.com/en-us/windows/win32/debug/pe-format -// -// As a result, we choose a slightly shorter name! As to why -// `.note.rustc` works on MinGW, see -// https://github.com/llvm/llvm-project/blob/llvmorg-12.0.0/lld/COFF/Writer.cpp#L1190-L1197 -pub fn create_compressed_metadata_file( - sess: &Session, - metadata: &EncodedMetadata, - symbol_name: &str, -) -> Vec { - let mut packed_metadata = rustc_metadata::METADATA_HEADER.to_vec(); - packed_metadata.write_all(&(metadata.raw_data().len() as u64).to_le_bytes()).unwrap(); - packed_metadata.extend(metadata.raw_data()); - - let Some(mut file) = create_object_file(sess) else { - if sess.target.is_like_wasm { - return create_metadata_file_for_wasm(sess, &packed_metadata, ".rustc"); - } - return packed_metadata.to_vec(); - }; - if file.format() == BinaryFormat::Xcoff { - return create_compressed_metadata_file_for_xcoff(file, &packed_metadata, symbol_name); - } - let section = file.add_section( - file.segment_name(StandardSegment::Data).to_vec(), - b".rustc".to_vec(), - SectionKind::ReadOnlyData, - ); - match file.format() { - BinaryFormat::Elf => { - // Explicitly set no flags to avoid SHF_ALLOC default for data section. - file.section_mut(section).flags = SectionFlags::Elf { sh_flags: 0 }; - } - _ => {} - }; - let offset = file.append_section_data(section, &packed_metadata, 1); - - // For MachO and probably PE this is necessary to prevent the linker from throwing away the - // .rustc section. For ELF this isn't necessary, but it also doesn't harm. - file.add_symbol(Symbol { - name: symbol_name.as_bytes().to_vec(), - value: offset, - size: packed_metadata.len() as u64, - kind: SymbolKind::Data, - scope: SymbolScope::Dynamic, - weak: false, - section: SymbolSection::Section(section), - flags: SymbolFlags::None, - }); - - file.write().unwrap() -} - -/// * Xcoff - On AIX, custom sections are merged into predefined sections, -/// so custom .rustc section is not preserved during linking. -/// For this reason, we store metadata in predefined .info section, and -/// define a symbol to reference the metadata. To preserve metadata during -/// linking on AIX, we have to -/// 1. Create an empty .text section, a empty .data section. -/// 2. Define an empty symbol named `symbol_name` inside .data section. -/// 3. Define an symbol named `AIX_METADATA_SYMBOL_NAME` referencing -/// data inside .info section. -/// From XCOFF's view, (2) creates a csect entry in the symbol table, the -/// symbol created by (3) is a info symbol for the preceding csect. Thus -/// two symbols are preserved during linking and we can use the second symbol -/// to reference the metadata. -pub fn create_compressed_metadata_file_for_xcoff( - mut file: write::Object<'_>, - data: &[u8], - symbol_name: &str, -) -> Vec { - assert!(file.format() == BinaryFormat::Xcoff); - // AIX system linker may aborts if it meets a valid XCOFF file in archive with no .text, no .data and no .bss. - file.add_section(Vec::new(), b".text".to_vec(), SectionKind::Text); - let data_section = file.add_section(Vec::new(), b".data".to_vec(), SectionKind::Data); - let section = file.add_section(Vec::new(), b".info".to_vec(), SectionKind::Debug); - file.add_file_symbol("lib.rmeta".into()); - file.section_mut(section).flags = SectionFlags::Xcoff { s_flags: xcoff::STYP_INFO as u32 }; - // Add a global symbol to data_section. - file.add_symbol(Symbol { - name: symbol_name.as_bytes().into(), - value: 0, - size: 0, - kind: SymbolKind::Data, - scope: SymbolScope::Dynamic, - weak: true, - section: SymbolSection::Section(data_section), - flags: SymbolFlags::None, - }); - let len: u32 = data.len().try_into().unwrap(); - let offset = file.append_section_data(section, &len.to_be_bytes(), 1); - // Add a symbol referring to the rustc metadata. - file.add_symbol(Symbol { - name: AIX_METADATA_SYMBOL_NAME.into(), - value: offset + 4, // The metadata is preceded by a 4-byte length field. - size: 0, - kind: SymbolKind::Unknown, - scope: SymbolScope::Dynamic, - weak: false, - section: SymbolSection::Section(section), - flags: SymbolFlags::Xcoff { - n_sclass: xcoff::C_INFO, - x_smtyp: xcoff::C_HIDEXT, - x_smclas: xcoff::C_HIDEXT, - containing_csect: None, - }, - }); - file.append_section_data(section, data, 1); - file.write().unwrap() -} - -/// Creates a simple WebAssembly object file, which is itself a wasm module, -/// that contains a custom section of the name `section_name` with contents -/// `data`. -/// -/// NB: the `object` crate does not yet have support for writing the wasm -/// object file format. In lieu of that the `wasm-encoder` crate is used to -/// build a wasm file by hand. -/// -/// The wasm object file format is defined at -/// -/// and mainly consists of a `linking` custom section. In this case the custom -/// section there is empty except for a version marker indicating what format -/// it's in. -/// -/// The main purpose of this is to contain a custom section with `section_name`, -/// which is then appended after `linking`. -/// -/// As a further detail the object needs to have a 64-bit memory if `wasm64` is -/// the target or otherwise it's interpreted as a 32-bit object which is -/// incompatible with 64-bit ones. -pub fn create_metadata_file_for_wasm(sess: &Session, data: &[u8], section_name: &str) -> Vec { - assert!(sess.target.is_like_wasm); - let mut module = wasm_encoder::Module::new(); - let mut imports = wasm_encoder::ImportSection::new(); - - if sess.target.pointer_width == 64 { - imports.import( - "env", - "__linear_memory", - wasm_encoder::MemoryType { minimum: 0, maximum: None, memory64: true, shared: false }, - ); - } - - if imports.len() > 0 { - module.section(&imports); - } - module.section(&wasm_encoder::CustomSection { - name: "linking".into(), - data: Cow::Borrowed(&[2]), - }); - module.section(&wasm_encoder::CustomSection { name: section_name.into(), data: data.into() }); - module.finish() -} +use std::borrow::Cow;use std::fs::File;use std::io::Write;use std::path::Path;// +use object::write::{self,StandardSegment, Symbol,SymbolSection};use object::{elf +,pe,xcoff,Architecture,BinaryFormat,Endianness,FileFlags,Object,ObjectSection,// +ObjectSymbol,SectionFlags,SectionKind,SubArchitecture,SymbolFlags,SymbolKind,//; +SymbolScope,};use rustc_data_structures ::memmap::Mmap;use rustc_data_structures +::owned_slice::{try_slice_owned,OwnedSlice};use rustc_metadata::creader:://({}); +MetadataLoader;use rustc_metadata::fs::METADATA_FILENAME;use rustc_metadata:://; +EncodedMetadata;use rustc_session::Session; use rustc_span::sym;use rustc_target +::abi::Endian;use rustc_target::spec:: {ef_avr_arch,RelocModel,Target};#[derive( +Debug)]pub struct DefaultMetadataLoader;static AIX_METADATA_SYMBOL_NAME:&//({}); +'static str=("__aix_rust_metadata");fn load_metadata_with(path:&Path,f:impl for< +'a>FnOnce(&'a[u8])->Result<&'a[u8],String>,)->Result{({});let +file=(File::open(path)). map_err(|e|format!("failed to open file '{}': {}",path. +display(),e))?;let _=||();let _=||();unsafe{Mmap::map(file)}.map_err(|e|format!( +"failed to mmap file '{}': {}",path.display(),e)).and_then(|mmap|//loop{break;}; +try_slice_owned(mmap,(((((|mmap|(((((f(mmap)))))))))))))}impl MetadataLoader for +DefaultMetadataLoader{fn get_rlib_metadata(&self,target:&Target,path:&Path)->//; +Result{load_metadata_with(path,|data|{();let archive=object:: +read::archive::ArchiveFile::parse((((((&((((*data)))) )))))).map_err(|e|format!( +"failed to parse rlib '{}': {}",path.display(),e))?;;for entry_result in archive +.members(){loop{break;};if let _=(){};let entry=entry_result.map_err(|e|format!( +"failed to parse rlib '{}': {}",path.display(),e))?;let _=||();if entry.name()== +METADATA_FILENAME.as_bytes(){{();};let data=entry.data(data).map_err(|e|format!( +"failed to parse rlib '{}': {}",path.display(),e))?;();if target.is_like_aix{(); +return get_metadata_xcoff(path,data);;}else{return search_for_section(path,data, +".rmeta");3;}}}Err(format!("metadata not found in rlib '{}'",path.display()))})} +fn get_dylib_metadata(&self,target:&Target,path:&Path)->Result{if target.is_like_aix{ load_metadata_with(path,|data|get_metadata_xcoff( +path,data))}else{load_metadata_with(path,|data|search_for_section(path,data,//3; +".rustc"))}}}pub(super)fn search_for_section<'a>(path:&Path,bytes:&'a[u8],//{;}; +section:&str,)->Result<&'a[u8],String>{3;let Ok(file)=object::File::parse(bytes) +else{3;return Ok(bytes);3;};;file.section_by_name(section).ok_or_else(||format!( +"no `{}` section in '{}'",section,path.display()))?.data().map_err(|e|format!(// +"failed to read {} section in '{}': {}",section,path.display(),e))}fn//let _=(); +add_gnu_property_note(file:&mut write::Object<'static>,architecture://if true{}; +Architecture,binary_format:BinaryFormat,endianness:Endianness,){if //let _=||(); +binary_format!=BinaryFormat::Elf||!matches!(architecture,Architecture::X86_64|// +Architecture::Aarch64){;return;;}let section=file.add_section(file.segment_name( +StandardSegment::Data).to_vec(),((b".note.gnu.property").to_vec()),SectionKind:: +Note,);;;let mut data:Vec=Vec::new();;let n_namsz:u32=4;let n_descsz:u32=16; +let n_type:u32=object::elf::NT_GNU_PROPERTY_TYPE_0;;;let header_values=[n_namsz, +n_descsz,n_type];();3;header_values.iter().for_each(|v|{data.extend_from_slice(& +match endianness{Endianness::Little=>((((v.to_le_bytes())))),Endianness::Big=>v. +to_be_bytes(),})});3;3;data.extend_from_slice(b"GNU\0");3;;let pr_type:u32=match +architecture{Architecture::X86_64=> object::elf::GNU_PROPERTY_X86_FEATURE_1_AND, +Architecture::Aarch64=>object::elf::GNU_PROPERTY_AARCH64_FEATURE_1_AND,_=>//{;}; +unreachable!(),};;let pr_datasz:u32=4;let pr_data:u32=3;let pr_padding:u32=0;let +property_values=[pr_type,pr_datasz,pr_data,pr_padding];;;property_values.iter(). +for_each(|v|{data.extend_from_slice(&match endianness{Endianness::Little=>v.//3; +to_le_bytes(),Endianness::Big=>v.to_be_bytes(),})});3;;file.append_section_data( +section,&data,8);3;}pub(super)fn get_metadata_xcoff<'a>(path:&Path,data:&'a[u8]) +->Result<&'a[u8],String>{;let Ok(file)=object::File::parse(data)else{;return Ok( +data);3;};3;;let info_data=search_for_section(path,data,".info")?;;;if let Some( +metadata_symbol)=((((((file.symbols())))))).find( |sym|(((((sym.name())))))==Ok( +AIX_METADATA_SYMBOL_NAME)){();let offset=metadata_symbol.address()as usize;3;if +offset<4{;return Err(format!("Invalid metadata symbol offset: {offset}"));;};let +len=(u32::from_be_bytes((info_data[(offset-4 )..offset].try_into().unwrap())))as +usize;((),());if offset+len>(info_data.len()as usize){*&*&();return Err(format!( +"Metadata at offset {offset} with size {len} is beyond .info section"));;}return +Ok(&info_data[offset..(offset+len)]);let _=();}else{let _=();return Err(format!( +"Unable to find symbol {AIX_METADATA_SYMBOL_NAME}"));{();};};{();};}pub(crate)fn +create_object_file(sess:&Session)->Option>{let _=||();let +endianness=match sess.target.options. endian{Endian::Little=>Endianness::Little, +Endian::Big=>Endianness::Big,};3;;let(architecture,sub_architecture)=match&sess. +target.arch[..]{"arm"=>(((Architecture::Arm ,None))),"aarch64"=>(if sess.target. +pointer_width==32{Architecture::Aarch64_Ilp32 }else{Architecture::Aarch64},None, +),"x86"=>((Architecture::I386,None)),"s390x"=>(Architecture::S390x,None),"mips"| +"mips32r6"=>((((Architecture::Mips,None)))),"mips64"|"mips64r6"=>(Architecture:: +Mips64,None),"x86_64"=>(if (( sess.target.pointer_width==((32)))){Architecture:: +X86_64_X32}else{Architecture::X86_64},None, ),"powerpc"=>(Architecture::PowerPc, +None),"powerpc64"=>(((Architecture::PowerPc64,None))),"riscv32"=>(Architecture:: +Riscv32,None),"riscv64"=>((Architecture::Riscv64,None)),"sparc64"=>(Architecture +::Sparc64,None),"avr"=>(Architecture:: Avr,None),"msp430"=>(Architecture::Msp430 +,None),"hexagon"=>(Architecture::Hexagon,None ),"bpf"=>(Architecture::Bpf,None), +"loongarch64"=>(((Architecture::LoongArch64,None))),"csky"=>(Architecture::Csky, +None),"arm64ec"=>((Architecture::Aarch64,( Some(SubArchitecture::Arm64EC)))),_=> +return None,};;let binary_format=if sess.target.is_like_osx{BinaryFormat::MachO} +else if sess.target.is_like_windows{BinaryFormat::Coff}else if sess.target.//(); +is_like_aix{BinaryFormat::Xcoff}else{BinaryFormat::Elf};3;3;let mut file=write:: +Object::new(binary_format,architecture,endianness);3;;file.set_sub_architecture( +sub_architecture);;if sess.target.is_like_osx{if macho_is_arm64e(&sess.target){; +file.set_macho_cpu_subtype(object::macho::CPU_SUBTYPE_ARM64E);loop{break};}file. +set_macho_build_version(macho_object_build_version_for_target(&sess .target))}if +binary_format==BinaryFormat::Coff{;let original_mangling=file.mangling();;;file. +set_mangling(object::write::Mangling::None);{;};();let mut feature=0;();if file. +architecture()==object::Architecture::I386{;feature|=1;}file.add_symbol(object:: +write::Symbol{name:((("@feat.00").into())) ,value:feature,size:(0),kind:object:: +SymbolKind::Data,scope:object::SymbolScope:: Compilation,weak:((false)),section: +object::write::SymbolSection::Absolute,flags:object::SymbolFlags::None,});;file. +set_mangling(original_mangling);;};let e_flags=match architecture{Architecture:: +Mips=>{let _=||();let arch=match sess.target.options.cpu.as_ref(){"mips1"=>elf:: +EF_MIPS_ARCH_1,"mips2"=>elf::EF_MIPS_ARCH_2,"mips3"=>elf::EF_MIPS_ARCH_3,//({}); +"mips4"=>elf::EF_MIPS_ARCH_4,"mips5"=>elf::EF_MIPS_ARCH_5,s if s.contains("r6") +=>elf::EF_MIPS_ARCH_32R6,_=>elf::EF_MIPS_ARCH_32R2,};();();let mut e_flags=elf:: +EF_MIPS_CPIC|arch;;match sess.target.options.llvm_abiname.to_lowercase().as_str( +){"n32"=>(e_flags|=elf::EF_MIPS_ABI2),"o32"=>(e_flags|=elf::EF_MIPS_ABI_O32),_=> +e_flags|=elf::EF_MIPS_ABI_O32,};*&*&();if sess.target.options.relocation_model!= +RelocModel::Static{{;};e_flags|=elf::EF_MIPS_PIC;();}if sess.target.options.cpu. +contains("r6"){;e_flags|=elf::EF_MIPS_NAN2008;;}e_flags}Architecture::Mips64=>{; +let e_flags=(((elf::EF_MIPS_CPIC|elf::EF_MIPS_PIC)))|if sess.target.options.cpu. +contains(((("r6")))){((elf:: EF_MIPS_ARCH_64R6|elf::EF_MIPS_NAN2008))}else{elf:: +EF_MIPS_ARCH_64R2};3;e_flags}Architecture::Riscv32|Architecture::Riscv64=>{3;let +mut e_flags:u32=0x0;;if sess.unstable_target_features.contains(&sym::c){;e_flags +|=elf::EF_RISCV_RVC;({});}match&*sess.target.llvm_abiname{""|"ilp32"|"lp64"=>(), +"ilp32f"|"lp64f"=>((e_flags|=elf::EF_RISCV_FLOAT_ABI_SINGLE)),"ilp32d"|"lp64d"=> +e_flags|=elf::EF_RISCV_FLOAT_ABI_DOUBLE,"ilp32e"=>(e_flags|=elf::EF_RISCV_RVE),_ +=>bug!("unknown RISC-V ABI name"),}e_flags}Architecture::LoongArch64=>{3;let mut +e_flags:u32=elf::EF_LARCH_OBJABI_V1;();match&*sess.target.llvm_abiname{"ilp32s"| +"lp64s"=>e_flags|=elf::EF_LARCH_ABI_SOFT_FLOAT ,"ilp32f"|"lp64f"=>e_flags|=elf:: +EF_LARCH_ABI_SINGLE_FLOAT,"ilp32d"|"lp64d"=>e_flags|=elf:://if true{};if true{}; +EF_LARCH_ABI_DOUBLE_FLOAT,_=>(((bug! ("unknown LoongArch ABI name")))),}e_flags} +Architecture::Avr=>{ef_avr_arch(&sess.target.options.cpu)}Architecture::Csky=>{; +let e_flags=match sess.target.options. abi.as_ref(){"abiv2"=>elf::EF_CSKY_ABIV2, +_=>elf::EF_CSKY_ABIV1,};;e_flags}_=>0,};let os_abi=match sess.target.options.os. +as_ref(){"hermit"=>elf::ELFOSABI_STANDALONE,"freebsd"=>elf::ELFOSABI_FREEBSD,//; +"solaris"=>elf::ELFOSABI_SOLARIS,_=>elf::ELFOSABI_NONE,};3;;let abi_version=0;;; +add_gnu_property_note(&mut file,architecture,binary_format,endianness);3;3;file. +flags=FileFlags::Elf{os_abi,abi_version,e_flags};let _=();let _=();Some(file)}fn +macho_object_build_version_for_target(target:&Target)->object::write:://((),()); +MachOBuildVersion{();fn pack_version((major,minor):(u32,u32))->u32{(major<<16)|( +minor<<8)}();();let platform=rustc_target::spec::current_apple_platform(target). +expect("unknown Apple target OS");((),());*&*&();let min_os=rustc_target::spec:: +current_apple_deployment_target(target).expect("unknown Apple target OS");3;;let +sdk=((((((rustc_target::spec:: current_apple_sdk_version(platform))))))).expect( +"unknown Apple target OS");((),());((),());let mut build_version=object::write:: +MachOBuildVersion::default();3;;build_version.platform=platform;;;build_version. +minos=pack_version(min_os);;build_version.sdk=pack_version(sdk);build_version}fn +macho_is_arm64e(target:&Target)->bool{{;};return target.llvm_target.starts_with( +"arm64e");{;};}pub enum MetadataPosition{First,Last,}pub fn create_wrapper_file( +sess:&Session,section_name:String,data:&[u8],)->(Vec,MetadataPosition){3;let +Some(mut file)=create_object_file(sess)else{if sess.target.is_like_wasm{;return( +create_metadata_file_for_wasm(sess,data,& section_name),MetadataPosition::First, +);;};return(data.to_vec(),MetadataPosition::Last);};let section=if file.format() +==BinaryFormat::Xcoff{file.add_section(Vec::new (),b".info".to_vec(),SectionKind +::Debug)}else{file.add_section( file.segment_name(StandardSegment::Debug).to_vec +(),section_name.into_bytes(),SectionKind::Debug,)};({});{;};match file.format(){ +BinaryFormat::Coff=>{((),());file.section_mut(section).flags=SectionFlags::Coff{ +characteristics:pe::IMAGE_SCN_LNK_REMOVE};;}BinaryFormat::Elf=>{file.section_mut +(section).flags=SectionFlags::Elf{sh_flags:elf::SHF_EXCLUDE as u64};let _=||();} +BinaryFormat::Xcoff=>{;file.add_section(Vec::new(),b".text".to_vec(),SectionKind +::Text);();3;file.section_mut(section).flags=SectionFlags::Xcoff{s_flags:xcoff:: +STYP_INFO as u32};;;let len:u32=data.len().try_into().unwrap();;let offset=file. +append_section_data(section,&len.to_be_bytes(),1);;;file.add_symbol(Symbol{name: +AIX_METADATA_SYMBOL_NAME.into(),value:offset+4 ,size:0,kind:SymbolKind::Unknown, +scope:SymbolScope::Compilation,weak:((( false))),section:SymbolSection::Section( +section),flags:SymbolFlags::Xcoff{n_sclass:xcoff::C_INFO,x_smtyp:xcoff:://{();}; +C_HIDEXT,x_smclas:xcoff::C_HIDEXT,containing_csect:None,},});3;}_=>{}};3;3;file. +append_section_data(section,data,1);();(file.write().unwrap(),MetadataPosition:: +First)}pub fn create_compressed_metadata_file(sess:&Session,metadata:&//((),()); +EncodedMetadata,symbol_name:&str,)->Vec{loop{break};let mut packed_metadata= +rustc_metadata::METADATA_HEADER.to_vec();;;packed_metadata.write_all(&(metadata. +raw_data().len()as u64).to_le_bytes()).unwrap();;packed_metadata.extend(metadata +.raw_data());3;3;let Some(mut file)=create_object_file(sess)else{if sess.target. +is_like_wasm{((),());return create_metadata_file_for_wasm(sess,&packed_metadata, +".rustc");;};return packed_metadata.to_vec();;};if file.format()==BinaryFormat:: +Xcoff{();return create_compressed_metadata_file_for_xcoff(file,&packed_metadata, +symbol_name);;};let section=file.add_section(file.segment_name(StandardSegment:: +Data).to_vec(),b".rustc".to_vec(),SectionKind::ReadOnlyData,);;match file.format +(){BinaryFormat::Elf=>{*&*&();file.section_mut(section).flags=SectionFlags::Elf{ +sh_flags:0};({});}_=>{}};({});({});let offset=file.append_section_data(section,& +packed_metadata,1);;file.add_symbol(Symbol{name:symbol_name.as_bytes().to_vec(), +value:offset,size:(((packed_metadata.len())as u64)),kind:SymbolKind::Data,scope: +SymbolScope::Dynamic,weak:(false),section:SymbolSection::Section(section),flags: +SymbolFlags::None,});*&*&();((),());((),());((),());file.write().unwrap()}pub fn +create_compressed_metadata_file_for_xcoff(mut file:write::Object <'_>,data:&[u8] +,symbol_name:&str,)->Vec{;assert!(file.format()==BinaryFormat::Xcoff);;file. +add_section(Vec::new(),b".text".to_vec(),SectionKind::Text);3;;let data_section= +file.add_section(Vec::new(),b".data".to_vec(),SectionKind::Data);3;;let section= +file.add_section(Vec::new(),b".info".to_vec(),SectionKind::Debug);({});{;};file. +add_file_symbol("lib.rmeta".into());{();};{();};file.section_mut(section).flags= +SectionFlags::Xcoff{s_flags:xcoff::STYP_INFO as u32};3;3;file.add_symbol(Symbol{ +name:(symbol_name.as_bytes().into()),value:0,size:0,kind:SymbolKind::Data,scope: +SymbolScope::Dynamic,weak:(true),section:(SymbolSection::Section(data_section)), +flags:SymbolFlags::None,});3;3;let len:u32=data.len().try_into().unwrap();3;;let +offset=file.append_section_data(section,&len.to_be_bytes(),1);;;file.add_symbol( +Symbol{name:(AIX_METADATA_SYMBOL_NAME.into()),value:( offset+(4)),size:(0),kind: +SymbolKind::Unknown,scope:SymbolScope::Dynamic, weak:false,section:SymbolSection +::Section(section),flags:SymbolFlags::Xcoff{n_sclass:xcoff::C_INFO,x_smtyp://(); +xcoff::C_HIDEXT,x_smclas:xcoff::C_HIDEXT,containing_csect:None,},});{;};();file. +append_section_data(section,data,1);((),());((),());file.write().unwrap()}pub fn +create_metadata_file_for_wasm(sess:&Session,data:&[ u8],section_name:&str)->Vec< +u8>{;assert!(sess.target.is_like_wasm);let mut module=wasm_encoder::Module::new( +);{;};{;};let mut imports=wasm_encoder::ImportSection::new();{;};if sess.target. +pointer_width==64{let _=();imports.import("env","__linear_memory",wasm_encoder:: +MemoryType{minimum:0,maximum:None,memory64:true,shared:false},);;}if imports.len +()>0{;module.section(&imports);}module.section(&wasm_encoder::CustomSection{name +:"linking".into(),data:Cow::Borrowed(&[2]),});3;3;module.section(&wasm_encoder:: +CustomSection{name:section_name.into(),data:data.into()});{();};module.finish()} diff --git a/compiler/rustc_codegen_ssa/src/back/mod.rs b/compiler/rustc_codegen_ssa/src/back/mod.rs index d11ed54eb209f..e17a660a2f108 100644 --- a/compiler/rustc_codegen_ssa/src/back/mod.rs +++ b/compiler/rustc_codegen_ssa/src/back/mod.rs @@ -1,9 +1,2 @@ -pub mod archive; -pub mod command; -pub mod link; -pub mod linker; -pub mod lto; -pub mod metadata; -pub mod rpath; -pub mod symbol_export; -pub mod write; +pub mod archive;pub mod command;pub mod link;pub mod linker;pub mod lto;pub mod +metadata;pub mod rpath;pub mod symbol_export;pub mod write;//let _=();if true{}; diff --git a/compiler/rustc_codegen_ssa/src/back/rpath.rs b/compiler/rustc_codegen_ssa/src/back/rpath.rs index ebbf49af18487..6bc7332256a70 100644 --- a/compiler/rustc_codegen_ssa/src/back/rpath.rs +++ b/compiler/rustc_codegen_ssa/src/back/rpath.rs @@ -1,118 +1,30 @@ -use pathdiff::diff_paths; -use rustc_data_structures::fx::FxHashSet; -use rustc_fs_util::try_canonicalize; -use std::ffi::OsString; -use std::path::{Path, PathBuf}; - -pub struct RPathConfig<'a> { - pub libs: &'a [&'a Path], - pub out_filename: PathBuf, - pub is_like_osx: bool, - pub has_rpath: bool, - pub linker_is_gnu: bool, -} - -pub fn get_rpath_flags(config: &RPathConfig<'_>) -> Vec { - // No rpath on windows - if !config.has_rpath { - return Vec::new(); - } - - debug!("preparing the RPATH!"); - - let rpaths = get_rpaths(config); - let mut flags = rpaths_to_flags(rpaths); - - if config.linker_is_gnu { - // Use DT_RUNPATH instead of DT_RPATH if available - flags.push("-Wl,--enable-new-dtags".into()); - - // Set DF_ORIGIN for substitute $ORIGIN - flags.push("-Wl,-z,origin".into()); - } - - flags -} - -fn rpaths_to_flags(rpaths: Vec) -> Vec { - let mut ret = Vec::with_capacity(rpaths.len()); // the minimum needed capacity - - for rpath in rpaths { - if rpath.to_string_lossy().contains(',') { - ret.push("-Wl,-rpath".into()); - ret.push("-Xlinker".into()); - ret.push(rpath); - } else { - let mut single_arg = OsString::from("-Wl,-rpath,"); - single_arg.push(rpath); - ret.push(single_arg); - } - } - - ret -} - -fn get_rpaths(config: &RPathConfig<'_>) -> Vec { - debug!("output: {:?}", config.out_filename.display()); - debug!("libs:"); - for libpath in config.libs { - debug!(" {:?}", libpath.display()); - } - - // Use relative paths to the libraries. Binaries can be moved - // as long as they maintain the relative relationship to the - // crates they depend on. - let rpaths = get_rpaths_relative_to_output(config); - - debug!("rpaths:"); - for rpath in &rpaths { - debug!(" {:?}", rpath); - } - - // Remove duplicates - minimize_rpaths(&rpaths) -} - -fn get_rpaths_relative_to_output(config: &RPathConfig<'_>) -> Vec { - config.libs.iter().map(|a| get_rpath_relative_to_output(config, a)).collect() -} - -fn get_rpath_relative_to_output(config: &RPathConfig<'_>, lib: &Path) -> OsString { - // Mac doesn't appear to support $ORIGIN - let prefix = if config.is_like_osx { "@loader_path" } else { "$ORIGIN" }; - - // Strip filenames - let lib = lib.parent().unwrap(); - let output = config.out_filename.parent().unwrap(); - let lib = try_canonicalize(lib).unwrap(); - let output = try_canonicalize(output).unwrap(); - let relative = path_relative_from(&lib, &output) - .unwrap_or_else(|| panic!("couldn't create relative path from {output:?} to {lib:?}")); - - let mut rpath = OsString::from(prefix); - rpath.push("/"); - rpath.push(relative); - rpath -} - -// This routine is adapted from the *old* Path's `path_relative_from` -// function, which works differently from the new `relative_from` function. -// In particular, this handles the case on unix where both paths are -// absolute but with only the root as the common directory. -fn path_relative_from(path: &Path, base: &Path) -> Option { - diff_paths(path, base) -} - -fn minimize_rpaths(rpaths: &[OsString]) -> Vec { - let mut set = FxHashSet::default(); - let mut minimized = Vec::new(); - for rpath in rpaths { - if set.insert(rpath) { - minimized.push(rpath.clone()); - } - } - minimized -} - -#[cfg(all(unix, test))] -mod tests; +use pathdiff::diff_paths;use rustc_data_structures::fx::FxHashSet;use//let _=(); +rustc_fs_util::try_canonicalize;use std::ffi::OsString;use std::path::{Path,//3; +PathBuf};pub struct RPathConfig<'a>{pub libs:&'a[&'a Path],pub out_filename://3; +PathBuf,pub is_like_osx:bool,pub has_rpath:bool,pub linker_is_gnu:bool,}pub fn// +get_rpath_flags(config:&RPathConfig<'_>)->Vec{if!config.has_rpath{{;}; +return Vec::new();;}debug!("preparing the RPATH!");let rpaths=get_rpaths(config) +;3;3;let mut flags=rpaths_to_flags(rpaths);;if config.linker_is_gnu{;flags.push( +"-Wl,--enable-new-dtags".into());;;flags.push("-Wl,-z,origin".into());;}flags}fn +rpaths_to_flags(rpaths:Vec)->Vec{if true{};let mut ret=Vec:: +with_capacity(rpaths.len());({});for rpath in rpaths{if rpath.to_string_lossy(). +contains(','){;ret.push("-Wl,-rpath".into());;;ret.push("-Xlinker".into());;ret. +push(rpath);;}else{;let mut single_arg=OsString::from("-Wl,-rpath,");single_arg. +push(rpath);;ret.push(single_arg);}}ret}fn get_rpaths(config:&RPathConfig<'_>)-> +Vec{3;debug!("output: {:?}",config.out_filename.display());3;3;debug!( +"libs:");;for libpath in config.libs{;debug!(" {:?}",libpath.display());;}let +rpaths=get_rpaths_relative_to_output(config);3;;debug!("rpaths:");;for rpath in& +rpaths{if true{};debug!(" {:?}",rpath);if true{};}minimize_rpaths(&rpaths)}fn +get_rpaths_relative_to_output(config:&RPathConfig<'_>)->Vec{config.//; +libs.iter().map(((|a|((get_rpath_relative_to_output (config,a)))))).collect()}fn +get_rpath_relative_to_output(config:&RPathConfig<'_>,lib:&Path)->OsString{();let +prefix=if config.is_like_osx{"@loader_path"}else{"$ORIGIN"};;let lib=lib.parent( +).unwrap();();();let output=config.out_filename.parent().unwrap();();();let lib= +try_canonicalize(lib).unwrap();;let output=try_canonicalize(output).unwrap();let +relative=(((path_relative_from(((&lib)),((&output)))))).unwrap_or_else(||panic!( +"couldn't create relative path from {output:?} to {lib:?}"));();3;let mut rpath= +OsString::from(prefix);();();rpath.push("/");3;3;rpath.push(relative);3;rpath}fn +path_relative_from(path:&Path,base:&Path) ->Option{diff_paths(path,base +)}fn minimize_rpaths(rpaths:&[OsString])->Vec{;let mut set=FxHashSet:: +default();;let mut minimized=Vec::new();for rpath in rpaths{if set.insert(rpath) +{();minimized.push(rpath.clone());3;}}minimized}#[cfg(all(unix,test))]mod tests; diff --git a/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs b/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs index ac2e54072c416..66887c4b39557 100644 --- a/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs +++ b/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs @@ -1,73 +1,19 @@ -use super::RPathConfig; -use super::{get_rpath_relative_to_output, minimize_rpaths, rpaths_to_flags}; -use std::ffi::OsString; -use std::path::{Path, PathBuf}; - -#[test] -fn test_rpaths_to_flags() { - let flags = rpaths_to_flags(vec!["path1".into(), "path2".into()]); - assert_eq!(flags, ["-Wl,-rpath,path1", "-Wl,-rpath,path2"]); -} - -#[test] -fn test_minimize1() { - let res = minimize_rpaths(&["rpath1".into(), "rpath2".into(), "rpath1".into()]); - assert!(res == ["rpath1", "rpath2",]); -} - -#[test] -fn test_minimize2() { - let res = minimize_rpaths(&[ - "1a".into(), - "2".into(), - "2".into(), - "1a".into(), - "4a".into(), - "1a".into(), - "2".into(), - "3".into(), - "4a".into(), - "3".into(), - ]); - assert!(res == ["1a", "2", "4a", "3",]); -} - -#[test] -fn test_rpath_relative() { - if cfg!(target_os = "macos") { - let config = &mut RPathConfig { - libs: &[], - has_rpath: true, - is_like_osx: true, - linker_is_gnu: false, - out_filename: PathBuf::from("bin/rustc"), - }; - let res = get_rpath_relative_to_output(config, Path::new("lib/libstd.so")); - assert_eq!(res, "@loader_path/../lib"); - } else { - let config = &mut RPathConfig { - libs: &[], - out_filename: PathBuf::from("bin/rustc"), - has_rpath: true, - is_like_osx: false, - linker_is_gnu: true, - }; - let res = get_rpath_relative_to_output(config, Path::new("lib/libstd.so")); - assert_eq!(res, "$ORIGIN/../lib"); - } -} - -#[test] -fn test_xlinker() { - let args = rpaths_to_flags(vec!["a/normal/path".into(), "a,comma,path".into()]); - - assert_eq!( - args, - vec![ - OsString::from("-Wl,-rpath,a/normal/path"), - OsString::from("-Wl,-rpath"), - OsString::from("-Xlinker"), - OsString::from("a,comma,path") - ] - ); -} +use super::RPathConfig;use super::{get_rpath_relative_to_output,minimize_rpaths +,rpaths_to_flags};use std::ffi::OsString;use std::path::{Path,PathBuf};#[test]// +fn test_rpaths_to_flags(){;let flags=rpaths_to_flags(vec!["path1".into(),"path2" +.into()]);;;assert_eq!(flags,["-Wl,-rpath,path1","-Wl,-rpath,path2"]);}#[test]fn +test_minimize1(){({});let res=minimize_rpaths(&["rpath1".into(),"rpath2".into(), +"rpath1".into()]);;assert!(res==["rpath1","rpath2",]);}#[test]fn test_minimize2( +){;let res=minimize_rpaths(&["1a".into(),"2".into(),"2".into(),"1a".into(),"4a". +into(),"1a".into(),"2".into(),"3".into(),"4a".into(),"3".into(),]);;;assert!(res +==["1a","2","4a","3",]);({});}#[test]fn test_rpath_relative(){if cfg!(target_os= +"macos"){3;let config=&mut RPathConfig{libs:&[],has_rpath:true,is_like_osx:true, +linker_is_gnu:false,out_filename:PathBuf::from("bin/rustc"),};({});({});let res= +get_rpath_relative_to_output(config,Path::new("lib/libstd.so"));;assert_eq!(res, +"@loader_path/../lib");;}else{let config=&mut RPathConfig{libs:&[],out_filename: +PathBuf::from("bin/rustc"),has_rpath:true ,is_like_osx:false,linker_is_gnu:true, +};3;3;let res=get_rpath_relative_to_output(config,Path::new("lib/libstd.so"));;; +assert_eq!(res,"$ORIGIN/../lib");{();};}}#[test]fn test_xlinker(){({});let args= +rpaths_to_flags(vec!["a/normal/path".into(),"a,comma,path".into()]);;assert_eq!( +args,vec![OsString::from("-Wl,-rpath,a/normal/path"),OsString::from(//if true{}; +"-Wl,-rpath"),OsString::from("-Xlinker"),OsString::from("a,comma,path")]);({});} diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index b19f52182b650..4dfe3d6dc98a4 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -1,668 +1,192 @@ -use crate::base::allocator_kind_for_codegen; - -use std::collections::hash_map::Entry::*; - -use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE}; -use rustc_data_structures::unord::UnordMap; -use rustc_hir::def::DefKind; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; -use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::middle::exported_symbols::{ - metadata_symbol_name, ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel, -}; -use rustc_middle::query::LocalCrate; -use rustc_middle::ty::Instance; -use rustc_middle::ty::{self, SymbolName, TyCtxt}; -use rustc_middle::ty::{GenericArgKind, GenericArgsRef}; -use rustc_middle::util::Providers; -use rustc_session::config::{CrateType, OomStrategy}; -use rustc_target::spec::{SanitizerSet, TlsModel}; - -pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel { - crates_export_threshold(tcx.crate_types()) -} - -fn crate_export_threshold(crate_type: CrateType) -> SymbolExportLevel { - match crate_type { - CrateType::Executable | CrateType::Staticlib | CrateType::ProcMacro | CrateType::Cdylib => { - SymbolExportLevel::C - } - CrateType::Rlib | CrateType::Dylib => SymbolExportLevel::Rust, - } -} - -pub fn crates_export_threshold(crate_types: &[CrateType]) -> SymbolExportLevel { - if crate_types - .iter() - .any(|&crate_type| crate_export_threshold(crate_type) == SymbolExportLevel::Rust) - { - SymbolExportLevel::Rust - } else { - SymbolExportLevel::C - } -} - -fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap { - if !tcx.sess.opts.output_types.should_codegen() { - return Default::default(); - } - - // Check to see if this crate is a "special runtime crate". These - // crates, implementation details of the standard library, typically - // have a bunch of `pub extern` and `#[no_mangle]` functions as the - // ABI between them. We don't want their symbols to have a `C` - // export level, however, as they're just implementation details. - // Down below we'll hardwire all of the symbols to the `Rust` export - // level instead. - let special_runtime_crate = - tcx.is_panic_runtime(LOCAL_CRATE) || tcx.is_compiler_builtins(LOCAL_CRATE); - - let mut reachable_non_generics: DefIdMap<_> = tcx - .reachable_set(()) - .items() - .filter_map(|&def_id| { - // We want to ignore some FFI functions that are not exposed from - // this crate. Reachable FFI functions can be lumped into two - // categories: - // - // 1. Those that are included statically via a static library - // 2. Those included otherwise (e.g., dynamically or via a framework) - // - // Although our LLVM module is not literally emitting code for the - // statically included symbols, it's an export of our library which - // needs to be passed on to the linker and encoded in the metadata. - // - // As a result, if this id is an FFI item (foreign item) then we only - // let it through if it's included statically. - if let Some(parent_id) = tcx.opt_local_parent(def_id) - && let DefKind::ForeignMod = tcx.def_kind(parent_id) - { - let library = tcx.native_library(def_id)?; - return library.kind.is_statically_included().then_some(def_id); - } - - // Only consider nodes that actually have exported symbols. - match tcx.def_kind(def_id) { - DefKind::Fn | DefKind::Static { .. } => {} - DefKind::AssocFn if tcx.impl_of_method(def_id.to_def_id()).is_some() => {} - _ => return None, - }; - - let generics = tcx.generics_of(def_id); - if generics.requires_monomorphization(tcx) { - return None; - } - - // Functions marked with #[inline] are codegened with "internal" - // linkage and are not exported unless marked with an extern - // indicator - if !Instance::mono(tcx, def_id.to_def_id()).def.generates_cgu_internal_copy(tcx) - || tcx.codegen_fn_attrs(def_id.to_def_id()).contains_extern_indicator() - { - Some(def_id) - } else { - None - } - }) - .map(|def_id| { - // We won't link right if this symbol is stripped during LTO. - let name = tcx.symbol_name(Instance::mono(tcx, def_id.to_def_id())).name; - let used = name == "rust_eh_personality"; - - let export_level = if special_runtime_crate { - SymbolExportLevel::Rust - } else { - symbol_export_level(tcx, def_id.to_def_id()) - }; - let codegen_attrs = tcx.codegen_fn_attrs(def_id.to_def_id()); - debug!( - "EXPORTED SYMBOL (local): {} ({:?})", - tcx.symbol_name(Instance::mono(tcx, def_id.to_def_id())), - export_level - ); - let info = SymbolExportInfo { - level: export_level, - kind: if tcx.is_static(def_id.to_def_id()) { - if codegen_attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) { - SymbolExportKind::Tls - } else { - SymbolExportKind::Data - } - } else { - SymbolExportKind::Text - }, - used: codegen_attrs.flags.contains(CodegenFnAttrFlags::USED) - || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) - || used, - }; - (def_id.to_def_id(), info) - }) - .into(); - - if let Some(id) = tcx.proc_macro_decls_static(()) { - reachable_non_generics.insert( - id.to_def_id(), - SymbolExportInfo { - level: SymbolExportLevel::C, - kind: SymbolExportKind::Data, - used: false, - }, - ); - } - - reachable_non_generics -} - -fn is_reachable_non_generic_provider_local(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { - let export_threshold = threshold(tcx); - - if let Some(&info) = tcx.reachable_non_generics(LOCAL_CRATE).get(&def_id.to_def_id()) { - info.level.is_below_threshold(export_threshold) - } else { - false - } -} - -fn is_reachable_non_generic_provider_extern(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - tcx.reachable_non_generics(def_id.krate).contains_key(&def_id) -} - -fn exported_symbols_provider_local( - tcx: TyCtxt<'_>, - _: LocalCrate, -) -> &[(ExportedSymbol<'_>, SymbolExportInfo)] { - if !tcx.sess.opts.output_types.should_codegen() { - return &[]; - } - - // FIXME: Sorting this is unnecessary since we are sorting later anyway. - // Can we skip the later sorting? - let sorted = tcx.with_stable_hashing_context(|hcx| { - tcx.reachable_non_generics(LOCAL_CRATE).to_sorted(&hcx, true) - }); - - let mut symbols: Vec<_> = - sorted.iter().map(|(&def_id, &info)| (ExportedSymbol::NonGeneric(def_id), info)).collect(); - - // Export TLS shims - if !tcx.sess.target.dll_tls_export { - symbols.extend(sorted.iter().filter_map(|(&def_id, &info)| { - tcx.needs_thread_local_shim(def_id).then(|| { - ( - ExportedSymbol::ThreadLocalShim(def_id), - SymbolExportInfo { - level: info.level, - kind: SymbolExportKind::Text, - used: info.used, - }, - ) - }) - })) - } - - if tcx.entry_fn(()).is_some() { - let exported_symbol = - ExportedSymbol::NoDefId(SymbolName::new(tcx, tcx.sess.target.entry_name.as_ref())); - - symbols.push(( - exported_symbol, - SymbolExportInfo { - level: SymbolExportLevel::C, - kind: SymbolExportKind::Text, - used: false, - }, - )); - } - - // Mark allocator shim symbols as exported only if they were generated. - if allocator_kind_for_codegen(tcx).is_some() { - for symbol_name in ALLOCATOR_METHODS - .iter() - .map(|method| format!("__rust_{}", method.name)) - .chain(["__rust_alloc_error_handler".to_string(), OomStrategy::SYMBOL.to_string()]) - { - let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name)); - - symbols.push(( - exported_symbol, - SymbolExportInfo { - level: SymbolExportLevel::Rust, - kind: SymbolExportKind::Text, - used: false, - }, - )); - } - - let exported_symbol = - ExportedSymbol::NoDefId(SymbolName::new(tcx, NO_ALLOC_SHIM_IS_UNSTABLE)); - symbols.push(( - exported_symbol, - SymbolExportInfo { - level: SymbolExportLevel::Rust, - kind: SymbolExportKind::Data, - used: false, - }, - )) - } - - if tcx.sess.instrument_coverage() || tcx.sess.opts.cg.profile_generate.enabled() { - // These are weak symbols that point to the profile version and the - // profile name, which need to be treated as exported so LTO doesn't nix - // them. - const PROFILER_WEAK_SYMBOLS: [&str; 2] = - ["__llvm_profile_raw_version", "__llvm_profile_filename"]; - - symbols.extend(PROFILER_WEAK_SYMBOLS.iter().map(|sym| { - let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, sym)); - ( - exported_symbol, - SymbolExportInfo { - level: SymbolExportLevel::C, - kind: SymbolExportKind::Data, - used: false, - }, - ) - })); - } - - if tcx.sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::MEMORY) { - let mut msan_weak_symbols = Vec::new(); - - // Similar to profiling, preserve weak msan symbol during LTO. - if tcx.sess.opts.unstable_opts.sanitizer_recover.contains(SanitizerSet::MEMORY) { - msan_weak_symbols.push("__msan_keep_going"); - } - - if tcx.sess.opts.unstable_opts.sanitizer_memory_track_origins != 0 { - msan_weak_symbols.push("__msan_track_origins"); - } - - symbols.extend(msan_weak_symbols.into_iter().map(|sym| { - let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, sym)); - ( - exported_symbol, - SymbolExportInfo { - level: SymbolExportLevel::C, - kind: SymbolExportKind::Data, - used: false, - }, - ) - })); - } - - if tcx.crate_types().contains(&CrateType::Dylib) - || tcx.crate_types().contains(&CrateType::ProcMacro) - { - let symbol_name = metadata_symbol_name(tcx); - let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name)); - - symbols.push(( - exported_symbol, - SymbolExportInfo { - level: SymbolExportLevel::C, - kind: SymbolExportKind::Data, - used: true, - }, - )); - } - - if tcx.sess.opts.share_generics() && tcx.local_crate_exports_generics() { - use rustc_middle::mir::mono::{Linkage, MonoItem, Visibility}; - use rustc_middle::ty::InstanceDef; - - // Normally, we require that shared monomorphizations are not hidden, - // because if we want to re-use a monomorphization from a Rust dylib, it - // needs to be exported. - // However, on platforms that don't allow for Rust dylibs, having - // external linkage is enough for monomorphization to be linked to. - let need_visibility = tcx.sess.target.dynamic_linking && !tcx.sess.target.only_cdylib; - - let (_, cgus) = tcx.collect_and_partition_mono_items(()); - - // The symbols created in this loop are sorted below it - #[allow(rustc::potential_query_instability)] - for (mono_item, data) in cgus.iter().flat_map(|cgu| cgu.items().iter()) { - if data.linkage != Linkage::External { - // We can only re-use things with external linkage, otherwise - // we'll get a linker error - continue; - } - - if need_visibility && data.visibility == Visibility::Hidden { - // If we potentially share things from Rust dylibs, they must - // not be hidden - continue; - } - - match *mono_item { - MonoItem::Fn(Instance { def: InstanceDef::Item(def), args }) => { - if args.non_erasable_generics(tcx, def).next().is_some() { - let symbol = ExportedSymbol::Generic(def, args); - symbols.push(( - symbol, - SymbolExportInfo { - level: SymbolExportLevel::Rust, - kind: SymbolExportKind::Text, - used: false, - }, - )); - } - } - MonoItem::Fn(Instance { def: InstanceDef::DropGlue(def_id, Some(ty)), args }) => { - // A little sanity-check - debug_assert_eq!( - args.non_erasable_generics(tcx, def_id).next(), - Some(GenericArgKind::Type(ty)) - ); - symbols.push(( - ExportedSymbol::DropGlue(ty), - SymbolExportInfo { - level: SymbolExportLevel::Rust, - kind: SymbolExportKind::Text, - used: false, - }, - )); - } - _ => { - // Any other symbols don't qualify for sharing - } - } - } - } - - // Sort so we get a stable incr. comp. hash. - symbols.sort_by_cached_key(|s| s.0.symbol_name_for_local_instance(tcx)); - - tcx.arena.alloc_from_iter(symbols) -} - -fn upstream_monomorphizations_provider( - tcx: TyCtxt<'_>, - (): (), -) -> DefIdMap, CrateNum>> { - let cnums = tcx.crates(()); - - let mut instances: DefIdMap> = Default::default(); - - let drop_in_place_fn_def_id = tcx.lang_items().drop_in_place_fn(); - - for &cnum in cnums.iter() { - for (exported_symbol, _) in tcx.exported_symbols(cnum).iter() { - let (def_id, args) = match *exported_symbol { - ExportedSymbol::Generic(def_id, args) => (def_id, args), - ExportedSymbol::DropGlue(ty) => { - if let Some(drop_in_place_fn_def_id) = drop_in_place_fn_def_id { - (drop_in_place_fn_def_id, tcx.mk_args(&[ty.into()])) - } else { - // `drop_in_place` in place does not exist, don't try - // to use it. - continue; - } - } - ExportedSymbol::NonGeneric(..) - | ExportedSymbol::ThreadLocalShim(..) - | ExportedSymbol::NoDefId(..) => { - // These are no monomorphizations - continue; - } - }; - - let args_map = instances.entry(def_id).or_default(); - - match args_map.entry(args) { - Occupied(mut e) => { - // If there are multiple monomorphizations available, - // we select one deterministically. - let other_cnum = *e.get(); - if tcx.stable_crate_id(other_cnum) > tcx.stable_crate_id(cnum) { - e.insert(cnum); - } - } - Vacant(e) => { - e.insert(cnum); - } - } - } - } - - instances -} - -fn upstream_monomorphizations_for_provider( - tcx: TyCtxt<'_>, - def_id: DefId, -) -> Option<&UnordMap, CrateNum>> { - debug_assert!(!def_id.is_local()); - tcx.upstream_monomorphizations(()).get(&def_id) -} - -fn upstream_drop_glue_for_provider<'tcx>( - tcx: TyCtxt<'tcx>, - args: GenericArgsRef<'tcx>, -) -> Option { - if let Some(def_id) = tcx.lang_items().drop_in_place_fn() { - tcx.upstream_monomorphizations_for(def_id).and_then(|monos| monos.get(&args).cloned()) - } else { - None - } -} - -fn is_unreachable_local_definition_provider(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { - !tcx.reachable_set(()).contains(&def_id) -} - -pub fn provide(providers: &mut Providers) { - providers.reachable_non_generics = reachable_non_generics_provider; - providers.is_reachable_non_generic = is_reachable_non_generic_provider_local; - providers.exported_symbols = exported_symbols_provider_local; - providers.upstream_monomorphizations = upstream_monomorphizations_provider; - providers.is_unreachable_local_definition = is_unreachable_local_definition_provider; - providers.upstream_drop_glue_for = upstream_drop_glue_for_provider; - providers.wasm_import_module_map = wasm_import_module_map; - providers.extern_queries.is_reachable_non_generic = is_reachable_non_generic_provider_extern; - providers.extern_queries.upstream_monomorphizations_for = - upstream_monomorphizations_for_provider; -} - -fn symbol_export_level(tcx: TyCtxt<'_>, sym_def_id: DefId) -> SymbolExportLevel { - // We export anything that's not mangled at the "C" layer as it probably has - // to do with ABI concerns. We do not, however, apply such treatment to - // special symbols in the standard library for various plumbing between - // core/std/allocators/etc. For example symbols used to hook up allocation - // are not considered for export - let codegen_fn_attrs = tcx.codegen_fn_attrs(sym_def_id); - let is_extern = codegen_fn_attrs.contains_extern_indicator(); - let std_internal = - codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL); - - if is_extern && !std_internal { - let target = &tcx.sess.target.llvm_target; - // WebAssembly cannot export data symbols, so reduce their export level - if target.contains("emscripten") { - if let DefKind::Static { .. } = tcx.def_kind(sym_def_id) { - return SymbolExportLevel::Rust; - } - } - - SymbolExportLevel::C - } else { - SymbolExportLevel::Rust - } -} - -/// This is the symbol name of the given instance instantiated in a specific crate. -pub fn symbol_name_for_instance_in_crate<'tcx>( - tcx: TyCtxt<'tcx>, - symbol: ExportedSymbol<'tcx>, - instantiating_crate: CrateNum, -) -> String { - // If this is something instantiated in the local crate then we might - // already have cached the name as a query result. - if instantiating_crate == LOCAL_CRATE { - return symbol.symbol_name_for_local_instance(tcx).to_string(); - } - - // This is something instantiated in an upstream crate, so we have to use - // the slower (because uncached) version of computing the symbol name. - match symbol { - ExportedSymbol::NonGeneric(def_id) => { - rustc_symbol_mangling::symbol_name_for_instance_in_crate( - tcx, - Instance::mono(tcx, def_id), - instantiating_crate, - ) - } - ExportedSymbol::Generic(def_id, args) => { - rustc_symbol_mangling::symbol_name_for_instance_in_crate( - tcx, - Instance::new(def_id, args), - instantiating_crate, - ) - } - ExportedSymbol::ThreadLocalShim(def_id) => { - rustc_symbol_mangling::symbol_name_for_instance_in_crate( - tcx, - ty::Instance { - def: ty::InstanceDef::ThreadLocalShim(def_id), - args: ty::GenericArgs::empty(), - }, - instantiating_crate, - ) - } - ExportedSymbol::DropGlue(ty) => rustc_symbol_mangling::symbol_name_for_instance_in_crate( - tcx, - Instance::resolve_drop_in_place(tcx, ty), - instantiating_crate, - ), - ExportedSymbol::NoDefId(symbol_name) => symbol_name.to_string(), - } -} - -/// This is the symbol name of the given instance as seen by the linker. -/// -/// On 32-bit Windows symbols are decorated according to their calling conventions. -pub fn linking_symbol_name_for_instance_in_crate<'tcx>( - tcx: TyCtxt<'tcx>, - symbol: ExportedSymbol<'tcx>, - instantiating_crate: CrateNum, -) -> String { - use rustc_target::abi::call::Conv; - - let mut undecorated = symbol_name_for_instance_in_crate(tcx, symbol, instantiating_crate); - - // thread local will not be a function call, - // so it is safe to return before windows symbol decoration check. - if let Some(name) = maybe_emutls_symbol_name(tcx, symbol, &undecorated) { - return name; - } - - let target = &tcx.sess.target; - if !target.is_like_windows { - // Mach-O has a global "_" suffix and `object` crate will handle it. - // ELF does not have any symbol decorations. - return undecorated; - } - - let prefix = match &target.arch[..] { - "x86" => Some('_'), - "x86_64" => None, - "arm64ec" => Some('#'), - // Only x86/64 use symbol decorations. - _ => return undecorated, - }; - - let instance = match symbol { - ExportedSymbol::NonGeneric(def_id) | ExportedSymbol::Generic(def_id, _) - if tcx.is_static(def_id) => - { - None - } - ExportedSymbol::NonGeneric(def_id) => Some(Instance::mono(tcx, def_id)), - ExportedSymbol::Generic(def_id, args) => Some(Instance::new(def_id, args)), - // DropGlue always use the Rust calling convention and thus follow the target's default - // symbol decoration scheme. - ExportedSymbol::DropGlue(..) => None, - // NoDefId always follow the target's default symbol decoration scheme. - ExportedSymbol::NoDefId(..) => None, - // ThreadLocalShim always follow the target's default symbol decoration scheme. - ExportedSymbol::ThreadLocalShim(..) => None, - }; - - let (conv, args) = instance - .map(|i| { - tcx.fn_abi_of_instance(ty::ParamEnv::reveal_all().and((i, ty::List::empty()))) - .unwrap_or_else(|_| bug!("fn_abi_of_instance({i:?}) failed")) - }) - .map(|fnabi| (fnabi.conv, &fnabi.args[..])) - .unwrap_or((Conv::Rust, &[])); - - // Decorate symbols with prefixes, suffixes and total number of bytes of arguments. - // Reference: https://docs.microsoft.com/en-us/cpp/build/reference/decorated-names?view=msvc-170 - let (prefix, suffix) = match conv { - Conv::X86Fastcall => ("@", "@"), - Conv::X86Stdcall => ("_", "@"), - Conv::X86VectorCall => ("", "@@"), - _ => { - if let Some(prefix) = prefix { - undecorated.insert(0, prefix); - } - return undecorated; - } - }; - - let args_in_bytes: u64 = args - .iter() - .map(|abi| abi.layout.size.bytes().next_multiple_of(target.pointer_width as u64 / 8)) - .sum(); - format!("{prefix}{undecorated}{suffix}{args_in_bytes}") -} - -pub fn exporting_symbol_name_for_instance_in_crate<'tcx>( - tcx: TyCtxt<'tcx>, - symbol: ExportedSymbol<'tcx>, - cnum: CrateNum, -) -> String { - let undecorated = symbol_name_for_instance_in_crate(tcx, symbol, cnum); - maybe_emutls_symbol_name(tcx, symbol, &undecorated).unwrap_or(undecorated) -} - -fn maybe_emutls_symbol_name<'tcx>( - tcx: TyCtxt<'tcx>, - symbol: ExportedSymbol<'tcx>, - undecorated: &str, -) -> Option { - if matches!(tcx.sess.tls_model(), TlsModel::Emulated) - && let ExportedSymbol::NonGeneric(def_id) = symbol - && tcx.is_thread_local_static(def_id) - { - // When using emutls, LLVM will add the `__emutls_v.` prefix to thread local symbols, - // and exported symbol name need to match this. - Some(format!("__emutls_v.{undecorated}")) - } else { - None - } -} - -fn wasm_import_module_map(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap { - // Build up a map from DefId to a `NativeLib` structure, where - // `NativeLib` internally contains information about - // `#[link(wasm_import_module = "...")]` for example. - let native_libs = tcx.native_libraries(cnum); - - let def_id_to_native_lib = native_libs - .iter() - .filter_map(|lib| lib.foreign_module.map(|id| (id, lib))) - .collect::>(); - - let mut ret = DefIdMap::default(); - for (def_id, lib) in tcx.foreign_modules(cnum).iter() { - let module = def_id_to_native_lib.get(def_id).and_then(|s| s.wasm_import_module()); - let Some(module) = module else { continue }; - ret.extend(lib.foreign_items.iter().map(|id| { - assert_eq!(id.krate, cnum); - (*id, module.to_string()) - })); - } - - ret -} +use crate::base::allocator_kind_for_codegen;use std::collections::hash_map:://3; +Entry::*;use rustc_ast::expand::allocator::{ALLOCATOR_METHODS,//((),());((),()); +NO_ALLOC_SHIM_IS_UNSTABLE};use rustc_data_structures::unord::UnordMap;use//({}); +rustc_hir::def::DefKind;use rustc_hir::def_id::{CrateNum,DefId,DefIdMap,//{();}; +LocalDefId,LOCAL_CRATE};use rustc_middle::middle::codegen_fn_attrs:://if true{}; +CodegenFnAttrFlags;use rustc_middle::middle::exported_symbols::{//if let _=(){}; +metadata_symbol_name,ExportedSymbol,SymbolExportInfo,SymbolExportKind,//((),()); +SymbolExportLevel,};use rustc_middle::query::LocalCrate;use rustc_middle::ty::// +Instance;use rustc_middle::ty::{self, SymbolName,TyCtxt};use rustc_middle::ty::{ +GenericArgKind,GenericArgsRef};use rustc_middle::util::Providers;use//if true{}; +rustc_session::config::{CrateType,OomStrategy};use rustc_target::spec::{//{();}; +SanitizerSet,TlsModel};pub fn threshold(tcx:TyCtxt<'_>)->SymbolExportLevel{//(); +crates_export_threshold(tcx.crate_types() )}fn crate_export_threshold(crate_type +:CrateType)->SymbolExportLevel{match crate_type{CrateType::Executable|CrateType +::Staticlib|CrateType::ProcMacro|CrateType::Cdylib=>{SymbolExportLevel::C}//{;}; +CrateType::Rlib|CrateType::Dylib=>SymbolExportLevel::Rust,}}pub fn//loop{break}; +crates_export_threshold(crate_types:&[CrateType])->SymbolExportLevel{if //{();}; +crate_types.iter().any(|&crate_type|((((crate_export_threshold(crate_type)))))== +SymbolExportLevel::Rust){SymbolExportLevel::Rust}else{SymbolExportLevel::C}}fn// +reachable_non_generics_provider(tcx:TyCtxt<'_>,_:LocalCrate)->DefIdMap{if!tcx.sess.opts.output_types.should_codegen(){;return Default +::default();;};let special_runtime_crate=tcx.is_panic_runtime(LOCAL_CRATE)||tcx. +is_compiler_builtins(LOCAL_CRATE);3;;let mut reachable_non_generics:DefIdMap<_>= +tcx.reachable_set((())).items().filter_map(|&def_id|{if let Some(parent_id)=tcx. +opt_local_parent(def_id)&&let DefKind::ForeignMod=tcx.def_kind(parent_id){();let +library=tcx.native_library(def_id)?;;return library.kind.is_statically_included( +).then_some(def_id);;}match tcx.def_kind(def_id){DefKind::Fn|DefKind::Static{..} +=>{}DefKind::AssocFn if tcx.impl_of_method(def_id .to_def_id()).is_some()=>{}_=> +return None,};{();};{();};let generics=tcx.generics_of(def_id);({});if generics. +requires_monomorphization(tcx){{;};return None;();}if!Instance::mono(tcx,def_id. +to_def_id()).def.generates_cgu_internal_copy(tcx )||tcx.codegen_fn_attrs(def_id. +to_def_id()).contains_extern_indicator(){Some(def_id )}else{None}}).map(|def_id| +{;let name=tcx.symbol_name(Instance::mono(tcx,def_id.to_def_id())).name;let used +=name=="rust_eh_personality";({});{;};let export_level=if special_runtime_crate{ +SymbolExportLevel::Rust}else{symbol_export_level(tcx,def_id.to_def_id())};3;;let +codegen_attrs=tcx.codegen_fn_attrs(def_id.to_def_id());let _=();let _=();debug!( +"EXPORTED SYMBOL (local): {} ({:?})",tcx.symbol_name(Instance ::mono(tcx,def_id. +to_def_id())),export_level);;;let info=SymbolExportInfo{level:export_level,kind: +if (((tcx.is_static(((def_id.to_def_id() )))))){if codegen_attrs.flags.contains( +CodegenFnAttrFlags::THREAD_LOCAL){SymbolExportKind ::Tls}else{SymbolExportKind:: +Data}}else{SymbolExportKind::Text},used:codegen_attrs.flags.contains(//let _=(); +CodegenFnAttrFlags::USED)||codegen_attrs.flags.contains(CodegenFnAttrFlags:://3; +USED_LINKER)||used,};3;(def_id.to_def_id(),info)}).into();3;if let Some(id)=tcx. +proc_macro_decls_static(()){*&*&();reachable_non_generics.insert(id.to_def_id(), +SymbolExportInfo{level:SymbolExportLevel::C,kind:SymbolExportKind::Data,used://; +false,},);();}reachable_non_generics}fn is_reachable_non_generic_provider_local( +tcx:TyCtxt<'_>,def_id:LocalDefId)->bool{;let export_threshold=threshold(tcx);;if +let Some(&info)=tcx.reachable_non_generics(LOCAL_CRATE ).get(&def_id.to_def_id() +){((((info.level.is_below_threshold(export_threshold)))))}else{((((false))))}}fn +is_reachable_non_generic_provider_extern(tcx:TyCtxt<'_>, def_id:DefId)->bool{tcx +.reachable_non_generics(def_id.krate).contains_key((((((((((&def_id))))))))))}fn +exported_symbols_provider_local(tcx:TyCtxt<'_>,_:LocalCrate,)->&[(//loop{break}; +ExportedSymbol<'_>,SymbolExportInfo)]{if!tcx.sess.opts.output_types.//if true{}; +should_codegen(){;return&[];;};let sorted=tcx.with_stable_hashing_context(|hcx|{ +tcx.reachable_non_generics(LOCAL_CRATE).to_sorted(&hcx,true)});;let mut symbols: +Vec<_>=(sorted.iter()).map(|(&def_id,&info)|(ExportedSymbol::NonGeneric(def_id), +info)).collect();;if!tcx.sess.target.dll_tls_export{symbols.extend(sorted.iter() +.filter_map(|(&def_id,&info)|{(( tcx.needs_thread_local_shim(def_id))).then(||{( +ExportedSymbol::ThreadLocalShim(def_id), SymbolExportInfo{level:info.level,kind: +SymbolExportKind::Text,used:info.used,},)})}))}if tcx.entry_fn(()).is_some(){(); +let exported_symbol=ExportedSymbol::NoDefId(SymbolName ::new(tcx,tcx.sess.target +.entry_name.as_ref()));3;3;symbols.push((exported_symbol,SymbolExportInfo{level: +SymbolExportLevel::C,kind:SymbolExportKind::Text,used:false,},));let _=||();}if +allocator_kind_for_codegen(tcx).is_some(){ for symbol_name in ALLOCATOR_METHODS. +iter().map((((((|method|(((((format!("__rust_{}",method.name)))))))))))).chain([ +"__rust_alloc_error_handler".to_string(),OomStrategy::SYMBOL.to_string()]){3;let +exported_symbol=ExportedSymbol::NoDefId(SymbolName::new(tcx,&symbol_name));();3; +symbols.push((exported_symbol,SymbolExportInfo{level:SymbolExportLevel::Rust,//; +kind:SymbolExportKind::Text,used:false,},));;}let exported_symbol=ExportedSymbol +::NoDefId(SymbolName::new(tcx,NO_ALLOC_SHIM_IS_UNSTABLE));((),());symbols.push(( +exported_symbol,SymbolExportInfo{level:SymbolExportLevel::Rust,kind://if true{}; +SymbolExportKind::Data,used:(false),},))}if tcx.sess.instrument_coverage()||tcx. +sess.opts.cg.profile_generate.enabled(){3;const PROFILER_WEAK_SYMBOLS:[&str;2]=[ +"__llvm_profile_raw_version","__llvm_profile_filename"];({});{;};symbols.extend( +PROFILER_WEAK_SYMBOLS.iter().map(|sym|{({});let exported_symbol=ExportedSymbol:: +NoDefId(SymbolName::new(tcx,sym));{();};(exported_symbol,SymbolExportInfo{level: +SymbolExportLevel::C,kind:SymbolExportKind::Data,used:false,},)}));;}if tcx.sess +.opts.unstable_opts.sanitizer.contains(SanitizerSet::MEMORY){loop{break};let mut +msan_weak_symbols=Vec::new();3;if tcx.sess.opts.unstable_opts.sanitizer_recover. +contains(SanitizerSet::MEMORY){;msan_weak_symbols.push("__msan_keep_going");}if +tcx.sess.opts.unstable_opts.sanitizer_memory_track_origins!=0{;msan_weak_symbols +.push("__msan_track_origins");;}symbols.extend(msan_weak_symbols.into_iter().map +(|sym|{;let exported_symbol=ExportedSymbol::NoDefId(SymbolName::new(tcx,sym));;( +exported_symbol,SymbolExportInfo{level:SymbolExportLevel::C,kind://loop{break;}; +SymbolExportKind::Data,used:false,},)}));*&*&();}if tcx.crate_types().contains(& +CrateType::Dylib)||tcx.crate_types().contains(&CrateType::ProcMacro){((),());let +symbol_name=metadata_symbol_name(tcx);();();let exported_symbol=ExportedSymbol:: +NoDefId(SymbolName::new(tcx,&symbol_name));{;};();symbols.push((exported_symbol, +SymbolExportInfo{level:SymbolExportLevel::C,kind:SymbolExportKind::Data,used://; +true,},));;}if tcx.sess.opts.share_generics()&&tcx.local_crate_exports_generics( +){;use rustc_middle::mir::mono::{Linkage,MonoItem,Visibility};use rustc_middle:: +ty::InstanceDef;;let need_visibility=tcx.sess.target.dynamic_linking&&!tcx.sess. +target.only_cdylib;;let(_,cgus)=tcx.collect_and_partition_mono_items(());#[allow +(rustc::potential_query_instability)]for(mono_item,data) in cgus.iter().flat_map +(|cgu|cgu.items().iter()){if data.linkage!=Linkage::External{();continue;();}if +need_visibility&&data.visibility==Visibility::Hidden{;continue;}match*mono_item{ +MonoItem::Fn(Instance{def:InstanceDef::Item(def),args})=>{if args.//loop{break}; +non_erasable_generics(tcx,def).next().is_some(){({});let symbol=ExportedSymbol:: +Generic(def,args);;symbols.push((symbol,SymbolExportInfo{level:SymbolExportLevel +::Rust,kind:SymbolExportKind::Text,used:false,},));;}}MonoItem::Fn(Instance{def: +InstanceDef::DropGlue(def_id,Some(ty)),args})=>{if true{};debug_assert_eq!(args. +non_erasable_generics(tcx,def_id).next(),Some(GenericArgKind::Type(ty)));{;};(); +symbols.push(((((((((ExportedSymbol::DropGlue(ty)))))))),SymbolExportInfo{level: +SymbolExportLevel::Rust,kind:SymbolExportKind::Text,used:false,},));3;}_=>{}}}}; +symbols.sort_by_cached_key(|s|s.0.symbol_name_for_local_instance(tcx));({});tcx. +arena.alloc_from_iter(symbols)}fn upstream_monomorphizations_provider(tcx://{;}; +TyCtxt<'_>,():(),)->DefIdMap,CrateNum>>{3;let cnums= +tcx.crates(());;let mut instances:DefIdMap>=Default::default();let +drop_in_place_fn_def_id=tcx.lang_items().drop_in_place_fn();3;for&cnum in cnums. +iter(){for(exported_symbol,_)in tcx.exported_symbols(cnum).iter(){();let(def_id, +args)=match*exported_symbol{ExportedSymbol::Generic (def_id,args)=>(def_id,args) +,ExportedSymbol::DropGlue(ty)=>{if let Some(drop_in_place_fn_def_id)=//let _=(); +drop_in_place_fn_def_id{((drop_in_place_fn_def_id,(tcx.mk_args(&[ty.into()]))))} +else{;continue;}}ExportedSymbol::NonGeneric(..)|ExportedSymbol::ThreadLocalShim( +..)|ExportedSymbol::NoDefId(..)=>{3;continue;;}};;;let args_map=instances.entry( +def_id).or_default();{();};match args_map.entry(args){Occupied(mut e)=>{({});let +other_cnum=*e.get();;if tcx.stable_crate_id(other_cnum)>tcx.stable_crate_id(cnum +){({});e.insert(cnum);({});}}Vacant(e)=>{{;};e.insert(cnum);{;};}}}}instances}fn +upstream_monomorphizations_for_provider(tcx:TyCtxt<'_>, def_id:DefId,)->Option<& +UnordMap,CrateNum>>{3;debug_assert!(!def_id.is_local());;tcx. +upstream_monomorphizations(()).get( &def_id)}fn upstream_drop_glue_for_provider< +'tcx>(tcx:TyCtxt<'tcx>,args:GenericArgsRef<'tcx>,)->Option{if let//(); +Some(def_id)=(((((((((((((tcx.lang_items( ))))))).drop_in_place_fn()))))))){tcx. +upstream_monomorphizations_for(def_id).and_then(|monos| monos.get(&args).cloned( +))}else{None}} fn is_unreachable_local_definition_provider(tcx:TyCtxt<'_>,def_id +:LocalDefId)->bool{(!(tcx.reachable_set(() ).contains(&def_id)))}pub fn provide( +providers:&mut Providers){if true{};let _=||();providers.reachable_non_generics= +reachable_non_generics_provider;*&*&();{();};providers.is_reachable_non_generic= +is_reachable_non_generic_provider_local;*&*&();{();};providers.exported_symbols= +exported_symbols_provider_local;{();};({});providers.upstream_monomorphizations= +upstream_monomorphizations_provider;;;providers.is_unreachable_local_definition= +is_unreachable_local_definition_provider;();();providers.upstream_drop_glue_for= +upstream_drop_glue_for_provider;((),());*&*&();providers.wasm_import_module_map= +wasm_import_module_map;{;};();providers.extern_queries.is_reachable_non_generic= +is_reachable_non_generic_provider_extern;*&*&();*&*&();providers.extern_queries. +upstream_monomorphizations_for=upstream_monomorphizations_for_provider;{();};}fn +symbol_export_level(tcx:TyCtxt<'_>,sym_def_id:DefId)->SymbolExportLevel{({});let +codegen_fn_attrs=tcx.codegen_fn_attrs(sym_def_id);((),());((),());let is_extern= +codegen_fn_attrs.contains_extern_indicator();;let std_internal=codegen_fn_attrs. +flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL);();if is_extern&&! +std_internal{{;};let target=&tcx.sess.target.llvm_target;{;};if target.contains( +"emscripten"){if let DefKind::Static{..}=tcx.def_kind(sym_def_id){((),());return +SymbolExportLevel::Rust;();}}SymbolExportLevel::C}else{SymbolExportLevel::Rust}} +pub fn symbol_name_for_instance_in_crate<'tcx>(tcx:TyCtxt<'tcx>,symbol://*&*&(); +ExportedSymbol<'tcx>,instantiating_crate:CrateNum,)->String{if //*&*&();((),()); +instantiating_crate==LOCAL_CRATE{3;return symbol.symbol_name_for_local_instance( +tcx).to_string();loop{break};}match symbol{ExportedSymbol::NonGeneric(def_id)=>{ +rustc_symbol_mangling::symbol_name_for_instance_in_crate(tcx, Instance::mono(tcx +,def_id),instantiating_crate,)}ExportedSymbol::Generic(def_id,args)=>{//((),()); +rustc_symbol_mangling::symbol_name_for_instance_in_crate(tcx,Instance::new(//(); +def_id,args),instantiating_crate,)}ExportedSymbol::ThreadLocalShim(def_id)=>{//; +rustc_symbol_mangling::symbol_name_for_instance_in_crate(tcx,ty::Instance{def:// +ty::InstanceDef::ThreadLocalShim(def_id),args: (((ty::GenericArgs::empty()))),}, +instantiating_crate,)}ExportedSymbol::DropGlue(ty)=>rustc_symbol_mangling:://(); +symbol_name_for_instance_in_crate(tcx,(Instance::resolve_drop_in_place(tcx,ty)), +instantiating_crate,),ExportedSymbol::NoDefId(symbol_name)=>symbol_name.//{();}; +to_string(),}}pub fn linking_symbol_name_for_instance_in_crate<'tcx>(tcx:TyCtxt +<'tcx>,symbol:ExportedSymbol<'tcx>,instantiating_crate:CrateNum,)->String{();use +rustc_target::abi::call::Conv;*&*&();((),());*&*&();((),());let mut undecorated= +symbol_name_for_instance_in_crate(tcx,symbol,instantiating_crate);3;if let Some( +name)=maybe_emutls_symbol_name(tcx,symbol,&undecorated){;return name;}let target +=&tcx.sess.target;3;if!target.is_like_windows{;return undecorated;;};let prefix= +match(&target.arch[..]){"x86"=>Some('_'),"x86_64"=>None,"arm64ec"=>Some('#'),_=> +return undecorated,};();();let instance=match symbol{ExportedSymbol::NonGeneric( +def_id)|ExportedSymbol::Generic(def_id,_)if (((tcx.is_static(def_id))))=>{None} +ExportedSymbol::NonGeneric(def_id)=>(((Some((( Instance::mono(tcx,def_id))))))), +ExportedSymbol::Generic(def_id,args)=>((Some( ((Instance::new(def_id,args)))))), +ExportedSymbol::DropGlue(..)=>None,ExportedSymbol::NoDefId(..)=>None,//let _=(); +ExportedSymbol::ThreadLocalShim(..)=>None,};;let(conv,args)=instance.map(|i|{tcx +.fn_abi_of_instance(((ty::ParamEnv::reveal_all()).and(( i,ty::List::empty())))). +unwrap_or_else(|_|bug!("fn_abi_of_instance({i:?}) failed")) }).map(|fnabi|(fnabi +.conv,&fnabi.args[..])).unwrap_or((Conv::Rust,&[]));3;3;let(prefix,suffix)=match +conv{Conv::X86Fastcall=>((("@"),("@"))),Conv::X86Stdcall=>((("_"),("@"))),Conv:: +X86VectorCall=>("","@@"),_=>{if let Some(prefix)=prefix{();undecorated.insert(0, +prefix);;};return undecorated;}};let args_in_bytes:u64=args.iter().map(|abi|abi. +layout.size.bytes().next_multiple_of(target.pointer_width as u64/8)).sum();({}); +format!("{prefix}{undecorated}{suffix}{args_in_bytes}")}pub fn//((),());((),()); +exporting_symbol_name_for_instance_in_crate<'tcx>(tcx:TyCtxt<'tcx>,symbol://{;}; +ExportedSymbol<'tcx>,cnum:CrateNum,)->String{let _=();if true{};let undecorated= +symbol_name_for_instance_in_crate(tcx,symbol,cnum);;maybe_emutls_symbol_name(tcx +,symbol,&undecorated).unwrap_or (undecorated)}fn maybe_emutls_symbol_name<'tcx>( +tcx:TyCtxt<'tcx>,symbol:ExportedSymbol<'tcx >,undecorated:&str,)->Option +{if ((matches!(tcx.sess. tls_model(),TlsModel::Emulated)))&&let ExportedSymbol:: +NonGeneric(def_id)=symbol&&((tcx.is_thread_local_static (def_id))){Some(format!( +"__emutls_v.{undecorated}"))}else{None} }fn wasm_import_module_map(tcx:TyCtxt<'_ +>,cnum:CrateNum)->DefIdMap{;let native_libs=tcx.native_libraries(cnum);; +let def_id_to_native_lib=native_libs.iter() .filter_map(|lib|lib.foreign_module. +map(|id|(id,lib))).collect::>();;let mut ret=DefIdMap::default();for +(def_id,lib)in tcx.foreign_modules(cnum).iter(){;let module=def_id_to_native_lib +.get(def_id).and_then(|s|s.wasm_import_module());;;let Some(module)=module else{ +continue};;ret.extend(lib.foreign_items.iter().map(|id|{assert_eq!(id.krate,cnum +);let _=||();loop{break};(*id,module.to_string())}));let _=||();let _=||();}ret} diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index b7bcaac3b18f6..b7d18831cae4f 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -1,2114 +1,526 @@ -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 jobserver::{Acquired, Client}; -use rustc_ast::attr; -use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; -use rustc_data_structures::memmap::Mmap; -use rustc_data_structures::profiling::{SelfProfilerRef, VerboseTimingGuard}; -use rustc_data_structures::sync::Lrc; -use rustc_errors::emitter::Emitter; -use rustc_errors::translation::Translate; -use rustc_errors::{ - Diag, DiagArgMap, DiagCtxt, DiagMessage, ErrCode, FatalError, FluentBundle, Level, MultiSpan, - Style, -}; -use rustc_fs_util::link_or_copy; -use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; -use rustc_incremental::{ - copy_cgu_workproduct_to_incr_comp_cache_dir, in_incr_comp_dir, in_incr_comp_dir_sess, -}; -use rustc_metadata::fs::copy_to_stdout; -use rustc_metadata::EncodedMetadata; -use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; -use rustc_middle::middle::exported_symbols::SymbolExportInfo; -use rustc_middle::ty::TyCtxt; -use rustc_session::config::{self, CrateType, Lto, OutFileName, OutputFilenames, OutputType}; -use rustc_session::config::{Passes, SwitchWithOptPath}; -use rustc_session::Session; -use rustc_span::source_map::SourceMap; -use rustc_span::symbol::sym; -use rustc_span::{BytePos, FileName, InnerSpan, Pos, Span}; -use rustc_target::spec::{MergeFunctions, SanitizerSet}; - -use crate::errors::ErrorCreatingRemarkDir; -use std::any::Any; -use std::fs; -use std::io; -use std::marker::PhantomData; -use std::mem; -use std::path::{Path, PathBuf}; -use std::str; -use std::sync::mpsc::{channel, Receiver, Sender}; -use std::sync::Arc; -use std::thread; - -const PRE_LTO_BC_EXT: &str = "pre-lto.bc"; - -/// What kind of object file to emit. -#[derive(Clone, Copy, PartialEq)] -pub enum EmitObj { - // No object file. - None, - - // Just uncompressed llvm bitcode. Provides easy compatibility with - // emscripten's ecc compiler, when used as the linker. - Bitcode, - - // Object code, possibly augmented with a bitcode section. - ObjectCode(BitcodeSection), -} - -/// What kind of llvm bitcode section to embed in an object file. -#[derive(Clone, Copy, PartialEq)] -pub enum BitcodeSection { - // No bitcode section. - None, - - // A full, uncompressed bitcode section. - Full, -} - -/// Module-specific configuration for `optimize_and_codegen`. -pub struct ModuleConfig { - /// Names of additional optimization passes to run. - pub passes: Vec, - /// Some(level) to optimize at a certain level, or None to run - /// absolutely no optimizations (used for the metadata module). - pub opt_level: Option, - - /// Some(level) to optimize binary size, or None to not affect program size. - pub opt_size: Option, - - pub pgo_gen: SwitchWithOptPath, - pub pgo_use: Option, - pub pgo_sample_use: Option, - pub debug_info_for_profiling: bool, - pub instrument_coverage: bool, - pub instrument_gcov: bool, - - pub sanitizer: SanitizerSet, - pub sanitizer_recover: SanitizerSet, - pub sanitizer_dataflow_abilist: Vec, - pub sanitizer_memory_track_origins: usize, - - // Flags indicating which outputs to produce. - pub emit_pre_lto_bc: bool, - pub emit_no_opt_bc: bool, - pub emit_bc: bool, - pub emit_ir: bool, - pub emit_asm: bool, - pub emit_obj: EmitObj, - pub emit_thin_lto: bool, - pub bc_cmdline: String, - - // Miscellaneous flags. These are mostly copied from command-line - // options. - pub verify_llvm_ir: bool, - pub no_prepopulate_passes: bool, - pub no_builtins: bool, - pub time_module: bool, - pub vectorize_loop: bool, - pub vectorize_slp: bool, - pub merge_functions: bool, - pub inline_threshold: Option, - pub emit_lifetime_markers: bool, - pub llvm_plugins: Vec, -} - -impl ModuleConfig { - fn new( - kind: ModuleKind, - tcx: TyCtxt<'_>, - no_builtins: bool, - is_compiler_builtins: bool, - ) -> ModuleConfig { - // If it's a regular module, use `$regular`, otherwise use `$other`. - // `$regular` and `$other` are evaluated lazily. - macro_rules! if_regular { - ($regular: expr, $other: expr) => { - if let ModuleKind::Regular = kind { $regular } else { $other } - }; - } - - let sess = tcx.sess; - let opt_level_and_size = if_regular!(Some(sess.opts.optimize), None); - - let save_temps = sess.opts.cg.save_temps; - - let should_emit_obj = sess.opts.output_types.contains_key(&OutputType::Exe) - || match kind { - ModuleKind::Regular => sess.opts.output_types.contains_key(&OutputType::Object), - ModuleKind::Allocator => false, - ModuleKind::Metadata => sess.opts.output_types.contains_key(&OutputType::Metadata), - }; - - let emit_obj = if !should_emit_obj { - EmitObj::None - } else if sess.target.obj_is_bitcode - || (sess.opts.cg.linker_plugin_lto.enabled() && !no_builtins) - { - // This case is selected if the target uses objects as bitcode, or - // if linker plugin LTO is enabled. In the linker plugin LTO case - // the assumption is that the final link-step will read the bitcode - // and convert it to object code. This may be done by either the - // native linker or rustc itself. - // - // Note, however, that the linker-plugin-lto requested here is - // explicitly ignored for `#![no_builtins]` crates. These crates are - // specifically ignored by rustc's LTO passes and wouldn't work if - // loaded into the linker. These crates define symbols that LLVM - // lowers intrinsics to, and these symbol dependencies aren't known - // until after codegen. As a result any crate marked - // `#![no_builtins]` is assumed to not participate in LTO and - // instead goes on to generate object code. - EmitObj::Bitcode - } else if need_bitcode_in_object(tcx) { - EmitObj::ObjectCode(BitcodeSection::Full) - } else { - EmitObj::ObjectCode(BitcodeSection::None) - }; - - ModuleConfig { - passes: if_regular!(sess.opts.cg.passes.clone(), vec![]), - - opt_level: opt_level_and_size, - opt_size: opt_level_and_size, - - pgo_gen: if_regular!( - sess.opts.cg.profile_generate.clone(), - SwitchWithOptPath::Disabled - ), - pgo_use: if_regular!(sess.opts.cg.profile_use.clone(), None), - pgo_sample_use: if_regular!(sess.opts.unstable_opts.profile_sample_use.clone(), None), - debug_info_for_profiling: sess.opts.unstable_opts.debug_info_for_profiling, - instrument_coverage: if_regular!(sess.instrument_coverage(), false), - instrument_gcov: if_regular!( - // compiler_builtins overrides the codegen-units settings, - // which is incompatible with -Zprofile which requires that - // only a single codegen unit is used per crate. - sess.opts.unstable_opts.profile && !is_compiler_builtins, - false - ), - - sanitizer: if_regular!(sess.opts.unstable_opts.sanitizer, SanitizerSet::empty()), - sanitizer_dataflow_abilist: if_regular!( - sess.opts.unstable_opts.sanitizer_dataflow_abilist.clone(), - Vec::new() - ), - sanitizer_recover: if_regular!( - sess.opts.unstable_opts.sanitizer_recover, - SanitizerSet::empty() - ), - sanitizer_memory_track_origins: if_regular!( - sess.opts.unstable_opts.sanitizer_memory_track_origins, - 0 - ), - - emit_pre_lto_bc: if_regular!( - save_temps || need_pre_lto_bitcode_for_incr_comp(sess), - false - ), - emit_no_opt_bc: if_regular!(save_temps, false), - emit_bc: if_regular!( - save_temps || sess.opts.output_types.contains_key(&OutputType::Bitcode), - save_temps - ), - emit_ir: if_regular!( - sess.opts.output_types.contains_key(&OutputType::LlvmAssembly), - false - ), - emit_asm: if_regular!( - sess.opts.output_types.contains_key(&OutputType::Assembly), - false - ), - emit_obj, - emit_thin_lto: sess.opts.unstable_opts.emit_thin_lto, - bc_cmdline: sess.target.bitcode_llvm_cmdline.to_string(), - - verify_llvm_ir: sess.verify_llvm_ir(), - no_prepopulate_passes: sess.opts.cg.no_prepopulate_passes, - no_builtins: no_builtins || sess.target.no_builtins, - - // Exclude metadata and allocator modules from time_passes output, - // since they throw off the "LLVM passes" measurement. - time_module: if_regular!(true, false), - - // Copy what clang does by turning on loop vectorization at O2 and - // slp vectorization at O3. - vectorize_loop: !sess.opts.cg.no_vectorize_loops - && (sess.opts.optimize == config::OptLevel::Default - || sess.opts.optimize == config::OptLevel::Aggressive), - vectorize_slp: !sess.opts.cg.no_vectorize_slp - && sess.opts.optimize == config::OptLevel::Aggressive, - - // Some targets (namely, NVPTX) interact badly with the - // MergeFunctions pass. This is because MergeFunctions can generate - // new function calls which may interfere with the target calling - // convention; e.g. for the NVPTX target, PTX kernels should not - // call other PTX kernels. MergeFunctions can also be configured to - // generate aliases instead, but aliases are not supported by some - // backends (again, NVPTX). Therefore, allow targets to opt out of - // the MergeFunctions pass, but otherwise keep the pass enabled (at - // O2 and O3) since it can be useful for reducing code size. - merge_functions: match sess - .opts - .unstable_opts - .merge_functions - .unwrap_or(sess.target.merge_functions) - { - MergeFunctions::Disabled => false, - MergeFunctions::Trampolines | MergeFunctions::Aliases => { - use config::OptLevel::*; - match sess.opts.optimize { - Aggressive | Default | SizeMin | Size => true, - Less | No => false, - } - } - }, - - inline_threshold: sess.opts.cg.inline_threshold, - emit_lifetime_markers: sess.emit_lifetime_markers(), - llvm_plugins: if_regular!(sess.opts.unstable_opts.llvm_plugins.clone(), vec![]), - } - } - - pub fn bitcode_needed(&self) -> bool { - self.emit_bc - || self.emit_obj == EmitObj::Bitcode - || self.emit_obj == EmitObj::ObjectCode(BitcodeSection::Full) - } -} - -/// Configuration passed to the function returned by the `target_machine_factory`. -pub struct TargetMachineFactoryConfig { - /// Split DWARF is enabled in LLVM by checking that `TM.MCOptions.SplitDwarfFile` isn't empty, - /// so the path to the dwarf object has to be provided when we create the target machine. - /// This can be ignored by backends which do not need it for their Split DWARF support. - pub split_dwarf_file: Option, - - /// The name of the output object file. Used for setting OutputFilenames in target options - /// so that LLVM can emit the CodeView S_OBJNAME record in pdb files - pub output_obj_file: Option, -} - -impl TargetMachineFactoryConfig { - pub fn new( - cgcx: &CodegenContext, - module_name: &str, - ) -> TargetMachineFactoryConfig { - let split_dwarf_file = if cgcx.target_can_use_split_dwarf { - cgcx.output_filenames.split_dwarf_path( - cgcx.split_debuginfo, - cgcx.split_dwarf_kind, - Some(module_name), - ) - } else { - None - }; - - let output_obj_file = - Some(cgcx.output_filenames.temp_path(OutputType::Object, Some(module_name))); - TargetMachineFactoryConfig { split_dwarf_file, output_obj_file } - } -} - -pub type TargetMachineFactoryFn = Arc< - dyn Fn( - TargetMachineFactoryConfig, - ) -> Result< - ::TargetMachine, - ::TargetMachineError, - > + Send - + Sync, ->; - -pub type ExportedSymbols = FxHashMap>>; - -/// Additional resources used by optimize_and_codegen (not module specific) -#[derive(Clone)] -pub struct CodegenContext { - // Resources needed when running LTO - pub prof: SelfProfilerRef, - pub lto: Lto, - pub save_temps: bool, - pub fewer_names: bool, - pub time_trace: bool, - pub exported_symbols: Option>, - pub opts: Arc, - pub crate_types: Vec, - pub each_linked_rlib_for_lto: Vec<(CrateNum, PathBuf)>, - pub output_filenames: Arc, - pub regular_module_config: Arc, - pub metadata_module_config: Arc, - pub allocator_module_config: Arc, - pub tm_factory: TargetMachineFactoryFn, - pub msvc_imps_needed: bool, - pub is_pe_coff: bool, - pub target_can_use_split_dwarf: bool, - pub target_arch: String, - pub split_debuginfo: rustc_target::spec::SplitDebuginfo, - pub split_dwarf_kind: rustc_session::config::SplitDwarfKind, - - /// All commandline args used to invoke the compiler, with @file args fully expanded. - /// This will only be used within debug info, e.g. in the pdb file on windows - /// This is mainly useful for other tools that reads that debuginfo to figure out - /// how to call the compiler with the same arguments. - pub expanded_args: Vec, - - /// Emitter to use for diagnostics produced during codegen. - pub diag_emitter: SharedEmitter, - /// LLVM optimizations for which we want to print remarks. - pub remark: Passes, - /// Directory into which should the LLVM optimization remarks be written. - /// If `None`, they will be written to stderr. - pub remark_dir: Option, - /// The incremental compilation session directory, or None if we are not - /// compiling incrementally - pub incr_comp_session_dir: Option, - /// Channel back to the main control thread to send messages to - pub coordinator_send: Sender>, - /// `true` if the codegen should be run in parallel. - /// - /// Depends on [`CodegenBackend::supports_parallel()`] and `-Zno_parallel_backend`. - pub parallel: bool, -} - -impl CodegenContext { - pub fn create_dcx(&self) -> DiagCtxt { - DiagCtxt::new(Box::new(self.diag_emitter.clone())) - } - - pub fn config(&self, kind: ModuleKind) -> &ModuleConfig { - match kind { - ModuleKind::Regular => &self.regular_module_config, - ModuleKind::Metadata => &self.metadata_module_config, - ModuleKind::Allocator => &self.allocator_module_config, - } - } -} - -fn generate_lto_work( - cgcx: &CodegenContext, - needs_fat_lto: Vec>, - needs_thin_lto: Vec<(String, B::ThinBuffer)>, - import_only_modules: Vec<(SerializedModule, WorkProduct)>, -) -> Vec<(WorkItem, u64)> { - let _prof_timer = cgcx.prof.generic_activity("codegen_generate_lto_work"); - - if !needs_fat_lto.is_empty() { - assert!(needs_thin_lto.is_empty()); - let module = - B::run_fat_lto(cgcx, needs_fat_lto, import_only_modules).unwrap_or_else(|e| e.raise()); - // We are adding a single work item, so the cost doesn't matter. - vec![(WorkItem::LTO(module), 0)] - } else { - assert!(needs_fat_lto.is_empty()); - let (lto_modules, copy_jobs) = B::run_thin_lto(cgcx, needs_thin_lto, import_only_modules) - .unwrap_or_else(|e| e.raise()); - lto_modules - .into_iter() - .map(|module| { - let cost = module.cost(); - (WorkItem::LTO(module), cost) - }) - .chain(copy_jobs.into_iter().map(|wp| { - ( - WorkItem::CopyPostLtoArtifacts(CachedModuleCodegen { - name: wp.cgu_name.clone(), - source: wp, - }), - 0, // copying is very cheap - ) - })) - .collect() - } -} - -pub struct CompiledModules { - pub modules: Vec, - pub allocator_module: Option, -} - -fn need_bitcode_in_object(tcx: TyCtxt<'_>) -> bool { - let sess = tcx.sess; - let requested_for_rlib = sess.opts.cg.embed_bitcode - && tcx.crate_types().contains(&CrateType::Rlib) - && sess.opts.output_types.contains_key(&OutputType::Exe); - let forced_by_target = sess.target.forces_embed_bitcode; - requested_for_rlib || forced_by_target -} - -fn need_pre_lto_bitcode_for_incr_comp(sess: &Session) -> bool { - if sess.opts.incremental.is_none() { - return false; - } - - match sess.lto() { - Lto::No => false, - Lto::Fat | Lto::Thin | Lto::ThinLocal => true, - } -} - -pub fn start_async_codegen( - backend: B, - tcx: TyCtxt<'_>, - target_cpu: String, - metadata: EncodedMetadata, - metadata_module: Option, -) -> OngoingCodegen { - let (coordinator_send, coordinator_receive) = channel(); - let sess = tcx.sess; - - let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID); - let no_builtins = attr::contains_name(crate_attrs, sym::no_builtins); - let is_compiler_builtins = attr::contains_name(crate_attrs, sym::compiler_builtins); - - let crate_info = CrateInfo::new(tcx, target_cpu); - - let regular_config = - ModuleConfig::new(ModuleKind::Regular, tcx, no_builtins, is_compiler_builtins); - let metadata_config = - ModuleConfig::new(ModuleKind::Metadata, tcx, no_builtins, is_compiler_builtins); - let allocator_config = - ModuleConfig::new(ModuleKind::Allocator, tcx, no_builtins, is_compiler_builtins); - - let (shared_emitter, shared_emitter_main) = SharedEmitter::new(); - let (codegen_worker_send, codegen_worker_receive) = channel(); - - let coordinator_thread = start_executing_work( - backend.clone(), - tcx, - &crate_info, - shared_emitter, - codegen_worker_send, - coordinator_receive, - sess.jobserver.clone(), - Arc::new(regular_config), - Arc::new(metadata_config), - Arc::new(allocator_config), - coordinator_send.clone(), - ); - - OngoingCodegen { - backend, - metadata, - metadata_module, - crate_info, - - codegen_worker_receive, - shared_emitter_main, - coordinator: Coordinator { - sender: coordinator_send, - future: Some(coordinator_thread), - phantom: PhantomData, - }, - output_filenames: tcx.output_filenames(()).clone(), - } -} - -fn copy_all_cgu_workproducts_to_incr_comp_cache_dir( - sess: &Session, - compiled_modules: &CompiledModules, -) -> FxIndexMap { - let mut work_products = FxIndexMap::default(); - - if sess.opts.incremental.is_none() { - return work_products; - } - - let _timer = sess.timer("copy_all_cgu_workproducts_to_incr_comp_cache_dir"); - - for module in compiled_modules.modules.iter().filter(|m| m.kind == ModuleKind::Regular) { - let mut files = Vec::new(); - if let Some(object_file_path) = &module.object { - files.push(("o", object_file_path.as_path())); - } - if let Some(dwarf_object_file_path) = &module.dwarf_object { - files.push(("dwo", dwarf_object_file_path.as_path())); - } - - if let Some((id, product)) = - copy_cgu_workproduct_to_incr_comp_cache_dir(sess, &module.name, files.as_slice()) - { - work_products.insert(id, product); - } - } - - work_products -} - -fn produce_final_output_artifacts( - sess: &Session, - compiled_modules: &CompiledModules, - crate_output: &OutputFilenames, -) { - let mut user_wants_bitcode = false; - let mut user_wants_objects = false; - - // Produce final compile outputs. - let copy_gracefully = |from: &Path, to: &OutFileName| match to { - OutFileName::Stdout => { - if let Err(e) = copy_to_stdout(from) { - sess.dcx().emit_err(errors::CopyPath::new(from, to.as_path(), e)); - } - } - OutFileName::Real(path) => { - if let Err(e) = fs::copy(from, path) { - sess.dcx().emit_err(errors::CopyPath::new(from, path, e)); - } - } - }; - - let copy_if_one_unit = |output_type: OutputType, keep_numbered: bool| { - if compiled_modules.modules.len() == 1 { - // 1) Only one codegen unit. In this case it's no difficulty - // to copy `foo.0.x` to `foo.x`. - let module_name = Some(&compiled_modules.modules[0].name[..]); - let path = crate_output.temp_path(output_type, module_name); - let output = crate_output.path(output_type); - if !output_type.is_text_output() && output.is_tty() { - sess.dcx() - .emit_err(errors::BinaryOutputToTty { shorthand: output_type.shorthand() }); - } else { - copy_gracefully(&path, &output); - } - if !sess.opts.cg.save_temps && !keep_numbered { - // The user just wants `foo.x`, not `foo.#module-name#.x`. - ensure_removed(sess.dcx(), &path); - } - } else { - let extension = crate_output - .temp_path(output_type, None) - .extension() - .unwrap() - .to_str() - .unwrap() - .to_owned(); - - if crate_output.outputs.contains_explicit_name(&output_type) { - // 2) Multiple codegen units, with `--emit foo=some_name`. We have - // no good solution for this case, so warn the user. - sess.dcx().emit_warn(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.dcx().emit_warn(errors::IgnoringOutput { extension }); - } else { - // 4) Multiple codegen units, but no explicit name. We - // just leave the `foo.0.x` files in place. - // (We don't have to do any work in this case.) - } - } - }; - - // Flag to indicate whether the user explicitly requested bitcode. - // Otherwise, we produced it only as a temporary output, and will need - // to get rid of it. - for output_type in crate_output.outputs.keys() { - match *output_type { - OutputType::Bitcode => { - user_wants_bitcode = true; - // Copy to .bc, but always keep the .0.bc. There is a later - // check to figure out if we should delete .0.bc files, or keep - // them for making an rlib. - copy_if_one_unit(OutputType::Bitcode, true); - } - OutputType::LlvmAssembly => { - copy_if_one_unit(OutputType::LlvmAssembly, false); - } - OutputType::Assembly => { - copy_if_one_unit(OutputType::Assembly, false); - } - OutputType::Object => { - user_wants_objects = true; - copy_if_one_unit(OutputType::Object, true); - } - OutputType::Mir | OutputType::Metadata | OutputType::Exe | OutputType::DepInfo => {} - } - } - - // Clean up unwanted temporary files. - - // We create the following files by default: - // - #crate#.#module-name#.bc - // - #crate#.#module-name#.o - // - #crate#.crate.metadata.bc - // - #crate#.crate.metadata.o - // - #crate#.o (linked from crate.##.o) - // - #crate#.bc (copied from crate.##.bc) - // We may create additional files if requested by the user (through - // `-C save-temps` or `--emit=` flags). - - if !sess.opts.cg.save_temps { - // Remove the temporary .#module-name#.o objects. If the user didn't - // explicitly request bitcode (with --emit=bc), and the bitcode is not - // needed for building an rlib, then we must remove .#module-name#.bc as - // well. - - // Specific rules for keeping .#module-name#.bc: - // - If the user requested bitcode (`user_wants_bitcode`), and - // codegen_units > 1, then keep it. - // - If the user requested bitcode but codegen_units == 1, then we - // can toss .#module-name#.bc because we copied it to .bc earlier. - // - If we're not building an rlib and the user didn't request - // bitcode, then delete .#module-name#.bc. - // If you change how this works, also update back::link::link_rlib, - // where .#module-name#.bc files are (maybe) deleted after making an - // rlib. - let needs_crate_object = crate_output.outputs.contains_key(&OutputType::Exe); - - let keep_numbered_bitcode = user_wants_bitcode && sess.codegen_units().as_usize() > 1; - - let keep_numbered_objects = - needs_crate_object || (user_wants_objects && sess.codegen_units().as_usize() > 1); - - for module in compiled_modules.modules.iter() { - if let Some(ref path) = module.object { - if !keep_numbered_objects { - ensure_removed(sess.dcx(), path); - } - } - - if let Some(ref path) = module.dwarf_object { - if !keep_numbered_objects { - ensure_removed(sess.dcx(), path); - } - } - - if let Some(ref path) = module.bytecode { - if !keep_numbered_bitcode { - ensure_removed(sess.dcx(), path); - } - } - } - - if !user_wants_bitcode { - if let Some(ref allocator_module) = compiled_modules.allocator_module { - if let Some(ref path) = allocator_module.bytecode { - ensure_removed(sess.dcx(), path); - } - } - } - } - - // We leave the following files around by default: - // - #crate#.o - // - #crate#.crate.metadata.o - // - #crate#.bc - // These are used in linking steps and will be cleaned up afterward. -} - -pub(crate) enum WorkItem { - /// Optimize a newly codegened, totally unoptimized module. - Optimize(ModuleCodegen), - /// Copy the post-LTO artifacts from the incremental cache to the output - /// directory. - CopyPostLtoArtifacts(CachedModuleCodegen), - /// Performs (Thin)LTO on the given module. - LTO(lto::LtoModuleCodegen), -} - -impl WorkItem { - pub fn module_kind(&self) -> ModuleKind { - match *self { - WorkItem::Optimize(ref m) => m.kind, - WorkItem::CopyPostLtoArtifacts(_) | WorkItem::LTO(_) => ModuleKind::Regular, - } - } - - /// Generate a short description of this work item suitable for use as a thread name. - fn short_description(&self) -> String { - // `pthread_setname()` on *nix ignores anything beyond the first 15 - // bytes. Use short descriptions to maximize the space available for - // the module name. - #[cfg(not(windows))] - fn desc(short: &str, _long: &str, name: &str) -> String { - // The short label is three bytes, and is followed by a space. That - // leaves 11 bytes for the CGU name. How we obtain those 11 bytes - // depends on the CGU name form. - // - // - Non-incremental, e.g. `regex.f10ba03eb5ec7975-cgu.0`: the part - // before the `-cgu.0` is the same for every CGU, so use the - // `cgu.0` part. The number suffix will be different for each - // CGU. - // - // - Incremental (normal), e.g. `2i52vvl2hco29us0`: use the whole - // name because each CGU will have a unique ASCII hash, and the - // first 11 bytes will be enough to identify it. - // - // - Incremental (with `-Zhuman-readable-cgu-names`), e.g. - // `regex.f10ba03eb5ec7975-re_builder.volatile`: use the whole - // name. The first 11 bytes won't be enough to uniquely identify - // it, but no obvious substring will, and this is a rarely used - // option so it doesn't matter much. - // - assert_eq!(short.len(), 3); - let name = if let Some(index) = name.find("-cgu.") { - &name[index + 1..] // +1 skips the leading '-'. - } else { - name - }; - format!("{short} {name}") - } - - // Windows has no thread name length limit, so use more descriptive names. - #[cfg(windows)] - fn desc(_short: &str, long: &str, name: &str) -> String { - format!("{long} {name}") - } - - match self { - WorkItem::Optimize(m) => desc("opt", "optimize module", &m.name), - WorkItem::CopyPostLtoArtifacts(m) => desc("cpy", "copy LTO artifacts for", &m.name), - WorkItem::LTO(m) => desc("lto", "LTO module", m.name()), - } - } -} - -/// A result produced by the backend. -pub(crate) enum WorkItemResult { - /// The backend has finished compiling a CGU, nothing more required. - Finished(CompiledModule), - - /// The backend has finished compiling a CGU, which now needs linking - /// because `-Zcombine-cgu` was specified. - NeedsLink(ModuleCodegen), - - /// The backend has finished compiling a CGU, which now needs to go through - /// fat LTO. - NeedsFatLto(FatLtoInput), - - /// The backend has finished compiling a CGU, which now needs to go through - /// thin LTO. - NeedsThinLto(String, B::ThinBuffer), -} - -pub enum FatLtoInput { - Serialized { name: String, buffer: B::ModuleBuffer }, - InMemory(ModuleCodegen), -} - -/// Actual LTO type we end up choosing based on multiple factors. -pub enum ComputedLtoType { - No, - Thin, - Fat, -} - -pub fn compute_per_cgu_lto_type( - sess_lto: &Lto, - opts: &config::Options, - sess_crate_types: &[CrateType], - module_kind: ModuleKind, -) -> ComputedLtoType { - // Metadata modules never participate in LTO regardless of the lto - // settings. - if module_kind == ModuleKind::Metadata { - return ComputedLtoType::No; - } - - // If the linker does LTO, we don't have to do it. Note that we - // keep doing full LTO, if it is requested, as not to break the - // assumption that the output will be a single module. - let linker_does_lto = opts.cg.linker_plugin_lto.enabled(); - - // When we're automatically doing ThinLTO for multi-codegen-unit - // builds we don't actually want to LTO the allocator modules if - // it shows up. This is due to various linker shenanigans that - // we'll encounter later. - let is_allocator = module_kind == ModuleKind::Allocator; - - // We ignore a request for full crate graph LTO if the crate type - // is only an rlib, as there is no full crate graph to process, - // that'll happen later. - // - // This use case currently comes up primarily for targets that - // require LTO so the request for LTO is always unconditionally - // passed down to the backend, but we don't actually want to do - // anything about it yet until we've got a final product. - let is_rlib = sess_crate_types.len() == 1 && sess_crate_types[0] == CrateType::Rlib; - - match sess_lto { - Lto::ThinLocal if !linker_does_lto && !is_allocator => ComputedLtoType::Thin, - Lto::Thin if !linker_does_lto && !is_rlib => ComputedLtoType::Thin, - Lto::Fat if !is_rlib => ComputedLtoType::Fat, - _ => ComputedLtoType::No, - } -} - -fn execute_optimize_work_item( - cgcx: &CodegenContext, - module: ModuleCodegen, - module_config: &ModuleConfig, -) -> Result, FatalError> { - let dcx = cgcx.create_dcx(); - - unsafe { - B::optimize(cgcx, &dcx, &module, module_config)?; - } - - // After we've done the initial round of optimizations we need to - // decide whether to synchronously codegen this module or ship it - // back to the coordinator thread for further LTO processing (which - // has to wait for all the initial modules to be optimized). - - let lto_type = compute_per_cgu_lto_type(&cgcx.lto, &cgcx.opts, &cgcx.crate_types, module.kind); - - // If we're doing some form of incremental LTO then we need to be sure to - // save our module to disk first. - let bitcode = if cgcx.config(module.kind).emit_pre_lto_bc { - let filename = pre_lto_bitcode_filename(&module.name); - cgcx.incr_comp_session_dir.as_ref().map(|path| path.join(&filename)) - } else { - None - }; - - match lto_type { - ComputedLtoType::No => finish_intra_module_work(cgcx, module, module_config), - ComputedLtoType::Thin => { - let (name, thin_buffer) = B::prepare_thin(module); - if let Some(path) = bitcode { - fs::write(&path, thin_buffer.data()).unwrap_or_else(|e| { - panic!("Error writing pre-lto-bitcode file `{}`: {}", path.display(), e); - }); - } - Ok(WorkItemResult::NeedsThinLto(name, thin_buffer)) - } - ComputedLtoType::Fat => match bitcode { - Some(path) => { - let (name, buffer) = B::serialize_module(module); - fs::write(&path, buffer.data()).unwrap_or_else(|e| { - panic!("Error writing pre-lto-bitcode file `{}`: {}", path.display(), e); - }); - Ok(WorkItemResult::NeedsFatLto(FatLtoInput::Serialized { name, buffer })) - } - None => Ok(WorkItemResult::NeedsFatLto(FatLtoInput::InMemory(module))), - }, - } -} - -fn execute_copy_from_cache_work_item( - cgcx: &CodegenContext, - module: CachedModuleCodegen, - module_config: &ModuleConfig, -) -> WorkItemResult { - assert!(module_config.emit_obj != EmitObj::None); - - let incr_comp_session_dir = cgcx.incr_comp_session_dir.as_ref().unwrap(); - - let load_from_incr_comp_dir = |output_path: PathBuf, saved_path: &str| { - let source_file = in_incr_comp_dir(incr_comp_session_dir, saved_path); - debug!( - "copying preexisting module `{}` from {:?} to {}", - module.name, - source_file, - output_path.display() - ); - match link_or_copy(&source_file, &output_path) { - Ok(_) => Some(output_path), - Err(error) => { - cgcx.create_dcx().emit_err(errors::CopyPathBuf { source_file, output_path, error }); - None - } - } - }; - - let object = load_from_incr_comp_dir( - cgcx.output_filenames.temp_path(OutputType::Object, Some(&module.name)), - module.source.saved_files.get("o").unwrap_or_else(|| { - cgcx.create_dcx().emit_fatal(errors::NoSavedObjectFile { cgu_name: &module.name }) - }), - ); - let dwarf_object = - module.source.saved_files.get("dwo").as_ref().and_then(|saved_dwarf_object_file| { - let dwarf_obj_out = cgcx - .output_filenames - .split_dwarf_path(cgcx.split_debuginfo, cgcx.split_dwarf_kind, Some(&module.name)) - .expect( - "saved dwarf object in work product but `split_dwarf_path` returned `None`", - ); - load_from_incr_comp_dir(dwarf_obj_out, saved_dwarf_object_file) - }); - - WorkItemResult::Finished(CompiledModule { - name: module.name, - kind: ModuleKind::Regular, - object, - dwarf_object, - bytecode: None, - }) -} - -fn execute_lto_work_item( - cgcx: &CodegenContext, - module: lto::LtoModuleCodegen, - module_config: &ModuleConfig, -) -> Result, FatalError> { - let module = unsafe { module.optimize(cgcx)? }; - finish_intra_module_work(cgcx, module, module_config) -} - -fn finish_intra_module_work( - cgcx: &CodegenContext, - module: ModuleCodegen, - module_config: &ModuleConfig, -) -> Result, FatalError> { - let dcx = cgcx.create_dcx(); - - if !cgcx.opts.unstable_opts.combine_cgu - || module.kind == ModuleKind::Metadata - || module.kind == ModuleKind::Allocator - { - let module = unsafe { B::codegen(cgcx, &dcx, module, module_config)? }; - Ok(WorkItemResult::Finished(module)) - } else { - Ok(WorkItemResult::NeedsLink(module)) - } -} - -/// Messages sent to the coordinator. -pub(crate) enum Message { - /// A jobserver token has become available. Sent from the jobserver helper - /// thread. - Token(io::Result), - - /// The backend has finished processing a work item for a codegen unit. - /// Sent from a backend worker thread. - WorkItem { result: Result, Option>, worker_id: usize }, - - /// The frontend has finished generating something (backend IR or a - /// post-LTO artifact) for a codegen unit, and it should be passed to the - /// backend. Sent from the main thread. - CodegenDone { llvm_work_item: WorkItem, cost: u64 }, - - /// Similar to `CodegenDone`, but for reusing a pre-LTO artifact - /// Sent from the main thread. - AddImportOnlyModule { - module_data: SerializedModule, - work_product: WorkProduct, - }, - - /// The frontend has finished generating everything for all codegen units. - /// Sent from the main thread. - CodegenComplete, - - /// Some normal-ish compiler error occurred, and codegen should be wound - /// down. Sent from the main thread. - CodegenAborted, -} - -/// A message sent from the coordinator thread to the main thread telling it to -/// process another codegen unit. -pub struct CguMessage; - -// A cut-down version of `rustc_errors::DiagInner` that impls `Send`, which -// can be used to send diagnostics from codegen threads to the main thread. -// It's missing the following fields from `rustc_errors::DiagInner`. -// - `span`: it doesn't impl `Send`. -// - `suggestions`: it doesn't impl `Send`, and isn't used for codegen -// diagnostics. -// - `sort_span`: it doesn't impl `Send`. -// - `is_lint`: lints aren't relevant during codegen. -// - `emitted_at`: not used for codegen diagnostics. -struct Diagnostic { - level: Level, - messages: Vec<(DiagMessage, Style)>, - code: Option, - children: Vec, - args: DiagArgMap, -} - -// A cut-down version of `rustc_errors::Subdiag` that impls `Send`. It's -// missing the following fields from `rustc_errors::Subdiag`. -// - `span`: it doesn't impl `Send`. -pub struct Subdiagnostic { - level: Level, - messages: Vec<(DiagMessage, Style)>, -} - -#[derive(PartialEq, Clone, Copy, Debug)] -enum MainThreadState { - /// Doing nothing. - Idle, - - /// Doing codegen, i.e. MIR-to-LLVM-IR conversion. - Codegenning, - - /// Idle, but lending the compiler process's Token to an LLVM thread so it can do useful work. - Lending, -} - -fn start_executing_work( - backend: B, - tcx: TyCtxt<'_>, - crate_info: &CrateInfo, - shared_emitter: SharedEmitter, - codegen_worker_send: Sender, - coordinator_receive: Receiver>, - jobserver: Client, - regular_config: Arc, - metadata_config: Arc, - allocator_config: Arc, - tx_to_llvm_workers: Sender>, -) -> thread::JoinHandle> { - 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(crate_info, None, &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(); - - let copy_symbols = |cnum| { - let symbols = tcx - .exported_symbols(cnum) - .iter() - .map(|&(s, lvl)| (symbol_name_for_instance_in_crate(tcx, s, cnum), lvl)) - .collect(); - Arc::new(symbols) - }; - - match sess.lto() { - Lto::No => None, - Lto::ThinLocal => { - exported_symbols.insert(LOCAL_CRATE, copy_symbols(LOCAL_CRATE)); - Some(Arc::new(exported_symbols)) - } - Lto::Fat | Lto::Thin => { - exported_symbols.insert(LOCAL_CRATE, copy_symbols(LOCAL_CRATE)); - for &(cnum, ref _path) in &each_linked_rlib_for_lto { - exported_symbols.insert(cnum, copy_symbols(cnum)); - } - Some(Arc::new(exported_symbols)) - } - } - }; - - // First up, convert our jobserver into a helper thread so we can use normal - // mpsc channels to manage our messages and such. - // After we've requested tokens then we'll, when we can, - // get tokens on `coordinator_receive` which will - // get managed in the main loop below. - let coordinator_send2 = coordinator_send.clone(); - let helper = jobserver - .into_helper_thread(move |token| { - drop(coordinator_send2.send(Box::new(Message::Token::(token)))); - }) - .expect("failed to spawn helper thread"); - - 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. - config::OptLevel::No - } else { - tcx.backend_optimization_level(()) - }; - let backend_features = tcx.global_backend_features(()); - - let remark_dir = if let Some(ref dir) = sess.opts.unstable_opts.remark_dir { - let result = fs::create_dir_all(dir).and_then(|_| dir.canonicalize()); - match result { - Ok(dir) => Some(dir), - Err(error) => sess.dcx().emit_fatal(ErrorCreatingRemarkDir { error }), - } - } else { - None - }; - - let cgcx = CodegenContext:: { - crate_types: tcx.crate_types().to_vec(), - each_linked_rlib_for_lto, - lto: sess.lto(), - fewer_names: sess.fewer_names(), - save_temps: sess.opts.cg.save_temps, - time_trace: sess.opts.unstable_opts.llvm_time_trace, - opts: Arc::new(sess.opts.clone()), - prof: sess.prof.clone(), - exported_symbols, - remark: sess.opts.cg.remark.clone(), - remark_dir, - incr_comp_session_dir: sess.incr_comp_session_dir_opt().map(|r| r.clone()), - coordinator_send, - expanded_args: tcx.sess.expanded_args.clone(), - diag_emitter: shared_emitter.clone(), - output_filenames: tcx.output_filenames(()).clone(), - regular_module_config: regular_config, - metadata_module_config: metadata_config, - allocator_module_config: allocator_config, - tm_factory: backend.target_machine_factory(tcx.sess, ol, backend_features), - msvc_imps_needed: msvc_imps_needed(tcx), - is_pe_coff: tcx.sess.target.is_like_windows, - target_can_use_split_dwarf: tcx.sess.target_can_use_split_dwarf(), - target_arch: tcx.sess.target.arch.to_string(), - split_debuginfo: tcx.sess.split_debuginfo(), - split_dwarf_kind: tcx.sess.opts.unstable_opts.split_dwarf_kind, - parallel: backend.supports_parallel() && !sess.opts.unstable_opts.no_parallel_backend, - }; - - // This is the "main loop" of parallel work happening for parallel codegen. - // It's here that we manage parallelism, schedule work, and work with - // messages coming from clients. - // - // There are a few environmental pre-conditions that shape how the system - // is set up: - // - // - Error reporting can only happen on the main thread because that's the - // only place where we have access to the compiler `Session`. - // - LLVM work can be done on any thread. - // - Codegen can only happen on the main thread. - // - Each thread doing substantial work must be in possession of a `Token` - // from the `Jobserver`. - // - The compiler process always holds one `Token`. Any additional `Tokens` - // have to be requested from the `Jobserver`. - // - // Error Reporting - // =============== - // The error reporting restriction is handled separately from the rest: We - // set up a `SharedEmitter` that holds an open channel to the main thread. - // When an error occurs on any thread, the shared emitter will send the - // error message to the receiver main thread (`SharedEmitterMain`). The - // main thread will periodically query this error message queue and emit - // any error messages it has received. It might even abort compilation if - // it has received a fatal error. In this case we rely on all other threads - // being torn down automatically with the main thread. - // Since the main thread will often be busy doing codegen work, error - // reporting will be somewhat delayed, since the message queue can only be - // checked in between two work packages. - // - // Work Processing Infrastructure - // ============================== - // The work processing infrastructure knows three major actors: - // - // - the coordinator thread, - // - the main thread, and - // - LLVM worker threads - // - // The coordinator thread is running a message loop. It instructs the main - // thread about what work to do when, and it will spawn off LLVM worker - // threads as open LLVM WorkItems become available. - // - // The job of the main thread is to codegen CGUs into LLVM work packages - // (since the main thread is the only thread that can do this). The main - // thread will block until it receives a message from the coordinator, upon - // which it will codegen one CGU, send it to the coordinator and block - // again. This way the coordinator can control what the main thread is - // doing. - // - // The coordinator keeps a queue of LLVM WorkItems, and when a `Token` is - // available, it will spawn off a new LLVM worker thread and let it process - // a WorkItem. When a LLVM worker thread is done with its WorkItem, - // it will just shut down, which also frees all resources associated with - // the given LLVM module, and sends a message to the coordinator that the - // WorkItem has been completed. - // - // Work Scheduling - // =============== - // The scheduler's goal is to minimize the time it takes to complete all - // work there is, however, we also want to keep memory consumption low - // if possible. These two goals are at odds with each other: If memory - // consumption were not an issue, we could just let the main thread produce - // LLVM WorkItems at full speed, assuring maximal utilization of - // Tokens/LLVM worker threads. However, since codegen is usually faster - // than LLVM processing, the queue of LLVM WorkItems would fill up and each - // WorkItem potentially holds on to a substantial amount of memory. - // - // So the actual goal is to always produce just enough LLVM WorkItems as - // not to starve our LLVM worker threads. That means, once we have enough - // WorkItems in our queue, we can block the main thread, so it does not - // produce more until we need them. - // - // Doing LLVM Work on the Main Thread - // ---------------------------------- - // Since the main thread owns the compiler process's implicit `Token`, it is - // wasteful to keep it blocked without doing any work. Therefore, what we do - // in this case is: We spawn off an additional LLVM worker thread that helps - // reduce the queue. The work it is doing corresponds to the implicit - // `Token`. The coordinator will mark the main thread as being busy with - // LLVM work. (The actual work happens on another OS thread but we just care - // about `Tokens`, not actual threads). - // - // When any LLVM worker thread finishes while the main thread is marked as - // "busy with LLVM work", we can do a little switcheroo: We give the Token - // of the just finished thread to the LLVM worker thread that is working on - // behalf of the main thread's implicit Token, thus freeing up the main - // thread again. The coordinator can then again decide what the main thread - // should do. This allows the coordinator to make decisions at more points - // in time. - // - // Striking a Balance between Throughput and Memory Consumption - // ------------------------------------------------------------ - // Since our two goals, (1) use as many Tokens as possible and (2) keep - // memory consumption as low as possible, are in conflict with each other, - // we have to find a trade off between them. Right now, the goal is to keep - // all workers busy, which means that no worker should find the queue empty - // when it is ready to start. - // How do we do achieve this? Good question :) We actually never know how - // many `Tokens` are potentially available so it's hard to say how much to - // fill up the queue before switching the main thread to LLVM work. Also we - // currently don't have a means to estimate how long a running LLVM worker - // will still be busy with it's current WorkItem. However, we know the - // maximal count of available Tokens that makes sense (=the number of CPU - // cores), so we can take a conservative guess. The heuristic we use here - // is implemented in the `queue_full_enough()` function. - // - // Some Background on Jobservers - // ----------------------------- - // It's worth also touching on the management of parallelism here. We don't - // want to just spawn a thread per work item because while that's optimal - // parallelism it may overload a system with too many threads or violate our - // configuration for the maximum amount of cpu to use for this process. To - // manage this we use the `jobserver` crate. - // - // Job servers are an artifact of GNU make and are used to manage - // parallelism between processes. A jobserver is a glorified IPC semaphore - // basically. Whenever we want to run some work we acquire the semaphore, - // and whenever we're done with that work we release the semaphore. In this - // manner we can ensure that the maximum number of parallel workers is - // capped at any one point in time. - // - // LTO and the coordinator thread - // ------------------------------ - // - // The final job the coordinator thread is responsible for is managing LTO - // and how that works. When LTO is requested what we'll do is collect all - // optimized LLVM modules into a local vector on the coordinator. Once all - // modules have been codegened and optimized we hand this to the `lto` - // module for further optimization. The `lto` module will return back a list - // of more modules to work on, which the coordinator will continue to spawn - // work for. - // - // Each LLVM module is automatically sent back to the coordinator for LTO if - // necessary. There's already optimizations in place to avoid sending work - // back to the coordinator if LTO isn't requested. - return B::spawn_named_thread(cgcx.time_trace, "coordinator".to_string(), move || { - let mut worker_id_counter = 0; - let mut free_worker_ids = Vec::new(); - let mut get_worker_id = |free_worker_ids: &mut Vec| { - if let Some(id) = free_worker_ids.pop() { - id - } else { - let id = worker_id_counter; - worker_id_counter += 1; - id - } - }; - - // This is where we collect codegen units that have gone all the way - // through codegen and LLVM. - let mut compiled_modules = vec![]; - let mut compiled_allocator_module = None; - let mut needs_link = Vec::new(); - let mut needs_fat_lto = Vec::new(); - let mut needs_thin_lto = Vec::new(); - let mut lto_import_only_modules = Vec::new(); - let mut started_lto = false; - - /// Possible state transitions: - /// - Ongoing -> Completed - /// - Ongoing -> Aborted - /// - Completed -> Aborted - #[derive(Debug, PartialEq)] - enum CodegenState { - Ongoing, - Completed, - Aborted, - } - use CodegenState::*; - let mut codegen_state = Ongoing; - - // This is the queue of LLVM work items that still need processing. - let mut work_items = Vec::<(WorkItem, u64)>::new(); - - // This are the Jobserver Tokens we currently hold. Does not include - // the implicit Token the compiler process owns no matter what. - let mut tokens = Vec::new(); - - let mut main_thread_state = MainThreadState::Idle; - - // How many LLVM worker threads are running while holding a Token. This - // *excludes* any that the main thread is lending a Token to. - let mut running_with_own_token = 0; - - // How many LLVM worker threads are running in total. This *includes* - // any that the main thread is lending a Token to. - let running_with_any_token = |main_thread_state, running_with_own_token| { - running_with_own_token - + if main_thread_state == MainThreadState::Lending { 1 } else { 0 } - }; - - let mut llvm_start_time: Option> = None; - - // Run the message loop while there's still anything that needs message - // processing. Note that as soon as codegen is aborted we simply want to - // wait for all existing work to finish, so many of the conditions here - // only apply if codegen hasn't been aborted as they represent pending - // work to be done. - loop { - // While there are still CGUs to be codegened, the coordinator has - // to decide how to utilize the compiler processes implicit Token: - // For codegenning more CGU or for running them through LLVM. - if codegen_state == Ongoing { - if main_thread_state == MainThreadState::Idle { - // Compute the number of workers that will be running once we've taken as many - // items from the work queue as we can, plus one for the main thread. It's not - // critically important that we use this instead of just - // `running_with_own_token`, but it prevents the `queue_full_enough` heuristic - // from fluctuating just because a worker finished up and we decreased the - // `running_with_own_token` count, even though we're just going to increase it - // right after this when we put a new worker to work. - let extra_tokens = tokens.len().checked_sub(running_with_own_token).unwrap(); - let additional_running = std::cmp::min(extra_tokens, work_items.len()); - let anticipated_running = running_with_own_token + additional_running + 1; - - if !queue_full_enough(work_items.len(), anticipated_running) { - // The queue is not full enough, process more codegen units: - if codegen_worker_send.send(CguMessage).is_err() { - panic!("Could not send CguMessage to main thread") - } - main_thread_state = MainThreadState::Codegenning; - } else { - // The queue is full enough to not let the worker - // threads starve. Use the implicit Token to do some - // LLVM work too. - let (item, _) = - work_items.pop().expect("queue empty - queue_full_enough() broken?"); - main_thread_state = MainThreadState::Lending; - spawn_work( - &cgcx, - &mut llvm_start_time, - get_worker_id(&mut free_worker_ids), - item, - ); - } - } - } else if codegen_state == Completed { - if running_with_any_token(main_thread_state, running_with_own_token) == 0 - && work_items.is_empty() - { - // All codegen work is done. Do we have LTO work to do? - if needs_fat_lto.is_empty() - && needs_thin_lto.is_empty() - && lto_import_only_modules.is_empty() - { - // Nothing more to do! - break; - } - - // We have LTO work to do. Perform the serial work here of - // figuring out what we're going to LTO and then push a - // bunch of work items onto our queue to do LTO. This all - // happens on the coordinator thread but it's very quick so - // we don't worry about tokens. - assert!(!started_lto); - started_lto = true; - - let needs_fat_lto = mem::take(&mut needs_fat_lto); - let needs_thin_lto = mem::take(&mut needs_thin_lto); - let import_only_modules = mem::take(&mut lto_import_only_modules); - - for (work, cost) in - generate_lto_work(&cgcx, needs_fat_lto, needs_thin_lto, import_only_modules) - { - let insertion_index = work_items - .binary_search_by_key(&cost, |&(_, cost)| cost) - .unwrap_or_else(|e| e); - work_items.insert(insertion_index, (work, cost)); - if cgcx.parallel { - helper.request_token(); - } - } - } - - // In this branch, we know that everything has been codegened, - // so it's just a matter of determining whether the implicit - // Token is free to use for LLVM work. - match main_thread_state { - MainThreadState::Idle => { - if let Some((item, _)) = work_items.pop() { - main_thread_state = MainThreadState::Lending; - spawn_work( - &cgcx, - &mut llvm_start_time, - get_worker_id(&mut free_worker_ids), - item, - ); - } else { - // There is no unstarted work, so let the main thread - // take over for a running worker. Otherwise the - // implicit token would just go to waste. - // We reduce the `running` counter by one. The - // `tokens.truncate()` below will take care of - // giving the Token back. - debug_assert!(running_with_own_token > 0); - running_with_own_token -= 1; - main_thread_state = MainThreadState::Lending; - } - } - MainThreadState::Codegenning => bug!( - "codegen worker should not be codegenning after \ +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,//if true{}; +CompiledModule,CrateInfo,ModuleCodegen,ModuleKind,};use jobserver::{Acquired,//; +Client};use rustc_ast::attr;use rustc_data_structures::fx::{FxHashMap,//((),()); +FxIndexMap};use rustc_data_structures:: memmap::Mmap;use rustc_data_structures:: +profiling::{SelfProfilerRef,VerboseTimingGuard };use rustc_data_structures::sync +::Lrc;use rustc_errors::emitter::Emitter;use rustc_errors::translation:://{();}; +Translate;use rustc_errors::{Diag,DiagArgMap,DiagCtxt,DiagMessage,ErrCode,//{;}; +FatalError,FluentBundle,Level,MultiSpan, Style,};use rustc_fs_util::link_or_copy +;use rustc_hir::def_id::{CrateNum,LOCAL_CRATE};use rustc_incremental::{//*&*&(); +copy_cgu_workproduct_to_incr_comp_cache_dir,in_incr_comp_dir,//((),());let _=(); +in_incr_comp_dir_sess,};use rustc_metadata::fs::copy_to_stdout;use//loop{break}; +rustc_metadata::EncodedMetadata;use rustc_middle::dep_graph::{WorkProduct,//{;}; +WorkProductId};use rustc_middle:: middle::exported_symbols::SymbolExportInfo;use +rustc_middle::ty::TyCtxt;use rustc_session::config::{self,CrateType,Lto,//{();}; +OutFileName,OutputFilenames,OutputType};use rustc_session::config::{Passes,//(); +SwitchWithOptPath};use rustc_session::Session;use rustc_span::source_map:://{;}; +SourceMap;use rustc_span::symbol::sym;use rustc_span::{BytePos,FileName,//{();}; +InnerSpan,Pos,Span};use rustc_target::spec::{MergeFunctions,SanitizerSet};use//; +crate::errors::ErrorCreatingRemarkDir;use std::any:: Any;use std::fs;use std::io +;use std::marker::PhantomData;use std::mem;use std::path::{Path,PathBuf};use//3; +std::str;use std::sync::mpsc::{channel,Receiver,Sender};use std::sync::Arc;use// +std::thread;const PRE_LTO_BC_EXT:&str= (((("pre-lto.bc"))));#[derive(Clone,Copy, +PartialEq)]pub enum EmitObj{None,Bitcode,ObjectCode(BitcodeSection),}#[derive(// +Clone,Copy,PartialEq)]pub enum BitcodeSection{None,Full,}pub struct//let _=||(); +ModuleConfig{pub passes:Vec,pub opt_level:Option,pub// +opt_size:Option,pub pgo_gen:SwitchWithOptPath,pub pgo_use://3; +Option,pub pgo_sample_use :Option,pub debug_info_for_profiling +:bool,pub instrument_coverage:bool,pub instrument_gcov:bool,pub sanitizer://{;}; +SanitizerSet,pub sanitizer_recover: SanitizerSet,pub sanitizer_dataflow_abilist: +Vec,pub sanitizer_memory_track_origins:usize,pub emit_pre_lto_bc:bool,// +pub emit_no_opt_bc:bool,pub emit_bc:bool, pub emit_ir:bool,pub emit_asm:bool,pub +emit_obj:EmitObj,pub emit_thin_lto:bool,pub bc_cmdline:String,pub//loop{break;}; +verify_llvm_ir:bool,pub no_prepopulate_passes:bool,pub no_builtins:bool,pub//(); +time_module:bool,pub vectorize_loop:bool,pub vectorize_slp:bool,pub//let _=||(); +merge_functions:bool,pub inline_threshold: Option,pub emit_lifetime_markers +:bool,pub llvm_plugins:Vec,}impl ModuleConfig{fn new(kind:ModuleKind,//; +tcx:TyCtxt<'_>,no_builtins:bool,is_compiler_builtins:bool,)->ModuleConfig{{();}; +macro_rules!if_regular{($regular:expr,$other :expr)=>{if let ModuleKind::Regular +=kind{$regular}else{$other}};}();3;let sess=tcx.sess;3;3;let opt_level_and_size= +if_regular!(Some(sess.opts.optimize),None);({});{;};let save_temps=sess.opts.cg. +save_temps;;;let should_emit_obj=sess.opts.output_types.contains_key(&OutputType +::Exe)||match kind{ModuleKind::Regular=>sess.opts.output_types.contains_key(&//; +OutputType::Object),ModuleKind::Allocator=>((false)),ModuleKind::Metadata=>sess. +opts.output_types.contains_key(&OutputType::Metadata),};{;};{;};let emit_obj=if! +should_emit_obj{EmitObj::None}else if sess .target.obj_is_bitcode||(sess.opts.cg +.linker_plugin_lto.enabled()&&(((((!no_builtins))))) ){EmitObj::Bitcode}else if +need_bitcode_in_object(tcx){((EmitObj::ObjectCode (BitcodeSection::Full)))}else{ +EmitObj::ObjectCode(BitcodeSection::None)};;ModuleConfig{passes:if_regular!(sess +.opts.cg.passes.clone(),vec![]),opt_level:opt_level_and_size,opt_size://((),()); +opt_level_and_size,pgo_gen:if_regular!(sess.opts.cg.profile_generate.clone(),//; +SwitchWithOptPath::Disabled),pgo_use:if_regular !(sess.opts.cg.profile_use.clone +(),None),pgo_sample_use: if_regular!(sess.opts.unstable_opts.profile_sample_use. +clone(),None),debug_info_for_profiling:sess.opts.unstable_opts.//*&*&();((),()); +debug_info_for_profiling,instrument_coverage:if_regular!(sess.//((),());((),()); +instrument_coverage(),false),instrument_gcov:if_regular!(sess.opts.//let _=||(); +unstable_opts.profile&&!is_compiler_builtins,false) ,sanitizer:if_regular!(sess. +opts.unstable_opts.sanitizer,SanitizerSet:: empty()),sanitizer_dataflow_abilist: +if_regular!(sess.opts.unstable_opts. sanitizer_dataflow_abilist.clone(),Vec::new +()),sanitizer_recover:if_regular!(sess.opts.unstable_opts.sanitizer_recover,//3; +SanitizerSet::empty()),sanitizer_memory_track_origins:if_regular!(sess.opts.//3; +unstable_opts.sanitizer_memory_track_origins,0),emit_pre_lto_bc:if_regular!(//3; +save_temps||need_pre_lto_bitcode_for_incr_comp(sess),false),emit_no_opt_bc://(); +if_regular!(save_temps,false),emit_bc:if_regular!(save_temps||sess.opts.//{();}; +output_types.contains_key(&OutputType::Bitcode) ,save_temps),emit_ir:if_regular! +(sess.opts.output_types.contains_key(& OutputType::LlvmAssembly),false),emit_asm +:if_regular!(sess.opts.output_types. contains_key(&OutputType::Assembly),false), +emit_obj,emit_thin_lto:sess.opts.unstable_opts.emit_thin_lto,bc_cmdline:sess.//; +target.bitcode_llvm_cmdline.to_string(), verify_llvm_ir:(sess.verify_llvm_ir()), +no_prepopulate_passes:sess.opts.cg.no_prepopulate_passes,no_builtins://let _=(); +no_builtins||sess.target.no_builtins,time_module :(((if_regular!(true,false)))), +vectorize_loop:(!sess.opts.cg.no_vectorize_loops)&&(sess.opts.optimize==config:: +OptLevel::Default||(((((sess.opts.optimize ==config::OptLevel::Aggressive)))))), +vectorize_slp:(((!sess.opts.cg.no_vectorize_slp)))&&sess.opts.optimize==config:: +OptLevel::Aggressive,merge_functions:match sess.opts.unstable_opts.//let _=||(); +merge_functions.unwrap_or(sess.target .merge_functions){MergeFunctions::Disabled +=>false,MergeFunctions::Trampolines|MergeFunctions::Aliases=>{{();};use config:: +OptLevel::*;;match sess.opts.optimize{Aggressive|Default|SizeMin|Size=>true,Less +|No=>(((((((((false))))))))),}}},inline_threshold:sess.opts.cg.inline_threshold, +emit_lifetime_markers:((sess.emit_lifetime_markers())),llvm_plugins:if_regular!( +sess.opts.unstable_opts.llvm_plugins.clone(),vec![]),}}pub fn bitcode_needed(&// +self)->bool{((self.emit_bc||(self.emit_obj==EmitObj::Bitcode)))||self.emit_obj== +EmitObj::ObjectCode(BitcodeSection::Full)}}pub struct//loop{break};loop{break;}; +TargetMachineFactoryConfig{pub split_dwarf_file:Option,pub//let _=||(); +output_obj_file:Option,}impl TargetMachineFactoryConfig{pub fn new(//3; +cgcx:&CodegenContext,module_name:&str,)->//let _=||(); +TargetMachineFactoryConfig{loop{break};loop{break};let split_dwarf_file=if cgcx. +target_can_use_split_dwarf{cgcx.output_filenames.split_dwarf_path(cgcx.//*&*&(); +split_debuginfo,cgcx.split_dwarf_kind,Some(module_name),)}else{None};{;};{;};let +output_obj_file=Some(cgcx.output_filenames.temp_path(OutputType::Object,Some(//; +module_name)));();TargetMachineFactoryConfig{split_dwarf_file,output_obj_file}}} +pub type TargetMachineFactoryFn=Arc//3; +Result< ::TargetMachine,::// +TargetMachineError,>+Send+Sync,>;pub type ExportedSymbols=FxHashMap>>; #[derive(Clone)]pub struct CodegenContext< +B:WriteBackendMethods>{pub prof:SelfProfilerRef, pub lto:Lto,pub save_temps:bool +,pub fewer_names:bool,pub time_trace:bool,pub exported_symbols:Option>,pub opts:Arc,pub crate_types:Vec, +pub each_linked_rlib_for_lto:Vec<(CrateNum,PathBuf)>,pub output_filenames:Arc,pub regular_module_config:Arc,pub//if let _=(){}; +metadata_module_config:Arc,pub allocator_module_config:Arc,pub tm_factory:TargetMachineFactoryFn,pub msvc_imps_needed://3; +bool,pub is_pe_coff:bool,pub target_can_use_split_dwarf:bool,pub target_arch://; +String,pub split_debuginfo:rustc_target::spec::SplitDebuginfo,pub//loop{break;}; +split_dwarf_kind:rustc_session::config::SplitDwarfKind,pub expanded_args:Vec,pub diag_emitter:SharedEmitter,pub remark:Passes,pub remark_dir:Option< +PathBuf>,pub incr_comp_session_dir:Option< PathBuf>,pub coordinator_send:Sender< +Box>,pub parallel:bool,}implCodegenContext +{pub fn create_dcx(&self)->DiagCtxt {DiagCtxt::new(Box::new(self.diag_emitter +.clone()))}pub fn config(&self,kind:ModuleKind)->&ModuleConfig{match kind{//{;}; +ModuleKind::Regular=>(&self.regular_module_config ),ModuleKind::Metadata=>&self. +metadata_module_config,ModuleKind::Allocator=> &self.allocator_module_config,}}} +fn generate_lto_work(cgcx:&CodegenContext,//if true{}; +needs_fat_lto:Vec>,needs_thin_lto:Vec<(String,B::ThinBuffer)>,//; +import_only_modules:Vec<(SerializedModule,WorkProduct)>,)->Vec +<(WorkItem,u64)>{((),());let _=();let _prof_timer=cgcx.prof.generic_activity( +"codegen_generate_lto_work");;if!needs_fat_lto.is_empty(){assert!(needs_thin_lto +.is_empty());;let module=B::run_fat_lto(cgcx,needs_fat_lto,import_only_modules). +unwrap_or_else(|e|e.raise());();vec![(WorkItem::LTO(module),0)]}else{();assert!( +needs_fat_lto.is_empty());();();let(lto_modules,copy_jobs)=B::run_thin_lto(cgcx, +needs_thin_lto,import_only_modules).unwrap_or_else(|e|e.raise());();lto_modules. +into_iter().map(|module|{;let cost=module.cost();(WorkItem::LTO(module),cost)}). +chain((((((copy_jobs.into_iter()))))).map( |wp|{(WorkItem::CopyPostLtoArtifacts( +CachedModuleCodegen{name:wp.cgu_name.clone(),source:wp,}) ,0,)})).collect()}}pub +struct CompiledModules{pub modules:Vec,pub allocator_module://3; +Option,}fn need_bitcode_in_object(tcx:TyCtxt<'_>)->bool{({});let +sess=tcx.sess;{();};({});let requested_for_rlib=sess.opts.cg.embed_bitcode&&tcx. +crate_types().contains(&CrateType::Rlib) &&sess.opts.output_types.contains_key(& +OutputType::Exe);();();let forced_by_target=sess.target.forces_embed_bitcode;(); +requested_for_rlib||forced_by_target} fn need_pre_lto_bitcode_for_incr_comp(sess +:&Session)->bool{if sess.opts.incremental.is_none(){3;return false;;}match sess. +lto(){Lto::No=>(((false))),Lto::Fat| Lto::Thin|Lto::ThinLocal=>((true)),}}pub fn +start_async_codegen(backend:B ,tcx:TyCtxt<'_>,target_cpu: +String,metadata:EncodedMetadata,metadata_module:Option,)->//{;}; +OngoingCodegen{;let(coordinator_send,coordinator_receive)=channel();let sess= +tcx.sess;();();let crate_attrs=tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);();3;let +no_builtins=attr::contains_name(crate_attrs,sym::no_builtins);((),());*&*&();let +is_compiler_builtins=attr::contains_name(crate_attrs,sym::compiler_builtins);3;; +let crate_info=CrateInfo::new(tcx,target_cpu);;let regular_config=ModuleConfig:: +new(ModuleKind::Regular,tcx,no_builtins,is_compiler_builtins);((),());*&*&();let +metadata_config=ModuleConfig::new(ModuleKind::Metadata,tcx,no_builtins,//*&*&(); +is_compiler_builtins);{;};();let allocator_config=ModuleConfig::new(ModuleKind:: +Allocator,tcx,no_builtins,is_compiler_builtins);*&*&();{();};let(shared_emitter, +shared_emitter_main)=SharedEmitter::new();*&*&();*&*&();let(codegen_worker_send, +codegen_worker_receive)=channel();;;let coordinator_thread=start_executing_work( +backend.clone(),tcx, ((((((&crate_info)))))),shared_emitter,codegen_worker_send, +coordinator_receive,(sess.jobserver.clone()), Arc::new(regular_config),Arc::new( +metadata_config),Arc::new(allocator_config),coordinator_send.clone(),);let _=(); +OngoingCodegen{backend,metadata,metadata_module,crate_info,//let _=();if true{}; +codegen_worker_receive,shared_emitter_main,coordinator:Coordinator{sender://{;}; +coordinator_send,future:((((Some(coordinator_thread) )))),phantom:PhantomData,}, +output_filenames:(((((((((tcx.output_filenames(((((()))))))))).clone()))))),}}fn +copy_all_cgu_workproducts_to_incr_comp_cache_dir(sess: &Session,compiled_modules +:&CompiledModules,)->FxIndexMap{if let _=(){};let mut +work_products=FxIndexMap::default();3;if sess.opts.incremental.is_none(){;return +work_products;let _=||();let _=||();}if true{};let _=||();let _timer=sess.timer( +"copy_all_cgu_workproducts_to_incr_comp_cache_dir");if let _=(){};for module in +compiled_modules.modules.iter().filter(|m|m.kind==ModuleKind::Regular){3;let mut +files=Vec::new();;if let Some(object_file_path)=&module.object{;files.push(("o", +object_file_path.as_path()));{();};}if let Some(dwarf_object_file_path)=&module. +dwarf_object{;files.push(("dwo",dwarf_object_file_path.as_path()));}if let Some( +(id,product))=copy_cgu_workproduct_to_incr_comp_cache_dir(sess,((&module.name)), +files.as_slice()){{();};work_products.insert(id,product);({});}}work_products}fn +produce_final_output_artifacts(sess:&Session ,compiled_modules:&CompiledModules, +crate_output:&OutputFilenames,){();let mut user_wants_bitcode=false;();3;let mut +user_wants_objects=false;;;let copy_gracefully=|from:&Path,to:&OutFileName|match +to{OutFileName::Stdout=>{if let Err(e)=copy_to_stdout(from){;sess.dcx().emit_err +(errors::CopyPath::new(from,to.as_path(),e));;}}OutFileName::Real(path)=>{if let +Err(e)=fs::copy(from,path){3;sess.dcx().emit_err(errors::CopyPath::new(from,path +,e));;}}};;;let copy_if_one_unit=|output_type:OutputType,keep_numbered:bool|{if +compiled_modules.modules.len()==1{*&*&();let module_name=Some(&compiled_modules. +modules[0].name[..]);;;let path=crate_output.temp_path(output_type,module_name); +let output=crate_output.path(output_type);({});if!output_type.is_text_output()&& +output.is_tty(){((),());sess.dcx().emit_err(errors::BinaryOutputToTty{shorthand: +output_type.shorthand()});;}else{copy_gracefully(&path,&output);}if!sess.opts.cg +.save_temps&&!keep_numbered{();ensure_removed(sess.dcx(),&path);();}}else{();let +extension=crate_output.temp_path(output_type,None ).extension().unwrap().to_str( +).unwrap().to_owned();if true{};if crate_output.outputs.contains_explicit_name(& +output_type){;sess.dcx().emit_warn(errors::IgnoringEmitPath{extension});}else if +crate_output.single_output_file.is_some(){let _=();sess.dcx().emit_warn(errors:: +IgnoringOutput{extension});3;}else{}}};;for output_type in crate_output.outputs. +keys(){match*output_type{OutputType::Bitcode=>{();user_wants_bitcode=true;();(); +copy_if_one_unit(OutputType::Bitcode,true);({});}OutputType::LlvmAssembly=>{{;}; +copy_if_one_unit(OutputType::LlvmAssembly,false);{;};}OutputType::Assembly=>{(); +copy_if_one_unit(OutputType::Assembly,false);*&*&();}OutputType::Object=>{{();}; +user_wants_objects=true;;copy_if_one_unit(OutputType::Object,true);}OutputType:: +Mir|OutputType::Metadata|OutputType::Exe|OutputType:: DepInfo=>{}}}if!sess.opts. +cg.save_temps{((),());let needs_crate_object=crate_output.outputs.contains_key(& +OutputType::Exe);{();};{();};let keep_numbered_bitcode=user_wants_bitcode&&sess. +codegen_units().as_usize()>1;3;3;let keep_numbered_objects=needs_crate_object||( +user_wants_objects&&sess.codegen_units().as_usize()>1);let _=||();for module in +compiled_modules.modules.iter(){if let Some(ref path)=module.object{if!//*&*&(); +keep_numbered_objects{;ensure_removed(sess.dcx(),path);;}}if let Some(ref path)= +module.dwarf_object{if!keep_numbered_objects{;ensure_removed(sess.dcx(),path);}} +if let Some(ref path)=module.bytecode{if!keep_numbered_bitcode{3;ensure_removed( +sess.dcx(),path);{;};}}}if!user_wants_bitcode{if let Some(ref allocator_module)= +compiled_modules.allocator_module{if let Some(ref path)=allocator_module.//({}); +bytecode{{;};ensure_removed(sess.dcx(),path);{;};}}}}}pub(crate)enum WorkItem{Optimize(ModuleCodegen),CopyPostLtoArtifacts(//; +CachedModuleCodegen),LTO(lto::LtoModuleCodegen),}impl +WorkItem{pub fn module_kind(&self )->ModuleKind{match*self{WorkItem::Optimize +(ref m)=>m.kind,WorkItem::CopyPostLtoArtifacts(_)|WorkItem::LTO(_)=>ModuleKind// +::Regular,}}fn short_description(&self)->String{{;};#[cfg(not(windows))]fn desc( +short:&str,_long:&str,name:&str)->String{;assert_eq!(short.len(),3);;let name=if +let Some(index)=name.find("-cgu."){&name[index+1..]}else{name};let _=();format!( +"{short} {name}")}();3;#[cfg(windows)]fn desc(_short:&str,long:&str,name:&str)-> +String{format!("{long} {name}")}();match self{WorkItem::Optimize(m)=>desc("opt", +"optimize module",((&m.name))),WorkItem ::CopyPostLtoArtifacts(m)=>desc(("cpy"), +"copy LTO artifacts for",(&m.name)),WorkItem::LTO(m)=>desc("lto","LTO module",m. +name()),}}}pub(crate)enum WorkItemResult{Finished(//({}); +CompiledModule),NeedsLink(ModuleCodegen),NeedsFatLto(FatLtoInput) +,NeedsThinLto(String,B::ThinBuffer), }pub enum FatLtoInput{Serialized{name:String,buffer:B::ModuleBuffer},InMemory(ModuleCodegen),}pub enum ComputedLtoType{ No,Thin,Fat,}pub fn compute_per_cgu_lto_type +(sess_lto:&Lto,opts:&config:: Options,sess_crate_types:&[CrateType],module_kind: +ModuleKind,)->ComputedLtoType{if module_kind==ModuleKind::Metadata{*&*&();return +ComputedLtoType::No;;};let linker_does_lto=opts.cg.linker_plugin_lto.enabled();; +let is_allocator=module_kind==ModuleKind::Allocator;((),());((),());let is_rlib= +sess_crate_types.len()==1&&sess_crate_types[0]==CrateType::Rlib;;match sess_lto{ +Lto::ThinLocal if(!linker_does_lto&& !is_allocator)=>ComputedLtoType::Thin,Lto:: +Thin if(!linker_does_lto&&!is_rlib)=>ComputedLtoType::Thin,Lto::Fat if!is_rlib=> +ComputedLtoType::Fat,_=>ComputedLtoType::No,}}fn execute_optimize_work_item(cgcx:&CodegenContext,module:ModuleCodegen,//; +module_config:&ModuleConfig,)->Result,FatalError>{{;};let dcx= +cgcx.create_dcx();3;unsafe{;B::optimize(cgcx,&dcx,&module,module_config)?;;};let +lto_type=compute_per_cgu_lto_type(&cgcx.lto, &cgcx.opts,&cgcx.crate_types,module +.kind);3;;let bitcode=if cgcx.config(module.kind).emit_pre_lto_bc{;let filename= +pre_lto_bitcode_filename(&module.name);;cgcx.incr_comp_session_dir.as_ref().map( +|path|path.join(&filename))}else{None};({});match lto_type{ComputedLtoType::No=> +finish_intra_module_work(cgcx,module,module_config),ComputedLtoType::Thin=>{;let +(name,thin_buffer)=B::prepare_thin(module);;if let Some(path)=bitcode{fs::write( +&path,thin_buffer.data()).unwrap_or_else(|e|{if let _=(){};if let _=(){};panic!( +"Error writing pre-lto-bitcode file `{}`: {}",path.display(),e);({});});{;};}Ok( +WorkItemResult::NeedsThinLto(name,thin_buffer))}ComputedLtoType::Fat=>match//(); +bitcode{Some(path)=>{;let(name,buffer)=B::serialize_module(module);;;fs::write(& +path,buffer.data()).unwrap_or_else(|e|{((),());let _=();((),());let _=();panic!( +"Error writing pre-lto-bitcode file `{}`: {}",path.display(),e);({});});({});Ok( +WorkItemResult::NeedsFatLto(((FatLtoInput::Serialized{name,buffer}))))}None=>Ok( +WorkItemResult::NeedsFatLto((((((((FatLtoInput::InMemory(module)))))))))),},}}fn +execute_copy_from_cache_work_item (cgcx:&CodegenContext,module:CachedModuleCodegen,module_config:&ModuleConfig,)->WorkItemResult{3; +assert!(module_config.emit_obj!=EmitObj::None);;;let incr_comp_session_dir=cgcx. +incr_comp_session_dir.as_ref().unwrap();{();};({});let load_from_incr_comp_dir=| +output_path:PathBuf,saved_path:&str|{if true{};let source_file=in_incr_comp_dir( +incr_comp_session_dir,saved_path);if true{};if true{};let _=();if true{};debug!( +"copying preexisting module `{}` from {:?} to {}",module.name,source_file,//{;}; +output_path.display());{;};match link_or_copy(&source_file,&output_path){Ok(_)=> +Some(output_path),Err(error)=>{3;cgcx.create_dcx().emit_err(errors::CopyPathBuf{ +source_file,output_path,error});;None}}};let object=load_from_incr_comp_dir(cgcx +.output_filenames.temp_path(OutputType::Object,((Some((&module.name))))),module. +source.saved_files.get(("o")).unwrap_or_else( ||{(cgcx.create_dcx()).emit_fatal( +errors::NoSavedObjectFile{cgu_name:&module.name})}),);;;let dwarf_object=module. +source.saved_files.get("dwo").as_ref().and_then(|saved_dwarf_object_file|{();let +dwarf_obj_out=cgcx.output_filenames. split_dwarf_path(cgcx.split_debuginfo,cgcx. +split_dwarf_kind,(((((((((Some((((((((((&module.name)))))))))))))))))))).expect( +"saved dwarf object in work product but `split_dwarf_path` returned `None`",);3; +load_from_incr_comp_dir(dwarf_obj_out,saved_dwarf_object_file)});;WorkItemResult +::Finished(CompiledModule{name:module.name,kind:ModuleKind::Regular,object,//(); +dwarf_object,bytecode:None,})}fn execute_lto_work_item(// +cgcx:&CodegenContext,module:lto::LtoModuleCodegen,module_config:&//*&*&(); +ModuleConfig,)->Result,FatalError>{3;let module=unsafe{module. +optimize(cgcx)?};let _=();finish_intra_module_work(cgcx,module,module_config)}fn +finish_intra_module_work(cgcx :&CodegenContext,module: +ModuleCodegen,module_config: &ModuleConfig,)->Result,FatalError>{;let dcx=cgcx.create_dcx();;if!cgcx.opts.unstable_opts.combine_cgu +||module.kind==ModuleKind::Metadata||module.kind==ModuleKind::Allocator{({});let +module=unsafe{B::codegen(cgcx,&dcx,module,module_config)?};3;Ok(WorkItemResult:: +Finished(module))}else{(Ok((WorkItemResult::NeedsLink(module))))}}pub(crate)enum +Message{Token(io::Result),WorkItem{result://(); +Result,Option< WorkerFatalError>>,worker_id:usize},CodegenDone +{llvm_work_item:WorkItem,cost:u64},AddImportOnlyModule{module_data://((),()); +SerializedModule,work_product:WorkProduct,},CodegenComplete,//; +CodegenAborted,}pub struct CguMessage;struct Diagnostic{level:Level,messages://; +Vec<(DiagMessage,Style)>,code:Option ,children:Vec,args: +DiagArgMap,}pub struct Subdiagnostic{level:Level,messages:Vec<(DiagMessage,//(); +Style)>,}#[derive(PartialEq,Clone,Copy,Debug)]enum MainThreadState{Idle,//{();}; +Codegenning,Lending,}fn start_executing_work(backend:B,// +tcx:TyCtxt<'_>,crate_info:&CrateInfo,shared_emitter:SharedEmitter,//loop{break}; +codegen_worker_send:Sender,coordinator_receive :Receiver>,jobserver:Client,regular_config:Arc,metadata_config:Arc,allocator_config:Arc,tx_to_llvm_workers:Sender>,)->thread::JoinHandle>{loop{break};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(crate_info,None +,&mut|cnum,path|{if link::ignored_for_lto(sess,crate_info,cnum){();return;();}3; +each_linked_rlib_for_lto.push((cnum,path.to_path_buf()));{();};}));({});({});let +exported_symbols={({});let mut exported_symbols=FxHashMap::default();{;};{;};let +copy_symbols=|cnum|{;let symbols=tcx.exported_symbols(cnum).iter().map(|&(s,lvl) +|(symbol_name_for_instance_in_crate(tcx,s,cnum),lvl)).collect();*&*&();Arc::new( +symbols)};();match sess.lto(){Lto::No=>None,Lto::ThinLocal=>{3;exported_symbols. +insert(LOCAL_CRATE,copy_symbols(LOCAL_CRATE));;Some(Arc::new(exported_symbols))} +Lto::Fat|Lto::Thin=>{if true{};exported_symbols.insert(LOCAL_CRATE,copy_symbols( +LOCAL_CRATE));;for&(cnum,ref _path)in&each_linked_rlib_for_lto{exported_symbols. +insert(cnum,copy_symbols(cnum));();}Some(Arc::new(exported_symbols))}}};();3;let +coordinator_send2=coordinator_send.clone();((),());((),());let helper=jobserver. +into_helper_thread(move|token|{();drop(coordinator_send2.send(Box::new(Message:: +Token::(token))));;}).expect("failed to spawn helper thread");;let ol=if tcx. +sess.opts.unstable_opts.no_codegen||! tcx.sess.opts.output_types.should_codegen( +){config::OptLevel::No}else{tcx.backend_optimization_level(())};*&*&();{();};let +backend_features=tcx.global_backend_features(());;let remark_dir=if let Some(ref +dir)=sess.opts.unstable_opts.remark_dir{({});let result=fs::create_dir_all(dir). +and_then(|_|dir.canonicalize());{;};match result{Ok(dir)=>Some(dir),Err(error)=> +sess.dcx().emit_fatal(ErrorCreatingRemarkDir{error}),}}else{None};();3;let cgcx= +CodegenContext::{crate_types:((((((((((tcx .crate_types()))))).to_vec()))))), +each_linked_rlib_for_lto,lto:((sess.lto())) ,fewer_names:((sess.fewer_names())), +save_temps:sess.opts.cg.save_temps,time_trace:sess.opts.unstable_opts.//((),()); +llvm_time_trace,opts:((Arc::new((sess.opts.clone())))),prof:(sess.prof.clone()), +exported_symbols,remark:((((((((sess.opts.cg .remark.clone())))))))),remark_dir, +incr_comp_session_dir:((sess.incr_comp_session_dir_opt()).map(( |r|r.clone()))), +coordinator_send,expanded_args:((tcx.sess. expanded_args.clone())),diag_emitter: +shared_emitter.clone(),output_filenames:((tcx. output_filenames((()))).clone()), +regular_module_config:regular_config,metadata_module_config:metadata_config,//3; +allocator_module_config:allocator_config,tm_factory:backend.//let _=();let _=(); +target_machine_factory(tcx.sess,ol,backend_features),msvc_imps_needed://((),()); +msvc_imps_needed(tcx),is_pe_coff:tcx.sess.target.is_like_windows,//loop{break;}; +target_can_use_split_dwarf:(tcx.sess. target_can_use_split_dwarf()),target_arch: +tcx.sess.target.arch.to_string(),split_debuginfo:((tcx.sess.split_debuginfo())), +split_dwarf_kind:tcx.sess.opts.unstable_opts .split_dwarf_kind,parallel:backend. +supports_parallel()&&!sess.opts.unstable_opts.no_parallel_backend,};;;return B:: +spawn_named_thread(cgcx.time_trace,"coordinator".to_string(),move||{({});let mut +worker_id_counter=0;;;let mut free_worker_ids=Vec::new();let mut get_worker_id=| +free_worker_ids:&mut Vec|{if let Some(id)=free_worker_ids.pop(){id}else{; +let id=worker_id_counter;;worker_id_counter+=1;id}};let mut compiled_modules=vec +![];;;let mut compiled_allocator_module=None;;;let mut needs_link=Vec::new();let +mut needs_fat_lto=Vec::new();();();let mut needs_thin_lto=Vec::new();3;3;let mut +lto_import_only_modules=Vec::new();;;let mut started_lto=false;;;#[derive(Debug, +PartialEq)]enum CodegenState{Ongoing,Completed,Aborted,};use CodegenState::*;let +mut codegen_state=Ongoing;;;let mut work_items=Vec::<(WorkItem,u64)>::new();; +let mut tokens=Vec::new();;;let mut main_thread_state=MainThreadState::Idle;;let +mut running_with_own_token=0;();3;let running_with_any_token=|main_thread_state, +running_with_own_token|{running_with_own_token+if main_thread_state==//let _=(); +MainThreadState::Lending{1}else{0}};*&*&();{();};let mut llvm_start_time:Option< +VerboseTimingGuard<'_>>=None;((),());let _=();loop{if codegen_state==Ongoing{if +main_thread_state==MainThreadState::Idle{let _=();let extra_tokens=tokens.len(). +checked_sub(running_with_own_token).unwrap();;;let additional_running=std::cmp:: +min(extra_tokens,work_items.len());let _=||();if true{};let anticipated_running= +running_with_own_token+additional_running+1;;if!queue_full_enough(work_items.len +(),anticipated_running){if codegen_worker_send .send(CguMessage).is_err(){panic! +("Could not send CguMessage to main thread")}3;main_thread_state=MainThreadState +::Codegenning;loop{break};}else{loop{break};let(item,_)=work_items.pop().expect( +"queue empty - queue_full_enough() broken?");;;main_thread_state=MainThreadState +::Lending;*&*&();*&*&();spawn_work(&cgcx,&mut llvm_start_time,get_worker_id(&mut +free_worker_ids),item,);((),());let _=();}}}else if codegen_state==Completed{if +running_with_any_token(main_thread_state,running_with_own_token) ==0&&work_items +.is_empty(){if ((((needs_fat_lto.is_empty()))&&((needs_thin_lto.is_empty()))))&& +lto_import_only_modules.is_empty(){;break;;};assert!(!started_lto);;started_lto= +true;;;let needs_fat_lto=mem::take(&mut needs_fat_lto);;let needs_thin_lto=mem:: +take(&mut needs_thin_lto);((),());((),());let import_only_modules=mem::take(&mut +lto_import_only_modules);;for(work,cost)in generate_lto_work(&cgcx,needs_fat_lto +,needs_thin_lto,import_only_modules){loop{break};let insertion_index=work_items. +binary_search_by_key(&cost,|&(_,cost)|cost).unwrap_or_else(|e|e);3;3;work_items. +insert(insertion_index,(work,cost));;if cgcx.parallel{helper.request_token();}}} +match main_thread_state{MainThreadState::Idle=>{if let Some((item,_))=//((),()); +work_items.pop(){;main_thread_state=MainThreadState::Lending;;spawn_work(&cgcx,& +mut llvm_start_time,get_worker_id(&mut free_worker_ids),item,);{();};}else{({}); +debug_assert!(running_with_own_token>0);{;};{;};running_with_own_token-=1;();(); +main_thread_state=MainThreadState::Lending;;}}MainThreadState::Codegenning=>bug! +(//let _=();if true{};let _=();if true{};let _=();if true{};if true{};if true{}; +"codegen worker should not be codegenning after \ codegen was already completed" - ), - MainThreadState::Lending => { - // Already making good use of that token - } - } - } else { - // Don't queue up any more work if codegen was aborted, we're - // just waiting for our existing children to finish. - assert!(codegen_state == Aborted); - if running_with_any_token(main_thread_state, running_with_own_token) == 0 { - break; - } - } - - // Spin up what work we can, only doing this while we've got available - // parallelism slots and work left to spawn. - if codegen_state != Aborted { - while !work_items.is_empty() && running_with_own_token < tokens.len() { - let (item, _) = work_items.pop().unwrap(); - spawn_work( - &cgcx, - &mut llvm_start_time, - get_worker_id(&mut free_worker_ids), - item, - ); - running_with_own_token += 1; - } - } - - // Relinquish accidentally acquired extra tokens. - tokens.truncate(running_with_own_token); - - // If a thread exits successfully then we drop a token associated - // with that worker and update our `running_with_own_token` count. - // We may later re-acquire a token to continue running more work. - // We may also not actually drop a token here if the worker was - // running with an "ephemeral token". - let mut free_worker = |worker_id| { - if main_thread_state == MainThreadState::Lending { - main_thread_state = MainThreadState::Idle; - } else { - running_with_own_token -= 1; - } - - free_worker_ids.push(worker_id); - }; - - let msg = coordinator_receive.recv().unwrap(); - match *msg.downcast::>().ok().unwrap() { - // Save the token locally and the next turn of the loop will use - // this to spawn a new unit of work, or it may get dropped - // immediately if we have no more work to spawn. - Message::Token(token) => { - match token { - Ok(token) => { - tokens.push(token); - - if main_thread_state == MainThreadState::Lending { - // If the main thread token is used for LLVM work - // at the moment, we turn that thread into a regular - // LLVM worker thread, so the main thread is free - // to react to codegen demand. - main_thread_state = MainThreadState::Idle; - running_with_own_token += 1; - } - } - Err(e) => { - let msg = &format!("failed to acquire jobserver token: {e}"); - shared_emitter.fatal(msg); - codegen_state = Aborted; - } - } - } - - Message::CodegenDone { llvm_work_item, cost } => { - // We keep the queue sorted by estimated processing cost, - // so that more expensive items are processed earlier. This - // is good for throughput as it gives the main thread more - // time to fill up the queue and it avoids scheduling - // expensive items to the end. - // Note, however, that this is not ideal for memory - // consumption, as LLVM module sizes are not evenly - // distributed. - let insertion_index = work_items.binary_search_by_key(&cost, |&(_, cost)| cost); - let insertion_index = match insertion_index { - Ok(idx) | Err(idx) => idx, - }; - work_items.insert(insertion_index, (llvm_work_item, cost)); - - if cgcx.parallel { - helper.request_token(); - } - assert_eq!(main_thread_state, MainThreadState::Codegenning); - main_thread_state = MainThreadState::Idle; - } - - Message::CodegenComplete => { - if codegen_state != Aborted { - codegen_state = Completed; - } - assert_eq!(main_thread_state, MainThreadState::Codegenning); - main_thread_state = MainThreadState::Idle; - } - - // If codegen is aborted that means translation was aborted due - // to some normal-ish compiler error. In this situation we want - // to exit as soon as possible, but we want to make sure all - // existing work has finished. Flag codegen as being done, and - // then conditions above will ensure no more work is spawned but - // we'll keep executing this loop until `running_with_own_token` - // hits 0. - Message::CodegenAborted => { - codegen_state = Aborted; - } - - Message::WorkItem { result, worker_id } => { - free_worker(worker_id); - - match result { - Ok(WorkItemResult::Finished(compiled_module)) => { - match compiled_module.kind { - ModuleKind::Regular => { - assert!(needs_link.is_empty()); - compiled_modules.push(compiled_module); - } - ModuleKind::Allocator => { - assert!(compiled_allocator_module.is_none()); - compiled_allocator_module = Some(compiled_module); - } - ModuleKind::Metadata => bug!("Should be handled separately"), - } - } - Ok(WorkItemResult::NeedsLink(module)) => { - assert!(compiled_modules.is_empty()); - needs_link.push(module); - } - Ok(WorkItemResult::NeedsFatLto(fat_lto_input)) => { - assert!(!started_lto); - assert!(needs_thin_lto.is_empty()); - needs_fat_lto.push(fat_lto_input); - } - Ok(WorkItemResult::NeedsThinLto(name, thin_buffer)) => { - assert!(!started_lto); - assert!(needs_fat_lto.is_empty()); - needs_thin_lto.push((name, thin_buffer)); - } - Err(Some(WorkerFatalError)) => { - // Like `CodegenAborted`, wait for remaining work to finish. - codegen_state = Aborted; - } - Err(None) => { - // If the thread failed that means it panicked, so - // we abort immediately. - bug!("worker thread panicked"); - } - } - } - - Message::AddImportOnlyModule { module_data, work_product } => { - assert!(!started_lto); - assert_eq!(codegen_state, Ongoing); - assert_eq!(main_thread_state, MainThreadState::Codegenning); - lto_import_only_modules.push((module_data, work_product)); - main_thread_state = MainThreadState::Idle; - } - } - } - - if codegen_state == Aborted { - return Err(()); - } - - let needs_link = mem::take(&mut needs_link); - if !needs_link.is_empty() { - assert!(compiled_modules.is_empty()); - let dcx = cgcx.create_dcx(); - let module = B::run_link(&cgcx, &dcx, needs_link).map_err(|_| ())?; - let module = unsafe { - B::codegen(&cgcx, &dcx, module, cgcx.config(ModuleKind::Regular)).map_err(|_| ())? - }; - compiled_modules.push(module); - } - - // Drop to print timings - drop(llvm_start_time); - - // Regardless of what order these modules completed in, report them to - // the backend in the same order every time to ensure that we're handing - // out deterministic results. - compiled_modules.sort_by(|a, b| a.name.cmp(&b.name)); - - Ok(CompiledModules { - modules: compiled_modules, - allocator_module: compiled_allocator_module, - }) - }) - .expect("failed to spawn coordinator thread"); - - // A heuristic that determines if we have enough LLVM WorkItems in the - // queue so that the main thread can do LLVM work instead of codegen - fn queue_full_enough(items_in_queue: usize, workers_running: usize) -> bool { - // This heuristic scales ahead-of-time codegen according to available - // concurrency, as measured by `workers_running`. The idea is that the - // more concurrency we have available, the more demand there will be for - // work items, and the fuller the queue should be kept to meet demand. - // An important property of this approach is that we codegen ahead of - // time only as much as necessary, so as to keep fewer LLVM modules in - // memory at once, thereby reducing memory consumption. - // - // When the number of workers running is less than the max concurrency - // available to us, this heuristic can cause us to instruct the main - // thread to work on an LLVM item (that is, tell it to "LLVM") instead - // of codegen, even though it seems like it *should* be codegenning so - // that we can create more work items and spawn more LLVM workers. - // - // But this is not a problem. When the main thread is told to LLVM, - // according to this heuristic and how work is scheduled, there is - // always at least one item in the queue, and therefore at least one - // pending jobserver token request. If there *is* more concurrency - // available, we will immediately receive a token, which will upgrade - // the main thread's LLVM worker to a real one (conceptually), and free - // up the main thread to codegen if necessary. On the other hand, if - // there isn't more concurrency, then the main thread working on an LLVM - // item is appropriate, as long as the queue is full enough for demand. - // - // Speaking of which, how full should we keep the queue? Probably less - // full than you'd think. A lot has to go wrong for the queue not to be - // full enough and for that to have a negative effect on compile times. - // - // Workers are unlikely to finish at exactly the same time, so when one - // finishes and takes another work item off the queue, we often have - // ample time to codegen at that point before the next worker finishes. - // But suppose that codegen takes so long that the workers exhaust the - // queue, and we have one or more workers that have nothing to work on. - // Well, it might not be so bad. Of all the LLVM modules we create and - // optimize, one has to finish last. It's not necessarily the case that - // by losing some concurrency for a moment, we delay the point at which - // that last LLVM module is finished and the rest of compilation can - // proceed. Also, when we can't take advantage of some concurrency, we - // give tokens back to the job server. That enables some other rustc to - // potentially make use of the available concurrency. That could even - // *decrease* overall compile time if we're lucky. But yes, if no other - // rustc can make use of the concurrency, then we've squandered it. - // - // However, keeping the queue full is also beneficial when we have a - // surge in available concurrency. Then items can be taken from the - // queue immediately, without having to wait for codegen. - // - // So, the heuristic below tries to keep one item in the queue for every - // four running workers. Based on limited benchmarking, this appears to - // be more than sufficient to avoid increasing compilation times. - let quarter_of_workers = workers_running - 3 * workers_running / 4; - items_in_queue > 0 && items_in_queue >= quarter_of_workers - } -} - -/// `FatalError` is explicitly not `Send`. -#[must_use] -pub struct WorkerFatalError; - -fn spawn_work<'a, B: ExtraBackendMethods>( - cgcx: &'a CodegenContext, - llvm_start_time: &mut Option>, - worker_id: usize, - work: WorkItem, -) { - if cgcx.config(work.module_kind()).time_module && llvm_start_time.is_none() { - *llvm_start_time = Some(cgcx.prof.verbose_generic_activity("LLVM_passes")); - } - - let cgcx = cgcx.clone(); - - B::spawn_named_thread(cgcx.time_trace, work.short_description(), move || { - // Set up a destructor which will fire off a message that we're done as - // we exit. - struct Bomb { - coordinator_send: Sender>, - result: Option, FatalError>>, - worker_id: usize, - } - impl Drop for Bomb { - fn drop(&mut self) { - let worker_id = self.worker_id; - let msg = match self.result.take() { - Some(Ok(result)) => Message::WorkItem:: { result: Ok(result), worker_id }, - Some(Err(FatalError)) => { - Message::WorkItem:: { result: Err(Some(WorkerFatalError)), worker_id } - } - None => Message::WorkItem:: { result: Err(None), worker_id }, - }; - drop(self.coordinator_send.send(Box::new(msg))); - } - } - - let mut bomb = - Bomb:: { coordinator_send: cgcx.coordinator_send.clone(), result: None, worker_id }; - - // Execute the work itself, and if it finishes successfully then flag - // ourselves as a success as well. - // - // Note that we ignore any `FatalError` coming out of `execute_work_item`, - // as a diagnostic was already sent off to the main thread - just - // surface that there was an error in this worker. - bomb.result = { - let module_config = cgcx.config(work.module_kind()); - - Some(match work { - WorkItem::Optimize(m) => { - let _timer = - cgcx.prof.generic_activity_with_arg("codegen_module_optimize", &*m.name); - execute_optimize_work_item(&cgcx, m, module_config) - } - WorkItem::CopyPostLtoArtifacts(m) => { - let _timer = cgcx.prof.generic_activity_with_arg( - "codegen_copy_artifacts_from_incr_cache", - &*m.name, - ); - Ok(execute_copy_from_cache_work_item(&cgcx, m, module_config)) - } - WorkItem::LTO(m) => { - let _timer = - cgcx.prof.generic_activity_with_arg("codegen_module_perform_lto", m.name()); - execute_lto_work_item(&cgcx, m, module_config) - } - }) - }; - }) - .expect("failed to spawn work thread"); -} - -enum SharedEmitterMessage { - Diagnostic(Diagnostic), - InlineAsmError(u32, String, Level, Option<(String, Vec)>), - Fatal(String), -} - -#[derive(Clone)] -pub struct SharedEmitter { - sender: Sender, -} - -pub struct SharedEmitterMain { - receiver: Receiver, -} - -impl SharedEmitter { - pub fn new() -> (SharedEmitter, SharedEmitterMain) { - let (sender, receiver) = channel(); - - (SharedEmitter { sender }, SharedEmitterMain { receiver }) - } - - pub fn inline_asm_error( - &self, - cookie: u32, - msg: String, - level: Level, - source: Option<(String, Vec)>, - ) { - drop(self.sender.send(SharedEmitterMessage::InlineAsmError(cookie, msg, level, source))); - } - - pub fn fatal(&self, msg: &str) { - drop(self.sender.send(SharedEmitterMessage::Fatal(msg.to_string()))); - } -} - -impl Translate for SharedEmitter { - fn fluent_bundle(&self) -> Option<&Lrc> { - None - } - - fn fallback_fluent_bundle(&self) -> &FluentBundle { - panic!("shared emitter attempted to translate a diagnostic"); - } -} - -impl Emitter for SharedEmitter { - fn emit_diagnostic(&mut self, mut diag: rustc_errors::DiagInner) { - // Check that we aren't missing anything interesting when converting to - // the cut-down local `DiagInner`. - assert_eq!(diag.span, MultiSpan::new()); - assert_eq!(diag.suggestions, Ok(vec![])); - assert_eq!(diag.sort_span, rustc_span::DUMMY_SP); - assert_eq!(diag.is_lint, None); - // No sensible check for `diag.emitted_at`. - - let args = mem::replace(&mut diag.args, DiagArgMap::default()); - drop( - self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic { - level: diag.level(), - messages: diag.messages, - code: diag.code, - children: diag - .children - .into_iter() - .map(|child| Subdiagnostic { level: child.level, messages: child.messages }) - .collect(), - args, - })), - ); - } - - fn source_map(&self) -> Option<&Lrc> { - None - } -} - -impl SharedEmitterMain { - pub fn check(&self, sess: &Session, blocking: bool) { - loop { - let message = if blocking { - match self.receiver.recv() { - Ok(message) => Ok(message), - Err(_) => Err(()), - } - } else { - match self.receiver.try_recv() { - Ok(message) => Ok(message), - Err(_) => Err(()), - } - }; - - match message { - Ok(SharedEmitterMessage::Diagnostic(diag)) => { - // The diagnostic has been received on the main thread. - // Convert it back to a full `Diagnostic` and emit. - let dcx = sess.dcx(); - let mut d = - rustc_errors::DiagInner::new_with_messages(diag.level, diag.messages); - d.code = diag.code; // may be `None`, that's ok - d.children = diag - .children - .into_iter() - .map(|sub| rustc_errors::Subdiag { - level: sub.level, - messages: sub.messages, - span: MultiSpan::new(), - }) - .collect(); - d.args = diag.args; - dcx.emit_diagnostic(d); - sess.dcx().abort_if_errors(); - } - Ok(SharedEmitterMessage::InlineAsmError(cookie, msg, level, source)) => { - assert!(matches!(level, Level::Error | Level::Warning | Level::Note)); - let msg = msg.strip_prefix("error: ").unwrap_or(&msg).to_string(); - let mut err = Diag::<()>::new(sess.dcx(), level, msg); - - // If the cookie is 0 then we don't have span information. - if cookie != 0 { - let pos = BytePos::from_u32(cookie); - let span = Span::with_root_ctxt(pos, pos); - err.span(span); - }; - - // Point to the generated assembly if it is available. - if let Some((buffer, spans)) = source { - let source = sess - .source_map() - .new_source_file(FileName::inline_asm_source_code(&buffer), buffer); - let spans: Vec<_> = spans - .iter() - .map(|sp| { - Span::with_root_ctxt( - source.normalized_byte_pos(sp.start as u32), - source.normalized_byte_pos(sp.end as u32), - ) - }) - .collect(); - err.span_note(spans, "instantiated into assembly here"); - } - - err.emit(); - } - Ok(SharedEmitterMessage::Fatal(msg)) => { - sess.dcx().fatal(msg); - } - Err(_) => { - break; - } - } - } - } -} - -pub struct Coordinator { - pub sender: Sender>, - future: Option>>, - // Only used for the Message type. - phantom: PhantomData, -} - -impl Coordinator { - fn join(mut self) -> std::thread::Result> { - self.future.take().unwrap().join() - } -} - -impl Drop for Coordinator { - fn drop(&mut self) { - if let Some(future) = self.future.take() { - // If we haven't joined yet, signal to the coordinator that it should spawn no more - // work, and wait for worker threads to finish. - drop(self.sender.send(Box::new(Message::CodegenAborted::))); - drop(future.join()); - } - } -} - -pub struct OngoingCodegen { - pub backend: B, - pub metadata: EncodedMetadata, - pub metadata_module: Option, - pub crate_info: CrateInfo, - pub codegen_worker_receive: Receiver, - pub shared_emitter_main: SharedEmitterMain, - pub output_filenames: Arc, - pub coordinator: Coordinator, -} - -impl OngoingCodegen { - pub fn join(self, sess: &Session) -> (CodegenResults, FxIndexMap) { - let _timer = sess.timer("finish_ongoing_codegen"); - - self.shared_emitter_main.check(sess, true); - let compiled_modules = sess.time("join_worker_thread", || match self.coordinator.join() { - Ok(Ok(compiled_modules)) => compiled_modules, - Ok(Err(())) => { - sess.dcx().abort_if_errors(); - panic!("expected abort due to worker thread errors") - } - Err(_) => { - bug!("panic during codegen/LLVM phase"); - } - }); - - sess.dcx().abort_if_errors(); - - let work_products = - copy_all_cgu_workproducts_to_incr_comp_cache_dir(sess, &compiled_modules); - produce_final_output_artifacts(sess, &compiled_modules, &self.output_filenames); - - // FIXME: time_llvm_passes support - does this use a global context or - // something? - if sess.codegen_units().as_usize() == 1 && sess.opts.unstable_opts.time_llvm_passes { - self.backend.print_pass_timings() - } - - if sess.print_llvm_stats() { - self.backend.print_statistics() - } - - ( - CodegenResults { - metadata: self.metadata, - crate_info: self.crate_info, - - modules: compiled_modules.modules, - allocator_module: compiled_modules.allocator_module, - metadata_module: self.metadata_module, - }, - work_products, - ) - } - - pub fn codegen_finished(&self, tcx: TyCtxt<'_>) { - self.wait_for_signal_to_codegen_item(); - self.check_for_errors(tcx.sess); - drop(self.coordinator.sender.send(Box::new(Message::CodegenComplete::))); - } - - pub fn check_for_errors(&self, sess: &Session) { - self.shared_emitter_main.check(sess, false); - } - - pub fn wait_for_signal_to_codegen_item(&self) { - match self.codegen_worker_receive.recv() { - Ok(CguMessage) => { - // Ok to proceed. - } - Err(_) => { - // One of the LLVM threads must have panicked, fall through so - // error handling can be reached. - } - } - } -} - -pub fn submit_codegened_module_to_llvm( - _backend: &B, - tx_to_llvm_workers: &Sender>, - module: ModuleCodegen, - cost: u64, -) { - let llvm_work_item = WorkItem::Optimize(module); - drop(tx_to_llvm_workers.send(Box::new(Message::CodegenDone:: { llvm_work_item, cost }))); -} - -pub fn submit_post_lto_module_to_llvm( - _backend: &B, - tx_to_llvm_workers: &Sender>, - module: CachedModuleCodegen, -) { - let llvm_work_item = WorkItem::CopyPostLtoArtifacts(module); - drop(tx_to_llvm_workers.send(Box::new(Message::CodegenDone:: { llvm_work_item, cost: 0 }))); -} - -pub fn submit_pre_lto_module_to_llvm( - _backend: &B, - tcx: TyCtxt<'_>, - tx_to_llvm_workers: &Sender>, - module: CachedModuleCodegen, -) { - let filename = pre_lto_bitcode_filename(&module.name); - let bc_path = in_incr_comp_dir_sess(tcx.sess, &filename); - let file = fs::File::open(&bc_path) - .unwrap_or_else(|e| panic!("failed to open bitcode file `{}`: {}", bc_path.display(), e)); - - let mmap = unsafe { - Mmap::map(file).unwrap_or_else(|e| { - panic!("failed to mmap bitcode file `{}`: {}", bc_path.display(), e) - }) - }; - // Schedule the module to be loaded - drop(tx_to_llvm_workers.send(Box::new(Message::AddImportOnlyModule:: { - module_data: SerializedModule::FromUncompressedFile(mmap), - work_product: module.source, - }))); -} - -fn pre_lto_bitcode_filename(module_name: &str) -> String { - format!("{module_name}.{PRE_LTO_BC_EXT}") -} - -fn msvc_imps_needed(tcx: TyCtxt<'_>) -> bool { - // This should never be true (because it's not supported). If it is true, - // something is wrong with commandline arg validation. - assert!( - !(tcx.sess.opts.cg.linker_plugin_lto.enabled() - && tcx.sess.target.is_like_windows - && tcx.sess.opts.cg.prefer_dynamic) - ); - - tcx.sess.target.is_like_windows && - tcx.crate_types().iter().any(|ct| *ct == CrateType::Rlib) && - // ThinLTO can't handle this workaround in all cases, so we don't - // emit the `__imp_` symbols. Instead we make them unnecessary by disallowing - // dynamic linking when linker plugin LTO is enabled. - !tcx.sess.opts.cg.linker_plugin_lto.enabled() -} +),MainThreadState::Lending=>{}}}else{{;};assert!(codegen_state==Aborted);{;};if +running_with_any_token(main_thread_state,running_with_own_token)==0{;break;}}if +codegen_state!=Aborted{while(!(work_items .is_empty()))&&running_with_own_token< +tokens.len(){();let(item,_)=work_items.pop().unwrap();();3;spawn_work(&cgcx,&mut +llvm_start_time,get_worker_id(&mut free_worker_ids),item,);let _=||();if true{}; +running_with_own_token+=1;3;}};tokens.truncate(running_with_own_token);;;let mut +free_worker=|worker_id|{if main_thread_state==MainThreadState::Lending{let _=(); +main_thread_state=MainThreadState::Idle;3;}else{3;running_with_own_token-=1;3;}; +free_worker_ids.push(worker_id);;};;let msg=coordinator_receive.recv().unwrap(); +match(*msg.downcast::>().ok().unwrap()){Message::Token(token)=>{match +token{Ok(token)=>{3;tokens.push(token);3;if main_thread_state==MainThreadState:: +Lending{;main_thread_state=MainThreadState::Idle;running_with_own_token+=1;}}Err +(e)=>{;let msg=&format!("failed to acquire jobserver token: {e}");shared_emitter +.fatal(msg);;;codegen_state=Aborted;}}}Message::CodegenDone{llvm_work_item,cost} +=>{;let insertion_index=work_items.binary_search_by_key(&cost,|&(_,cost)|cost);; +let insertion_index=match insertion_index{Ok(idx)|Err(idx)=>idx,};3;;work_items. +insert(insertion_index,(llvm_work_item,cost));({});if cgcx.parallel{({});helper. +request_token();;};assert_eq!(main_thread_state,MainThreadState::Codegenning);;; +main_thread_state=MainThreadState::Idle;let _=();}Message::CodegenComplete=>{if +codegen_state!=Aborted{;codegen_state=Completed;;};assert_eq!(main_thread_state, +MainThreadState::Codegenning);;;main_thread_state=MainThreadState::Idle;}Message +::CodegenAborted=>{;codegen_state=Aborted;}Message::WorkItem{result,worker_id}=> +{((),());free_worker(worker_id);*&*&();match result{Ok(WorkItemResult::Finished( +compiled_module))=>{match compiled_module.kind{ModuleKind::Regular=>{();assert!( +needs_link.is_empty());3;3;compiled_modules.push(compiled_module);;}ModuleKind:: +Allocator=>{((),());assert!(compiled_allocator_module.is_none());((),());*&*&(); +compiled_allocator_module=Some(compiled_module);{;};}ModuleKind::Metadata=>bug!( +"Should be handled separately"),}}Ok(WorkItemResult::NeedsLink(module))=>{{();}; +assert!(compiled_modules.is_empty());;needs_link.push(module);}Ok(WorkItemResult +::NeedsFatLto(fat_lto_input))=>{;assert!(!started_lto);;;assert!(needs_thin_lto. +is_empty());;needs_fat_lto.push(fat_lto_input);}Ok(WorkItemResult::NeedsThinLto( +name,thin_buffer))=>{;assert!(!started_lto);;;assert!(needs_fat_lto.is_empty()); +needs_thin_lto.push((name,thin_buffer));({});}Err(Some(WorkerFatalError))=>{{;}; +codegen_state=Aborted;;}Err(None)=>{;bug!("worker thread panicked");}}}Message:: +AddImportOnlyModule{module_data,work_product}=>{;assert!(!started_lto);assert_eq +!(codegen_state,Ongoing);({});{;};assert_eq!(main_thread_state,MainThreadState:: +Codegenning);();();lto_import_only_modules.push((module_data,work_product));3;3; +main_thread_state=MainThreadState::Idle;;}}}if codegen_state==Aborted{return Err +(());;}let needs_link=mem::take(&mut needs_link);if!needs_link.is_empty(){assert +!(compiled_modules.is_empty());;let dcx=cgcx.create_dcx();let module=B::run_link +(&cgcx,&dcx,needs_link).map_err(|_|())?;;let module=unsafe{B::codegen(&cgcx,&dcx +,module,cgcx.config(ModuleKind::Regular)).map_err(|_|())?};3;3;compiled_modules. +push(module);;}drop(llvm_start_time);compiled_modules.sort_by(|a,b|a.name.cmp(&b +.name));let _=||();Ok(CompiledModules{modules:compiled_modules,allocator_module: +compiled_allocator_module,})}).expect("failed to spawn coordinator thread");;;fn +queue_full_enough(items_in_queue:usize,workers_running:usize)->bool{let _=();let +quarter_of_workers=workers_running-3*workers_running/4;*&*&();items_in_queue>0&& +items_in_queue>=quarter_of_workers}();}#[must_use]pub struct WorkerFatalError;fn +spawn_work<'a,B:ExtraBackendMethods>(cgcx :&'a CodegenContext,llvm_start_time +:&mut Option>,worker_id:usize ,work:WorkItem,){if cgcx +.config(work.module_kind()).time_module&&llvm_start_time.is_none(){loop{break};* +llvm_start_time=Some(cgcx.prof.verbose_generic_activity("LLVM_passes"));3;}3;let +cgcx=cgcx.clone();;B::spawn_named_thread(cgcx.time_trace,work.short_description( +),move||{;struct Bomb{coordinator_send:Sender>,result:Option,FatalError>>,worker_id:usize,}3;; +implDrop for Bomb{fn drop(&mut self){();let worker_id= +self.worker_id;();3;let msg=match self.result.take(){Some(Ok(result))=>Message:: +WorkItem::{result:((Ok(result))),worker_id},Some(Err(FatalError))=>{Message:: +WorkItem::{result:(Err((Some( WorkerFatalError)))),worker_id}}None=>Message:: +WorkItem::{result:Err(None),worker_id},};;drop(self.coordinator_send.send(Box +::new(msg)));;}};;let mut bomb=Bomb::{coordinator_send:cgcx.coordinator_send. +clone(),result:None,worker_id};;bomb.result={let module_config=cgcx.config(work. +module_kind());3;Some(match work{WorkItem::Optimize(m)=>{3;let _timer=cgcx.prof. +generic_activity_with_arg("codegen_module_optimize",&*m.name);let _=();let _=(); +execute_optimize_work_item(((((((((((&cgcx)))))))))),m,module_config)}WorkItem:: +CopyPostLtoArtifacts(m)=>{*&*&();let _timer=cgcx.prof.generic_activity_with_arg( +"codegen_copy_artifacts_from_incr_cache",&*m.name,);loop{break};loop{break;};Ok( +execute_copy_from_cache_work_item(&cgcx,m,module_config))}WorkItem::LTO(m)=>{(); +let _timer=cgcx.prof.generic_activity_with_arg(("codegen_module_perform_lto"),m. +name());*&*&();execute_lto_work_item(&cgcx,m,module_config)}})};{();};}).expect( +"failed to spawn work thread");;}enum SharedEmitterMessage{Diagnostic(Diagnostic +),InlineAsmError(u32,String,Level,Option<( String,Vec)>),Fatal(String +),}#[derive(Clone)]pub struct SharedEmitter{sender:Sender +,}pub struct SharedEmitterMain{receiver:Receiver,}impl//3; +SharedEmitter{pub fn new()->(SharedEmitter,SharedEmitterMain){*&*&();let(sender, +receiver)=channel();3;(SharedEmitter{sender},SharedEmitterMain{receiver})}pub fn +inline_asm_error(&self,cookie:u32,msg:String ,level:Level,source:Option<(String, +Vec)>,){3;drop(self.sender.send(SharedEmitterMessage::InlineAsmError( +cookie,msg,level,source)));;}pub fn fatal(&self,msg:&str){drop(self.sender.send( +SharedEmitterMessage::Fatal(msg.to_string())));loop{break;};}}impl Translate for +SharedEmitter{fn fluent_bundle(&self)->Option<&Lrc>{None}fn//({}); +fallback_fluent_bundle(&self)->&FluentBundle{if let _=(){};if let _=(){};panic!( +"shared emitter attempted to translate a diagnostic");((),());}}impl Emitter for +SharedEmitter{fn emit_diagnostic(&mut self,mut diag:rustc_errors::DiagInner){(); +assert_eq!(diag.span,MultiSpan::new());;assert_eq!(diag.suggestions,Ok(vec![])); +assert_eq!(diag.sort_span,rustc_span::DUMMY_SP);;;assert_eq!(diag.is_lint,None); +let args=mem::replace(&mut diag.args,DiagArgMap::default());3;;drop(self.sender. +send(SharedEmitterMessage::Diagnostic(Diagnostic{level :(diag.level()),messages: +diag.messages,code:diag.code,children:(( diag.children.into_iter())).map(|child| +Subdiagnostic{level:child.level,messages:child.messages}).collect(),args,})),);; +}fn source_map(&self)->Option<& Lrc>{None}}impl SharedEmitterMain{pub +fn check(&self,sess:&Session,blocking:bool){loop{3;let message=if blocking{match +(self.receiver.recv()){Ok(message)=>(Ok(message)), Err(_)=>Err(()),}}else{match +self.receiver.try_recv(){Ok(message)=>Ok(message),Err(_)=>Err(()),}};{();};match +message{Ok(SharedEmitterMessage::Diagnostic(diag))=>{;let dcx=sess.dcx();let mut +d=rustc_errors::DiagInner::new_with_messages(diag.level,diag.messages);;;d.code= +diag.code;;;d.children=diag.children.into_iter().map(|sub|rustc_errors::Subdiag{ +level:sub.level,messages:sub.messages,span:MultiSpan::new(),}).collect();;d.args +=diag.args;();();dcx.emit_diagnostic(d);();3;sess.dcx().abort_if_errors();3;}Ok( +SharedEmitterMessage::InlineAsmError(cookie,msg,level,source))=>{*&*&();assert!( +matches!(level,Level::Error|Level::Warning|Level::Note));{();};({});let msg=msg. +strip_prefix("error: ").unwrap_or(&msg).to_string();;let mut err=Diag::<()>::new +(sess.dcx(),level,msg);;if cookie!=0{let pos=BytePos::from_u32(cookie);let span= +Span::with_root_ctxt(pos,pos);3;;err.span(span);;};;if let Some((buffer,spans))= +source{let _=();let _=();let source=sess.source_map().new_source_file(FileName:: +inline_asm_source_code(&buffer),buffer);;let spans:Vec<_>=spans.iter().map(|sp|{ +Span::with_root_ctxt(((source.normalized_byte_pos(((sp.start as u32))))),source. +normalized_byte_pos(sp.end as u32),)}).collect();{();};({});err.span_note(spans, +"instantiated into assembly here");;}err.emit();}Ok(SharedEmitterMessage::Fatal( +msg))=>{;sess.dcx().fatal(msg);;}Err(_)=>{;break;;}}}}}pub struct Coordinator{pub sender:Sender>,future:Option>>,phantom:PhantomData,}implCoordinator{fn join(mut self)->std::thread::Result>{((((self.future.take( )).unwrap()).join()))}}implDrop for Coordinator{fn drop(&mut self){if let Some(//(); +future)=self.future.take(){loop{break;};drop(self.sender.send(Box::new(Message:: +CodegenAborted::)));3;3;drop(future.join());3;}}}pub struct OngoingCodegen{pub backend:B,pub metadata:EncodedMetadata,pub//let _=||(); +metadata_module:Option,pub crate_info:CrateInfo,pub//let _=||(); +codegen_worker_receive:Receiver,pub shared_emitter_main://if true{}; +SharedEmitterMain,pub output_filenames:Arc,pub coordinator://3; +Coordinator,}implOngoingCodegen{pub fn join(self,// +sess:&Session)->(CodegenResults,FxIndexMap){{();};let +_timer=sess.timer("finish_ongoing_codegen");;self.shared_emitter_main.check(sess +,true);{;};{;};let compiled_modules=sess.time("join_worker_thread",||match self. +coordinator.join(){Ok(Ok(compiled_modules))=>compiled_modules,Ok(Err(()))=>{{;}; +sess.dcx().abort_if_errors();let _=||();let _=||();let _=||();let _=||();panic!( +"expected abort due to worker thread errors")}Err(_)=>{if true{};if true{};bug!( +"panic during codegen/LLVM phase");3;}});3;3;sess.dcx().abort_if_errors();3;;let +work_products=copy_all_cgu_workproducts_to_incr_comp_cache_dir(sess,&//let _=(); +compiled_modules);;;produce_final_output_artifacts(sess,&compiled_modules,&self. +output_filenames);loop{break;};if sess.codegen_units().as_usize()==1&&sess.opts. +unstable_opts.time_llvm_passes{(((self.backend. print_pass_timings())))}if sess. +print_llvm_stats(){((self.backend.print_statistics()))}(CodegenResults{metadata: +self.metadata,crate_info:self.crate_info,modules:compiled_modules.modules,//{;}; +allocator_module:compiled_modules.allocator_module,metadata_module:self.//{();}; +metadata_module,},work_products,)}pub fn codegen_finished(&self,tcx:TyCtxt<'_>) +{;self.wait_for_signal_to_codegen_item();;;self.check_for_errors(tcx.sess);drop( +self.coordinator.sender.send(Box::new(Message::CodegenComplete::)));3;}pub fn +check_for_errors(&self,sess:&Session){;self.shared_emitter_main.check(sess,false +);if true{};if true{};}pub fn wait_for_signal_to_codegen_item(&self){match self. +codegen_worker_receive.recv(){Ok(CguMessage)=>{}Err(_)=>{}}}}pub fn//let _=||(); +submit_codegened_module_to_llvm(_backend:&B,//let _=||(); +tx_to_llvm_workers:&Sender>,module:ModuleCodegen,// +cost:u64,){{();};let llvm_work_item=WorkItem::Optimize(module);{();};{();};drop( +tx_to_llvm_workers.send(Box::new(Message ::CodegenDone::{llvm_work_item,cost} +)));3;}pub fn submit_post_lto_module_to_llvm(_backend:&B, +tx_to_llvm_workers:&Sender>,module:CachedModuleCodegen,){3;let +llvm_work_item=WorkItem::CopyPostLtoArtifacts(module);;;drop(tx_to_llvm_workers. +send(Box::new(Message::CodegenDone::{llvm_work_item,cost:0})));*&*&();}pub fn +submit_pre_lto_module_to_llvm(_backend: &B,tcx:TyCtxt<'_> +,tx_to_llvm_workers:&Sender>,module:CachedModuleCodegen,){;let +filename=pre_lto_bitcode_filename(&module.name);if true{};if true{};let bc_path= +in_incr_comp_dir_sess(tcx.sess,&filename);3;3;let file=fs::File::open(&bc_path). +unwrap_or_else(|e| panic!("failed to open bitcode file `{}`: {}",bc_path.display +(),e));((),());*&*&();let mmap=unsafe{Mmap::map(file).unwrap_or_else(|e|{panic!( +"failed to mmap bitcode file `{}`: {}",bc_path.display(),e)})};{();};{();};drop( +tx_to_llvm_workers.send(Box::new( Message::AddImportOnlyModule::{module_data: +SerializedModule::FromUncompressedFile(mmap),work_product:module.source,})));3;} +fn pre_lto_bitcode_filename(module_name:&str)->String{format!(//((),());((),()); +"{module_name}.{PRE_LTO_BC_EXT}")}fn msvc_imps_needed(tcx:TyCtxt<'_>)->bool{{;}; +assert!(!(tcx.sess.opts.cg.linker_plugin_lto.enabled()&&tcx.sess.target.//{();}; +is_like_windows&&tcx.sess.opts.cg.prefer_dynamic));loop{break;};tcx.sess.target. +is_like_windows&&(tcx.crate_types().iter().any(|ct|*ct==CrateType::Rlib))&&!tcx. +sess.opts.cg.linker_plugin_lto.enabled()}//let _=();let _=();let _=();if true{}; diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index f7f2bfca838ea..600909ebd3ef3 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -1,1056 +1,308 @@ -use crate::assert_module_sources::CguReuse; -use crate::back::link::are_upstream_rust_objects_already_included; -use crate::back::metadata::create_compressed_metadata_file; -use crate::back::write::{ - compute_per_cgu_lto_type, start_async_codegen, submit_codegened_module_to_llvm, - submit_post_lto_module_to_llvm, submit_pre_lto_module_to_llvm, ComputedLtoType, OngoingCodegen, -}; -use crate::common::{IntPredicate, RealPredicate, TypeKind}; -use crate::errors; -use crate::meth; -use crate::mir; -use crate::mir::operand::OperandValue; -use crate::mir::place::PlaceRef; -use crate::traits::*; -use crate::{CachedModuleCodegen, CompiledModule, CrateInfo, MemFlags, ModuleCodegen, ModuleKind}; - -use rustc_ast::expand::allocator::{global_fn_name, AllocatorKind, ALLOCATOR_METHODS}; -use rustc_attr as attr; -use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; -use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; -use rustc_data_structures::sync::par_map; -use rustc_data_structures::unord::UnordMap; -use rustc_hir as hir; -use rustc_hir::def_id::{DefId, LOCAL_CRATE}; -use rustc_hir::lang_items::LangItem; -use rustc_metadata::EncodedMetadata; -use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; -use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType}; -use rustc_middle::middle::exported_symbols; -use rustc_middle::middle::exported_symbols::SymbolExportKind; -use rustc_middle::middle::lang_items; -use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem}; -use rustc_middle::query::Providers; -use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; -use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; -use rustc_session::config::{self, CrateType, EntryFnType, OutputType}; -use rustc_session::Session; -use rustc_span::symbol::sym; -use rustc_span::Symbol; -use rustc_target::abi::{Align, FIRST_VARIANT}; - -use std::cmp; -use std::collections::BTreeSet; -use std::time::{Duration, Instant}; - -use itertools::Itertools; - -pub fn bin_op_to_icmp_predicate(op: hir::BinOpKind, signed: bool) -> IntPredicate { - match op { - hir::BinOpKind::Eq => IntPredicate::IntEQ, - hir::BinOpKind::Ne => IntPredicate::IntNE, - hir::BinOpKind::Lt => { - if signed { - IntPredicate::IntSLT - } else { - IntPredicate::IntULT - } - } - hir::BinOpKind::Le => { - if signed { - IntPredicate::IntSLE - } else { - IntPredicate::IntULE - } - } - hir::BinOpKind::Gt => { - if signed { - IntPredicate::IntSGT - } else { - IntPredicate::IntUGT - } - } - hir::BinOpKind::Ge => { - if signed { - IntPredicate::IntSGE - } else { - IntPredicate::IntUGE - } - } - op => bug!( - "comparison_op_to_icmp_predicate: expected comparison operator, \ - found {:?}", - op - ), - } -} - -pub fn bin_op_to_fcmp_predicate(op: hir::BinOpKind) -> RealPredicate { - match op { - hir::BinOpKind::Eq => RealPredicate::RealOEQ, - hir::BinOpKind::Ne => RealPredicate::RealUNE, - hir::BinOpKind::Lt => RealPredicate::RealOLT, - hir::BinOpKind::Le => RealPredicate::RealOLE, - hir::BinOpKind::Gt => RealPredicate::RealOGT, - hir::BinOpKind::Ge => RealPredicate::RealOGE, - op => { - bug!( - "comparison_op_to_fcmp_predicate: expected comparison operator, \ - found {:?}", - op - ); - } - } -} - -pub fn compare_simd_types<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - bx: &mut Bx, - lhs: Bx::Value, - rhs: Bx::Value, - t: Ty<'tcx>, - ret_ty: Bx::Type, - op: hir::BinOpKind, -) -> Bx::Value { - let signed = match t.kind() { - ty::Float(_) => { - let cmp = bin_op_to_fcmp_predicate(op); - let cmp = bx.fcmp(cmp, lhs, rhs); - return bx.sext(cmp, ret_ty); - } - ty::Uint(_) => false, - ty::Int(_) => true, - _ => bug!("compare_simd_types: invalid SIMD type"), - }; - - let cmp = bin_op_to_icmp_predicate(op, signed); - let cmp = bx.icmp(cmp, lhs, rhs); - // LLVM outputs an `< size x i1 >`, so we need to perform a sign extension - // to get the correctly sized type. This will compile to a single instruction - // once the IR is converted to assembly if the SIMD instruction is supported - // by the target architecture. - bx.sext(cmp, ret_ty) -} - -/// Retrieves the information we are losing (making dynamic) in an unsizing -/// adjustment. -/// -/// The `old_info` argument is a bit odd. It is intended for use in an upcast, -/// where the new vtable for an object will be derived from the old one. -pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - bx: &mut Bx, - source: Ty<'tcx>, - target: Ty<'tcx>, - old_info: Option, -) -> Bx::Value { - let cx = bx.cx(); - let (source, target) = - cx.tcx().struct_lockstep_tails_erasing_lifetimes(source, target, bx.param_env()); - match (source.kind(), target.kind()) { - (&ty::Array(_, len), &ty::Slice(_)) => { - cx.const_usize(len.eval_target_usize(cx.tcx(), ty::ParamEnv::reveal_all())) - } - (&ty::Dynamic(data_a, _, src_dyn_kind), &ty::Dynamic(data_b, _, target_dyn_kind)) - if 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() { - // A NOP cast that doesn't actually change anything, should be allowed even with invalid vtables. - return old_info; - } - - // trait upcasting coercion - - let vptr_entry_idx = - cx.tcx().vtable_trait_upcasting_coercion_new_vptr_slot((source, target)); - - if let Some(entry_idx) = vptr_entry_idx { - let ptr_size = bx.data_layout().pointer_size; - let ptr_align = bx.data_layout().pointer_align.abi; - let vtable_byte_offset = u64::try_from(entry_idx).unwrap() * ptr_size.bytes(); - let gep = bx.inbounds_ptradd(old_info, bx.const_usize(vtable_byte_offset)); - let new_vptr = bx.load(bx.type_ptr(), gep, ptr_align); - bx.nonnull_metadata(new_vptr); - // VTable loads are invariant. - bx.set_invariant_load(new_vptr); - new_vptr - } else { - old_info - } - } - (_, ty::Dynamic(data, _, _)) => meth::get_vtable(cx, source, data.principal()), - _ => bug!("unsized_info: invalid unsizing {:?} -> {:?}", source, target), - } -} - -/// Coerces `src` to `dst_ty`. `src_ty` must be a pointer. -pub fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - bx: &mut Bx, - src: Bx::Value, - src_ty: Ty<'tcx>, - dst_ty: Ty<'tcx>, - old_info: Option, -) -> (Bx::Value, Bx::Value) { - debug!("unsize_ptr: {:?} => {:?}", src_ty, dst_ty); - match (src_ty.kind(), dst_ty.kind()) { - (&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(b, _)) - | (&ty::RawPtr(a, _), &ty::RawPtr(b, _)) => { - assert_eq!(bx.cx().type_is_sized(a), old_info.is_none()); - (src, unsized_info(bx, a, b, old_info)) - } - (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => { - assert_eq!(def_a, def_b); // implies same number of fields - let src_layout = bx.cx().layout_of(src_ty); - let dst_layout = bx.cx().layout_of(dst_ty); - if src_ty == dst_ty { - return (src, old_info.unwrap()); - } - let mut result = None; - for i in 0..src_layout.fields.count() { - let src_f = src_layout.field(bx.cx(), i); - if src_f.is_1zst() { - // We are looking for the one non-1-ZST field; this is not it. - continue; - } - - assert_eq!(src_layout.fields.offset(i).bytes(), 0); - assert_eq!(dst_layout.fields.offset(i).bytes(), 0); - assert_eq!(src_layout.size, src_f.size); - - let dst_f = dst_layout.field(bx.cx(), i); - assert_ne!(src_f.ty, dst_f.ty); - assert_eq!(result, None); - result = Some(unsize_ptr(bx, src, src_f.ty, dst_f.ty, old_info)); - } - result.unwrap() - } - _ => bug!("unsize_ptr: called on bad types"), - } -} - -/// 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) { - 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*" - ); - let src = match bx.cx().type_kind(bx.cx().backend_type(src_ty_and_layout)) { - TypeKind::Pointer => src, - TypeKind::Integer => bx.inttoptr(src, bx.type_ptr()), - // FIXME(dyn-star): We probably have to do a bitcast first, then inttoptr. - kind => bug!("unexpected TypeKind for left-hand side of `dyn*` cast: {kind:?}"), - }; - (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>>( - bx: &mut Bx, - src: PlaceRef<'tcx, Bx::Value>, - dst: PlaceRef<'tcx, Bx::Value>, -) { - let src_ty = src.layout.ty; - let dst_ty = dst.layout.ty; - match (src_ty.kind(), dst_ty.kind()) { - (&ty::Ref(..), &ty::Ref(..) | &ty::RawPtr(..)) | (&ty::RawPtr(..), &ty::RawPtr(..)) => { - let (base, info) = match bx.load_operand(src).val { - OperandValue::Pair(base, info) => unsize_ptr(bx, base, src_ty, dst_ty, Some(info)), - OperandValue::Immediate(base) => unsize_ptr(bx, base, src_ty, dst_ty, None), - OperandValue::Ref(..) | OperandValue::ZeroSized => bug!(), - }; - OperandValue::Pair(base, info).store(bx, dst); - } - - (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => { - assert_eq!(def_a, def_b); // implies same number of fields - - for i in def_a.variant(FIRST_VARIANT).fields.indices() { - let src_f = src.project_field(bx, i.as_usize()); - let dst_f = dst.project_field(bx, i.as_usize()); - - if dst_f.layout.is_zst() { - // No data here, nothing to copy/coerce. - continue; - } - - if src_f.layout.ty == dst_f.layout.ty { - memcpy_ty( - bx, - dst_f.llval, - dst_f.align, - src_f.llval, - src_f.align, - src_f.layout, - MemFlags::empty(), - ); - } else { - coerce_unsized_into(bx, src_f, dst_f); - } - } - } - _ => bug!("coerce_unsized_into: invalid coercion {:?} -> {:?}", src_ty, dst_ty,), - } -} - -pub fn cast_shift_expr_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - bx: &mut Bx, - lhs: Bx::Value, - rhs: Bx::Value, -) -> Bx::Value { - // Shifts may have any size int on the 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 { - // We zero-extend even if the RHS is signed. So e.g. `(x: i32) << -1i8` will zero-extend the - // RHS to `255i32`. But then we mask the shift amount to be within the size of the LHS - // anyway so the result is `31` as it should be. All the extra bits introduced by zext - // are masked off so their value does not matter. - // FIXME: if we ever support 512bit integers, this will be wrong! For such large integers, - // the extra bits introduced by zext are *not* all masked away any more. - assert!(lhs_sz <= 256); - bx.zext(rhs, lhs_llty) - } else { - rhs - } -} - -// Returns `true` if this session's target will use native wasm -// exceptions. This means that the VM does the unwinding for -// us -pub fn wants_wasm_eh(sess: &Session) -> bool { - sess.target.is_like_wasm && sess.target.os != "emscripten" -} - -/// Returns `true` if this session's target will use SEH-based unwinding. -/// -/// This is only true for MSVC targets, and even then the 64-bit MSVC target -/// currently uses SEH-ish unwinding with DWARF info tables to the side (same as -/// 64-bit MinGW) instead of "full SEH". -pub fn wants_msvc_seh(sess: &Session) -> bool { - sess.target.is_like_msvc -} - -/// Returns `true` if this session's target requires the new exception -/// handling LLVM IR instructions (catchpad / cleanuppad / ... instead -/// of landingpad) -pub fn wants_new_eh_instructions(sess: &Session) -> bool { - wants_wasm_eh(sess) || wants_msvc_seh(sess) -} - -pub fn memcpy_ty<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - bx: &mut Bx, - dst: Bx::Value, - dst_align: Align, - src: Bx::Value, - src_align: Align, - layout: TyAndLayout<'tcx>, - flags: MemFlags, -) { - let size = layout.size.bytes(); - if size == 0 { - return; - } - - if flags == MemFlags::empty() - && let Some(bty) = bx.cx().scalar_copy_backend_type(layout) - { - let temp = bx.load(bty, src, src_align); - bx.store(temp, dst, dst_align); - } else { - bx.memcpy(dst, dst_align, src, src_align, bx.cx().const_usize(size), flags); - } -} - -pub fn codegen_instance<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( - cx: &'a Bx::CodegenCx, - instance: Instance<'tcx>, -) { - // this is an info! to allow collecting monomorphization statistics - // and to allow finding the last function before LLVM aborts from - // release builds. - info!("codegen_instance({})", instance); - - mir::codegen_mir::(cx, instance); -} - -/// Creates the `main` function which will initialize the rust runtime and call -/// users main function. -pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - cx: &'a Bx::CodegenCx, -) -> Option { - let (main_def_id, entry_type) = cx.tcx().entry_fn(())?; - let main_is_local = main_def_id.is_local(); - let instance = Instance::mono(cx.tcx(), main_def_id); - - if main_is_local { - // We want to create the wrapper in the same codegen unit as Rust's main - // function. - if !cx.codegen_unit().contains_item(&MonoItem::Fn(instance)) { - return None; - } - } else if !cx.codegen_unit().is_primary() { - // We want to create the wrapper only when the codegen unit is the primary one - return None; - } - - let main_llfn = cx.get_fn_addr(instance); - - let entry_fn = create_entry_fn::(cx, main_llfn, main_def_id, entry_type); - return Some(entry_fn); - - fn create_entry_fn<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - cx: &'a Bx::CodegenCx, - rust_main: Bx::Value, - rust_main_def_id: DefId, - entry_type: EntryFnType, - ) -> Bx::Function { - // The entry function is either `int main(void)` or `int main(int argc, char **argv)`, or - // `usize efi_main(void *handle, void *system_table)` depending on the target. - let llfty = if cx.sess().target.os.contains("uefi") { - cx.type_func(&[cx.type_ptr(), cx.type_ptr()], cx.type_isize()) - } else if cx.sess().target.main_needs_argc_argv { - cx.type_func(&[cx.type_int(), cx.type_ptr()], cx.type_int()) - } else { - cx.type_func(&[], cx.type_int()) - }; - - let main_ret_ty = cx.tcx().fn_sig(rust_main_def_id).no_bound_vars().unwrap().output(); - // Given that `main()` has no arguments, - // then its return type cannot have - // late-bound regions, since late-bound - // regions must appear in the argument - // listing. - let main_ret_ty = cx.tcx().normalize_erasing_regions( - ty::ParamEnv::reveal_all(), - main_ret_ty.no_bound_vars().unwrap(), - ); - - let Some(llfn) = cx.declare_c_main(llfty) else { - // FIXME: We should be smart and show a better diagnostic here. - let span = cx.tcx().def_span(rust_main_def_id); - cx.tcx().dcx().emit_fatal(errors::MultipleMainFunctions { span }); - }; - - // `main` should respect same config for frame pointer elimination as rest of code - cx.set_frame_pointer_type(llfn); - cx.apply_target_cpu_attr(llfn); - - let llbb = Bx::append_block(cx, llfn, "top"); - let mut bx = Bx::build(cx, llbb); - - bx.insert_reference_to_gdb_debug_scripts_section_global(); - - let isize_ty = cx.type_isize(); - let ptr_ty = cx.type_ptr(); - let (arg_argc, arg_argv) = get_argc_argv(cx, &mut bx); - - let (start_fn, start_ty, args, instance) = if let EntryFnType::Main { sigpipe } = entry_type - { - let start_def_id = cx.tcx().require_lang_item(LangItem::Start, None); - let start_instance = ty::Instance::expect_resolve( - cx.tcx(), - ty::ParamEnv::reveal_all(), - start_def_id, - cx.tcx().mk_args(&[main_ret_ty.into()]), - ); - let start_fn = cx.get_fn_addr(start_instance); - - let i8_ty = cx.type_i8(); - let arg_sigpipe = bx.const_u8(sigpipe); - - let start_ty = cx.type_func(&[cx.val_ty(rust_main), isize_ty, ptr_ty, i8_ty], isize_ty); - ( - start_fn, - start_ty, - vec![rust_main, arg_argc, arg_argv, arg_sigpipe], - Some(start_instance), - ) - } else { - debug!("using user-defined start fn"); - let start_ty = cx.type_func(&[isize_ty, ptr_ty], isize_ty); - (rust_main, start_ty, vec![arg_argc, arg_argv], None) - }; - - let result = bx.call(start_ty, None, None, start_fn, &args, None, instance); - if cx.sess().target.os.contains("uefi") { - bx.ret(result); - } else { - let cast = bx.intcast(result, cx.type_int(), true); - bx.ret(cast); - } - - llfn - } -} - -/// Obtain the `argc` and `argv` values to pass to the rust start function. -fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - cx: &'a Bx::CodegenCx, - bx: &mut Bx, -) -> (Bx::Value, Bx::Value) { - if cx.sess().target.os.contains("uefi") { - // Params for UEFI - let param_handle = bx.get_param(0); - let param_system_table = bx.get_param(1); - let ptr_size = bx.tcx().data_layout.pointer_size; - let ptr_align = bx.tcx().data_layout.pointer_align.abi; - let arg_argc = bx.const_int(cx.type_isize(), 2); - let arg_argv = bx.alloca(cx.type_array(cx.type_ptr(), 2), ptr_align); - bx.store(param_handle, arg_argv, ptr_align); - let arg_argv_el1 = bx.inbounds_ptradd(arg_argv, bx.const_usize(ptr_size.bytes())); - bx.store(param_system_table, arg_argv_el1, ptr_align); - (arg_argc, arg_argv) - } else if cx.sess().target.main_needs_argc_argv { - // Params from native `main()` used as args for rust start function - let param_argc = bx.get_param(0); - let param_argv = bx.get_param(1); - let arg_argc = bx.intcast(param_argc, cx.type_isize(), true); - let arg_argv = param_argv; - (arg_argc, arg_argv) - } else { - // The Rust start function doesn't need `argc` and `argv`, so just pass zeros. - let arg_argc = bx.const_int(cx.type_int(), 0); - let arg_argv = bx.const_null(cx.type_ptr()); - (arg_argc, arg_argv) - } -} - -/// This function returns all of the debugger visualizers specified for the -/// current crate as well as all upstream crates transitively that match the -/// `visualizer_type` specified. -pub fn collect_debugger_visualizers_transitive( - tcx: TyCtxt<'_>, - visualizer_type: DebuggerVisualizerType, -) -> BTreeSet { - tcx.debugger_visualizers(LOCAL_CRATE) - .iter() - .chain( - tcx.crates(()) - .iter() - .filter(|&cnum| { - let used_crate_source = tcx.used_crate_source(*cnum); - used_crate_source.rlib.is_some() || used_crate_source.rmeta.is_some() - }) - .flat_map(|&cnum| tcx.debugger_visualizers(cnum)), - ) - .filter(|visualizer| visualizer.visualizer_type == visualizer_type) - .cloned() - .collect::>() -} - -/// Decide allocator kind to codegen. If `Some(_)` this will be the same as -/// `tcx.allocator_kind`, but it may be `None` in more cases (e.g. if using -/// allocator definitions from a dylib dependency). -pub fn allocator_kind_for_codegen(tcx: TyCtxt<'_>) -> Option { - // If the crate doesn't have an `allocator_kind` set then there's definitely - // no shim to generate. Otherwise we also check our dependency graph for all - // our output crate types. If anything there looks like its a `Dynamic` - // linkage, then it's already got an allocator shim and we'll be using that - // one instead. If nothing exists then it's our job to generate the - // allocator! - let any_dynamic_crate = tcx.dependency_formats(()).iter().any(|(_, list)| { - use rustc_middle::middle::dependency_format::Linkage; - list.iter().any(|&linkage| linkage == Linkage::Dynamic) - }); - if any_dynamic_crate { None } else { tcx.allocator_kind(()) } -} - -pub fn codegen_crate( - backend: B, - tcx: TyCtxt<'_>, - target_cpu: String, - metadata: EncodedMetadata, - need_metadata_module: bool, -) -> OngoingCodegen { - // Skip crate items and just output metadata in -Z no-codegen mode. - if tcx.sess.opts.unstable_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() { - let ongoing_codegen = start_async_codegen(backend, tcx, target_cpu, metadata, None); - - ongoing_codegen.codegen_finished(tcx); - - ongoing_codegen.check_for_errors(tcx.sess); - - return ongoing_codegen; - } - - let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx); - - // Run the monomorphization collector and partition the collected items into - // codegen units. - let codegen_units = tcx.collect_and_partition_mono_items(()).1; - - // Force all codegen_unit queries so they are already either red or green - // when compile_codegen_unit accesses them. We are not able to re-execute - // the codegen_unit query from just the DepNode, so an unknown color would - // lead to having to re-execute compile_codegen_unit, possibly - // unnecessarily. - if tcx.dep_graph.is_fully_enabled() { - for cgu in codegen_units { - tcx.ensure().codegen_unit(cgu.name()); - } - } - - let metadata_module = need_metadata_module.then(|| { - // Emit compressed metadata object. - let metadata_cgu_name = - cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("metadata")).to_string(); - tcx.sess.time("write_compressed_metadata", || { - let file_name = - tcx.output_filenames(()).temp_path(OutputType::Metadata, Some(&metadata_cgu_name)); - let data = create_compressed_metadata_file( - tcx.sess, - &metadata, - &exported_symbols::metadata_symbol_name(tcx), - ); - if let Err(error) = std::fs::write(&file_name, data) { - tcx.dcx().emit_fatal(errors::MetadataObjectFileWrite { error }); - } - CompiledModule { - name: metadata_cgu_name, - kind: ModuleKind::Metadata, - object: Some(file_name), - dwarf_object: None, - bytecode: None, - } - }) - }); - - let ongoing_codegen = - start_async_codegen(backend.clone(), tcx, target_cpu, metadata, metadata_module); - - // Codegen an allocator shim, if necessary. - if let Some(kind) = allocator_kind_for_codegen(tcx) { - let llmod_id = - cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("allocator")).to_string(); - let module_llvm = tcx.sess.time("write_allocator_module", || { - backend.codegen_allocator( - tcx, - &llmod_id, - kind, - // If allocator_kind is Some then alloc_error_handler_kind must - // also be Some. - tcx.alloc_error_handler_kind(()).unwrap(), - ) - }); - - ongoing_codegen.wait_for_signal_to_codegen_item(); - ongoing_codegen.check_for_errors(tcx.sess); - - // These modules are generally cheap and won't throw off scheduling. - let cost = 0; - submit_codegened_module_to_llvm( - &backend, - &ongoing_codegen.coordinator.sender, - ModuleCodegen { name: llmod_id, module_llvm, kind: ModuleKind::Allocator }, - cost, - ); - } - - // For better throughput during parallel processing by LLVM, we used to sort - // CGUs largest to smallest. This would lead to better thread utilization - // by, for example, preventing a large CGU from being processed last and - // having only one LLVM thread working while the rest remained idle. - // - // However, this strategy would lead to high memory usage, as it meant the - // LLVM-IR for all of the largest CGUs would be resident in memory at once. - // - // Instead, we can compromise by ordering CGUs such that the largest and - // smallest are first, second largest and smallest are next, etc. If there - // are large size variations, this can reduce memory usage significantly. - let codegen_units: Vec<_> = { - let mut sorted_cgus = codegen_units.iter().collect::>(); - sorted_cgus.sort_by_key(|cgu| cmp::Reverse(cgu.size_estimate())); - - let (first_half, second_half) = sorted_cgus.split_at(sorted_cgus.len() / 2); - first_half.iter().interleave(second_half.iter().rev()).copied().collect() - }; - - // Calculate the CGU reuse - let cgu_reuse = tcx.sess.time("find_cgu_reuse", || { - codegen_units.iter().map(|cgu| determine_cgu_reuse(tcx, cgu)).collect::>() - }); - - crate::assert_module_sources::assert_module_sources(tcx, &|cgu_reuse_tracker| { - for (i, cgu) in codegen_units.iter().enumerate() { - let cgu_reuse = cgu_reuse[i]; - cgu_reuse_tracker.set_actual_reuse(cgu.name().as_str(), cgu_reuse); - } - }); - - let mut total_codegen_time = Duration::new(0, 0); - let start_rss = tcx.sess.opts.unstable_opts.time_passes.then(|| get_resident_set_size()); - - // The non-parallel compiler can only translate codegen units to LLVM IR - // on a single thread, leading to a staircase effect where the N LLVM - // threads have to wait on the single codegen threads to generate work - // for them. The parallel compiler does not have this restriction, so - // we can pre-load the LLVM queue in parallel before handing off - // coordination to the OnGoingCodegen scheduler. - // - // This likely is a temporary measure. Once we don't have to support the - // non-parallel compiler anymore, we can compile CGUs end-to-end in - // parallel and get rid of the complicated scheduling logic. - let mut pre_compiled_cgus = if tcx.sess.threads() > 1 { - tcx.sess.time("compile_first_CGU_batch", || { - // Try to find one CGU to compile per thread. - let cgus: Vec<_> = cgu_reuse - .iter() - .enumerate() - .filter(|&(_, reuse)| reuse == &CguReuse::No) - .take(tcx.sess.threads()) - .collect(); - - // Compile the found CGUs in parallel. - let start_time = Instant::now(); - - let pre_compiled_cgus = par_map(cgus, |(i, _)| { - let module = backend.compile_codegen_unit(tcx, codegen_units[i].name()); - (i, module) - }); - - total_codegen_time += start_time.elapsed(); - - pre_compiled_cgus - }) - } else { - FxHashMap::default() - }; - - for (i, cgu) in codegen_units.iter().enumerate() { - ongoing_codegen.wait_for_signal_to_codegen_item(); - ongoing_codegen.check_for_errors(tcx.sess); - - let cgu_reuse = cgu_reuse[i]; - - match cgu_reuse { - CguReuse::No => { - let (module, cost) = if let Some(cgu) = pre_compiled_cgus.remove(&i) { - cgu - } else { - let start_time = Instant::now(); - let module = backend.compile_codegen_unit(tcx, cgu.name()); - total_codegen_time += start_time.elapsed(); - module - }; - // This will unwind if there are errors, which triggers our `AbortCodegenOnDrop` - // guard. Unfortunately, just skipping the `submit_codegened_module_to_llvm` makes - // compilation hang on post-monomorphization errors. - tcx.dcx().abort_if_errors(); - - submit_codegened_module_to_llvm( - &backend, - &ongoing_codegen.coordinator.sender, - module, - cost, - ); - } - CguReuse::PreLto => { - submit_pre_lto_module_to_llvm( - &backend, - tcx, - &ongoing_codegen.coordinator.sender, - CachedModuleCodegen { - name: cgu.name().to_string(), - source: cgu.previous_work_product(tcx), - }, - ); - } - CguReuse::PostLto => { - submit_post_lto_module_to_llvm( - &backend, - &ongoing_codegen.coordinator.sender, - CachedModuleCodegen { - name: cgu.name().to_string(), - source: cgu.previous_work_product(tcx), - }, - ); - } - } - } - - ongoing_codegen.codegen_finished(tcx); - - // Since the main thread is sometimes blocked during codegen, we keep track - // -Ztime-passes output manually. - if tcx.sess.opts.unstable_opts.time_passes { - let end_rss = get_resident_set_size(); - - print_time_passes_entry( - "codegen_to_LLVM_IR", - total_codegen_time, - start_rss.unwrap(), - end_rss, - tcx.sess.opts.unstable_opts.time_passes_format, - ); - } - - ongoing_codegen.check_for_errors(tcx.sess); - ongoing_codegen -} - -impl CrateInfo { - pub fn new(tcx: TyCtxt<'_>, target_cpu: String) -> CrateInfo { - let crate_types = tcx.crate_types().to_vec(); - let exported_symbols = crate_types - .iter() - .map(|&c| (c, crate::back::linker::exported_symbols(tcx, c))) - .collect(); - let linked_symbols = - crate_types.iter().map(|&c| (c, crate::back::linker::linked_symbols(tcx, c))).collect(); - let local_crate_name = tcx.crate_name(LOCAL_CRATE); - let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID); - let subsystem = attr::first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem); - let windows_subsystem = subsystem.map(|subsystem| { - if subsystem != sym::windows && subsystem != sym::console { - tcx.dcx().emit_fatal(errors::InvalidWindowsSubsystem { subsystem }); - } - subsystem.to_string() - }); - - // This list is used when generating the command line to pass through to - // system linker. The linker expects undefined symbols on the left of the - // command line to be defined in libraries on the right, not the other way - // around. For more info, see some comments in the add_used_library function - // below. - // - // In order to get this left-to-right dependency ordering, we use the reverse - // postorder of all crates putting the leaves at the right-most positions. - let mut compiler_builtins = None; - let mut used_crates: Vec<_> = tcx - .postorder_cnums(()) - .iter() - .rev() - .copied() - .filter(|&cnum| { - let link = !tcx.dep_kind(cnum).macros_only(); - if link && tcx.is_compiler_builtins(cnum) { - compiler_builtins = Some(cnum); - return false; - } - link - }) - .collect(); - // `compiler_builtins` are always placed last to ensure that they're linked correctly. - used_crates.extend(compiler_builtins); - - let crates = tcx.crates(()); - let n_crates = crates.len(); - let mut info = CrateInfo { - target_cpu, - crate_types, - exported_symbols, - linked_symbols, - local_crate_name, - compiler_builtins, - profiler_runtime: None, - is_no_builtins: Default::default(), - native_libraries: Default::default(), - used_libraries: tcx.native_libraries(LOCAL_CRATE).iter().map(Into::into).collect(), - crate_name: UnordMap::with_capacity(n_crates), - used_crates, - used_crate_source: UnordMap::with_capacity(n_crates), - dependency_formats: tcx.dependency_formats(()).clone(), - windows_subsystem, - natvis_debugger_visualizers: Default::default(), - }; - - info.native_libraries.reserve(n_crates); - - for &cnum in crates.iter() { - info.native_libraries - .insert(cnum, tcx.native_libraries(cnum).iter().map(Into::into).collect()); - info.crate_name.insert(cnum, tcx.crate_name(cnum)); - - let used_crate_source = tcx.used_crate_source(cnum); - info.used_crate_source.insert(cnum, used_crate_source.clone()); - if tcx.is_profiler_runtime(cnum) { - info.profiler_runtime = Some(cnum); - } - if tcx.is_no_builtins(cnum) { - info.is_no_builtins.insert(cnum); - } - } - - // Handle circular dependencies in the standard library. - // See comment before `add_linked_symbol_object` function for the details. - // If global LTO is enabled then almost everything (*) is glued into a single object file, - // so this logic is not necessary and can cause issues on some targets (due to weak lang - // item symbols being "privatized" to that object file), so we disable it. - // (*) Native libs, and `#[compiler_builtins]` and `#[no_builtins]` crates are not glued, - // and we assume that they cannot define weak lang items. This is not currently enforced - // by the compiler, but that's ok because all this stuff is unstable anyway. - let target = &tcx.sess.target; - if !are_upstream_rust_objects_already_included(tcx.sess) { - let missing_weak_lang_items: FxIndexSet = info - .used_crates - .iter() - .flat_map(|&cnum| tcx.missing_lang_items(cnum)) - .filter(|l| l.is_weak()) - .filter_map(|&l| { - let name = l.link_name()?; - lang_items::required(tcx, l).then_some(name) - }) - .collect(); - let prefix = match (target.is_like_windows, target.arch.as_ref()) { - (true, "x86") => "_", - (true, "arm64ec") => "#", - _ => "", - }; - - // This loop only adds new items to values of the hash map, so the order in which we - // iterate over the values is not important. - #[allow(rustc::potential_query_instability)] - info.linked_symbols - .iter_mut() - .filter(|(crate_type, _)| { - !matches!(crate_type, CrateType::Rlib | CrateType::Staticlib) - }) - .for_each(|(_, linked_symbols)| { - let mut symbols = missing_weak_lang_items - .iter() - .map(|item| (format!("{prefix}{item}"), SymbolExportKind::Text)) - .collect::>(); - symbols.sort_unstable_by(|a, b| a.0.cmp(&b.0)); - linked_symbols.extend(symbols); - if tcx.allocator_kind(()).is_some() { - // At least one crate needs a global allocator. This crate may be placed - // after the crate that defines it in the linker order, in which case some - // linkers return an error. By adding the global allocator shim methods to - // the linked_symbols list, linking the generated symbols.o will ensure that - // circular dependencies involving the global allocator don't lead to linker - // errors. - linked_symbols.extend(ALLOCATOR_METHODS.iter().map(|method| { - ( - format!("{prefix}{}", global_fn_name(method.name).as_str()), - SymbolExportKind::Text, - ) - })); - } - }); - } - - let embed_visualizers = tcx.crate_types().iter().any(|&crate_type| match crate_type { - CrateType::Executable | CrateType::Dylib | CrateType::Cdylib => { - // These are crate types for which we invoke the linker and can embed - // NatVis visualizers. - true - } - CrateType::ProcMacro => { - // We could embed NatVis for proc macro crates too (to improve the debugging - // experience for them) but it does not seem like a good default, since - // this is a rare use case and we don't want to slow down the common case. - false - } - CrateType::Staticlib | CrateType::Rlib => { - // We don't invoke the linker for these, so we don't need to collect the NatVis for them. - false - } - }); - - if target.is_like_msvc && embed_visualizers { - info.natvis_debugger_visualizers = - collect_debugger_visualizers_transitive(tcx, DebuggerVisualizerType::Natvis); - } - - info - } -} - -pub fn provide(providers: &mut Providers) { - providers.backend_optimization_level = |tcx, cratenum| { - let for_speed = match tcx.sess.opts.optimize { - // If globally no optimisation is done, #[optimize] has no effect. - // - // This is done because if we ended up "upgrading" to `-O2` here, we’d populate the - // pass manager and it is likely that some module-wide passes (such as inliner or - // cross-function constant propagation) would ignore the `optnone` annotation we put - // on the functions, thus necessarily involving these functions into optimisations. - config::OptLevel::No => return config::OptLevel::No, - // If globally optimise-speed is already specified, just use that level. - config::OptLevel::Less => return config::OptLevel::Less, - config::OptLevel::Default => return config::OptLevel::Default, - config::OptLevel::Aggressive => return config::OptLevel::Aggressive, - // If globally optimize-for-size has been requested, use -O2 instead (if optimize(size) - // are present). - config::OptLevel::Size => config::OptLevel::Default, - config::OptLevel::SizeMin => config::OptLevel::Default, - }; - - let (defids, _) = tcx.collect_and_partition_mono_items(cratenum); - - let any_for_speed = defids.items().any(|id| { - let CodegenFnAttrs { optimize, .. } = tcx.codegen_fn_attrs(*id); - match optimize { - attr::OptimizeAttr::None | attr::OptimizeAttr::Size => false, - attr::OptimizeAttr::Speed => true, - } - }); - - if any_for_speed { - return for_speed; - } - - tcx.sess.opts.optimize - }; -} - -pub fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> CguReuse { - if !tcx.dep_graph.is_fully_enabled() { - return CguReuse::No; - } - - let work_product_id = &cgu.work_product_id(); - if tcx.dep_graph.previous_work_product(work_product_id).is_none() { - // We don't have anything cached for this CGU. This can happen - // if the CGU did not exist in the previous session. - return CguReuse::No; - } - - // Try to mark the CGU as green. If it we can do so, it means that nothing - // affecting the LLVM module has changed and we can re-use a cached version. - // If we compile with any kind of LTO, this means we can re-use the bitcode - // of the Pre-LTO stage (possibly also the Post-LTO version but we'll only - // know that later). If we are not doing LTO, there is only one optimized - // version of each module, so we re-use that. - let dep_node = cgu.codegen_dep_node(tcx); - assert!( - !tcx.dep_graph.dep_node_exists(&dep_node), - "CompileCodegenUnit dep-node for CGU `{}` already exists before marking.", - cgu.name() - ); - - if tcx.try_mark_green(&dep_node) { - // We can re-use either the pre- or the post-thinlto state. If no LTO is - // being performed then we can use post-LTO artifacts, otherwise we must - // reuse pre-LTO artifacts - match compute_per_cgu_lto_type( - &tcx.sess.lto(), - &tcx.sess.opts, - tcx.crate_types(), - ModuleKind::Regular, - ) { - ComputedLtoType::No => CguReuse::PostLto, - _ => CguReuse::PreLto, - } - } else { - CguReuse::No - } -} +use crate::assert_module_sources::CguReuse;use crate::back::link:://loop{break}; +are_upstream_rust_objects_already_included;use crate::back::metadata:://((),()); +create_compressed_metadata_file;use crate::back::write::{//if true{};let _=||(); +compute_per_cgu_lto_type,start_async_codegen,submit_codegened_module_to_llvm,//; +submit_post_lto_module_to_llvm,submit_pre_lto_module_to_llvm,ComputedLtoType,//; +OngoingCodegen,};use crate::common::{IntPredicate,RealPredicate,TypeKind};use//; +crate::errors;use crate::meth;use crate::mir;use crate::mir::operand:://((),()); +OperandValue;use crate::mir::place::PlaceRef;use crate::traits::*;use crate::{// +CachedModuleCodegen,CompiledModule,CrateInfo, MemFlags,ModuleCodegen,ModuleKind} +;use rustc_ast::expand::allocator::{global_fn_name,AllocatorKind,//loop{break;}; +ALLOCATOR_METHODS};use rustc_attr as attr;use rustc_data_structures::fx::{//{;}; +FxHashMap,FxIndexSet};use rustc_data_structures::profiling::{//((),());let _=(); +get_resident_set_size,print_time_passes_entry};use rustc_data_structures::sync// +::par_map;use rustc_data_structures::unord::UnordMap;use rustc_hir as hir;use//; +rustc_hir::def_id::{DefId,LOCAL_CRATE};use rustc_hir::lang_items::LangItem;use// +rustc_metadata::EncodedMetadata;use rustc_middle::middle::codegen_fn_attrs:://3; +CodegenFnAttrs;use rustc_middle::middle::debugger_visualizer::{//*&*&();((),()); +DebuggerVisualizerFile,DebuggerVisualizerType};use rustc_middle::middle:://({}); +exported_symbols;use rustc_middle::middle::exported_symbols::SymbolExportKind;// +use rustc_middle::middle::lang_items;use rustc_middle::mir::mono::{CodegenUnit, +CodegenUnitNameBuilder,MonoItem};use rustc_middle::query::Providers;use//*&*&(); +rustc_middle::ty::layout::{HasTyCtxt, LayoutOf,TyAndLayout};use rustc_middle::ty +::{self,Instance,Ty,TyCtxt};use rustc_session::config::{self,CrateType,//*&*&(); +EntryFnType,OutputType};use rustc_session:: Session;use rustc_span::symbol::sym; +use rustc_span::Symbol;use rustc_target::abi::{Align,FIRST_VARIANT};use std:://; +cmp;use std::collections::BTreeSet;use std::time::{Duration,Instant};use//{();}; +itertools::Itertools;pub fn bin_op_to_icmp_predicate(op:hir::BinOpKind,signed:// +bool)->IntPredicate{match op{hir::BinOpKind::Eq=>IntPredicate::IntEQ,hir:://{;}; +BinOpKind::Ne=>IntPredicate::IntNE,hir::BinOpKind::Lt=>{if signed{IntPredicate// +::IntSLT}else{IntPredicate::IntULT}}hir ::BinOpKind::Le=>{if signed{IntPredicate +::IntSLE}else{IntPredicate::IntULE}}hir ::BinOpKind::Gt=>{if signed{IntPredicate +::IntSGT}else{IntPredicate::IntUGT}}hir ::BinOpKind::Ge=>{if signed{IntPredicate +::IntSGE}else{IntPredicate::IntUGE}}op=>bug!(//((),());((),());((),());let _=(); +"comparison_op_to_icmp_predicate: expected comparison operator, \ + found {:?}" +,op),}}pub fn bin_op_to_fcmp_predicate(op:hir::BinOpKind)->RealPredicate{match// +op{hir::BinOpKind::Eq=>RealPredicate ::RealOEQ,hir::BinOpKind::Ne=>RealPredicate +::RealUNE,hir::BinOpKind::Lt=>RealPredicate::RealOLT,hir::BinOpKind::Le=>//({}); +RealPredicate::RealOLE,hir::BinOpKind::Gt=>RealPredicate::RealOGT,hir:://*&*&(); +BinOpKind::Ge=>RealPredicate::RealOGE,op=>{((),());((),());((),());((),());bug!( +"comparison_op_to_fcmp_predicate: expected comparison operator, \ + found {:?}" +,op);();}}}pub fn compare_simd_types<'a,'tcx,Bx:BuilderMethods<'a,'tcx>>(bx:&mut +Bx,lhs:Bx::Value,rhs:Bx::Value,t:Ty <'tcx>,ret_ty:Bx::Type,op:hir::BinOpKind,)-> +Bx::Value{let _=||();let signed=match t.kind(){ty::Float(_)=>{if true{};let cmp= +bin_op_to_fcmp_predicate(op);;;let cmp=bx.fcmp(cmp,lhs,rhs);;return bx.sext(cmp, +ret_ty);loop{break;};if let _=(){};}ty::Uint(_)=>false,ty::Int(_)=>true,_=>bug!( +"compare_simd_types: invalid SIMD type"),};;let cmp=bin_op_to_icmp_predicate(op, +signed);;let cmp=bx.icmp(cmp,lhs,rhs);bx.sext(cmp,ret_ty)}pub fn unsized_info<'a +,'tcx,Bx:BuilderMethods<'a,'tcx>>(bx:&mut Bx,source:Ty<'tcx>,target:Ty<'tcx>,//; +old_info:Option,)->Bx::Value{;let cx=bx.cx();;;let(source,target)=cx. +tcx().struct_lockstep_tails_erasing_lifetimes(source,target,bx.param_env());{;}; +match(((source.kind()),(target.kind()))){(&ty::Array(_,len),&ty::Slice(_))=>{cx. +const_usize((len.eval_target_usize(cx.tcx(),ty::ParamEnv::reveal_all())))}(&ty:: +Dynamic(data_a,_,src_dyn_kind),&ty::Dynamic(data_b,_,target_dyn_kind))if //({}); +src_dyn_kind==target_dyn_kind=>{let _=();if true{};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(){({});return old_info;({});}{;};let +vptr_entry_idx=(cx.tcx()).vtable_trait_upcasting_coercion_new_vptr_slot((source, +target));3;if let Some(entry_idx)=vptr_entry_idx{;let ptr_size=bx.data_layout(). +pointer_size;{;};{;};let ptr_align=bx.data_layout().pointer_align.abi;{;};();let +vtable_byte_offset=u64::try_from(entry_idx).unwrap()*ptr_size.bytes();;;let gep= +bx.inbounds_ptradd(old_info,bx.const_usize(vtable_byte_offset));;let new_vptr=bx +.load(bx.type_ptr(),gep,ptr_align);();();bx.nonnull_metadata(new_vptr);();();bx. +set_invariant_load(new_vptr);3;new_vptr}else{old_info}}(_,ty::Dynamic(data,_,_)) +=>((((((meth::get_vtable(cx,source,((((((data. principal()))))))))))))),_=>bug!( +"unsized_info: invalid unsizing {:?} -> {:?}",source,target),}}pub fn//let _=(); +unsize_ptr<'a,'tcx,Bx:BuilderMethods<'a,'tcx>>( bx:&mut Bx,src:Bx::Value,src_ty: +Ty<'tcx>,dst_ty:Ty<'tcx>,old_info:Option,)->(Bx::Value,Bx::Value){(); +debug!("unsize_ptr: {:?} => {:?}",src_ty,dst_ty);{;};match(src_ty.kind(),dst_ty. +kind()){(&ty::Ref(_,a,_),&ty::Ref(_,b,_)|&ty::RawPtr(b,_))|(&ty::RawPtr(a,_),&// +ty::RawPtr(b,_))=>{;assert_eq!(bx.cx().type_is_sized(a),old_info.is_none());(src +,unsized_info(bx,a,b,old_info))}(&ty::Adt(def_a,_),&ty::Adt(def_b,_))=>{((),()); +assert_eq!(def_a,def_b);;let src_layout=bx.cx().layout_of(src_ty);let dst_layout +=bx.cx().layout_of(dst_ty);;if src_ty==dst_ty{return(src,old_info.unwrap());}let +mut result=None;();for i in 0..src_layout.fields.count(){3;let src_f=src_layout. +field(bx.cx(),i);3;if src_f.is_1zst(){;continue;;};assert_eq!(src_layout.fields. +offset(i).bytes(),0);();3;assert_eq!(dst_layout.fields.offset(i).bytes(),0);3;3; +assert_eq!(src_layout.size,src_f.size);;;let dst_f=dst_layout.field(bx.cx(),i);; +assert_ne!(src_f.ty,dst_f.ty);;assert_eq!(result,None);result=Some(unsize_ptr(bx +,src,src_f.ty,dst_f.ty,old_info));if true{};let _=||();}result.unwrap()}_=>bug!( +"unsize_ptr: called on bad types"),}}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){({}); +debug!("cast_to_dyn_star: {:?} => {:?}",src_ty_and_layout.ty,dst_ty);3;;assert!( +matches!(dst_ty.kind(),ty::Dynamic(_,_,ty::DynStar)),//loop{break};loop{break;}; +"destination type must be a dyn*");();3;let src=match bx.cx().type_kind(bx.cx(). +backend_type(src_ty_and_layout)){TypeKind::Pointer=>src,TypeKind::Integer=>bx.// +inttoptr(src,((((((((((((((((((((bx.type_ptr() ))))))))))))))))))))),kind=>bug!( +"unexpected TypeKind for left-hand side of `dyn*` cast: {kind:?}"),};{();};(src, +unsized_info(bx,src_ty_and_layout.ty,dst_ty,old_info))}pub fn//((),());let _=(); +coerce_unsized_into<'a,'tcx,Bx:BuilderMethods<'a, 'tcx>>(bx:&mut Bx,src:PlaceRef +<'tcx,Bx::Value>,dst:PlaceRef<'tcx,Bx::Value>,){3;let src_ty=src.layout.ty;;;let +dst_ty=dst.layout.ty;;match(src_ty.kind(),dst_ty.kind()){(&ty::Ref(..),&ty::Ref( +..)|&ty::RawPtr(..))|(&ty::RawPtr(..),&ty::RawPtr(..))=>{3;let(base,info)=match +bx.load_operand(src).val{OperandValue::Pair(base,info)=>unsize_ptr(bx,base,//(); +src_ty,dst_ty,((Some(info)))),OperandValue::Immediate(base)=>unsize_ptr(bx,base, +src_ty,dst_ty,None),OperandValue::Ref(..)|OperandValue::ZeroSized=>bug!(),};3;3; +OperandValue::Pair(base,info).store(bx,dst);;}(&ty::Adt(def_a,_),&ty::Adt(def_b, +_))=>{();assert_eq!(def_a,def_b);3;for i in def_a.variant(FIRST_VARIANT).fields. +indices(){{;};let src_f=src.project_field(bx,i.as_usize());{;};();let dst_f=dst. +project_field(bx,i.as_usize());3;if dst_f.layout.is_zst(){3;continue;;}if src_f. +layout.ty==dst_f.layout.ty{{;};memcpy_ty(bx,dst_f.llval,dst_f.align,src_f.llval, +src_f.align,src_f.layout,MemFlags::empty(),);;}else{coerce_unsized_into(bx,src_f +,dst_f);;}}}_=>bug!("coerce_unsized_into: invalid coercion {:?} -> {:?}",src_ty, +dst_ty,),}}pub fn cast_shift_expr_rhs<'a,'tcx,Bx:BuilderMethods<'a,'tcx>>(bx:&// +mut Bx,lhs:Bx::Value,rhs:Bx::Value,)->Bx::Value{;let mut rhs_llty=bx.cx().val_ty +(rhs);3;3;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{3;assert!(lhs_sz<=256);3;bx. +zext(rhs,lhs_llty)}else{rhs}}pub fn wants_wasm_eh(sess:&Session)->bool{sess.//3; +target.is_like_wasm&&(sess.target.os!="emscripten")}pub fn wants_msvc_seh(sess:& +Session)->bool{sess.target.is_like_msvc }pub fn wants_new_eh_instructions(sess:& +Session)->bool{(wants_wasm_eh(sess)|| wants_msvc_seh(sess))}pub fn memcpy_ty<'a, +'tcx,Bx:BuilderMethods<'a,'tcx>>(bx:&mut Bx,dst:Bx::Value,dst_align:Align,src:// +Bx::Value,src_align:Align,layout:TyAndLayout<'tcx>,flags:MemFlags,){();let size= +layout.size.bytes();;if size==0{;return;;}if flags==MemFlags::empty()&&let Some( +bty)=bx.cx().scalar_copy_backend_type(layout){let _=();let temp=bx.load(bty,src, +src_align);3;3;bx.store(temp,dst,dst_align);;}else{;bx.memcpy(dst,dst_align,src, +src_align,bx.cx().const_usize(size),flags);;}}pub fn codegen_instance<'a,'tcx:'a +,Bx:BuilderMethods<'a,'tcx>>(cx:&'a Bx::CodegenCx,instance:Instance<'tcx>,){{;}; +info!("codegen_instance({})",instance);;mir::codegen_mir::(cx,instance);}pub +fn maybe_create_entry_wrapper<'a,'tcx,Bx:BuilderMethods<'a,'tcx>>(cx:&'a Bx:://; +CodegenCx,)->Option{;let(main_def_id,entry_type)=cx.tcx().entry_fn +(())?;;;let main_is_local=main_def_id.is_local();let instance=Instance::mono(cx. +tcx(),main_def_id);((),());if main_is_local{if!cx.codegen_unit().contains_item(& +MonoItem::Fn(instance)){;return None;;}}else if!cx.codegen_unit().is_primary(){; +return None;{;};}{;};let main_llfn=cx.get_fn_addr(instance);{;};();let entry_fn= +create_entry_fn::(cx,main_llfn,main_def_id,entry_type);;return Some(entry_fn +);;;fn create_entry_fn<'a,'tcx,Bx:BuilderMethods<'a,'tcx>>(cx:&'a Bx::CodegenCx, +rust_main:Bx::Value,rust_main_def_id:DefId,entry_type:EntryFnType,)->Bx:://({}); +Function{();let llfty=if cx.sess().target.os.contains("uefi"){cx.type_func(&[cx. +type_ptr(),((cx.type_ptr()))],((cx.type_isize())))}else if ((cx.sess())).target. +main_needs_argc_argv{cx.type_func(&[cx.type_int(), cx.type_ptr()],cx.type_int()) +}else{cx.type_func(&[],cx.type_int())};({});{;};let main_ret_ty=cx.tcx().fn_sig( +rust_main_def_id).no_bound_vars().unwrap().output();3;;let main_ret_ty=cx.tcx(). +normalize_erasing_regions(ty::ParamEnv::reveal_all( ),main_ret_ty.no_bound_vars( +).unwrap(),);3;3;let Some(llfn)=cx.declare_c_main(llfty)else{;let span=cx.tcx(). +def_span(rust_main_def_id);if true{};let _=();cx.tcx().dcx().emit_fatal(errors:: +MultipleMainFunctions{span});();};();();cx.set_frame_pointer_type(llfn);();3;cx. +apply_target_cpu_attr(llfn);;let llbb=Bx::append_block(cx,llfn,"top");let mut bx +=Bx::build(cx,llbb);;;bx.insert_reference_to_gdb_debug_scripts_section_global(); +let isize_ty=cx.type_isize();;;let ptr_ty=cx.type_ptr();;let(arg_argc,arg_argv)= +get_argc_argv(cx,&mut bx);{();};({});let(start_fn,start_ty,args,instance)=if let +EntryFnType::Main{sigpipe}=entry_type{((),());((),());let start_def_id=cx.tcx(). +require_lang_item(LangItem::Start,None);{;};();let start_instance=ty::Instance:: +expect_resolve((cx.tcx()),(ty::ParamEnv:: reveal_all()),start_def_id,(cx.tcx()). +mk_args(&[main_ret_ty.into()]),);;;let start_fn=cx.get_fn_addr(start_instance);; +let i8_ty=cx.type_i8();;;let arg_sigpipe=bx.const_u8(sigpipe);;;let start_ty=cx. +type_func(&[cx.val_ty(rust_main),isize_ty,ptr_ty,i8_ty],isize_ty);{;};(start_fn, +start_ty,(vec![rust_main,arg_argc,arg_argv,arg_sigpipe]),Some(start_instance),)} +else{;debug!("using user-defined start fn");let start_ty=cx.type_func(&[isize_ty +,ptr_ty],isize_ty);();(rust_main,start_ty,vec![arg_argc,arg_argv],None)};3;3;let +result=bx.call(start_ty,None,None,start_fn,&args,None,instance);();if cx.sess(). +target.os.contains("uefi"){;bx.ret(result);;}else{let cast=bx.intcast(result,cx. +type_int(),true);;bx.ret(cast);}llfn}}fn get_argc_argv<'a,'tcx,Bx:BuilderMethods +<'a,'tcx>>(cx:&'a Bx::CodegenCx,bx:&mut Bx ,)->(Bx::Value,Bx::Value){if cx.sess( +).target.os.contains("uefi"){({});let param_handle=bx.get_param(0);({});({});let +param_system_table=bx.get_param(1);{();};({});let ptr_size=bx.tcx().data_layout. +pointer_size;;let ptr_align=bx.tcx().data_layout.pointer_align.abi;let arg_argc= +bx.const_int(cx.type_isize(),2);{;};{;};let arg_argv=bx.alloca(cx.type_array(cx. +type_ptr(),2),ptr_align);();();bx.store(param_handle,arg_argv,ptr_align);3;3;let +arg_argv_el1=bx.inbounds_ptradd(arg_argv,bx.const_usize(ptr_size.bytes()));;;bx. +store(param_system_table,arg_argv_el1,ptr_align);;(arg_argc,arg_argv)}else if cx +.sess().target.main_needs_argc_argv{{;};let param_argc=bx.get_param(0);();();let +param_argv=bx.get_param(1);;;let arg_argc=bx.intcast(param_argc,cx.type_isize(), +true);();3;let arg_argv=param_argv;3;(arg_argc,arg_argv)}else{3;let arg_argc=bx. +const_int(cx.type_int(),0);;let arg_argv=bx.const_null(cx.type_ptr());(arg_argc, +arg_argv)}}pub fn collect_debugger_visualizers_transitive(tcx:TyCtxt<'_>,//({}); +visualizer_type:DebuggerVisualizerType,)->BTreeSet{tcx. +debugger_visualizers(LOCAL_CRATE).iter().chain((tcx.crates(()).iter()).filter(|& +cnum|{;let used_crate_source=tcx.used_crate_source(*cnum);used_crate_source.rlib +.is_some()||((((((used_crate_source.rmeta.is_some()))))))}).flat_map(|&cnum|tcx. +debugger_visualizers(cnum)),).filter(|visualizer|visualizer.visualizer_type==//; +visualizer_type).cloned().collect::>()}pub fn//if true{};let _=||(); +allocator_kind_for_codegen(tcx:TyCtxt<'_>)->Option{let _=||();let +any_dynamic_crate=tcx.dependency_formats(()).iter().any(|(_,list)|{if true{};use +rustc_middle::middle::dependency_format::Linkage;({});list.iter().any(|&linkage| +linkage==Linkage::Dynamic)});;if any_dynamic_crate{None}else{tcx.allocator_kind( +())}}pub fn codegen_crate(backend:B,tcx:TyCtxt<'_>,//{;}; +target_cpu:String,metadata:EncodedMetadata,need_metadata_module:bool,)->//{();}; +OngoingCodegen{if tcx.sess.opts.unstable_opts.no_codegen||!tcx.sess.opts.//3; +output_types.should_codegen(){3;let ongoing_codegen=start_async_codegen(backend, +tcx,target_cpu,metadata,None);();();ongoing_codegen.codegen_finished(tcx);();(); +ongoing_codegen.check_for_errors(tcx.sess);();();return ongoing_codegen;3;}3;let +cgu_name_builder=&mut CodegenUnitNameBuilder::new(tcx);3;;let codegen_units=tcx. +collect_and_partition_mono_items(()).1;3;if tcx.dep_graph.is_fully_enabled(){for +cgu in codegen_units{{();};tcx.ensure().codegen_unit(cgu.name());({});}}({});let +metadata_module=need_metadata_module.then(||{loop{break;};let metadata_cgu_name= +cgu_name_builder.build_cgu_name(LOCAL_CRATE,(&([("crate")] )),Some("metadata")). +to_string();();tcx.sess.time("write_compressed_metadata",||{3;let file_name=tcx. +output_filenames(()).temp_path(OutputType::Metadata,Some(&metadata_cgu_name));;; +let data=create_compressed_metadata_file(tcx.sess ,&metadata,&exported_symbols:: +metadata_symbol_name(tcx),);;if let Err(error)=std::fs::write(&file_name,data){; +tcx.dcx().emit_fatal(errors::MetadataObjectFileWrite{error});();}CompiledModule{ +name:metadata_cgu_name,kind:ModuleKind::Metadata,object:((((Some(file_name))))), +dwarf_object:None,bytecode:None,}})});;;let ongoing_codegen=start_async_codegen( +backend.clone(),tcx,target_cpu,metadata,metadata_module);({});if let Some(kind)= +allocator_kind_for_codegen(tcx){();let llmod_id=cgu_name_builder.build_cgu_name( +LOCAL_CRATE,&["crate"],Some("allocator")).to_string();;let module_llvm=tcx.sess. +time(("write_allocator_module"),||{backend.codegen_allocator(tcx,&llmod_id,kind, +tcx.alloc_error_handler_kind(()).unwrap(),)});let _=();let _=();ongoing_codegen. +wait_for_signal_to_codegen_item();;;ongoing_codegen.check_for_errors(tcx.sess);; +let cost=0;{();};({});submit_codegened_module_to_llvm(&backend,&ongoing_codegen. +coordinator.sender,ModuleCodegen{name:llmod_id,module_llvm,kind:ModuleKind:://3; +Allocator},cost,);;}let codegen_units:Vec<_>={let mut sorted_cgus=codegen_units. +iter().collect::>();{;};();sorted_cgus.sort_by_key(|cgu|cmp::Reverse(cgu. +size_estimate()));;let(first_half,second_half)=sorted_cgus.split_at(sorted_cgus. +len()/2);*&*&();first_half.iter().interleave(second_half.iter().rev()).copied(). +collect()};;let cgu_reuse=tcx.sess.time("find_cgu_reuse",||{codegen_units.iter() +.map(|cgu|determine_cgu_reuse(tcx,cgu)).collect::>()});{();};({});crate:: +assert_module_sources::assert_module_sources(tcx,& |cgu_reuse_tracker|{for(i,cgu +)in codegen_units.iter().enumerate(){{();};let cgu_reuse=cgu_reuse[i];({});({}); +cgu_reuse_tracker.set_actual_reuse(cgu.name().as_str(),cgu_reuse);;}});;;let mut +total_codegen_time=Duration::new(0,0);;let start_rss=tcx.sess.opts.unstable_opts +.time_passes.then(||get_resident_set_size());;;let mut pre_compiled_cgus=if tcx. +sess.threads()>1{tcx.sess.time("compile_first_CGU_batch",||{{;};let cgus:Vec<_>= +cgu_reuse.iter().enumerate().filter(|&(_,reuse )|reuse==&CguReuse::No).take(tcx. +sess.threads()).collect();;;let start_time=Instant::now();let pre_compiled_cgus= +par_map(cgus,|(i,_)|{;let module=backend.compile_codegen_unit(tcx,codegen_units[ +i].name());{;};(i,module)});{;};{;};total_codegen_time+=start_time.elapsed();(); +pre_compiled_cgus})}else{FxHashMap::default()};;for(i,cgu)in codegen_units.iter( +).enumerate(){;ongoing_codegen.wait_for_signal_to_codegen_item();ongoing_codegen +.check_for_errors(tcx.sess);;let cgu_reuse=cgu_reuse[i];match cgu_reuse{CguReuse +::No=>{;let(module,cost)=if let Some(cgu)=pre_compiled_cgus.remove(&i){cgu}else{ +let start_time=Instant::now();;;let module=backend.compile_codegen_unit(tcx,cgu. +name());();();total_codegen_time+=start_time.elapsed();();module};3;3;tcx.dcx(). +abort_if_errors();3;3;submit_codegened_module_to_llvm(&backend,&ongoing_codegen. +coordinator.sender,module,cost,);if let _=(){};}CguReuse::PreLto=>{loop{break;}; +submit_pre_lto_module_to_llvm(&backend,tcx, &ongoing_codegen.coordinator.sender, +CachedModuleCodegen{name:((((((((((cgu.name() ))))).to_string()))))),source:cgu. +previous_work_product(tcx),},);if let _=(){};}CguReuse::PostLto=>{if let _=(){}; +submit_post_lto_module_to_llvm((&backend),(&ongoing_codegen.coordinator.sender), +CachedModuleCodegen{name:((((((((((cgu.name() ))))).to_string()))))),source:cgu. +previous_work_product(tcx),},);;}}}ongoing_codegen.codegen_finished(tcx);if tcx. +sess.opts.unstable_opts.time_passes{();let end_rss=get_resident_set_size();();3; +print_time_passes_entry(((("codegen_to_LLVM_IR"))),total_codegen_time,start_rss. +unwrap(),end_rss,tcx.sess.opts.unstable_opts.time_passes_format,);*&*&();}{();}; +ongoing_codegen.check_for_errors(tcx.sess);();ongoing_codegen}impl CrateInfo{pub +fn new(tcx:TyCtxt<'_>,target_cpu:String)->CrateInfo{((),());let crate_types=tcx. +crate_types().to_vec();;let exported_symbols=crate_types.iter().map(|&c|(c,crate +::back::linker::exported_symbols(tcx,c))).collect();({});{;};let linked_symbols= +crate_types.iter().map((|&c|((c, crate::back::linker::linked_symbols(tcx,c))))). +collect();;let local_crate_name=tcx.crate_name(LOCAL_CRATE);let crate_attrs=tcx. +hir().attrs(rustc_hir::CRATE_HIR_ID);loop{break};let _=||();let subsystem=attr:: +first_attr_value_str_by_name(crate_attrs,sym::windows_subsystem);{();};{();};let +windows_subsystem=subsystem.map(|subsystem|{if ((((subsystem!=sym::windows))))&& +subsystem!=sym::console{();tcx.dcx().emit_fatal(errors::InvalidWindowsSubsystem{ +subsystem});;}subsystem.to_string()});;;let mut compiler_builtins=None;;;let mut +used_crates:Vec<_>=tcx.postorder_cnums(()) .iter().rev().copied().filter(|&cnum| +{;let link=!tcx.dep_kind(cnum).macros_only();;if link&&tcx.is_compiler_builtins( +cnum){;compiler_builtins=Some(cnum);;return false;}link}).collect();used_crates. +extend(compiler_builtins);;;let crates=tcx.crates(());let n_crates=crates.len(); +let mut info=CrateInfo{target_cpu,crate_types,exported_symbols,linked_symbols,// +local_crate_name,compiler_builtins,profiler_runtime: None,is_no_builtins:Default +::default(),native_libraries:((((((Default::default ())))))),used_libraries:tcx. +native_libraries(LOCAL_CRATE).iter().map(Into::into).collect(),crate_name://{;}; +UnordMap::with_capacity(n_crates),used_crates,used_crate_source:UnordMap:://{;}; +with_capacity(n_crates),dependency_formats:(tcx.dependency_formats(()).clone()), +windows_subsystem,natvis_debugger_visualizers:Default::default(),};{;};{;};info. +native_libraries.reserve(n_crates);*&*&();for&cnum in crates.iter(){*&*&();info. +native_libraries.insert(cnum,tcx.native_libraries(cnum ).iter().map(Into::into). +collect());{;};{;};info.crate_name.insert(cnum,tcx.crate_name(cnum));{;};{;};let +used_crate_source=tcx.used_crate_source(cnum);3;3;info.used_crate_source.insert( +cnum,used_crate_source.clone());({});if tcx.is_profiler_runtime(cnum){({});info. +profiler_runtime=Some(cnum);3;}if tcx.is_no_builtins(cnum){;info.is_no_builtins. +insert(cnum);loop{break};}}let _=||();let target=&tcx.sess.target;let _=||();if! +are_upstream_rust_objects_already_included(tcx.sess){loop{break};loop{break};let +missing_weak_lang_items:FxIndexSet=(info.used_crates.iter()).flat_map(|& +cnum|tcx.missing_lang_items(cnum)).filter(|l|l.is_weak()).filter_map(|&l|{();let +name=l.link_name()?;;lang_items::required(tcx,l).then_some(name)}).collect();let +prefix=match((target.is_like_windows,target.arch.as_ref( ))){(true,"x86")=>"_",( +true,"arm64ec")=>"#",_=>"",};;;#[allow(rustc::potential_query_instability)]info. +linked_symbols.iter_mut().filter(|(crate_type,_)|{!matches!(crate_type,//*&*&(); +CrateType::Rlib|CrateType::Staticlib)}).for_each(|(_,linked_symbols)|{();let mut +symbols=(missing_weak_lang_items.iter()).map(|item|((format!("{prefix}{item}")), +SymbolExportKind::Text)).collect::>();;symbols.sort_unstable_by(|a,b|a.0. +cmp(&b.0));;;linked_symbols.extend(symbols);if tcx.allocator_kind(()).is_some(){ +linked_symbols.extend((((((ALLOCATOR_METHODS.iter()))))). map(|method|{(format!( +"{prefix}{}",global_fn_name(method.name).as_str()),SymbolExportKind::Text,)}));; +}});();}();let embed_visualizers=tcx.crate_types().iter().any(|&crate_type|match +crate_type{CrateType::Executable|CrateType::Dylib |CrateType::Cdylib=>{((true))} +CrateType::ProcMacro=>{false}CrateType::Staticlib|CrateType::Rlib=>{false}});;if +target.is_like_msvc&&embed_visualizers{((),());info.natvis_debugger_visualizers= +collect_debugger_visualizers_transitive(tcx,DebuggerVisualizerType::Natvis);();} +info}}pub fn provide(providers:&mut Providers){let _=||();loop{break};providers. +backend_optimization_level=|tcx,cratenum|{{;};let for_speed=match tcx.sess.opts. +optimize{config::OptLevel::No=>(return config::OptLevel::No),config::OptLevel:: +Less=>(return config::OptLevel::Less),config::OptLevel::Default=>return config:: +OptLevel::Default,config::OptLevel::Aggressive=>return config::OptLevel:://({}); +Aggressive,config::OptLevel::Size=> config::OptLevel::Default,config::OptLevel:: +SizeMin=>config::OptLevel::Default,};loop{break;};loop{break};let(defids,_)=tcx. +collect_and_partition_mono_items(cratenum);;let any_for_speed=defids.items().any +(|id|{;let CodegenFnAttrs{optimize,..}=tcx.codegen_fn_attrs(*id);match optimize{ +attr::OptimizeAttr::None|attr::OptimizeAttr:: Size=>(false),attr::OptimizeAttr:: +Speed=>true,}});;if any_for_speed{return for_speed;}tcx.sess.opts.optimize};}pub +fn determine_cgu_reuse<'tcx>(tcx:TyCtxt<'tcx>,cgu:&CodegenUnit<'tcx>)->//*&*&(); +CguReuse{if!tcx.dep_graph.is_fully_enabled(){{;};return CguReuse::No;{;};}();let +work_product_id=&cgu.work_product_id();3;if tcx.dep_graph.previous_work_product( +work_product_id).is_none(){({});return CguReuse::No;({});}({});let dep_node=cgu. +codegen_dep_node(tcx);{;};{;};assert!(!tcx.dep_graph.dep_node_exists(&dep_node), +"CompileCodegenUnit dep-node for CGU `{}` already exists before marking.",cgu.// +name());();if tcx.try_mark_green(&dep_node){match compute_per_cgu_lto_type(&tcx. +sess.lto(),((((&tcx.sess.opts)))),(((tcx.crate_types()))),ModuleKind::Regular,){ +ComputedLtoType::No=>CguReuse::PostLto,_=>CguReuse ::PreLto,}}else{CguReuse::No} +}//let _=();if true{};let _=();if true{};let _=();if true{};if true{};if true{}; diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 9c9e134f0337e..13c2e76881162 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -1,691 +1,194 @@ -use rustc_ast::{ast, attr, MetaItemKind, NestedMetaItem}; -use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr}; -use rustc_errors::{codes::*, struct_span_code_err}; -use rustc_hir as hir; -use rustc_hir::def::DefKind; -use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; -use rustc_hir::{lang_items, weak_lang_items::WEAK_LANG_ITEMS, LangItem}; -use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; -use rustc_middle::mir::mono::Linkage; -use rustc_middle::query::Providers; -use rustc_middle::ty::{self as ty, TyCtxt}; -use rustc_session::{lint, parse::feature_err}; -use rustc_span::symbol::Ident; -use rustc_span::{sym, Span}; -use rustc_target::spec::{abi, SanitizerSet}; - -use crate::errors; -use crate::target_features::from_target_feature; -use crate::{ - errors::{ExpectedCoverageSymbol, ExpectedUsedSymbol}, - target_features::check_target_feature_trait_unsafe, -}; - -fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage { - use rustc_middle::mir::mono::Linkage::*; - - // Use the names from src/llvm/docs/LangRef.rst here. Most types are only - // applicable to variable declarations and may not really make sense for - // Rust code in the first place but allow them anyway and trust that the - // user knows what they're doing. Who knows, unanticipated use cases may pop - // up in the future. - // - // ghost, dllimport, dllexport and linkonce_odr_autohide are not supported - // and don't have to be, LLVM treats them as no-ops. - match name { - "appending" => Appending, - "available_externally" => AvailableExternally, - "common" => Common, - "extern_weak" => ExternalWeak, - "external" => External, - "internal" => Internal, - "linkonce" => LinkOnceAny, - "linkonce_odr" => LinkOnceODR, - "private" => Private, - "weak" => WeakAny, - "weak_odr" => WeakODR, - _ => tcx.dcx().span_fatal(tcx.def_span(def_id), "invalid linkage specified"), - } -} - -fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { - if cfg!(debug_assertions) { - let def_kind = tcx.def_kind(did); - assert!( - def_kind.has_codegen_attrs(), - "unexpected `def_kind` in `codegen_fn_attrs`: {def_kind:?}", - ); - } - - let attrs = tcx.hir().attrs(tcx.local_def_id_to_hir_id(did)); - let mut codegen_fn_attrs = CodegenFnAttrs::new(); - if tcx.should_inherit_track_caller(did) { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER; - } - - // When `no_builtins` is applied at the crate level, we should add the - // `no-builtins` attribute to each function to ensure it takes effect in LTO. - let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID); - let no_builtins = attr::contains_name(crate_attrs, sym::no_builtins); - if no_builtins { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_BUILTINS; - } - - let supported_target_features = tcx.supported_target_features(LOCAL_CRATE); - - let mut inline_span = None; - let mut link_ordinal_span = None; - let mut no_sanitize_span = None; - - for attr in attrs.iter() { - // In some cases, attribute are only valid on functions, but it's the `check_attr` - // pass that check that they aren't used anywhere else, rather this module. - // In these cases, we bail from performing further checks that are only meaningful for - // functions (such as calling `fn_sig`, which ICEs if given a non-function). We also - // report a delayed bug, just in case `check_attr` isn't doing its job. - let fn_sig = || { - use DefKind::*; - - let def_kind = tcx.def_kind(did); - if let Fn | AssocFn | Variant | Ctor(..) = def_kind { - Some(tcx.fn_sig(did)) - } else { - tcx.dcx() - .span_delayed_bug(attr.span, "this attribute can only be applied to functions"); - None - } - }; - - let Some(Ident { name, .. }) = attr.ident() else { - continue; - }; - - match name { - sym::cold => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD, - sym::rustc_allocator => codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR, - sym::ffi_pure => codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_PURE, - sym::ffi_const => codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST, - sym::rustc_nounwind => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND, - sym::rustc_reallocator => codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR, - sym::rustc_deallocator => codegen_fn_attrs.flags |= CodegenFnAttrFlags::DEALLOCATOR, - sym::rustc_allocator_zeroed => { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED - } - sym::naked => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED, - sym::no_mangle => { - if tcx.opt_item_name(did.to_def_id()).is_some() { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE - } else { - tcx.dcx() - .struct_span_err( - attr.span, - format!( - "`#[no_mangle]` cannot be used on {} {} as it has no name", - tcx.def_descr_article(did.to_def_id()), - tcx.def_descr(did.to_def_id()), - ), - ) - .emit(); - } - } - sym::coverage => { - let inner = attr.meta_item_list(); - match inner.as_deref() { - Some([item]) if item.has_name(sym::off) => { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE; - } - Some([item]) if item.has_name(sym::on) => { - // Allow #[coverage(on)] for being explicit, maybe also in future to enable - // coverage on a smaller scope within an excluded larger scope. - } - Some(_) | None => { - tcx.dcx().emit_err(ExpectedCoverageSymbol { span: attr.span }); - } - } - } - sym::rustc_std_internal_symbol => { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL - } - sym::used => { - let inner = attr.meta_item_list(); - match inner.as_deref() { - Some([item]) if item.has_name(sym::linker) => { - if !tcx.features().used_with_arg { - feature_err( - &tcx.sess, - sym::used_with_arg, - attr.span, - "`#[used(linker)]` is currently unstable", - ) - .emit(); - } - codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER; - } - Some([item]) if item.has_name(sym::compiler) => { - if !tcx.features().used_with_arg { - feature_err( - &tcx.sess, - sym::used_with_arg, - attr.span, - "`#[used(compiler)]` is currently unstable", - ) - .emit(); - } - codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED; - } - Some(_) => { - tcx.dcx().emit_err(ExpectedUsedSymbol { span: attr.span }); - } - None => { - // Unfortunately, unconditionally using `llvm.used` causes - // issues in handling `.init_array` with the gold linker, - // but using `llvm.compiler.used` caused a nontrivial amount - // of unintentional ecosystem breakage -- particularly on - // Mach-O targets. - // - // As a result, we emit `llvm.compiler.used` only on ELF - // targets. This is somewhat ad-hoc, but actually follows - // our pre-LLVM 13 behavior (prior to the ecosystem - // breakage), and seems to match `clang`'s behavior as well - // (both before and after LLVM 13), possibly because they - // have similar compatibility concerns to us. See - // https://github.com/rust-lang/rust/issues/47384#issuecomment-1019080146 - // and following comments for some discussion of this, as - // well as the comments in `rustc_codegen_llvm` where these - // flags are handled. - // - // Anyway, to be clear: this is still up in the air - // somewhat, and is subject to change in the future (which - // is a good thing, because this would ideally be a bit - // more firmed up). - let is_like_elf = !(tcx.sess.target.is_like_osx - || tcx.sess.target.is_like_windows - || tcx.sess.target.is_like_wasm); - codegen_fn_attrs.flags |= if is_like_elf { - CodegenFnAttrFlags::USED - } else { - CodegenFnAttrFlags::USED_LINKER - }; - } - } - } - sym::cmse_nonsecure_entry => { - if let Some(fn_sig) = fn_sig() - && !matches!(fn_sig.skip_binder().abi(), abi::Abi::C { .. }) - { - struct_span_code_err!( - tcx.dcx(), - attr.span, - E0776, - "`#[cmse_nonsecure_entry]` requires C ABI" - ) - .emit(); - } - if !tcx.sess.target.llvm_target.contains("thumbv8m") { - struct_span_code_err!(tcx.dcx(), attr.span, E0775, "`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension") - .emit(); - } - codegen_fn_attrs.flags |= CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY - } - sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL, - sym::track_caller => { - let is_closure = tcx.is_closure_like(did.to_def_id()); - - if !is_closure - && let Some(fn_sig) = fn_sig() - && fn_sig.skip_binder().abi() != abi::Abi::Rust - { - struct_span_code_err!( - tcx.dcx(), - attr.span, - E0737, - "`#[track_caller]` requires Rust ABI" - ) - .emit(); - } - if is_closure - && !tcx.features().closure_track_caller - && !attr.span.allows_unstable(sym::closure_track_caller) - { - feature_err( - &tcx.sess, - sym::closure_track_caller, - attr.span, - "`#[track_caller]` on closures is currently unstable", - ) - .emit(); - } - codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER - } - sym::export_name => { - if let Some(s) = attr.value_str() { - if s.as_str().contains('\0') { - // `#[export_name = ...]` will be converted to a null-terminated string, - // so it may not contain any null characters. - struct_span_code_err!( - tcx.dcx(), - attr.span, - E0648, - "`export_name` may not contain null characters" - ) - .emit(); - } - codegen_fn_attrs.export_name = Some(s); - } - } - sym::target_feature => { - if !tcx.is_closure_like(did.to_def_id()) - && let Some(fn_sig) = fn_sig() - && fn_sig.skip_binder().unsafety() == hir::Unsafety::Normal - { - if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc { - // The `#[target_feature]` attribute is allowed on - // WebAssembly targets on all functions, including safe - // ones. Other targets require that `#[target_feature]` is - // only applied to unsafe functions (pending the - // `target_feature_11` feature) because on most targets - // execution of instructions that are not supported is - // considered undefined behavior. For WebAssembly which is a - // 100% safe target at execution time it's not possible to - // execute undefined instructions, and even if a future - // feature was added in some form for this it would be a - // deterministic trap. There is no undefined behavior when - // executing WebAssembly so `#[target_feature]` is allowed - // on safe functions (but again, only for WebAssembly) - // - // Note that this is also allowed if `actually_rustdoc` so - // if a target is documenting some wasm-specific code then - // it's not spuriously denied. - // - // This exception needs to be kept in sync with allowing - // `#[target_feature]` on `main` and `start`. - } else if !tcx.features().target_feature_11 { - feature_err( - &tcx.sess, - sym::target_feature_11, - attr.span, - "`#[target_feature(..)]` can only be applied to `unsafe` functions", - ) - .with_span_label(tcx.def_span(did), "not an `unsafe` function") - .emit(); - } else { - check_target_feature_trait_unsafe(tcx, did, attr.span); - } - } - from_target_feature( - tcx, - attr, - supported_target_features, - &mut codegen_fn_attrs.target_features, - ); - } - sym::linkage => { - if let Some(val) = attr.value_str() { - let linkage = Some(linkage_by_name(tcx, did, val.as_str())); - if tcx.is_foreign_item(did) { - codegen_fn_attrs.import_linkage = linkage; - } else { - codegen_fn_attrs.linkage = linkage; - } - } - } - sym::link_section => { - if let Some(val) = attr.value_str() { - if val.as_str().bytes().any(|b| b == 0) { - let msg = format!("illegal null byte in link_section value: `{}`", &val); - tcx.dcx().span_err(attr.span, msg); - } else { - codegen_fn_attrs.link_section = Some(val); - } - } - } - sym::link_name => codegen_fn_attrs.link_name = attr.value_str(), - sym::link_ordinal => { - link_ordinal_span = Some(attr.span); - if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) { - codegen_fn_attrs.link_ordinal = ordinal; - } - } - sym::no_sanitize => { - no_sanitize_span = Some(attr.span); - if let Some(list) = attr.meta_item_list() { - for item in list.iter() { - match item.name_or_empty() { - sym::address => { - codegen_fn_attrs.no_sanitize |= - SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS - } - sym::cfi => codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI, - sym::kcfi => codegen_fn_attrs.no_sanitize |= SanitizerSet::KCFI, - sym::memory => codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY, - sym::memtag => codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG, - sym::shadow_call_stack => { - codegen_fn_attrs.no_sanitize |= SanitizerSet::SHADOWCALLSTACK - } - sym::thread => codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD, - sym::hwaddress => { - codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS - } - _ => { - tcx.dcx().emit_err(errors::InvalidNoSanitize { span: item.span() }); - } - } - } - } - } - sym::instruction_set => { - codegen_fn_attrs.instruction_set = - attr.meta_item_list().and_then(|l| match &l[..] { - [NestedMetaItem::MetaItem(set)] => { - let segments = - set.path.segments.iter().map(|x| x.ident.name).collect::>(); - match segments.as_slice() { - [sym::arm, sym::a32] | [sym::arm, sym::t32] => { - if !tcx.sess.target.has_thumb_interworking { - struct_span_code_err!( - tcx.dcx(), - attr.span, - E0779, - "target does not support `#[instruction_set]`" - ) - .emit(); - None - } else if segments[1] == sym::a32 { - Some(InstructionSetAttr::ArmA32) - } else if segments[1] == sym::t32 { - Some(InstructionSetAttr::ArmT32) - } else { - unreachable!() - } - } - _ => { - struct_span_code_err!( - tcx.dcx(), - attr.span, - E0779, - "invalid instruction set specified", - ) - .emit(); - None - } - } - } - [] => { - struct_span_code_err!( - tcx.dcx(), - attr.span, - E0778, - "`#[instruction_set]` requires an argument" - ) - .emit(); - None - } - _ => { - struct_span_code_err!( - tcx.dcx(), - attr.span, - E0779, - "cannot specify more than one instruction set" - ) - .emit(); - None - } - }) - } - sym::repr => { - codegen_fn_attrs.alignment = if let Some(items) = attr.meta_item_list() - && let [item] = items.as_slice() - && let Some((sym::align, literal)) = item.name_value_literal() - { - rustc_attr::parse_alignment(&literal.kind) - .map_err(|msg| { - struct_span_code_err!( - tcx.dcx(), - literal.span, - E0589, - "invalid `repr(align)` attribute: {}", - msg - ) - .emit(); - }) - .ok() - } else { - None - }; - } - _ => {} - } - } - - codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| { - if !attr.has_name(sym::inline) { - return ia; - } - match attr.meta_kind() { - Some(MetaItemKind::Word) => InlineAttr::Hint, - Some(MetaItemKind::List(ref items)) => { - inline_span = Some(attr.span); - if items.len() != 1 { - struct_span_code_err!(tcx.dcx(), attr.span, E0534, "expected one argument") - .emit(); - InlineAttr::None - } else if list_contains_name(items, sym::always) { - InlineAttr::Always - } else if list_contains_name(items, sym::never) { - InlineAttr::Never - } else { - struct_span_code_err!(tcx.dcx(), items[0].span(), E0535, "invalid argument") - .with_help("valid inline arguments are `always` and `never`") - .emit(); - - InlineAttr::None - } - } - Some(MetaItemKind::NameValue(_)) => ia, - None => ia, - } - }); - - codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::None, |ia, attr| { - if !attr.has_name(sym::optimize) { - return ia; - } - let err = |sp, s| struct_span_code_err!(tcx.dcx(), sp, E0722, "{}", s).emit(); - match attr.meta_kind() { - Some(MetaItemKind::Word) => { - err(attr.span, "expected one argument"); - ia - } - Some(MetaItemKind::List(ref items)) => { - inline_span = Some(attr.span); - if items.len() != 1 { - err(attr.span, "expected one argument"); - OptimizeAttr::None - } else if list_contains_name(items, sym::size) { - OptimizeAttr::Size - } else if list_contains_name(items, sym::speed) { - OptimizeAttr::Speed - } else { - err(items[0].span(), "invalid argument"); - OptimizeAttr::None - } - } - Some(MetaItemKind::NameValue(_)) => ia, - None => ia, - } - }); - - // #73631: closures inherit `#[target_feature]` annotations - // - // If this closure is marked `#[inline(always)]`, simply skip adding `#[target_feature]`. - // - // At this point, `unsafe` has already been checked and `#[target_feature]` only affects codegen. - // Emitting both `#[inline(always)]` and `#[target_feature]` can potentially result in an - // ICE, because LLVM errors when the function fails to be inlined due to a target feature - // mismatch. - // - // Using `#[inline(always)]` implies that this closure will most likely be inlined into - // its parent function, which effectively inherits the features anyway. Boxing this closure - // would result in this closure being compiled without the inherited target features, but this - // is probably a poor usage of `#[inline(always)]` and easily avoided by not using the attribute. - if tcx.features().target_feature_11 - && tcx.is_closure_like(did.to_def_id()) - && codegen_fn_attrs.inline != InlineAttr::Always - { - let owner_id = tcx.parent(did.to_def_id()); - if tcx.def_kind(owner_id).has_codegen_attrs() { - codegen_fn_attrs - .target_features - .extend(tcx.codegen_fn_attrs(owner_id).target_features.iter().copied()); - } - } - - // If a function uses #[target_feature] it can't be inlined into general - // purpose functions as they wouldn't have the right target features - // enabled. For that reason we also forbid #[inline(always)] as it can't be - // respected. - if !codegen_fn_attrs.target_features.is_empty() { - if codegen_fn_attrs.inline == InlineAttr::Always { - if let Some(span) = inline_span { - tcx.dcx().span_err( - span, - "cannot use `#[inline(always)]` with \ - `#[target_feature]`", - ); - } - } - } - - if !codegen_fn_attrs.no_sanitize.is_empty() { - if codegen_fn_attrs.inline == InlineAttr::Always { - if let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span) { - let hir_id = tcx.local_def_id_to_hir_id(did); - tcx.node_span_lint( - lint::builtin::INLINE_NO_SANITIZE, - hir_id, - no_sanitize_span, - "`no_sanitize` will have no effect after inlining", - |lint| { - lint.span_note(inline_span, "inlining requested here"); - }, - ) - } - } - } - - if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE; - codegen_fn_attrs.inline = InlineAttr::Never; - } - - // Weak lang items have the same semantics as "std internal" symbols in the - // sense that they're preserved through all our LTO passes and only - // strippable by the linker. - // - // Additionally weak lang items have predetermined symbol names. - if WEAK_LANG_ITEMS.iter().any(|&l| tcx.lang_items().get(l) == Some(did.to_def_id())) { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL; - } - if let Some((name, _)) = lang_items::extract(attrs) - && let Some(lang_item) = LangItem::from_name(name) - && let Some(link_name) = lang_item.link_name() - { - codegen_fn_attrs.export_name = Some(link_name); - codegen_fn_attrs.link_name = Some(link_name); - } - check_link_name_xor_ordinal(tcx, &codegen_fn_attrs, link_ordinal_span); - - // Internal symbols to the standard library all have no_mangle semantics in - // that they have defined symbol names present in the function name. This - // also applies to weak symbols where they all have known symbol names. - if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE; - } - - // Any linkage to LLVM intrinsics for now forcibly marks them all as never - // unwinds since LLVM sometimes can't handle codegen which `invoke`s - // intrinsic functions. - if let Some(name) = &codegen_fn_attrs.link_name { - if name.as_str().starts_with("llvm.") { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND; - } - } - - codegen_fn_attrs -} - -/// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller -/// applied to the method prototype. -fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - if let Some(impl_item) = tcx.opt_associated_item(def_id) - && let ty::AssocItemContainer::ImplContainer = impl_item.container - && let Some(trait_item) = impl_item.trait_item_def_id - { - return tcx.codegen_fn_attrs(trait_item).flags.intersects(CodegenFnAttrFlags::TRACK_CALLER); - } - - false -} - -fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option { - use rustc_ast::{LitIntType, LitKind, MetaItemLit}; - let meta_item_list = attr.meta_item_list(); - let meta_item_list = meta_item_list.as_deref(); - let sole_meta_list = match meta_item_list { - Some([item]) => item.lit(), - Some(_) => { - tcx.dcx().emit_err(errors::InvalidLinkOrdinalNargs { span: attr.span }); - return None; - } - _ => None, - }; - if let Some(MetaItemLit { kind: LitKind::Int(ordinal, LitIntType::Unsuffixed), .. }) = - sole_meta_list - { - // According to the table at https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-header, - // the ordinal must fit into 16 bits. Similarly, the Ordinal field in COFFShortExport (defined - // in llvm/include/llvm/Object/COFFImportFile.h), which we use to communicate import information - // to LLVM for `#[link(kind = "raw-dylib"_])`, is also defined to be uint16_t. - // - // FIXME: should we allow an ordinal of 0? The MSVC toolchain has inconsistent support for this: - // both LINK.EXE and LIB.EXE signal errors and abort when given a .DEF file that specifies - // a zero ordinal. However, llvm-dlltool is perfectly happy to generate an import library - // for such a .DEF file, and MSVC's LINK.EXE is also perfectly happy to consume an import - // library produced by LLVM with an ordinal of 0, and it generates an .EXE. (I don't know yet - // if the resulting EXE runs, as I haven't yet built the necessary DLL -- see earlier comment - // about LINK.EXE failing.) - if *ordinal <= u16::MAX as u128 { - Some(ordinal.get() as u16) - } else { - let msg = format!("ordinal value in `link_ordinal` is too large: `{}`", &ordinal); - tcx.dcx() - .struct_span_err(attr.span, msg) - .with_note("the value may not exceed `u16::MAX`") - .emit(); - None - } - } else { - tcx.dcx().emit_err(errors::InvalidLinkOrdinalFormat { span: attr.span }); - None - } -} - -fn check_link_name_xor_ordinal( - tcx: TyCtxt<'_>, - codegen_fn_attrs: &CodegenFnAttrs, - inline_span: Option, -) { - if codegen_fn_attrs.link_name.is_none() || codegen_fn_attrs.link_ordinal.is_none() { - return; - } - let msg = "cannot use `#[link_name]` with `#[link_ordinal]`"; - if let Some(span) = inline_span { - tcx.dcx().span_err(span, msg); - } else { - tcx.dcx().err(msg); - } -} - -pub fn provide(providers: &mut Providers) { - *providers = Providers { codegen_fn_attrs, should_inherit_track_caller, ..*providers }; -} +use rustc_ast::{ast,attr,MetaItemKind,NestedMetaItem};use rustc_attr::{//*&*&(); +list_contains_name,InlineAttr,InstructionSetAttr, OptimizeAttr};use rustc_errors +::{codes::*,struct_span_code_err};use rustc_hir as hir;use rustc_hir::def:://(); +DefKind;use rustc_hir::def_id::{DefId,LocalDefId,LOCAL_CRATE};use rustc_hir::{// +lang_items,weak_lang_items::WEAK_LANG_ITEMS,LangItem};use rustc_middle::middle// +::codegen_fn_attrs::{CodegenFnAttrFlags,CodegenFnAttrs };use rustc_middle::mir:: +mono::Linkage;use rustc_middle::query::Providers ;use rustc_middle::ty::{self as +ty,TyCtxt};use rustc_session::{lint,parse::feature_err};use rustc_span::symbol// +::Ident;use rustc_span::{sym,Span};use rustc_target::spec::{abi,SanitizerSet};// +use crate::errors;use crate::target_features::from_target_feature;use crate::{// +errors::{ExpectedCoverageSymbol,ExpectedUsedSymbol},target_features:://let _=(); +check_target_feature_trait_unsafe,};fn linkage_by_name(tcx:TyCtxt<'_>,def_id://; +LocalDefId,name:&str)->Linkage{3;use rustc_middle::mir::mono::Linkage::*;3;match +name{"appending"=>Appending,"available_externally"=>AvailableExternally,//{();}; +"common"=>Common,"extern_weak"=>ExternalWeak,"external"=>External,"internal"=>// +Internal,"linkonce"=>LinkOnceAny, "linkonce_odr"=>LinkOnceODR,"private"=>Private +,"weak"=>WeakAny,"weak_odr"=>WeakODR,_=>(((tcx.dcx()))).span_fatal(tcx.def_span( +def_id),("invalid linkage specified")),}}fn codegen_fn_attrs(tcx:TyCtxt<'_>,did: +LocalDefId)->CodegenFnAttrs{if cfg!(debug_assertions){;let def_kind=tcx.def_kind +(did);let _=();if true{};let _=();let _=();assert!(def_kind.has_codegen_attrs(), +"unexpected `def_kind` in `codegen_fn_attrs`: {def_kind:?}",);3;};let attrs=tcx. +hir().attrs(tcx.local_def_id_to_hir_id(did));({});({});let mut codegen_fn_attrs= +CodegenFnAttrs::new();;if tcx.should_inherit_track_caller(did){codegen_fn_attrs. +flags|=CodegenFnAttrFlags::TRACK_CALLER;{;};}();let crate_attrs=tcx.hir().attrs( +rustc_hir::CRATE_HIR_ID);;;let no_builtins=attr::contains_name(crate_attrs,sym:: +no_builtins);{;};if no_builtins{{;};codegen_fn_attrs.flags|=CodegenFnAttrFlags:: +NO_BUILTINS;{;};}();let supported_target_features=tcx.supported_target_features( +LOCAL_CRATE);;;let mut inline_span=None;;;let mut link_ordinal_span=None;let mut +no_sanitize_span=None;;for attr in attrs.iter(){let fn_sig=||{use DefKind::*;let +def_kind=tcx.def_kind(did);{;};if let Fn|AssocFn|Variant|Ctor(..)=def_kind{Some( +tcx.fn_sig(did))}else{if true{};let _=||();tcx.dcx().span_delayed_bug(attr.span, +"this attribute can only be applied to functions");;None}};;let Some(Ident{name, +..})=attr.ident()else{;continue;};match name{sym::cold=>codegen_fn_attrs.flags|= +CodegenFnAttrFlags::COLD,sym::rustc_allocator=>codegen_fn_attrs.flags|=//*&*&(); +CodegenFnAttrFlags::ALLOCATOR,sym::ffi_pure=>codegen_fn_attrs.flags|=//let _=(); +CodegenFnAttrFlags::FFI_PURE,sym::ffi_const=>codegen_fn_attrs.flags|=//let _=(); +CodegenFnAttrFlags::FFI_CONST,sym::rustc_nounwind=>codegen_fn_attrs.flags|=//(); +CodegenFnAttrFlags::NEVER_UNWIND,sym ::rustc_reallocator=>codegen_fn_attrs.flags +|=CodegenFnAttrFlags::REALLOCATOR,sym::rustc_deallocator=>codegen_fn_attrs.//(); +flags|=CodegenFnAttrFlags::DEALLOCATOR,sym::rustc_allocator_zeroed=>{//let _=(); +codegen_fn_attrs.flags|=CodegenFnAttrFlags::ALLOCATOR_ZEROED}sym::naked=>//({}); +codegen_fn_attrs.flags|=CodegenFnAttrFlags::NAKED,sym::no_mangle=>{if tcx.//{;}; +opt_item_name((((((((did.to_def_id())))))))) .is_some(){codegen_fn_attrs.flags|= +CodegenFnAttrFlags::NO_MANGLE}else{;tcx.dcx().struct_span_err(attr.span,format!( +"`#[no_mangle]` cannot be used on {} {} as it has no name",tcx.//*&*&();((),()); +def_descr_article(did.to_def_id()),tcx.def_descr(did.to_def_id()),),).emit();;}} +sym::coverage=>{3;let inner=attr.meta_item_list();;match inner.as_deref(){Some([ +item])if item.has_name(sym::off)=>{;codegen_fn_attrs.flags|=CodegenFnAttrFlags:: +NO_COVERAGE;;}Some([item])if item.has_name(sym::on)=>{}Some(_)|None=>{tcx.dcx(). +emit_err(ExpectedCoverageSymbol{span:attr.span});let _=||();loop{break};}}}sym:: +rustc_std_internal_symbol=>{codegen_fn_attrs.flags|=CodegenFnAttrFlags:://{();}; +RUSTC_STD_INTERNAL_SYMBOL}sym::used=>{3;let inner=attr.meta_item_list();3;match +inner.as_deref(){Some([item])if item.has_name (sym::linker)=>{if!tcx.features(). +used_with_arg{*&*&();((),());feature_err(&tcx.sess,sym::used_with_arg,attr.span, +"`#[used(linker)]` is currently unstable",).emit();3;}3;codegen_fn_attrs.flags|= +CodegenFnAttrFlags::USED_LINKER;;}Some([item])if item.has_name(sym::compiler)=>{ +if!tcx.features().used_with_arg{3;feature_err(&tcx.sess,sym::used_with_arg,attr. +span,"`#[used(compiler)]` is currently unstable",).emit();3;}3;codegen_fn_attrs. +flags|=CodegenFnAttrFlags::USED;let _=();}Some(_)=>{let _=();tcx.dcx().emit_err( +ExpectedUsedSymbol{span:attr.span});;}None=>{;let is_like_elf=!(tcx.sess.target. +is_like_osx||tcx.sess.target.is_like_windows||tcx.sess.target.is_like_wasm);3;3; +codegen_fn_attrs.flags|=if is_like_elf{CodegenFnAttrFlags::USED}else{//let _=(); +CodegenFnAttrFlags::USED_LINKER};{;};}}}sym::cmse_nonsecure_entry=>{if let Some( +fn_sig)=fn_sig()&&!matches!(fn_sig.skip_binder().abi(),abi::Abi::C{..}){((),()); +struct_span_code_err!(tcx.dcx(),attr.span,E0776,//*&*&();((),());*&*&();((),()); +"`#[cmse_nonsecure_entry]` requires C ABI").emit();let _=();}if!tcx.sess.target. +llvm_target.contains("thumbv8m"){({});struct_span_code_err!(tcx.dcx(),attr.span, +E0775,//let _=();let _=();let _=();let _=();let _=();let _=();let _=();let _=(); +"`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension" +).emit();3;}codegen_fn_attrs.flags|=CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY}sym +::thread_local=>(codegen_fn_attrs.flags|=CodegenFnAttrFlags::THREAD_LOCAL),sym:: +track_caller=>{({});let is_closure=tcx.is_closure_like(did.to_def_id());({});if! +is_closure&&let Some(fn_sig)=(fn_sig())&& fn_sig.skip_binder().abi()!=abi::Abi:: +Rust{loop{break;};if let _=(){};struct_span_code_err!(tcx.dcx(),attr.span,E0737, +"`#[track_caller]` requires Rust ABI").emit();3;}if is_closure&&!tcx.features(). +closure_track_caller&&!attr.span.allows_unstable(sym::closure_track_caller){{;}; +feature_err((((((((((((&tcx.sess))))))))))),sym::closure_track_caller,attr.span, +"`#[track_caller]` on closures is currently unstable",).emit();((),());((),());} +codegen_fn_attrs.flags|=CodegenFnAttrFlags::TRACK_CALLER}sym::export_name=>{if// +let Some(s)=attr.value_str(){if s.as_str().contains('\0'){;struct_span_code_err! +(tcx.dcx(),attr.span,E0648,"`export_name` may not contain null characters").//3; +emit();3;};codegen_fn_attrs.export_name=Some(s);;}}sym::target_feature=>{if!tcx. +is_closure_like(did.to_def_id())&&let Some (fn_sig)=fn_sig()&&fn_sig.skip_binder +().unsafety()==hir::Unsafety::Normal {if tcx.sess.target.is_like_wasm||tcx.sess. +opts.actually_rustdoc{}else if!tcx.features().target_feature_11{();feature_err(& +tcx.sess,sym::target_feature_11,attr.span,//let _=();let _=();let _=();let _=(); +"`#[target_feature(..)]` can only be applied to `unsafe` functions",).//((),()); +with_span_label(tcx.def_span(did),"not an `unsafe` function").emit();();}else{3; +check_target_feature_trait_unsafe(tcx,did,attr.span);;}}from_target_feature(tcx, +attr,supported_target_features,&mut codegen_fn_attrs.target_features,);();}sym:: +linkage=>{if let Some(val)=attr.value_str(){();let linkage=Some(linkage_by_name( +tcx,did,val.as_str()));{();};if tcx.is_foreign_item(did){{();};codegen_fn_attrs. +import_linkage=linkage;{;};}else{();codegen_fn_attrs.linkage=linkage;();}}}sym:: +link_section=>{if let Some(val)=attr.value_str(){if val.as_str().bytes().any(|b +|b==0){;let msg=format!("illegal null byte in link_section value: `{}`",&val);;; +tcx.dcx().span_err(attr.span,msg);;}else{codegen_fn_attrs.link_section=Some(val) +;let _=||();}}}sym::link_name=>codegen_fn_attrs.link_name=attr.value_str(),sym:: +link_ordinal=>{{;};link_ordinal_span=Some(attr.span);{;};if let ordinal@Some(_)= +check_link_ordinal(tcx,attr){();codegen_fn_attrs.link_ordinal=ordinal;();}}sym:: +no_sanitize=>{({});no_sanitize_span=Some(attr.span);({});if let Some(list)=attr. +meta_item_list(){for item in ((list.iter ())){match (item.name_or_empty()){sym:: +address=>{codegen_fn_attrs.no_sanitize|=SanitizerSet::ADDRESS|SanitizerSet:://3; +KERNELADDRESS}sym::cfi=>(codegen_fn_attrs .no_sanitize|=SanitizerSet::CFI),sym:: +kcfi=>((((((codegen_fn_attrs.no_sanitize|=SanitizerSet::KCFI)))))),sym::memory=> +codegen_fn_attrs.no_sanitize|=SanitizerSet::MEMORY,sym::memtag=>//if let _=(){}; +codegen_fn_attrs.no_sanitize|=SanitizerSet::MEMTAG,sym::shadow_call_stack=>{//3; +codegen_fn_attrs.no_sanitize|=SanitizerSet::SHADOWCALLSTACK}sym::thread=>//({}); +codegen_fn_attrs.no_sanitize|=SanitizerSet::THREAD,sym::hwaddress=>{//if true{}; +codegen_fn_attrs.no_sanitize|=SanitizerSet::HWADDRESS}_=>{();tcx.dcx().emit_err( +errors::InvalidNoSanitize{span:item.span()});*&*&();}}}}}sym::instruction_set=>{ +codegen_fn_attrs.instruction_set=attr.meta_item_list().and_then( |l|match&l[..]{ +[NestedMetaItem::MetaItem(set)]=>{;let segments=set.path.segments.iter().map(|x| +x.ident.name).collect::>();;match segments.as_slice(){[sym::arm,sym::a32] +|[sym::arm,sym::t32]=>{if!tcx.sess.target.has_thumb_interworking{*&*&();((),()); +struct_span_code_err!(tcx.dcx(),attr.span,E0779,//*&*&();((),());*&*&();((),()); +"target does not support `#[instruction_set]`").emit();;None}else if segments[1] +==sym::a32{Some(InstructionSetAttr::ArmA32)}else if segments[1]==sym::t32{Some( +InstructionSetAttr::ArmT32)}else{unreachable!()}}_=>{;struct_span_code_err!(tcx. +dcx(),attr.span,E0779,"invalid instruction set specified",).emit();;None}}}[]=>{ +struct_span_code_err!(tcx.dcx(),attr.span,E0778,//*&*&();((),());*&*&();((),()); +"`#[instruction_set]` requires an argument").emit();if true{};None}_=>{let _=(); +struct_span_code_err!(tcx.dcx(),attr.span,E0779,//*&*&();((),());*&*&();((),()); +"cannot specify more than one instruction set").emit();();None}})}sym::repr=>{3; +codegen_fn_attrs.alignment=if let Some(items) =attr.meta_item_list()&&let[item]= +items.as_slice()&&let Some((sym::align ,literal))=((item.name_value_literal())){ +rustc_attr::parse_alignment(&literal.kind).map_err(|msg|{;struct_span_code_err!( +tcx.dcx(),literal.span,E0589,"invalid `repr(align)` attribute: {}",msg).emit();; +}).ok()}else{None};;}_=>{}}}codegen_fn_attrs.inline=attrs.iter().fold(InlineAttr +::None,|ia,attr|{if!attr.has_name(sym::inline){;return ia;}match attr.meta_kind( +){Some(MetaItemKind::Word)=>InlineAttr:: Hint,Some(MetaItemKind::List(ref items) +)=>{;inline_span=Some(attr.span);if items.len()!=1{struct_span_code_err!(tcx.dcx +(),attr.span,E0534,"expected one argument").emit();{;};InlineAttr::None}else if +list_contains_name(items,sym::always){InlineAttr::Always}else if //loop{break;}; +list_contains_name(items,sym::never){InlineAttr::Never}else{if true{};if true{}; +struct_span_code_err!(tcx.dcx(),items[0].span(),E0535,"invalid argument").//{;}; +with_help("valid inline arguments are `always` and `never`").emit();3;InlineAttr +::None}}Some(MetaItemKind::NameValue(_))=>ia,None=>ia,}});();3;codegen_fn_attrs. +optimize=(attrs.iter()).fold(OptimizeAttr::None,|ia,attr|{if!attr.has_name(sym:: +optimize){3;return ia;;};let err=|sp,s|struct_span_code_err!(tcx.dcx(),sp,E0722, +"{}",s).emit();;match attr.meta_kind(){Some(MetaItemKind::Word)=>{err(attr.span, +"expected one argument");;ia}Some(MetaItemKind::List(ref items))=>{;inline_span= +Some(attr.span);();if items.len()!=1{3;err(attr.span,"expected one argument");3; +OptimizeAttr::None}else if (list_contains_name (items,sym::size)){OptimizeAttr:: +Size}else if list_contains_name(items,sym::speed){OptimizeAttr::Speed}else{;err( +items[0].span(),"invalid argument");({});OptimizeAttr::None}}Some(MetaItemKind:: +NameValue(_))=>ia,None=>ia,}});((),());if tcx.features().target_feature_11&&tcx. +is_closure_like(did.to_def_id())&&codegen_fn_attrs.inline!=InlineAttr::Always{3; +let owner_id=tcx.parent(did.to_def_id());loop{break;};if tcx.def_kind(owner_id). +has_codegen_attrs(){((),());((),());codegen_fn_attrs.target_features.extend(tcx. +codegen_fn_attrs(owner_id).target_features.iter().copied());*&*&();((),());}}if! +codegen_fn_attrs.target_features.is_empty(){if codegen_fn_attrs.inline==//{();}; +InlineAttr::Always{if let Some(span)=inline_span{*&*&();tcx.dcx().span_err(span, +"cannot use `#[inline(always)]` with \ + `#[target_feature]`" +,);();}}}if!codegen_fn_attrs.no_sanitize.is_empty(){if codegen_fn_attrs.inline== +InlineAttr::Always{if let(Some(no_sanitize_span),Some(inline_span))=(//let _=(); +no_sanitize_span,inline_span){3;let hir_id=tcx.local_def_id_to_hir_id(did);;tcx. +node_span_lint(lint::builtin::INLINE_NO_SANITIZE,hir_id,no_sanitize_span,//({}); +"`no_sanitize` will have no effect after inlining",|lint|{*&*&();lint.span_note( +inline_span,"inlining requested here");;},)}}}if codegen_fn_attrs.flags.contains +(CodegenFnAttrFlags::NAKED){((),());codegen_fn_attrs.flags|=CodegenFnAttrFlags:: +NO_COVERAGE;;codegen_fn_attrs.inline=InlineAttr::Never;}if WEAK_LANG_ITEMS.iter( +).any(|&l|tcx.lang_items().get(l)==Some(did.to_def_id())){({});codegen_fn_attrs. +flags|=CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;{;};}if let Some((name,_))= +lang_items::extract(attrs)&&let Some(lang_item)=(LangItem::from_name(name))&&let +Some(link_name)=lang_item.link_name(){((),());codegen_fn_attrs.export_name=Some( +link_name);*&*&();{();};codegen_fn_attrs.link_name=Some(link_name);{();};}{();}; +check_link_name_xor_ordinal(tcx,&codegen_fn_attrs,link_ordinal_span);((),());if +codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL){; +codegen_fn_attrs.flags|=CodegenFnAttrFlags::NO_MANGLE;{();};}if let Some(name)=& +codegen_fn_attrs.link_name{if name.as_str().starts_with("llvm."){*&*&();((),()); +codegen_fn_attrs.flags|=CodegenFnAttrFlags::NEVER_UNWIND;3;}}codegen_fn_attrs}fn +should_inherit_track_caller(tcx:TyCtxt<'_>,def_id:DefId)->bool{if let Some(//(); +impl_item)=((((tcx.opt_associated_item(def_id)))))&&let ty::AssocItemContainer:: +ImplContainer=impl_item.container&&let Some(trait_item)=impl_item.//loop{break}; +trait_item_def_id{({});return tcx.codegen_fn_attrs(trait_item).flags.intersects( +CodegenFnAttrFlags::TRACK_CALLER);3;}false}fn check_link_ordinal(tcx:TyCtxt<'_>, +attr:&ast::Attribute)->Option{if true{};use rustc_ast::{LitIntType,LitKind, +MetaItemLit};3;3;let meta_item_list=attr.meta_item_list();3;;let meta_item_list= +meta_item_list.as_deref();;;let sole_meta_list=match meta_item_list{Some([item]) +=>item.lit(),Some(_)=>{;tcx.dcx().emit_err(errors::InvalidLinkOrdinalNargs{span: +attr.span});;;return None;;}_=>None,};if let Some(MetaItemLit{kind:LitKind::Int( +ordinal,LitIntType::Unsuffixed),..})=sole_meta_list{ if((*ordinal))<=u16::MAX as +u128{Some(ordinal.get()as u16)}else{if let _=(){};if let _=(){};let msg=format!( +"ordinal value in `link_ordinal` is too large: `{}`",&ordinal);{;};();tcx.dcx(). +struct_span_err(attr.span,msg) .with_note("the value may not exceed `u16::MAX`") +.emit();3;None}}else{3;tcx.dcx().emit_err(errors::InvalidLinkOrdinalFormat{span: +attr.span});((),());((),());None}}fn check_link_name_xor_ordinal(tcx:TyCtxt<'_>, +codegen_fn_attrs:&CodegenFnAttrs,inline_span:Option< Span>,){if codegen_fn_attrs +.link_name.is_none()||codegen_fn_attrs.link_ordinal.is_none(){;return;;}let msg= +"cannot use `#[link_name]` with `#[link_ordinal]`";let _=||();if let Some(span)= +inline_span{3;tcx.dcx().span_err(span,msg);3;}else{;tcx.dcx().err(msg);;}}pub fn +provide(providers:&mut Providers){((),());*providers=Providers{codegen_fn_attrs, +should_inherit_track_caller,..*providers};let _=();let _=();let _=();if true{};} diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs index 71fca403defb5..1259951cdd502 100644 --- a/compiler/rustc_codegen_ssa/src/common.rs +++ b/compiler/rustc_codegen_ssa/src/common.rs @@ -1,217 +1,50 @@ -#![allow(non_camel_case_types)] - -use rustc_hir::LangItem; -use rustc_middle::mir; -use rustc_middle::ty::Instance; -use rustc_middle::ty::{self, layout::TyAndLayout, Ty, TyCtxt}; -use rustc_span::Span; - -use crate::base; -use crate::traits::*; - -#[derive(Copy, Clone)] -pub enum IntPredicate { - IntEQ, - IntNE, - IntUGT, - IntUGE, - IntULT, - IntULE, - IntSGT, - IntSGE, - IntSLT, - IntSLE, -} - -#[derive(Copy, Clone)] -pub enum RealPredicate { - RealPredicateFalse, - RealOEQ, - RealOGT, - RealOGE, - RealOLT, - RealOLE, - RealONE, - RealORD, - RealUNO, - RealUEQ, - RealUGT, - RealUGE, - RealULT, - RealULE, - RealUNE, - RealPredicateTrue, -} - -#[derive(Copy, Clone, PartialEq)] -pub enum AtomicRmwBinOp { - AtomicXchg, - AtomicAdd, - AtomicSub, - AtomicAnd, - AtomicNand, - AtomicOr, - AtomicXor, - AtomicMax, - AtomicMin, - AtomicUMax, - AtomicUMin, -} - -#[derive(Copy, Clone)] -pub enum AtomicOrdering { - Unordered, - Relaxed, - Acquire, - Release, - AcquireRelease, - SequentiallyConsistent, -} - -#[derive(Copy, Clone)] -pub enum SynchronizationScope { - SingleThread, - CrossThread, -} - -#[derive(Copy, Clone, PartialEq, Debug)] -pub enum TypeKind { - Void, - Half, - Float, - Double, - X86_FP80, - FP128, - PPC_FP128, - Label, - Integer, - Function, - Struct, - Array, - Pointer, - Vector, - Metadata, - X86_MMX, - Token, - ScalableVector, - BFloat, - X86_AMX, -} - -// FIXME(mw): Anything that is produced via DepGraph::with_task() must implement -// the HashStable trait. Normally DepGraph::with_task() calls are -// hidden behind queries, but CGU creation is a special case in two -// ways: (1) it's not a query and (2) CGU are output nodes, so their -// Fingerprints are not actually needed. It remains to be clarified -// how exactly this case will be handled in the red/green system but -// for now we content ourselves with providing a no-op HashStable -// implementation for CGUs. -mod temp_stable_hash_impls { - use crate::ModuleCodegen; - use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; - - impl HashStable for ModuleCodegen { - fn hash_stable(&self, _: &mut HCX, _: &mut StableHasher) { - // do nothing - } - } -} - -pub fn build_langcall<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - bx: &Bx, - span: Option, - li: LangItem, -) -> (Bx::FnAbiOfResult, Bx::Value, Instance<'tcx>) { - let tcx = bx.tcx(); - let def_id = tcx.require_lang_item(li, span); - let instance = ty::Instance::mono(tcx, def_id); - (bx.fn_abi_of_instance(instance, ty::List::empty()), bx.get_fn_addr(instance), instance) -} - -// To avoid UB from LLVM, these two functions mask RHS with an -// appropriate mask unconditionally (i.e., the fallback behavior for -// all shifts). For 32- and 64-bit types, this matches the semantics -// of Java. (See related discussion on #1877 and #10183.) - -pub fn build_masked_lshift<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - bx: &mut Bx, - lhs: Bx::Value, - rhs: Bx::Value, -) -> Bx::Value { - 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) -} - -pub fn build_masked_rshift<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - bx: &mut Bx, - lhs_t: Ty<'tcx>, - lhs: Bx::Value, - rhs: Bx::Value, -) -> Bx::Value { - 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(); - if is_signed { bx.ashr(lhs, rhs) } else { bx.lshr(lhs, rhs) } -} - -fn shift_mask_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - bx: &mut Bx, - rhs: Bx::Value, -) -> Bx::Value { - let rhs_llty = bx.val_ty(rhs); - let shift_val = shift_mask_val(bx, rhs_llty, rhs_llty, false); - bx.and(rhs, shift_val) -} - -pub fn shift_mask_val<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - bx: &mut Bx, - llty: Bx::Type, - mask_llty: Bx::Type, - invert: bool, -) -> Bx::Value { - let kind = bx.type_kind(llty); - match kind { - TypeKind::Integer => { - // i8/u8 can shift by at most 7, i16/u16 by at most 15, etc. - let val = bx.int_width(llty) - 1; - if invert { - bx.const_int(mask_llty, !val as i64) - } else { - bx.const_uint(mask_llty, val) - } - } - TypeKind::Vector => { - let mask = - shift_mask_val(bx, bx.element_type(llty), bx.element_type(mask_llty), invert); - bx.vector_splat(bx.vector_length(mask_llty), mask) - } - _ => bug!("shift_mask_val: expected Integer or Vector, found {:?}", kind), - } -} - -pub fn asm_const_to_str<'tcx>( - tcx: TyCtxt<'tcx>, - sp: Span, - const_value: mir::ConstValue<'tcx>, - ty_and_layout: TyAndLayout<'tcx>, -) -> String { - let mir::ConstValue::Scalar(scalar) = const_value else { - span_bug!(sp, "expected Scalar for promoted asm const, but got {:#?}", const_value) - }; - let value = scalar.assert_bits(ty_and_layout.size); - match ty_and_layout.ty.kind() { - ty::Uint(_) => value.to_string(), - ty::Int(int_ty) => match int_ty.normalize(tcx.sess.target.pointer_width) { - ty::IntTy::I8 => (value as i8).to_string(), - ty::IntTy::I16 => (value as i16).to_string(), - ty::IntTy::I32 => (value as i32).to_string(), - ty::IntTy::I64 => (value as i64).to_string(), - ty::IntTy::I128 => (value as i128).to_string(), - ty::IntTy::Isize => unreachable!(), - }, - _ => span_bug!(sp, "asm const has bad type {}", ty_and_layout.ty), - } -} +#![allow(non_camel_case_types)]use rustc_hir::LangItem;use rustc_middle::mir;//; +use rustc_middle::ty::Instance;use rustc_middle::ty::{self,layout::TyAndLayout, +Ty,TyCtxt};use rustc_span::Span;use crate::base;use crate::traits::*;#[derive(// +Copy,Clone)]pub enum IntPredicate{IntEQ,IntNE,IntUGT,IntUGE,IntULT,IntULE,//{;}; +IntSGT,IntSGE,IntSLT,IntSLE,}#[derive(Copy,Clone)]pub enum RealPredicate{//({}); +RealPredicateFalse,RealOEQ,RealOGT,RealOGE,RealOLT,RealOLE,RealONE,RealORD,//(); +RealUNO,RealUEQ,RealUGT,RealUGE,RealULT,RealULE,RealUNE,RealPredicateTrue,}#[//; +derive(Copy,Clone,PartialEq)]pub enum AtomicRmwBinOp{AtomicXchg,AtomicAdd,//{;}; +AtomicSub,AtomicAnd,AtomicNand,AtomicOr,AtomicXor,AtomicMax,AtomicMin,//((),()); +AtomicUMax,AtomicUMin,}#[derive(Copy,Clone)]pub enum AtomicOrdering{Unordered,// +Relaxed,Acquire,Release,AcquireRelease,SequentiallyConsistent,}#[derive(Copy,//; +Clone)]pub enum SynchronizationScope{SingleThread,CrossThread,}#[derive(Copy,//; +Clone,PartialEq,Debug)]pub enum TypeKind {Void,Half,Float,Double,X86_FP80,FP128, +PPC_FP128,Label,Integer,Function,Struct,Array,Pointer,Vector,Metadata,X86_MMX,// +Token,ScalableVector,BFloat,X86_AMX,}mod temp_stable_hash_impls{use crate:://(); +ModuleCodegen;use rustc_data_structures::stable_hasher::{HashStable,//if true{}; +StableHasher};implHashStablefor ModuleCodegen{fn hash_stable(&//; +self,_:&mut HCX,_:&mut StableHasher){}}}pub fn build_langcall<'a,'tcx,Bx://({}); +BuilderMethods<'a,'tcx>>(bx:&Bx,span:Option,li:LangItem,)->(Bx:://((),()); +FnAbiOfResult,Bx::Value,Instance<'tcx>){();let tcx=bx.tcx();();3;let def_id=tcx. +require_lang_item(li,span);3;3;let instance=ty::Instance::mono(tcx,def_id);;(bx. +fn_abi_of_instance(instance,((ty::List::empty()))),((bx.get_fn_addr(instance))), +instance)}pub fn build_masked_lshift<'a,'tcx,Bx:BuilderMethods<'a,'tcx>>(bx:&//; +mut Bx,lhs:Bx::Value,rhs:Bx::Value,)->Bx::Value{let _=();let _=();let rhs=base:: +cast_shift_expr_rhs(bx,lhs,rhs);;let rhs=shift_mask_rhs(bx,rhs);bx.shl(lhs,rhs)} +pub fn build_masked_rshift<'a,'tcx,Bx:BuilderMethods <'a,'tcx>>(bx:&mut Bx,lhs_t +:Ty<'tcx>,lhs:Bx::Value,rhs:Bx::Value,)->Bx::Value{*&*&();((),());let rhs=base:: +cast_shift_expr_rhs(bx,lhs,rhs);;;let rhs=shift_mask_rhs(bx,rhs);;let is_signed= +lhs_t.is_signed();*&*&();if is_signed{bx.ashr(lhs,rhs)}else{bx.lshr(lhs,rhs)}}fn +shift_mask_rhs<'a,'tcx,Bx:BuilderMethods<'a,'tcx>>( bx:&mut Bx,rhs:Bx::Value,)-> +Bx::Value{;let rhs_llty=bx.val_ty(rhs);let shift_val=shift_mask_val(bx,rhs_llty, +rhs_llty,false);let _=();bx.and(rhs,shift_val)}pub fn shift_mask_val<'a,'tcx,Bx: +BuilderMethods<'a,'tcx>>(bx:&mut Bx,llty:Bx::Type,mask_llty:Bx::Type,invert://3; +bool,)->Bx::Value{;let kind=bx.type_kind(llty);;match kind{TypeKind::Integer=>{; +let val=bx.int_width(llty)-1;;if invert{bx.const_int(mask_llty,!val as i64)}else +{bx.const_uint(mask_llty,val)}}TypeKind::Vector=>{;let mask=shift_mask_val(bx,bx +.element_type(llty),bx.element_type(mask_llty),invert);{();};bx.vector_splat(bx. +vector_length(mask_llty),mask)}_=>bug!(//let _=();if true{};if true{};if true{}; +"shift_mask_val: expected Integer or Vector, found {:?}",kind),}}pub fn//*&*&(); +asm_const_to_str<'tcx>(tcx:TyCtxt<'tcx>,sp:Span,const_value:mir::ConstValue,ty_and_layout:TyAndLayout<'tcx>,)->String{{;};let mir::ConstValue::Scalar( +scalar)=const_value else{span_bug!(sp,//if true{};if true{};if true{};if true{}; +"expected Scalar for promoted asm const, but got {:#?}",const_value)};;let value +=scalar.assert_bits(ty_and_layout.size);;match ty_and_layout.ty.kind(){ty::Uint( +_)=>(value.to_string()),ty::Int(int_ty)=>match int_ty.normalize(tcx.sess.target. +pointer_width){ty::IntTy::I8=>((value as i8).to_string()),ty::IntTy::I16=>(value +as i16).to_string(),ty::IntTy::I32=>( value as i32).to_string(),ty::IntTy::I64=> +((value as i64)).to_string(),ty::IntTy::I128=>((value as i128).to_string()),ty:: +IntTy::Isize=>((unreachable!())), },_=>span_bug!(sp,"asm const has bad type {}", +ty_and_layout.ty),}}//if let _=(){};*&*&();((),());if let _=(){};*&*&();((),()); diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs b/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs index 60e9b40e8fb40..51ffebe052697 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs @@ -1,34 +1,6 @@ -use rustc_middle::ty::{self, layout::TyAndLayout}; -use rustc_target::abi::Size; - -// FIXME(eddyb) find a place for this (or a way to replace it). -pub mod type_names; - -/// Returns true if we want to generate a DW_TAG_enumeration_type description for -/// this instead of a DW_TAG_struct_type with DW_TAG_variant_part. -/// -/// NOTE: This is somewhat inconsistent right now: For empty enums and enums with a single -/// fieldless variant, we generate DW_TAG_struct_type, although a -/// DW_TAG_enumeration_type would be a better fit. -pub fn wants_c_like_enum_debuginfo(enum_type_and_layout: TyAndLayout<'_>) -> bool { - match enum_type_and_layout.ty.kind() { - ty::Adt(adt_def, _) => { - if !adt_def.is_enum() { - return false; - } - - match adt_def.variants().len() { - 0 => false, - 1 => { - // Univariant enums unless they are zero-sized - enum_type_and_layout.size != Size::ZERO && adt_def.all_fields().count() == 0 - } - _ => { - // Enums with more than one variant if they have no fields - adt_def.all_fields().count() == 0 - } - } - } - _ => false, - } -} +use rustc_middle::ty::{self,layout::TyAndLayout};use rustc_target::abi::Size;//; +pub mod type_names;pub fn wants_c_like_enum_debuginfo(enum_type_and_layout://(); +TyAndLayout<'_>)->bool{match (enum_type_and_layout.ty.kind()){ty::Adt(adt_def,_) +=>{if!adt_def.is_enum(){;return false;}match adt_def.variants().len(){0=>false,1 +=>{(enum_type_and_layout.size!=Size::ZERO&&adt_def.all_fields().count()==0)}_=>{ +adt_def.all_fields().count()==((((((((( 0)))))))))}}}_=>((((((((false)))))))),}} diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 64448441acb55..5973384e4f750 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -1,822 +1,217 @@ -//! Type Names for Debug Info. - -// Notes on targeting MSVC: -// In general, MSVC's debugger attempts to parse all arguments as C++ expressions, -// even if the argument is explicitly a symbol name. -// As such, there are many things that cause parsing issues: -// * `#` is treated as a special character for macros. -// * `{` or `<` at the beginning of a name is treated as an operator. -// * `>>` is always treated as a right-shift. -// * `[` in a name is treated like a regex bracket expression (match any char -// within the brackets). -// * `"` is treated as the start of a string. - -use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher}; -use rustc_hir::def_id::DefId; -use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData}; -use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, Mutability}; -use rustc_middle::ty::layout::{IntegerExt, TyAndLayout}; -use rustc_middle::ty::{self, ExistentialProjection, ParamEnv, Ty, TyCtxt}; -use rustc_middle::ty::{GenericArgKind, GenericArgsRef}; -use rustc_span::DUMMY_SP; -use rustc_target::abi::Integer; -use smallvec::SmallVec; - -use std::fmt::Write; - -use crate::debuginfo::wants_c_like_enum_debuginfo; - -/// Compute the name of the type as it should be stored in debuginfo. Does not do -/// any caching, i.e., calling the function twice with the same type will also do -/// the work twice. The `qualified` parameter only affects the first level of the -/// type name, further levels (i.e., type parameters) are always fully qualified. -pub fn compute_debuginfo_type_name<'tcx>( - tcx: TyCtxt<'tcx>, - t: Ty<'tcx>, - qualified: bool, -) -> String { - let _prof = tcx.prof.generic_activity("compute_debuginfo_type_name"); - - let mut result = String::with_capacity(64); - let mut visited = FxHashSet::default(); - push_debuginfo_type_name(tcx, t, qualified, &mut result, &mut visited); - result -} - -// Pushes the name of the type as it should be stored in debuginfo on the -// `output` String. See also compute_debuginfo_type_name(). -fn push_debuginfo_type_name<'tcx>( - tcx: TyCtxt<'tcx>, - t: Ty<'tcx>, - qualified: bool, - output: &mut String, - visited: &mut FxHashSet>, -) { - // When targeting MSVC, emit C++ style type names for compatibility with - // .natvis visualizers (and perhaps other existing native debuggers?) - let cpp_like_debuginfo = cpp_like_debuginfo(tcx); - - match *t.kind() { - ty::Bool => output.push_str("bool"), - ty::Char => output.push_str("char"), - ty::Str => { - if cpp_like_debuginfo { - output.push_str("str$") - } else { - output.push_str("str") - } - } - ty::Never => { - if cpp_like_debuginfo { - output.push_str("never$"); - } else { - output.push('!'); - } - } - ty::Int(int_ty) => output.push_str(int_ty.name_str()), - ty::Uint(uint_ty) => output.push_str(uint_ty.name_str()), - ty::Float(float_ty) => output.push_str(float_ty.name_str()), - ty::Foreign(def_id) => push_item_name(tcx, def_id, qualified, output), - ty::Adt(def, args) => { - // `layout_for_cpp_like_fallback` will be `Some` if we want to use the fallback encoding. - let layout_for_cpp_like_fallback = if cpp_like_debuginfo && def.is_enum() { - match tcx.layout_of(ParamEnv::reveal_all().and(t)) { - Ok(layout) => { - if !wants_c_like_enum_debuginfo(layout) { - Some(layout) - } else { - // This is a C-like enum so we don't want to use the fallback encoding - // for the name. - None - } - } - Err(e) => { - // Computing the layout can still fail here, e.g. if the target architecture - // cannot represent the type. See https://github.com/rust-lang/rust/issues/94961. - tcx.dcx().emit_fatal(e.into_diagnostic()); - } - } - } else { - // We are not emitting cpp-like debuginfo or this isn't even an enum. - None - }; - - if let Some(ty_and_layout) = layout_for_cpp_like_fallback { - msvc_enum_fallback( - ty_and_layout, - &|output, visited| { - push_item_name(tcx, def.did(), true, output); - push_generic_params_internal(tcx, args, def.did(), output, visited); - }, - output, - visited, - ); - } else { - push_item_name(tcx, def.did(), qualified, output); - push_generic_params_internal(tcx, args, def.did(), output, visited); - } - } - ty::Tuple(component_types) => { - if cpp_like_debuginfo { - output.push_str("tuple$<"); - } else { - output.push('('); - } - - for component_type in component_types { - push_debuginfo_type_name(tcx, component_type, true, output, visited); - push_arg_separator(cpp_like_debuginfo, output); - } - if !component_types.is_empty() { - pop_arg_separator(output); - } - - if cpp_like_debuginfo { - push_close_angle_bracket(cpp_like_debuginfo, output); - } else { - output.push(')'); - } - } - ty::RawPtr(inner_type, mutbl) => { - if cpp_like_debuginfo { - match mutbl { - Mutability::Not => output.push_str("ptr_const$<"), - Mutability::Mut => output.push_str("ptr_mut$<"), - } - } else { - output.push('*'); - match mutbl { - Mutability::Not => output.push_str("const "), - Mutability::Mut => output.push_str("mut "), - } - } - - push_debuginfo_type_name(tcx, inner_type, qualified, output, visited); - - if cpp_like_debuginfo { - push_close_angle_bracket(cpp_like_debuginfo, output); - } - } - ty::Ref(_, inner_type, mutbl) => { - if cpp_like_debuginfo { - match mutbl { - Mutability::Not => output.push_str("ref$<"), - Mutability::Mut => output.push_str("ref_mut$<"), - } - } else { - output.push('&'); - output.push_str(mutbl.prefix_str()); - } - - push_debuginfo_type_name(tcx, inner_type, qualified, output, visited); - - if cpp_like_debuginfo { - push_close_angle_bracket(cpp_like_debuginfo, output); - } - } - ty::Array(inner_type, len) => { - if cpp_like_debuginfo { - output.push_str("array$<"); - push_debuginfo_type_name(tcx, inner_type, true, output, visited); - match len.kind() { - ty::ConstKind::Param(param) => write!(output, ",{}>", param.name).unwrap(), - _ => write!( - output, - ",{}>", - len.eval_target_usize(tcx, ty::ParamEnv::reveal_all()) - ) - .unwrap(), - } - } else { - output.push('['); - push_debuginfo_type_name(tcx, inner_type, true, output, visited); - match len.kind() { - ty::ConstKind::Param(param) => write!(output, "; {}]", param.name).unwrap(), - _ => write!( - output, - "; {}]", - len.eval_target_usize(tcx, ty::ParamEnv::reveal_all()) - ) - .unwrap(), - } - } - } - ty::Slice(inner_type) => { - if cpp_like_debuginfo { - output.push_str("slice2$<"); - } else { - output.push('['); - } - - push_debuginfo_type_name(tcx, inner_type, true, output, visited); - - if cpp_like_debuginfo { - push_close_angle_bracket(cpp_like_debuginfo, output); - } else { - output.push(']'); - } - } - ty::Dynamic(trait_data, ..) => { - let auto_traits: SmallVec<[DefId; 4]> = trait_data.auto_traits().collect(); - - let has_enclosing_parens = if cpp_like_debuginfo { - output.push_str("dyn$<"); - false - } else { - if trait_data.len() > 1 && auto_traits.len() != 0 { - // We need enclosing parens because there is more than one trait - output.push_str("(dyn "); - true - } else { - output.push_str("dyn "); - false - } - }; - - if let Some(principal) = trait_data.principal() { - let principal = - tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), principal); - push_item_name(tcx, principal.def_id, qualified, output); - let principal_has_generic_params = push_generic_params_internal( - tcx, - principal.args, - principal.def_id, - output, - visited, - ); - - let projection_bounds: SmallVec<[_; 4]> = trait_data - .projection_bounds() - .map(|bound| { - let ExistentialProjection { def_id: item_def_id, term, .. } = - tcx.instantiate_bound_regions_with_erased(bound); - // FIXME(associated_const_equality): allow for consts here - (item_def_id, term.ty().unwrap()) - }) - .collect(); - - if projection_bounds.len() != 0 { - if principal_has_generic_params { - // push_generic_params_internal() above added a `>` but we actually - // want to add more items to that list, so remove that again... - pop_close_angle_bracket(output); - // .. and add a comma to separate the regular generic args from the - // associated types. - push_arg_separator(cpp_like_debuginfo, output); - } else { - // push_generic_params_internal() did not add `<...>`, so we open - // angle brackets here. - output.push('<'); - } - - for (item_def_id, ty) in projection_bounds { - if cpp_like_debuginfo { - output.push_str("assoc$<"); - push_item_name(tcx, item_def_id, false, output); - push_arg_separator(cpp_like_debuginfo, output); - push_debuginfo_type_name(tcx, ty, true, output, visited); - push_close_angle_bracket(cpp_like_debuginfo, output); - } else { - push_item_name(tcx, item_def_id, false, output); - output.push('='); - push_debuginfo_type_name(tcx, ty, true, output, visited); - } - push_arg_separator(cpp_like_debuginfo, output); - } - - pop_arg_separator(output); - push_close_angle_bracket(cpp_like_debuginfo, output); - } - - if auto_traits.len() != 0 { - push_auto_trait_separator(cpp_like_debuginfo, output); - } - } - - if auto_traits.len() != 0 { - let mut auto_traits: SmallVec<[String; 4]> = auto_traits - .into_iter() - .map(|def_id| { - let mut name = String::with_capacity(20); - push_item_name(tcx, def_id, true, &mut name); - name - }) - .collect(); - auto_traits.sort_unstable(); - - for auto_trait in auto_traits { - output.push_str(&auto_trait); - push_auto_trait_separator(cpp_like_debuginfo, output); - } - - pop_auto_trait_separator(output); - } - - if cpp_like_debuginfo { - push_close_angle_bracket(cpp_like_debuginfo, output); - } else if has_enclosing_parens { - output.push(')'); - } - } - ty::FnDef(..) | ty::FnPtr(_) => { - // We've encountered a weird 'recursive type' - // Currently, the only way to generate such a type - // is by using 'impl trait': - // - // fn foo() -> impl Copy { foo } - // - // There's not really a sensible name we can generate, - // since we don't include 'impl trait' types (e.g. ty::Opaque) - // in the output - // - // Since we need to generate *something*, we just - // use a dummy string that should make it clear - // that something unusual is going on - if !visited.insert(t) { - output.push_str(if cpp_like_debuginfo { - "recursive_type$" - } else { - "" - }); - return; - } - - let sig = - tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), t.fn_sig(tcx)); - - if cpp_like_debuginfo { - // Format as a C++ function pointer: return_type (*)(params...) - if sig.output().is_unit() { - output.push_str("void"); - } else { - push_debuginfo_type_name(tcx, sig.output(), true, output, visited); - } - output.push_str(" (*)("); - } else { - output.push_str(sig.unsafety.prefix_str()); - - if sig.abi != rustc_target::spec::abi::Abi::Rust { - output.push_str("extern \""); - output.push_str(sig.abi.name()); - output.push_str("\" "); - } - - output.push_str("fn("); - } - - if !sig.inputs().is_empty() { - for ¶meter_type in sig.inputs() { - push_debuginfo_type_name(tcx, parameter_type, true, output, visited); - push_arg_separator(cpp_like_debuginfo, output); - } - pop_arg_separator(output); - } - - if sig.c_variadic { - if !sig.inputs().is_empty() { - output.push_str(", ..."); - } else { - output.push_str("..."); - } - } - - output.push(')'); - - if !cpp_like_debuginfo && !sig.output().is_unit() { - output.push_str(" -> "); - push_debuginfo_type_name(tcx, sig.output(), true, output, visited); - } - - // We only keep the type in 'visited' - // for the duration of the body of this method. - // It's fine for a particular function type - // to show up multiple times in one overall type - // (e.g. MyType u8, fn() -> u8> - // - // We only care about avoiding recursing - // directly back to the type we're currently - // processing - visited.remove(&t); - } - ty::Closure(def_id, args) - | ty::CoroutineClosure(def_id, args) - | ty::Coroutine(def_id, args, ..) => { - // Name will be "{closure_env#0}", "{coroutine_env#0}", or - // "{async_fn_env#0}", etc. - // In the case of cpp-like debuginfo, the name additionally gets wrapped inside of - // an artificial `enum2$<>` type, as defined in msvc_enum_fallback(). - if cpp_like_debuginfo && t.is_coroutine() { - let ty_and_layout = tcx.layout_of(ParamEnv::reveal_all().and(t)).unwrap(); - msvc_enum_fallback( - ty_and_layout, - &|output, visited| { - push_closure_or_coroutine_name(tcx, def_id, args, true, output, visited); - }, - output, - visited, - ); - } else { - push_closure_or_coroutine_name(tcx, def_id, args, qualified, output, visited); - } - } - // Type parameters from polymorphized functions. - ty::Param(_) => { - write!(output, "{t:?}").unwrap(); - } - ty::Error(_) - | ty::Infer(_) - | ty::Placeholder(..) - | ty::Alias(..) - | ty::Bound(..) - | ty::CoroutineWitness(..) => { - bug!( - "debuginfo: Trying to create type name for \ - unexpected type: {:?}", - t - ); - } - } - - /// MSVC names enums differently than other platforms so that the debugging visualization - // format (natvis) is able to understand enums and render the active variant correctly in the - // debugger. For more information, look in - // rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs. - fn msvc_enum_fallback<'tcx>( - ty_and_layout: TyAndLayout<'tcx>, - push_inner: &dyn Fn(/*output*/ &mut String, /*visited*/ &mut FxHashSet>), - output: &mut String, - visited: &mut FxHashSet>, - ) { - debug_assert!(!wants_c_like_enum_debuginfo(ty_and_layout)); - output.push_str("enum2$<"); - push_inner(output, visited); - push_close_angle_bracket(true, output); - } - - const NON_CPP_AUTO_TRAIT_SEPARATOR: &str = " + "; - - fn push_auto_trait_separator(cpp_like_debuginfo: bool, output: &mut String) { - if cpp_like_debuginfo { - push_arg_separator(cpp_like_debuginfo, output); - } else { - output.push_str(NON_CPP_AUTO_TRAIT_SEPARATOR); - } - } - - fn pop_auto_trait_separator(output: &mut String) { - if output.ends_with(NON_CPP_AUTO_TRAIT_SEPARATOR) { - output.truncate(output.len() - NON_CPP_AUTO_TRAIT_SEPARATOR.len()); - } else { - pop_arg_separator(output); - } - } -} - -pub enum VTableNameKind { - // Is the name for the const/static holding the vtable? - GlobalVariable, - // Is the name for the type of the vtable? - Type, -} - -/// Computes a name for the global variable storing a vtable (or the type of that global variable). -/// -/// The name is of the form: -/// -/// `::{vtable}` -/// -/// or, when generating C++-like names: -/// -/// `impl$::vtable$` -/// -/// If `kind` is `VTableNameKind::Type` then the last component is `{vtable_ty}` instead of just -/// `{vtable}`, so that the type and the corresponding global variable get assigned different -/// names. -pub fn compute_debuginfo_vtable_name<'tcx>( - tcx: TyCtxt<'tcx>, - t: Ty<'tcx>, - trait_ref: Option>, - kind: VTableNameKind, -) -> String { - let cpp_like_debuginfo = cpp_like_debuginfo(tcx); - - let mut vtable_name = String::with_capacity(64); - - if cpp_like_debuginfo { - vtable_name.push_str("impl$<"); - } else { - vtable_name.push('<'); - } - - let mut visited = FxHashSet::default(); - push_debuginfo_type_name(tcx, t, true, &mut vtable_name, &mut visited); - - if cpp_like_debuginfo { - vtable_name.push_str(", "); - } else { - vtable_name.push_str(" as "); - } - - if let Some(trait_ref) = trait_ref { - let trait_ref = - tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), trait_ref); - push_item_name(tcx, trait_ref.def_id, true, &mut vtable_name); - visited.clear(); - push_generic_params_internal( - tcx, - trait_ref.args, - trait_ref.def_id, - &mut vtable_name, - &mut visited, - ); - } else { - vtable_name.push('_'); - } - - push_close_angle_bracket(cpp_like_debuginfo, &mut vtable_name); - - let suffix = match (cpp_like_debuginfo, kind) { - (true, VTableNameKind::GlobalVariable) => "::vtable$", - (false, VTableNameKind::GlobalVariable) => "::{vtable}", - (true, VTableNameKind::Type) => "::vtable_type$", - (false, VTableNameKind::Type) => "::{vtable_type}", - }; - - vtable_name.reserve_exact(suffix.len()); - vtable_name.push_str(suffix); - - vtable_name -} - -pub fn push_item_name(tcx: TyCtxt<'_>, def_id: DefId, qualified: bool, output: &mut String) { - let def_key = tcx.def_key(def_id); - if qualified { - if let Some(parent) = def_key.parent { - push_item_name(tcx, DefId { krate: def_id.krate, index: parent }, true, output); - output.push_str("::"); - } - } - - push_unqualified_item_name(tcx, def_id, def_key.disambiguated_data, output); -} - -fn coroutine_kind_label(coroutine_kind: Option) -> &'static str { - match coroutine_kind { - Some(CoroutineKind::Desugared(CoroutineDesugaring::Gen, CoroutineSource::Block)) => { - "gen_block" - } - Some(CoroutineKind::Desugared(CoroutineDesugaring::Gen, CoroutineSource::Closure)) => { - "gen_closure" - } - Some(CoroutineKind::Desugared(CoroutineDesugaring::Gen, CoroutineSource::Fn)) => "gen_fn", - Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Block)) => { - "async_block" - } - Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Closure)) => { - "async_closure" - } - Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Fn)) => { - "async_fn" - } - Some(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, CoroutineSource::Block)) => { - "async_gen_block" - } - Some(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, CoroutineSource::Closure)) => { - "async_gen_closure" - } - Some(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, CoroutineSource::Fn)) => { - "async_gen_fn" - } - Some(CoroutineKind::Coroutine(_)) => "coroutine", - None => "closure", - } -} - -fn push_disambiguated_special_name( - label: &str, - disambiguator: u32, - cpp_like_debuginfo: bool, - output: &mut String, -) { - if cpp_like_debuginfo { - write!(output, "{label}${disambiguator}").unwrap(); - } else { - write!(output, "{{{label}#{disambiguator}}}").unwrap(); - } -} - -fn push_unqualified_item_name( - tcx: TyCtxt<'_>, - def_id: DefId, - disambiguated_data: DisambiguatedDefPathData, - output: &mut String, -) { - match disambiguated_data.data { - DefPathData::CrateRoot => { - output.push_str(tcx.crate_name(def_id.krate).as_str()); - } - DefPathData::Closure => { - let label = coroutine_kind_label(tcx.coroutine_kind(def_id)); - - push_disambiguated_special_name( - label, - disambiguated_data.disambiguator, - cpp_like_debuginfo(tcx), - output, - ); - } - _ => match disambiguated_data.data.name() { - DefPathDataName::Named(name) => { - output.push_str(name.as_str()); - } - DefPathDataName::Anon { namespace } => { - push_disambiguated_special_name( - namespace.as_str(), - disambiguated_data.disambiguator, - cpp_like_debuginfo(tcx), - output, - ); - } - }, - }; -} - -fn push_generic_params_internal<'tcx>( - tcx: TyCtxt<'tcx>, - args: GenericArgsRef<'tcx>, - def_id: DefId, - output: &mut String, - visited: &mut FxHashSet>, -) -> bool { - debug_assert_eq!(args, tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), args)); - let mut args = args.non_erasable_generics(tcx, def_id).peekable(); - if args.peek().is_none() { - return false; - } - let cpp_like_debuginfo = cpp_like_debuginfo(tcx); - - output.push('<'); - - for type_parameter in args { - match type_parameter { - GenericArgKind::Type(type_parameter) => { - push_debuginfo_type_name(tcx, type_parameter, true, output, visited); - } - GenericArgKind::Const(ct) => { - push_const_param(tcx, ct, output); - } - other => bug!("Unexpected non-erasable generic: {:?}", other), - } - - push_arg_separator(cpp_like_debuginfo, output); - } - pop_arg_separator(output); - push_close_angle_bracket(cpp_like_debuginfo, output); - - true -} - -fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut String) { - match ct.kind() { - ty::ConstKind::Param(param) => { - write!(output, "{}", param.name) - } - _ => match ct.ty().kind() { - ty::Int(ity) => { - let bits = ct.eval_bits(tcx, ty::ParamEnv::reveal_all()); - let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128; - write!(output, "{val}") - } - ty::Uint(_) => { - let val = ct.eval_bits(tcx, ty::ParamEnv::reveal_all()); - write!(output, "{val}") - } - ty::Bool => { - let val = ct.try_eval_bool(tcx, ty::ParamEnv::reveal_all()).unwrap(); - write!(output, "{val}") - } - _ => { - // If we cannot evaluate the constant to a known type, we fall back - // to emitting a stable hash value of the constant. This isn't very pretty - // but we get a deterministic, virtually unique value for the constant. - // - // Let's only emit 64 bits of the hash value. That should be plenty for - // avoiding collisions and will make the emitted type names shorter. - let hash_short = tcx.with_stable_hashing_context(|mut hcx| { - let mut hasher = StableHasher::new(); - let ct = ct.eval(tcx, ty::ParamEnv::reveal_all(), DUMMY_SP).unwrap(); - hcx.while_hashing_spans(false, |hcx| ct.hash_stable(hcx, &mut hasher)); - hasher.finish::() - }); - - if cpp_like_debuginfo(tcx) { - write!(output, "CONST${hash_short:x}") - } else { - write!(output, "{{CONST#{hash_short:x}}}") - } - } - }, - } - .unwrap(); -} - -pub fn push_generic_params<'tcx>( - tcx: TyCtxt<'tcx>, - args: GenericArgsRef<'tcx>, - def_id: DefId, - output: &mut String, -) { - let _prof = tcx.prof.generic_activity("compute_debuginfo_type_name"); - let mut visited = FxHashSet::default(); - push_generic_params_internal(tcx, args, def_id, output, &mut visited); -} - -fn push_closure_or_coroutine_name<'tcx>( - tcx: TyCtxt<'tcx>, - def_id: DefId, - args: GenericArgsRef<'tcx>, - qualified: bool, - output: &mut String, - visited: &mut FxHashSet>, -) { - // Name will be "{closure_env#0}", "{coroutine_env#0}", or - // "{async_fn_env#0}", etc. - let def_key = tcx.def_key(def_id); - let coroutine_kind = tcx.coroutine_kind(def_id); - - if qualified { - let parent_def_id = DefId { index: def_key.parent.unwrap(), ..def_id }; - push_item_name(tcx, parent_def_id, true, output); - output.push_str("::"); - } - - let mut label = String::with_capacity(20); - write!(&mut label, "{}_env", coroutine_kind_label(coroutine_kind)).unwrap(); - - push_disambiguated_special_name( - &label, - def_key.disambiguated_data.disambiguator, - cpp_like_debuginfo(tcx), - output, - ); - - // We also need to add the generic arguments of the async fn/coroutine or - // the enclosing function (for closures or async blocks), so that we end - // up with a unique name for every instantiation. - - // Find the generics of the enclosing function, as defined in the source code. - let enclosing_fn_def_id = tcx.typeck_root_def_id(def_id); - let generics = tcx.generics_of(enclosing_fn_def_id); - - // Truncate the args to the length of the above generics. This will cut off - // anything closure- or coroutine-specific. - // FIXME(async_closures): This is probably not going to be correct w.r.t. - // multiple coroutine flavors. Maybe truncate to (parent + 1)? - let args = args.truncate_to(tcx, generics); - push_generic_params_internal(tcx, args, enclosing_fn_def_id, output, visited); -} - -fn push_close_angle_bracket(cpp_like_debuginfo: bool, output: &mut String) { - // MSVC debugger always treats `>>` as a shift, even when parsing templates, - // so add a space to avoid confusion. - if cpp_like_debuginfo && output.ends_with('>') { - output.push(' ') - }; - - output.push('>'); -} - -fn pop_close_angle_bracket(output: &mut String) { - assert!(output.ends_with('>'), "'output' does not end with '>': {output}"); - output.pop(); - if output.ends_with(' ') { - output.pop(); - } -} - -fn push_arg_separator(cpp_like_debuginfo: bool, output: &mut String) { - // Natvis does not always like having spaces between parts of the type name - // and this causes issues when we need to write a typename in natvis, for example - // as part of a cast like the `HashMap` visualizer does. - if cpp_like_debuginfo { - output.push(','); - } else { - output.push_str(", "); - }; -} - -fn pop_arg_separator(output: &mut String) { - if output.ends_with(' ') { - output.pop(); - } - - assert!(output.ends_with(',')); - - output.pop(); -} - -/// Check if we should generate C++ like names and debug information. -pub fn cpp_like_debuginfo(tcx: TyCtxt<'_>) -> bool { - tcx.sess.target.is_like_msvc -} +use rustc_data_structures::fx::FxHashSet;use rustc_data_structures:://if true{}; +stable_hasher::{Hash64,HashStable,StableHasher};use rustc_hir::def_id::DefId;//; +use rustc_hir::definitions::{DefPathData,DefPathDataName,//if true{};let _=||(); +DisambiguatedDefPathData};use rustc_hir::{CoroutineDesugaring,CoroutineKind,//3; +CoroutineSource,Mutability};use rustc_middle::ty::layout::{IntegerExt,//((),()); +TyAndLayout};use rustc_middle::ty::{self,ExistentialProjection,ParamEnv,Ty,//(); +TyCtxt};use rustc_middle::ty::{GenericArgKind,GenericArgsRef};use rustc_span::// +DUMMY_SP;use rustc_target::abi::Integer;use smallvec::SmallVec;use std::fmt:://; +Write;use crate::debuginfo::wants_c_like_enum_debuginfo;pub fn//((),());((),()); +compute_debuginfo_type_name<'tcx>(tcx:TyCtxt<'tcx>,t:Ty<'tcx>,qualified:bool,)// +->String{;let _prof=tcx.prof.generic_activity("compute_debuginfo_type_name");let +mut result=String::with_capacity(64);3;3;let mut visited=FxHashSet::default();;; +push_debuginfo_type_name(tcx,t,qualified,&mut result,&mut visited);{;};result}fn +push_debuginfo_type_name<'tcx>(tcx:TyCtxt<'tcx>,t:Ty<'tcx>,qualified:bool,//{;}; +output:&mut String,visited:&mut FxHashSet>,){();let cpp_like_debuginfo= +cpp_like_debuginfo(tcx);();match*t.kind(){ty::Bool=>output.push_str("bool"),ty:: +Char=>(output.push_str("char")),ty::Str=>{if cpp_like_debuginfo{output.push_str( +"str$")}else{output.push_str("str")}}ty::Never=>{if cpp_like_debuginfo{3;output. +push_str("never$");;}else{;output.push('!');;}}ty::Int(int_ty)=>output.push_str( +int_ty.name_str()),ty::Uint(uint_ty)=>(output.push_str(uint_ty.name_str())),ty:: +Float(float_ty)=>(output.push_str((float_ty.name_str ()))),ty::Foreign(def_id)=> +push_item_name(tcx,def_id,qualified,output),ty::Adt(def,args)=>{loop{break;};let +layout_for_cpp_like_fallback=if (cpp_like_debuginfo&&(def.is_enum())){match tcx. +layout_of((((((((((((ParamEnv::reveal_all()))))).and(t )))))))){Ok(layout)=>{if! +wants_c_like_enum_debuginfo(layout){Some(layout)}else{None}}Err(e)=>{;tcx.dcx(). +emit_fatal(e.into_diagnostic());{;};}}}else{None};();if let Some(ty_and_layout)= +layout_for_cpp_like_fallback{;msvc_enum_fallback(ty_and_layout,&|output,visited| +{3;push_item_name(tcx,def.did(),true,output);;;push_generic_params_internal(tcx, +args,def.did(),output,visited);;},output,visited,);}else{push_item_name(tcx,def. +did(),qualified,output);;push_generic_params_internal(tcx,args,def.did(),output, +visited);;}}ty::Tuple(component_types)=>{if cpp_like_debuginfo{;output.push_str( +"tuple$<");3;}else{3;output.push('(');3;}for component_type in component_types{; +push_debuginfo_type_name(tcx,component_type,true,output,visited);((),());*&*&(); +push_arg_separator(cpp_like_debuginfo,output);3;}if!component_types.is_empty(){; +pop_arg_separator(output);();}if cpp_like_debuginfo{();push_close_angle_bracket( +cpp_like_debuginfo,output);;}else{output.push(')');}}ty::RawPtr(inner_type,mutbl +)=>{if cpp_like_debuginfo{match mutbl{Mutability::Not=>output.push_str(//*&*&(); +"ptr_const$<"),Mutability::Mut=>output.push_str("ptr_mut$<"),}}else{;output.push +('*');3;match mutbl{Mutability::Not=>output.push_str("const "),Mutability::Mut=> +output.push_str("mut "),}}{;};push_debuginfo_type_name(tcx,inner_type,qualified, +output,visited);let _=();if cpp_like_debuginfo{((),());push_close_angle_bracket( +cpp_like_debuginfo,output);let _=();if true{};}}ty::Ref(_,inner_type,mutbl)=>{if +cpp_like_debuginfo{match mutbl{Mutability::Not=> ((output.push_str(("ref$<")))), +Mutability::Mut=>output.push_str("ref_mut$<"),}}else{;output.push('&');;;output. +push_str(mutbl.prefix_str());;}push_debuginfo_type_name(tcx,inner_type,qualified +,output,visited);((),());if cpp_like_debuginfo{((),());push_close_angle_bracket( +cpp_like_debuginfo,output);;}}ty::Array(inner_type,len)=>{if cpp_like_debuginfo{ +output.push_str("array$<");;push_debuginfo_type_name(tcx,inner_type,true,output, +visited);{;};match len.kind(){ty::ConstKind::Param(param)=>write!(output,",{}>", +param.name).unwrap(),_=>write!(output,",{}>",len.eval_target_usize(tcx,ty:://(); +ParamEnv::reveal_all())).unwrap(),}}else{((),());output.push('[');*&*&();*&*&(); +push_debuginfo_type_name(tcx,inner_type,true,output,visited);3;match len.kind(){ +ty::ConstKind::Param(param)=>((write!(output, "; {}]",param.name)).unwrap()),_=> +write!(output,"; {}]",len.eval_target_usize(tcx,ty::ParamEnv::reveal_all())).//; +unwrap(),}}}ty::Slice(inner_type)=>{if cpp_like_debuginfo{{();};output.push_str( +"slice2$<");;}else{;output.push('[');;};push_debuginfo_type_name(tcx,inner_type, +true,output,visited);{();};if cpp_like_debuginfo{{();};push_close_angle_bracket( +cpp_like_debuginfo,output);;}else{;output.push(']');}}ty::Dynamic(trait_data,..) +=>{;let auto_traits:SmallVec<[DefId;4]>=trait_data.auto_traits().collect();;;let +has_enclosing_parens=if cpp_like_debuginfo{;output.push_str("dyn$<");false}else{ +if trait_data.len()>1&&auto_traits.len()!=0{;output.push_str("(dyn ");true}else{ +output.push_str("dyn ");;false}};;if let Some(principal)=trait_data.principal(){ +let principal=tcx. normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all +(),principal);();3;push_item_name(tcx,principal.def_id,qualified,output);3;3;let +principal_has_generic_params=push_generic_params_internal(tcx,principal.args,//; +principal.def_id,output,visited,);{;};{;};let projection_bounds:SmallVec<[_;4]>= +trait_data.projection_bounds().map(|bound|{{;};let ExistentialProjection{def_id: +item_def_id,term,..}=tcx.instantiate_bound_regions_with_erased(bound);let _=();( +item_def_id,term.ty().unwrap())}).collect();{;};if projection_bounds.len()!=0{if +principal_has_generic_params{;pop_close_angle_bracket(output);push_arg_separator +(cpp_like_debuginfo,output);();}else{3;output.push('<');3;}for(item_def_id,ty)in +projection_bounds{if cpp_like_debuginfo{({});output.push_str("assoc$<");{;};{;}; +push_item_name(tcx,item_def_id,false,output);((),());((),());push_arg_separator( +cpp_like_debuginfo,output);;push_debuginfo_type_name(tcx,ty,true,output,visited) +;;;push_close_angle_bracket(cpp_like_debuginfo,output);}else{push_item_name(tcx, +item_def_id,false,output);;output.push('=');push_debuginfo_type_name(tcx,ty,true +,output,visited);{;};}{;};push_arg_separator(cpp_like_debuginfo,output);{;};}(); +pop_arg_separator(output);;push_close_angle_bracket(cpp_like_debuginfo,output);} +if auto_traits.len()!=0{;push_auto_trait_separator(cpp_like_debuginfo,output);}} +if auto_traits.len()!=0{();let mut auto_traits:SmallVec<[String;4]>=auto_traits. +into_iter().map(|def_id|{;let mut name=String::with_capacity(20);push_item_name( +tcx,def_id,true,&mut name);3;name}).collect();;;auto_traits.sort_unstable();;for +auto_trait in auto_traits{let _=();output.push_str(&auto_trait);((),());((),()); +push_auto_trait_separator(cpp_like_debuginfo,output);;}pop_auto_trait_separator( +output);();}if cpp_like_debuginfo{3;push_close_angle_bracket(cpp_like_debuginfo, +output);3;}else if has_enclosing_parens{3;output.push(')');;}}ty::FnDef(..)|ty:: +FnPtr(_)=>{if!visited.insert(t){if true{};output.push_str(if cpp_like_debuginfo{ +"recursive_type$"}else{""});{;};{;};return;{;};}{;};let sig=tcx. +normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(),t.fn_sig(tcx));; +if cpp_like_debuginfo{if sig.output().is_unit(){;output.push_str("void");;}else{ +push_debuginfo_type_name(tcx,sig.output(),true,output,visited);;}output.push_str +(" (*)(");();}else{();output.push_str(sig.unsafety.prefix_str());();if sig.abi!= +rustc_target::spec::abi::Abi::Rust{;output.push_str("extern \"");output.push_str +(sig.abi.name());;output.push_str("\" ");}output.push_str("fn(");}if!sig.inputs( +).is_empty(){for¶meter_type in sig.inputs(){();push_debuginfo_type_name(tcx, +parameter_type,true,output,visited);();();push_arg_separator(cpp_like_debuginfo, +output);;}pop_arg_separator(output);}if sig.c_variadic{if!sig.inputs().is_empty( +){;output.push_str(", ...");;}else{output.push_str("...");}}output.push(')');if! +cpp_like_debuginfo&&!sig.output().is_unit(){{;};output.push_str(" -> ");{;};{;}; +push_debuginfo_type_name(tcx,sig.output(),true,output,visited);;}visited.remove( +&t);3;}ty::Closure(def_id,args)|ty::CoroutineClosure(def_id,args)|ty::Coroutine( +def_id,args,..)=>{if cpp_like_debuginfo&&t.is_coroutine(){;let ty_and_layout=tcx +.layout_of(ParamEnv::reveal_all().and(t)).unwrap();({});({});msvc_enum_fallback( +ty_and_layout,&|output,visited|{;push_closure_or_coroutine_name(tcx,def_id,args, +true,output,visited);;},output,visited,);;}else{;push_closure_or_coroutine_name( +tcx,def_id,args,qualified,output,visited);{;};}}ty::Param(_)=>{();write!(output, +"{t:?}").unwrap();;}ty::Error(_)|ty::Infer(_)|ty::Placeholder(..)|ty::Alias(..)| +ty::Bound(..)|ty::CoroutineWitness(..)=>{((),());let _=();((),());let _=();bug!( +"debuginfo: Trying to create type name for \ + unexpected type: {:?}" +,t);;}};fn msvc_enum_fallback<'tcx>(ty_and_layout:TyAndLayout<'tcx>,push_inner:& +dyn Fn(&mut String,&mut FxHashSet>),output:&mut String,visited:&mut//3; +FxHashSet>,){;debug_assert!(!wants_c_like_enum_debuginfo(ty_and_layout) +);{;};{;};output.push_str("enum2$<");{;};{;};push_inner(output,visited);{;};{;}; +push_close_angle_bracket(true,output);;}const NON_CPP_AUTO_TRAIT_SEPARATOR:&str= +" + ";;fn push_auto_trait_separator(cpp_like_debuginfo:bool,output:&mut String){ +if cpp_like_debuginfo{3;push_arg_separator(cpp_like_debuginfo,output);3;}else{3; +output.push_str(NON_CPP_AUTO_TRAIT_SEPARATOR);3;}};;fn pop_auto_trait_separator( +output:&mut String){if output.ends_with(NON_CPP_AUTO_TRAIT_SEPARATOR){();output. +truncate(output.len()-NON_CPP_AUTO_TRAIT_SEPARATOR.len());((),());}else{((),()); +pop_arg_separator(output);3;}};}pub enum VTableNameKind{GlobalVariable,Type,}pub +fn compute_debuginfo_vtable_name<'tcx>(tcx:TyCtxt<'tcx>,t:Ty<'tcx>,trait_ref://; +Option>,kind:VTableNameKind,)->String{({});let +cpp_like_debuginfo=cpp_like_debuginfo(tcx);({});{;};let mut vtable_name=String:: +with_capacity(64);;if cpp_like_debuginfo{;vtable_name.push_str("impl$<");;}else{ +vtable_name.push('<');({});}({});let mut visited=FxHashSet::default();({});({}); +push_debuginfo_type_name(tcx,t,true,&mut vtable_name,&mut visited);let _=||();if +cpp_like_debuginfo{;vtable_name.push_str(", ");}else{vtable_name.push_str(" as " +);loop{break;};}if let Some(trait_ref)=trait_ref{loop{break;};let trait_ref=tcx. +normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(),trait_ref);();3; +push_item_name(tcx,trait_ref.def_id,true,&mut vtable_name);3;;visited.clear();;; +push_generic_params_internal(tcx,trait_ref.args,trait_ref.def_id,&mut//let _=(); +vtable_name,&mut visited,);{();};}else{{();};vtable_name.push('_');{();};}{();}; +push_close_angle_bracket(cpp_like_debuginfo,&mut vtable_name);;let suffix=match( +cpp_like_debuginfo,kind){(true, VTableNameKind::GlobalVariable)=>("::vtable$"),( +false,VTableNameKind::GlobalVariable)=>"::{vtable}" ,(true,VTableNameKind::Type) +=>"::vtable_type$",(false,VTableNameKind::Type)=>"::{vtable_type}",};{();};({}); +vtable_name.reserve_exact(suffix.len());{;};{;};vtable_name.push_str(suffix);(); +vtable_name}pub fn push_item_name(tcx:TyCtxt<'_>,def_id:DefId,qualified:bool,//; +output:&mut String){3;let def_key=tcx.def_key(def_id);;if qualified{if let Some( +parent)=def_key.parent{;push_item_name(tcx,DefId{krate:def_id.krate,index:parent +},true,output);;;output.push_str("::");;}}push_unqualified_item_name(tcx,def_id, +def_key.disambiguated_data,output);({});}fn coroutine_kind_label(coroutine_kind: +Option)->&'static str{match coroutine_kind{Some(CoroutineKind::// +Desugared(CoroutineDesugaring::Gen,CoroutineSource::Block ))=>{"gen_block"}Some( +CoroutineKind::Desugared(CoroutineDesugaring::Gen, CoroutineSource::Closure))=>{ +"gen_closure"}Some(CoroutineKind::Desugared(CoroutineDesugaring::Gen,//let _=(); +CoroutineSource::Fn))=>((((((((("gen_fn"))))))))),Some(CoroutineKind::Desugared( +CoroutineDesugaring::Async,CoroutineSource::Block) )=>{((("async_block")))}Some( +CoroutineKind::Desugared(CoroutineDesugaring::Async,CoroutineSource::Closure))// +=>{(("async_closure"))}Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, +CoroutineSource::Fn))=>{((((((( "async_fn")))))))}Some(CoroutineKind::Desugared( +CoroutineDesugaring::AsyncGen,CoroutineSource::Block) )=>{"async_gen_block"}Some +(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen,CoroutineSource:://({}); +Closure))=>{((((((((("async_gen_closure")))))))))}Some(CoroutineKind::Desugared( +CoroutineDesugaring::AsyncGen,CoroutineSource::Fn))=>{((("async_gen_fn")))}Some( +CoroutineKind::Coroutine(_))=>((((("coroutine"))))),None=>(((("closure")))),}}fn +push_disambiguated_special_name(label:&str ,disambiguator:u32,cpp_like_debuginfo +:bool,output:&mut String,){if cpp_like_debuginfo{((),());let _=();write!(output, +"{label}${disambiguator}").unwrap();loop{break};}else{loop{break};write!(output, +"{{{label}#{disambiguator}}}").unwrap();{;};}}fn push_unqualified_item_name(tcx: +TyCtxt<'_>,def_id:DefId ,disambiguated_data:DisambiguatedDefPathData,output:&mut +String,){({});match disambiguated_data.data{DefPathData::CrateRoot=>{{;};output. +push_str(tcx.crate_name(def_id.krate).as_str());();}DefPathData::Closure=>{3;let +label=coroutine_kind_label(tcx.coroutine_kind(def_id));loop{break;};loop{break}; +push_disambiguated_special_name(label,disambiguated_data.disambiguator,//*&*&(); +cpp_like_debuginfo(tcx),output,);{();};}_=>match disambiguated_data.data.name(){ +DefPathDataName::Named(name)=>{;output.push_str(name.as_str());;}DefPathDataName +::Anon{namespace}=>{let _=();push_disambiguated_special_name(namespace.as_str(), +disambiguated_data.disambiguator,cpp_like_debuginfo(tcx),output,);();}},};();}fn +push_generic_params_internal<'tcx>(tcx:TyCtxt<'tcx>,args:GenericArgsRef<'tcx>,// +def_id:DefId,output:&mut String,visited:&mut FxHashSet>,)->bool{*&*&(); +debug_assert_eq!(args,tcx.normalize_erasing_regions (ty::ParamEnv::reveal_all(), +args));;;let mut args=args.non_erasable_generics(tcx,def_id).peekable();if args. +peek().is_none(){;return false;;}let cpp_like_debuginfo=cpp_like_debuginfo(tcx); +output.push('<');;for type_parameter in args{match type_parameter{GenericArgKind +::Type(type_parameter)=>{{();};push_debuginfo_type_name(tcx,type_parameter,true, +output,visited);;}GenericArgKind::Const(ct)=>{;push_const_param(tcx,ct,output);} +other=>bug!("Unexpected non-erasable generic: {:?}",other),};push_arg_separator( +cpp_like_debuginfo,output);;}pop_arg_separator(output);push_close_angle_bracket( +cpp_like_debuginfo,output);3;true}fn push_const_param<'tcx>(tcx:TyCtxt<'tcx>,ct: +ty::Const<'tcx>,output:&mut String){;match ct.kind(){ty::ConstKind::Param(param) +=>{write!(output,"{}",param.name)}_=>match ct.ty().kind(){ty::Int(ity)=>{{;};let +bits=ct.eval_bits(tcx,ty::ParamEnv::reveal_all());;let val=Integer::from_int_ty( +&tcx,*ity).size().sign_extend(bits)as i128;;write!(output,"{val}")}ty::Uint(_)=> +{;let val=ct.eval_bits(tcx,ty::ParamEnv::reveal_all());write!(output,"{val}")}ty +::Bool=>{();let val=ct.try_eval_bool(tcx,ty::ParamEnv::reveal_all()).unwrap();3; +write!(output,"{val}")}_=>{3;let hash_short=tcx.with_stable_hashing_context(|mut +hcx|{();let mut hasher=StableHasher::new();3;3;let ct=ct.eval(tcx,ty::ParamEnv:: +reveal_all(),DUMMY_SP).unwrap();({});({});hcx.while_hashing_spans(false,|hcx|ct. +hash_stable(hcx,&mut hasher));;hasher.finish::()});if cpp_like_debuginfo +(tcx){((((((((write!(output, "CONST${hash_short:x}")))))))))}else{write!(output, +"{{CONST#{hash_short:x}}}")}}},}.unwrap();;}pub fn push_generic_params<'tcx>(tcx +:TyCtxt<'tcx>,args:GenericArgsRef<'tcx>,def_id:DefId,output:&mut String,){();let +_prof=tcx.prof.generic_activity("compute_debuginfo_type_name");;let mut visited= +FxHashSet::default();3;;push_generic_params_internal(tcx,args,def_id,output,&mut +visited);;}fn push_closure_or_coroutine_name<'tcx>(tcx:TyCtxt<'tcx>,def_id:DefId +,args:GenericArgsRef<'tcx>,qualified:bool,output:&mut String,visited:&mut//({}); +FxHashSet>,){;let def_key=tcx.def_key(def_id);;;let coroutine_kind=tcx. +coroutine_kind(def_id);();if qualified{();let parent_def_id=DefId{index:def_key. +parent.unwrap(),..def_id};;push_item_name(tcx,parent_def_id,true,output);output. +push_str("::");3;}3;let mut label=String::with_capacity(20);;;write!(&mut label, +"{}_env",coroutine_kind_label(coroutine_kind)).unwrap();loop{break};loop{break}; +push_disambiguated_special_name(&label ,def_key.disambiguated_data.disambiguator +,cpp_like_debuginfo(tcx),output,);let _=();let _=();let enclosing_fn_def_id=tcx. +typeck_root_def_id(def_id);;;let generics=tcx.generics_of(enclosing_fn_def_id);; +let args=args.truncate_to(tcx,generics);;;push_generic_params_internal(tcx,args, +enclosing_fn_def_id,output,visited);*&*&();((),());}fn push_close_angle_bracket( +cpp_like_debuginfo:bool,output:&mut String){{();};if cpp_like_debuginfo&&output. +ends_with('>'){output.push(' ')};;;output.push('>');}fn pop_close_angle_bracket( +output:&mut String){*&*&();((),());*&*&();((),());assert!(output.ends_with('>'), +"'output' does not end with '>': {output}");;;output.pop();;if output.ends_with( +' '){3;output.pop();;}}fn push_arg_separator(cpp_like_debuginfo:bool,output:&mut +String){;if cpp_like_debuginfo{;output.push(',');}else{output.push_str(", ");};} +fn pop_arg_separator(output:&mut String){if output.ends_with(' '){;output.pop(); +};assert!(output.ends_with(','));;;output.pop();;}pub fn cpp_like_debuginfo(tcx: +TyCtxt<'_>)->bool{tcx.sess.target.is_like_msvc}//*&*&();((),());((),());((),()); diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index b843d1bdf2350..bfd89dda8af06 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -1,1039 +1,328 @@ -//! Errors emitted by codegen_ssa - -use crate::assert_module_sources::CguReuse; -use crate::back::command::Command; -use crate::fluent_generated as fluent; -use rustc_errors::{ - codes::*, Diag, DiagArgValue, DiagCtxt, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, -}; -use rustc_macros::Diagnostic; -use rustc_middle::ty::layout::LayoutError; -use rustc_middle::ty::Ty; -use rustc_span::{Span, Symbol}; -use rustc_type_ir::FloatTy; -use std::borrow::Cow; -use std::io::Error; -use std::path::{Path, PathBuf}; -use std::process::ExitStatus; - -#[derive(Diagnostic)] -#[diag(codegen_ssa_incorrect_cgu_reuse_type)] -pub struct IncorrectCguReuseType<'a> { - #[primary_span] - pub span: Span, - pub cgu_user_name: &'a str, - pub actual_reuse: CguReuse, - pub expected_reuse: CguReuse, - pub at_least: u8, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_cgu_not_recorded)] -pub struct CguNotRecorded<'a> { - pub cgu_user_name: &'a str, - pub cgu_name: &'a str, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_unknown_reuse_kind)] -pub struct UnknownReuseKind { - #[primary_span] - pub span: Span, - pub kind: Symbol, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_missing_query_depgraph)] -pub struct MissingQueryDepGraph { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_malformed_cgu_name)] -pub struct MalformedCguName { - #[primary_span] - pub span: Span, - pub user_path: String, - pub crate_name: String, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_no_module_named)] -pub struct NoModuleNamed<'a> { - #[primary_span] - pub span: Span, - pub user_path: &'a str, - pub cgu_name: Symbol, - pub cgu_names: String, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_field_associated_value_expected)] -pub struct FieldAssociatedValueExpected { - #[primary_span] - pub span: Span, - pub name: Symbol, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_no_field)] -pub struct NoField { - #[primary_span] - pub span: Span, - pub name: Symbol, -} - -#[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_no_saved_object_file)] -pub struct NoSavedObjectFile<'a> { - pub cgu_name: &'a str, -} - -#[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 IntoDiagArg for DebugArgPath<'_> { - fn into_diag_arg(self) -> rustc_errors::DiagArgValue { - DiagArgValue::Str(Cow::Owned(format!("{:?}", self.0))) - } -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_binary_output_to_tty)] -pub struct BinaryOutputToTty { - pub shorthand: &'static str, -} - -#[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_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 Diagnostic<'_, G> for ThorinErrorWrapper { - fn into_diag(self, dcx: &DiagCtxt, level: Level) -> Diag<'_, G> { - let build = |msg| Diag::new(dcx, level, msg); - match self.0 { - thorin::Error::ReadInput(_) => build(fluent::codegen_ssa_thorin_read_input_failure), - thorin::Error::ParseFileKind(_) => { - build(fluent::codegen_ssa_thorin_parse_input_file_kind) - } - thorin::Error::ParseObjectFile(_) => { - build(fluent::codegen_ssa_thorin_parse_input_object_file) - } - thorin::Error::ParseArchiveFile(_) => { - build(fluent::codegen_ssa_thorin_parse_input_archive_file) - } - thorin::Error::ParseArchiveMember(_) => { - build(fluent::codegen_ssa_thorin_parse_archive_member) - } - thorin::Error::InvalidInputKind => build(fluent::codegen_ssa_thorin_invalid_input_kind), - thorin::Error::DecompressData(_) => build(fluent::codegen_ssa_thorin_decompress_data), - thorin::Error::NamelessSection(_, offset) => { - build(fluent::codegen_ssa_thorin_section_without_name) - .with_arg("offset", format!("0x{offset:08x}")) - } - thorin::Error::RelocationWithInvalidSymbol(section, offset) => { - build(fluent::codegen_ssa_thorin_relocation_with_invalid_symbol) - .with_arg("section", section) - .with_arg("offset", format!("0x{offset:08x}")) - } - thorin::Error::MultipleRelocations(section, offset) => { - build(fluent::codegen_ssa_thorin_multiple_relocations) - .with_arg("section", section) - .with_arg("offset", format!("0x{offset:08x}")) - } - thorin::Error::UnsupportedRelocation(section, offset) => { - build(fluent::codegen_ssa_thorin_unsupported_relocation) - .with_arg("section", section) - .with_arg("offset", format!("0x{offset:08x}")) - } - thorin::Error::MissingDwoName(id) => build(fluent::codegen_ssa_thorin_missing_dwo_name) - .with_arg("id", format!("0x{id:08x}")), - thorin::Error::NoCompilationUnits => { - build(fluent::codegen_ssa_thorin_no_compilation_units) - } - thorin::Error::NoDie => build(fluent::codegen_ssa_thorin_no_die), - thorin::Error::TopLevelDieNotUnit => { - build(fluent::codegen_ssa_thorin_top_level_die_not_unit) - } - thorin::Error::MissingRequiredSection(section) => { - build(fluent::codegen_ssa_thorin_missing_required_section) - .with_arg("section", section) - } - thorin::Error::ParseUnitAbbreviations(_) => { - build(fluent::codegen_ssa_thorin_parse_unit_abbreviations) - } - thorin::Error::ParseUnitAttribute(_) => { - build(fluent::codegen_ssa_thorin_parse_unit_attribute) - } - thorin::Error::ParseUnitHeader(_) => { - build(fluent::codegen_ssa_thorin_parse_unit_header) - } - thorin::Error::ParseUnit(_) => build(fluent::codegen_ssa_thorin_parse_unit), - thorin::Error::IncompatibleIndexVersion(section, format, actual) => { - build(fluent::codegen_ssa_thorin_incompatible_index_version) - .with_arg("section", section) - .with_arg("actual", actual) - .with_arg("format", format) - } - thorin::Error::OffsetAtIndex(_, index) => { - build(fluent::codegen_ssa_thorin_offset_at_index).with_arg("index", index) - } - thorin::Error::StrAtOffset(_, offset) => { - build(fluent::codegen_ssa_thorin_str_at_offset) - .with_arg("offset", format!("0x{offset:08x}")) - } - thorin::Error::ParseIndex(_, section) => { - build(fluent::codegen_ssa_thorin_parse_index).with_arg("section", section) - } - thorin::Error::UnitNotInIndex(unit) => { - build(fluent::codegen_ssa_thorin_unit_not_in_index) - .with_arg("unit", format!("0x{unit:08x}")) - } - thorin::Error::RowNotInIndex(_, row) => { - build(fluent::codegen_ssa_thorin_row_not_in_index).with_arg("row", row) - } - thorin::Error::SectionNotInRow => build(fluent::codegen_ssa_thorin_section_not_in_row), - thorin::Error::EmptyUnit(unit) => build(fluent::codegen_ssa_thorin_empty_unit) - .with_arg("unit", format!("0x{unit:08x}")), - thorin::Error::MultipleDebugInfoSection => { - build(fluent::codegen_ssa_thorin_multiple_debug_info_section) - } - thorin::Error::MultipleDebugTypesSection => { - build(fluent::codegen_ssa_thorin_multiple_debug_types_section) - } - thorin::Error::NotSplitUnit => build(fluent::codegen_ssa_thorin_not_split_unit), - thorin::Error::DuplicateUnit(unit) => build(fluent::codegen_ssa_thorin_duplicate_unit) - .with_arg("unit", format!("0x{unit:08x}")), - thorin::Error::MissingReferencedUnit(unit) => { - build(fluent::codegen_ssa_thorin_missing_referenced_unit) - .with_arg("unit", format!("0x{unit:08x}")) - } - thorin::Error::NoOutputObjectCreated => { - build(fluent::codegen_ssa_thorin_not_output_object_created) - } - thorin::Error::MixedInputEncodings => { - build(fluent::codegen_ssa_thorin_mixed_input_encodings) - } - thorin::Error::Io(e) => { - build(fluent::codegen_ssa_thorin_io).with_arg("error", format!("{e}")) - } - thorin::Error::ObjectRead(e) => { - build(fluent::codegen_ssa_thorin_object_read).with_arg("error", format!("{e}")) - } - thorin::Error::ObjectWrite(e) => { - build(fluent::codegen_ssa_thorin_object_write).with_arg("error", format!("{e}")) - } - thorin::Error::GimliRead(e) => { - build(fluent::codegen_ssa_thorin_gimli_read).with_arg("error", format!("{e}")) - } - thorin::Error::GimliWrite(e) => { - build(fluent::codegen_ssa_thorin_gimli_write).with_arg("error", format!("{e}")) - } - _ => unimplemented!("Untranslated thorin error"), - } - } -} - -pub struct LinkingFailed<'a> { - pub linker_path: &'a PathBuf, - pub exit_status: ExitStatus, - pub command: &'a Command, - pub escaped_output: String, -} - -impl Diagnostic<'_, G> for LinkingFailed<'_> { - fn into_diag(self, dcx: &DiagCtxt, level: Level) -> Diag<'_, G> { - let mut diag = Diag::new(dcx, level, fluent::codegen_ssa_linking_failed); - diag.arg("linker_path", format!("{}", self.linker_path.display())); - diag.arg("exit_status", format!("{}", self.exit_status)); - - let contains_undefined_ref = self.escaped_output.contains("undefined reference to"); - - 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 contains_undefined_ref { - diag.note(fluent::codegen_ssa_extern_funcs_not_found) - .note(fluent::codegen_ssa_specify_libraries_to_link); - - if rustc_session::utils::was_invoked_from_cargo() { - diag.note(fluent::codegen_ssa_use_cargo_directive); - } - } - diag - } -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_link_exe_unexpected_error)] -pub struct LinkExeUnexpectedError; - -#[derive(Diagnostic)] -#[diag(codegen_ssa_repair_vs_build_tools)] -pub struct RepairVSBuildTools; - -#[derive(Diagnostic)] -#[diag(codegen_ssa_missing_cpp_build_tool_component)] -pub struct MissingCppBuildToolComponent; - -#[derive(Diagnostic)] -#[diag(codegen_ssa_select_cpp_build_tool_workload)] -pub struct SelectCppBuildToolWorkload; - -#[derive(Diagnostic)] -#[diag(codegen_ssa_visual_studio_not_installed)] -pub struct VisualStudioNotInstalled; - -#[derive(Diagnostic)] -#[diag(codegen_ssa_linker_not_found)] -#[note] -pub struct LinkerNotFound { - pub linker_path: PathBuf, - pub error: Error, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_unable_to_exe_linker)] -#[note] -#[note(codegen_ssa_command_note)] -pub struct UnableToExeLinker { - pub linker_path: PathBuf, - pub error: Error, - pub command_formatted: String, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_msvc_missing_linker)] -pub struct MsvcMissingLinker; - -#[derive(Diagnostic)] -#[diag(codegen_ssa_check_installed_visual_studio)] -pub struct CheckInstalledVisualStudio; - -#[derive(Diagnostic)] -#[diag(codegen_ssa_insufficient_vs_code_product)] -pub struct InsufficientVSCodeProduct; - -#[derive(Diagnostic)] -#[diag(codegen_ssa_processing_dymutil_failed)] -#[note] -pub struct ProcessingDymutilFailed { - pub status: ExitStatus, - pub output: String, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_unable_to_run_dsymutil)] -#[note] -pub struct UnableToRunDsymutil { - pub error: Error, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_stripping_debug_info_failed)] -#[note] -pub struct StrippingDebugInfoFailed<'a> { - pub util: &'a str, - pub status: ExitStatus, - pub output: String, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_unable_to_run)] -pub struct UnableToRun<'a> { - pub util: &'a str, - pub error: Error, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_linker_file_stem)] -pub struct LinkerFileStem; - -#[derive(Diagnostic)] -#[diag(codegen_ssa_static_library_native_artifacts)] -pub struct StaticLibraryNativeArtifacts; - -#[derive(Diagnostic)] -#[diag(codegen_ssa_static_library_native_artifacts_to_file)] -pub struct StaticLibraryNativeArtifactsToFile<'a> { - pub path: &'a Path, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_link_script_unavailable)] -pub struct LinkScriptUnavailable; - -#[derive(Diagnostic)] -#[diag(codegen_ssa_link_script_write_failure)] -pub struct LinkScriptWriteFailure { - pub path: PathBuf, - pub error: Error, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_failed_to_write)] -pub struct FailedToWrite { - pub path: PathBuf, - pub error: Error, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_unable_to_write_debugger_visualizer)] -pub struct UnableToWriteDebuggerVisualizer { - pub path: PathBuf, - pub error: Error, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_rlib_archive_build_failure)] -pub struct RlibArchiveBuildFailure { - pub error: Error, -} - -#[derive(Diagnostic)] -pub enum ExtractBundledLibsError<'a> { - #[diag(codegen_ssa_extract_bundled_libs_open_file)] - OpenFile { rlib: &'a Path, error: Box }, - - #[diag(codegen_ssa_extract_bundled_libs_mmap_file)] - MmapFile { rlib: &'a Path, error: Box }, - - #[diag(codegen_ssa_extract_bundled_libs_parse_archive)] - ParseArchive { rlib: &'a Path, error: Box }, - - #[diag(codegen_ssa_extract_bundled_libs_read_entry)] - ReadEntry { rlib: &'a Path, error: Box }, - - #[diag(codegen_ssa_extract_bundled_libs_archive_member)] - ArchiveMember { rlib: &'a Path, error: Box }, - - #[diag(codegen_ssa_extract_bundled_libs_convert_name)] - ConvertName { rlib: &'a Path, error: Box }, - - #[diag(codegen_ssa_extract_bundled_libs_write_file)] - WriteFile { rlib: &'a Path, error: Box }, - - #[diag(codegen_ssa_extract_bundled_libs_write_file)] - ExtractSection { rlib: &'a Path, error: Box }, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_unsupported_arch)] -pub struct UnsupportedArch<'a> { - pub arch: &'a str, - pub os: &'a str, -} - -#[derive(Diagnostic)] -pub enum AppleSdkRootError<'a> { - #[diag(codegen_ssa_apple_sdk_error_sdk_path)] - SdkPath { sdk_name: &'a str, error: Error }, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_read_file)] -pub struct ReadFileError { - pub message: std::io::Error, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_unsupported_link_self_contained)] -pub struct UnsupportedLinkSelfContained; - -#[derive(Diagnostic)] -#[diag(codegen_ssa_archive_build_failure)] -// Public for rustc_codegen_llvm::back::archive -pub struct ArchiveBuildFailure { - pub error: std::io::Error, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_unknown_archive_kind)] -// Public for rustc_codegen_llvm::back::archive -pub struct UnknownArchiveKind<'a> { - pub kind: &'a str, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_expected_coverage_symbol)] -pub struct ExpectedCoverageSymbol { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_expected_used_symbol)] -pub struct ExpectedUsedSymbol { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_multiple_main_functions)] -#[help] -pub struct MultipleMainFunctions { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_metadata_object_file_write)] -pub struct MetadataObjectFileWrite { - pub error: Error, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_invalid_windows_subsystem)] -pub struct InvalidWindowsSubsystem { - pub subsystem: Symbol, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_shuffle_indices_evaluation)] -pub struct ShuffleIndicesEvaluation { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_missing_memory_ordering)] -pub struct MissingMemoryOrdering; - -#[derive(Diagnostic)] -#[diag(codegen_ssa_unknown_atomic_ordering)] -pub struct UnknownAtomicOrdering; - -#[derive(Diagnostic)] -#[diag(codegen_ssa_atomic_compare_exchange)] -pub struct AtomicCompareExchange; - -#[derive(Diagnostic)] -#[diag(codegen_ssa_unknown_atomic_operation)] -pub struct UnknownAtomicOperation; - -#[derive(Diagnostic)] -pub enum InvalidMonomorphization<'tcx> { - #[diag(codegen_ssa_invalid_monomorphization_basic_integer_type, code = E0511)] - BasicIntegerType { - #[primary_span] - span: Span, - name: Symbol, - ty: Ty<'tcx>, - }, - - #[diag(codegen_ssa_invalid_monomorphization_basic_float_type, code = E0511)] - BasicFloatType { - #[primary_span] - span: Span, - name: Symbol, - ty: Ty<'tcx>, - }, - - #[diag(codegen_ssa_invalid_monomorphization_float_to_int_unchecked, code = E0511)] - FloatToIntUnchecked { - #[primary_span] - span: Span, - ty: Ty<'tcx>, - }, - - #[diag(codegen_ssa_invalid_monomorphization_floating_point_vector, code = E0511)] - FloatingPointVector { - #[primary_span] - span: Span, - name: Symbol, - f_ty: FloatTy, - in_ty: Ty<'tcx>, - }, - - #[diag(codegen_ssa_invalid_monomorphization_floating_point_type, code = E0511)] - FloatingPointType { - #[primary_span] - span: Span, - name: Symbol, - in_ty: Ty<'tcx>, - }, - - #[diag(codegen_ssa_invalid_monomorphization_unrecognized_intrinsic, code = E0511)] - UnrecognizedIntrinsic { - #[primary_span] - span: Span, - name: Symbol, - }, - - #[diag(codegen_ssa_invalid_monomorphization_simd_argument, code = E0511)] - SimdArgument { - #[primary_span] - span: Span, - name: Symbol, - ty: Ty<'tcx>, - }, - - #[diag(codegen_ssa_invalid_monomorphization_simd_input, code = E0511)] - SimdInput { - #[primary_span] - span: Span, - name: Symbol, - ty: Ty<'tcx>, - }, - - #[diag(codegen_ssa_invalid_monomorphization_simd_first, code = E0511)] - SimdFirst { - #[primary_span] - span: Span, - name: Symbol, - ty: Ty<'tcx>, - }, - - #[diag(codegen_ssa_invalid_monomorphization_simd_second, code = E0511)] - SimdSecond { - #[primary_span] - span: Span, - name: Symbol, - ty: Ty<'tcx>, - }, - - #[diag(codegen_ssa_invalid_monomorphization_simd_third, code = E0511)] - SimdThird { - #[primary_span] - span: Span, - name: Symbol, - ty: Ty<'tcx>, - }, - - #[diag(codegen_ssa_invalid_monomorphization_simd_return, code = E0511)] - SimdReturn { - #[primary_span] - span: Span, - name: Symbol, - ty: Ty<'tcx>, - }, - - #[diag(codegen_ssa_invalid_monomorphization_invalid_bitmask, code = E0511)] - InvalidBitmask { - #[primary_span] - span: Span, - name: Symbol, - mask_ty: Ty<'tcx>, - expected_int_bits: u64, - expected_bytes: u64, - }, - - #[diag(codegen_ssa_invalid_monomorphization_return_length_input_type, code = E0511)] - ReturnLengthInputType { - #[primary_span] - span: Span, - name: Symbol, - in_len: u64, - in_ty: Ty<'tcx>, - ret_ty: Ty<'tcx>, - out_len: u64, - }, - - #[diag(codegen_ssa_invalid_monomorphization_second_argument_length, code = E0511)] - SecondArgumentLength { - #[primary_span] - span: Span, - name: Symbol, - in_len: u64, - in_ty: Ty<'tcx>, - arg_ty: Ty<'tcx>, - out_len: u64, - }, - - #[diag(codegen_ssa_invalid_monomorphization_third_argument_length, code = E0511)] - ThirdArgumentLength { - #[primary_span] - span: Span, - name: Symbol, - in_len: u64, - in_ty: Ty<'tcx>, - arg_ty: Ty<'tcx>, - out_len: u64, - }, - - #[diag(codegen_ssa_invalid_monomorphization_return_integer_type, code = E0511)] - ReturnIntegerType { - #[primary_span] - span: Span, - name: Symbol, - ret_ty: Ty<'tcx>, - out_ty: Ty<'tcx>, - }, - - #[diag(codegen_ssa_invalid_monomorphization_simd_shuffle, code = E0511)] - SimdShuffle { - #[primary_span] - span: Span, - name: Symbol, - ty: Ty<'tcx>, - }, - - #[diag(codegen_ssa_invalid_monomorphization_return_length, code = E0511)] - ReturnLength { - #[primary_span] - span: Span, - name: Symbol, - in_len: u64, - ret_ty: Ty<'tcx>, - out_len: u64, - }, - - #[diag(codegen_ssa_invalid_monomorphization_return_element, code = E0511)] - ReturnElement { - #[primary_span] - span: Span, - name: Symbol, - in_elem: Ty<'tcx>, - in_ty: Ty<'tcx>, - ret_ty: Ty<'tcx>, - out_ty: Ty<'tcx>, - }, - - #[diag(codegen_ssa_invalid_monomorphization_simd_index_out_of_bounds, code = E0511)] - SimdIndexOutOfBounds { - #[primary_span] - span: Span, - name: Symbol, - arg_idx: u64, - total_len: u128, - }, - - #[diag(codegen_ssa_invalid_monomorphization_inserted_type, code = E0511)] - InsertedType { - #[primary_span] - span: Span, - name: Symbol, - in_elem: Ty<'tcx>, - in_ty: Ty<'tcx>, - out_ty: Ty<'tcx>, - }, - - #[diag(codegen_ssa_invalid_monomorphization_return_type, code = E0511)] - ReturnType { - #[primary_span] - span: Span, - name: Symbol, - in_elem: Ty<'tcx>, - in_ty: Ty<'tcx>, - ret_ty: Ty<'tcx>, - }, - - #[diag(codegen_ssa_invalid_monomorphization_expected_return_type, code = E0511)] - ExpectedReturnType { - #[primary_span] - span: Span, - name: Symbol, - in_ty: Ty<'tcx>, - ret_ty: Ty<'tcx>, - }, - - #[diag(codegen_ssa_invalid_monomorphization_mismatched_lengths, code = E0511)] - MismatchedLengths { - #[primary_span] - span: Span, - name: Symbol, - m_len: u64, - v_len: u64, - }, - - #[diag(codegen_ssa_invalid_monomorphization_mask_type, code = E0511)] - MaskType { - #[primary_span] - span: Span, - name: Symbol, - ty: Ty<'tcx>, - }, - - #[diag(codegen_ssa_invalid_monomorphization_vector_argument, code = E0511)] - VectorArgument { - #[primary_span] - span: Span, - name: Symbol, - in_ty: Ty<'tcx>, - in_elem: Ty<'tcx>, - }, - - #[diag(codegen_ssa_invalid_monomorphization_cannot_return, code = E0511)] - CannotReturn { - #[primary_span] - span: Span, - name: Symbol, - ret_ty: Ty<'tcx>, - expected_int_bits: u64, - expected_bytes: u64, - }, - - #[diag(codegen_ssa_invalid_monomorphization_expected_element_type, code = E0511)] - ExpectedElementType { - #[primary_span] - span: Span, - name: Symbol, - expected_element: Ty<'tcx>, - second_arg: Ty<'tcx>, - in_elem: Ty<'tcx>, - in_ty: Ty<'tcx>, - mutability: ExpectedPointerMutability, - }, - - #[diag(codegen_ssa_invalid_monomorphization_third_arg_element_type, code = E0511)] - ThirdArgElementType { - #[primary_span] - span: Span, - name: Symbol, - expected_element: Ty<'tcx>, - third_arg: Ty<'tcx>, - }, - - #[diag(codegen_ssa_invalid_monomorphization_unsupported_symbol_of_size, code = E0511)] - UnsupportedSymbolOfSize { - #[primary_span] - span: Span, - name: Symbol, - symbol: Symbol, - in_ty: Ty<'tcx>, - in_elem: Ty<'tcx>, - size: u64, - ret_ty: Ty<'tcx>, - }, - - #[diag(codegen_ssa_invalid_monomorphization_unsupported_symbol, code = E0511)] - UnsupportedSymbol { - #[primary_span] - span: Span, - name: Symbol, - symbol: Symbol, - in_ty: Ty<'tcx>, - in_elem: Ty<'tcx>, - ret_ty: Ty<'tcx>, - }, - - #[diag(codegen_ssa_invalid_monomorphization_cast_fat_pointer, code = E0511)] - CastFatPointer { - #[primary_span] - span: Span, - name: Symbol, - ty: Ty<'tcx>, - }, - - #[diag(codegen_ssa_invalid_monomorphization_expected_pointer, code = E0511)] - ExpectedPointer { - #[primary_span] - span: Span, - name: Symbol, - ty: Ty<'tcx>, - }, - - #[diag(codegen_ssa_invalid_monomorphization_expected_usize, code = E0511)] - ExpectedUsize { - #[primary_span] - span: Span, - name: Symbol, - ty: Ty<'tcx>, - }, - - #[diag(codegen_ssa_invalid_monomorphization_unsupported_cast, code = E0511)] - UnsupportedCast { - #[primary_span] - span: Span, - name: Symbol, - in_ty: Ty<'tcx>, - in_elem: Ty<'tcx>, - ret_ty: Ty<'tcx>, - out_elem: Ty<'tcx>, - }, - - #[diag(codegen_ssa_invalid_monomorphization_unsupported_operation, code = E0511)] - UnsupportedOperation { - #[primary_span] - span: Span, - name: Symbol, - in_ty: Ty<'tcx>, - in_elem: Ty<'tcx>, - }, - - #[diag(codegen_ssa_invalid_monomorphization_expected_vector_element_type, code = E0511)] - ExpectedVectorElementType { - #[primary_span] - span: Span, - name: Symbol, - expected_element: Ty<'tcx>, - vector_type: Ty<'tcx>, - }, -} - -pub enum ExpectedPointerMutability { - Mut, - Not, -} - -impl IntoDiagArg for ExpectedPointerMutability { - fn into_diag_arg(self) -> DiagArgValue { - match self { - ExpectedPointerMutability::Mut => DiagArgValue::Str(Cow::Borrowed("*mut")), - ExpectedPointerMutability::Not => DiagArgValue::Str(Cow::Borrowed("*_")), - } - } -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_invalid_no_sanitize)] -#[note] -pub struct InvalidNoSanitize { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_invalid_link_ordinal_nargs)] -#[note] -pub struct InvalidLinkOrdinalNargs { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_illegal_link_ordinal_format)] -#[note] -pub struct InvalidLinkOrdinalFormat { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_target_feature_safe_trait)] -pub struct TargetFeatureSafeTrait { - #[primary_span] - #[label] - pub span: Span, - #[label(codegen_ssa_label_def)] - pub def: Span, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_failed_to_get_layout)] -pub struct FailedToGetLayout<'tcx> { - #[primary_span] - pub span: Span, - pub ty: Ty<'tcx>, - pub err: LayoutError<'tcx>, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_error_creating_remark_dir)] -pub struct ErrorCreatingRemarkDir { - pub error: std::io::Error, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_compiler_builtins_cannot_call)] -pub struct CompilerBuiltinsCannotCall { - pub caller: String, - pub callee: String, -} +use crate::assert_module_sources::CguReuse;use crate::back::command::Command;//; +use crate::fluent_generated as fluent;use rustc_errors::{codes::*,Diag,//*&*&(); +DiagArgValue,DiagCtxt,Diagnostic,EmissionGuarantee,IntoDiagArg,Level,};use//{;}; +rustc_macros::Diagnostic;use rustc_middle::ty::layout::LayoutError;use//((),()); +rustc_middle::ty::Ty;use rustc_span::{Span,Symbol};use rustc_type_ir::FloatTy;// +use std::borrow::Cow;use std::io::Error; use std::path::{Path,PathBuf};use std:: +process::ExitStatus;#[derive(Diagnostic)]#[diag(//*&*&();((),());*&*&();((),()); +codegen_ssa_incorrect_cgu_reuse_type)]pub struct IncorrectCguReuseType<'a>{#[//; +primary_span]pub span:Span,pub cgu_user_name :&'a str,pub actual_reuse:CguReuse, +pub expected_reuse:CguReuse,pub at_least:u8,}#[derive(Diagnostic)]#[diag(//({}); +codegen_ssa_cgu_not_recorded)]pub struct CguNotRecorded <'a>{pub cgu_user_name:& +'a str,pub cgu_name:&'a str,}#[derive(Diagnostic)]#[diag(//if true{};let _=||(); +codegen_ssa_unknown_reuse_kind)]pub struct UnknownReuseKind{#[primary_span]pub// +span:Span,pub kind:Symbol,}#[derive(Diagnostic)]#[diag(//let _=||();loop{break}; +codegen_ssa_missing_query_depgraph)]pub struct MissingQueryDepGraph{#[//((),()); +primary_span]pub span:Span,}#[derive(Diagnostic)]#[diag(//let _=||();let _=||(); +codegen_ssa_malformed_cgu_name)]pub struct MalformedCguName{#[primary_span]pub// +span:Span,pub user_path:String,pub crate_name:String,}#[derive(Diagnostic)]#[//; +diag(codegen_ssa_no_module_named)]pub struct NoModuleNamed<'a>{#[primary_span]// +pub span:Span,pub user_path:&'a str ,pub cgu_name:Symbol,pub cgu_names:String,}# +[derive(Diagnostic)]#[diag(codegen_ssa_field_associated_value_expected)]pub//(); +struct FieldAssociatedValueExpected{#[primary_span]pub span:Span,pub name://{;}; +Symbol,}#[derive(Diagnostic)]#[ diag(codegen_ssa_no_field)]pub struct NoField{#[ +primary_span]pub span:Span,pub name:Symbol,}#[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(//((),());((),());((),());let _=(); +codegen_ssa_ld64_unimplemented_modifier)]pub struct Ld64UnimplementedModifier;# +[derive(Diagnostic)]#[diag(codegen_ssa_linker_unsupported_modifier)]pub struct// +LinkerUnsupportedModifier;#[derive(Diagnostic)]#[diag(//loop{break};loop{break}; +codegen_ssa_L4Bender_exporting_symbols_unimplemented)]pub struct//if let _=(){}; +L4BenderExportingSymbolsUnimplemented;#[derive(Diagnostic)]#[diag(//loop{break}; +codegen_ssa_no_natvis_directory)]pub struct NoNatvisDirectory {pub error:Error,} +#[derive(Diagnostic)]#[diag(codegen_ssa_no_saved_object_file)]pub struct//{();}; +NoSavedObjectFile<'a>{pub cgu_name:&'a str,}#[derive(Diagnostic)]#[diag(//{();}; +codegen_ssa_copy_path_buf)]pub struct CopyPathBuf{pub source_file:PathBuf,pub//; +output_path:PathBuf,pub error:Error,}#[derive(Diagnostic)]#[diag(//loop{break;}; +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 IntoDiagArg// +for DebugArgPath<'_>{fn into_diag_arg(self)->rustc_errors::DiagArgValue{//{();}; +DiagArgValue::Str((Cow::Owned(format!("{:?}",self.0))))}}#[derive(Diagnostic)]#[ +diag(codegen_ssa_binary_output_to_tty)]pub struct BinaryOutputToTty{pub//*&*&(); +shorthand:&'static str,}#[derive(Diagnostic)]#[diag(//loop{break;};loop{break;}; +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(//loop{break;}; +codegen_ssa_create_temp_dir)]pub struct CreateTempDir{ pub error:Error,}#[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(//if let _=(){};*&*&();((),()); +codegen_ssa_rlib_missing_format)]MissingFormat,#[diag(//loop{break};loop{break}; +codegen_ssa_rlib_only_rmeta_found)]OnlyRmetaFound{crate_name:Symbol},#[diag(//3; +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//((),());let _=(); +ThorinErrorWrapper(pub thorin::Error);impl Diagnostic<'_,G> +for ThorinErrorWrapper{fn into_diag(self,dcx:& DiagCtxt,level:Level)->Diag<'_,G> +{;let build=|msg|Diag::new(dcx,level,msg);match self.0{thorin::Error::ReadInput( +_)=>((((build(fluent::codegen_ssa_thorin_read_input_failure))))),thorin::Error:: +ParseFileKind(_)=>{(( build(fluent::codegen_ssa_thorin_parse_input_file_kind)))} +thorin::Error::ParseObjectFile(_)=>{build(fluent:://if let _=(){};if let _=(){}; +codegen_ssa_thorin_parse_input_object_file)}thorin::Error::ParseArchiveFile(_)// +=>{(build(fluent:: codegen_ssa_thorin_parse_input_archive_file))}thorin::Error:: +ParseArchiveMember(_)=>{ build(fluent::codegen_ssa_thorin_parse_archive_member)} +thorin::Error::InvalidInputKind=>build(fluent:://*&*&();((),());((),());((),()); +codegen_ssa_thorin_invalid_input_kind),thorin::Error:: DecompressData(_)=>build( +fluent::codegen_ssa_thorin_decompress_data),thorin::Error::NamelessSection(_,//; +offset)=>{(((build(fluent::codegen_ssa_thorin_section_without_name)))).with_arg( +"offset",format!("0x{offset:08x}") )}thorin::Error::RelocationWithInvalidSymbol( +section,offset)=>{build(fluent:://let _=||();loop{break};let _=||();loop{break}; +codegen_ssa_thorin_relocation_with_invalid_symbol).with_arg( "section",section). +with_arg("offset",format!( "0x{offset:08x}"))}thorin::Error::MultipleRelocations +(section,offset)=>{(((build(fluent::codegen_ssa_thorin_multiple_relocations)))). +with_arg("section",section).with_arg( "offset",format!("0x{offset:08x}"))}thorin +::Error::UnsupportedRelocation(section,offset)=>{build(fluent:://*&*&();((),()); +codegen_ssa_thorin_unsupported_relocation).with_arg( "section",section).with_arg +(("offset"),format!("0x{offset:08x}"))}thorin::Error::MissingDwoName(id)=>build( +fluent::codegen_ssa_thorin_missing_dwo_name).with_arg( "id",format!("0x{id:08x}" +)),thorin::Error::NoCompilationUnits=>{build(fluent:://loop{break};loop{break;}; +codegen_ssa_thorin_no_compilation_units)}thorin::Error::NoDie=>build(fluent:://; +codegen_ssa_thorin_no_die),thorin::Error::TopLevelDieNotUnit=>{build(fluent:://; +codegen_ssa_thorin_top_level_die_not_unit)}thorin::Error:://if true{};if true{}; +MissingRequiredSection(section)=>{build(fluent:://*&*&();((),());*&*&();((),()); +codegen_ssa_thorin_missing_required_section).with_arg( "section",section)}thorin +::Error::ParseUnitAbbreviations(_)=>{build(fluent:://loop{break;};if let _=(){}; +codegen_ssa_thorin_parse_unit_abbreviations)}thorin ::Error::ParseUnitAttribute( +_)=>{((build(fluent ::codegen_ssa_thorin_parse_unit_attribute)))}thorin::Error:: +ParseUnitHeader(_)=>{build (fluent::codegen_ssa_thorin_parse_unit_header)}thorin +::Error::ParseUnit(_)=>((build(fluent::codegen_ssa_thorin_parse_unit))),thorin:: +Error::IncompatibleIndexVersion(section,format,actual)=>{build(fluent:://*&*&(); +codegen_ssa_thorin_incompatible_index_version).with_arg((( "section")),section). +with_arg(((("actual"))),actual).with_arg( ((("format"))),format)}thorin::Error:: +OffsetAtIndex(_,index)=>{ ((build(fluent::codegen_ssa_thorin_offset_at_index))). +with_arg(("index"),index)}thorin::Error:: StrAtOffset(_,offset)=>{build(fluent:: +codegen_ssa_thorin_str_at_offset).with_arg("offset", format!("0x{offset:08x}"))} +thorin::Error::ParseIndex(_,section)=>{build(fluent:://loop{break};loop{break;}; +codegen_ssa_thorin_parse_index).with_arg((("section")) ,section)}thorin::Error:: +UnitNotInIndex(unit)=>{(( build(fluent::codegen_ssa_thorin_unit_not_in_index))). +with_arg("unit",format!("0x{unit:08x}")) }thorin::Error::RowNotInIndex(_,row)=>{ +build(fluent::codegen_ssa_thorin_row_not_in_index).with_arg( "row",row)}thorin:: +Error::SectionNotInRow=>(build (fluent::codegen_ssa_thorin_section_not_in_row)), +thorin::Error::EmptyUnit(unit)=> (build(fluent::codegen_ssa_thorin_empty_unit)). +with_arg((((((("unit")))))),((((((format!("0x{unit:08x}")))))))),thorin::Error:: +MultipleDebugInfoSection=>{build(fluent:://let _=();let _=();let _=();if true{}; +codegen_ssa_thorin_multiple_debug_info_section)}thorin::Error:://*&*&();((),()); +MultipleDebugTypesSection=>{build(fluent:://let _=();let _=();let _=();let _=(); +codegen_ssa_thorin_multiple_debug_types_section)}thorin::Error::NotSplitUnit=>// +build(fluent::codegen_ssa_thorin_not_split_unit),thorin::Error::DuplicateUnit(// +unit)=>build(fluent::codegen_ssa_thorin_duplicate_unit) .with_arg("unit",format! +("0x{unit:08x}")),thorin::Error::MissingReferencedUnit(unit)=>{build(fluent:://; +codegen_ssa_thorin_missing_referenced_unit).with_arg((((((("unit")))))),format!( +"0x{unit:08x}"))}thorin::Error::NoOutputObjectCreated=>{build(fluent:://((),()); +codegen_ssa_thorin_not_output_object_created)}thorin::Error:://((),());let _=(); +MixedInputEncodings=>{(build(fluent::codegen_ssa_thorin_mixed_input_encodings))} +thorin::Error::Io(e)=>{(build (fluent::codegen_ssa_thorin_io)).with_arg("error", +format!("{e}"))}thorin::Error::ObjectRead(e)=>{build(fluent:://((),());let _=(); +codegen_ssa_thorin_object_read).with_arg(("error"),format!("{e}"))}thorin::Error +::ObjectWrite(e)=>{((build (fluent::codegen_ssa_thorin_object_write))).with_arg( +"error",((((((format!("{e}"))))))))}thorin::Error::GimliRead(e)=>{build(fluent:: +codegen_ssa_thorin_gimli_read).with_arg("error",format !("{e}"))}thorin::Error:: +GimliWrite(e)=>{build(fluent ::codegen_ssa_thorin_gimli_write).with_arg("error", +format!("{e}"))}_=>((unimplemented!("Untranslated thorin error"))),}}}pub struct +LinkingFailed<'a>{pub linker_path:&'a PathBuf,pub exit_status:ExitStatus,pub//3; +command:&'a Command,pub escaped_output:String,}impl//{();}; +Diagnostic<'_,G>for LinkingFailed<'_>{fn into_diag(self,dcx:&DiagCtxt,level://3; +Level)->Diag<'_,G>{if true{};if true{};let mut diag=Diag::new(dcx,level,fluent:: +codegen_ssa_linking_failed);{();};({});diag.arg("linker_path",format!("{}",self. +linker_path.display()));;diag.arg("exit_status",format!("{}",self.exit_status)); +let contains_undefined_ref=self.escaped_output.contains(//let _=||();let _=||(); +"undefined reference to");3;3;diag.note(format!("{:?}",self.command)).note(self. +escaped_output);if true{};if contains_undefined_ref{if true{};diag.note(fluent:: +codegen_ssa_extern_funcs_not_found).note(fluent:://if let _=(){};*&*&();((),()); +codegen_ssa_specify_libraries_to_link);((),());((),());if rustc_session::utils:: +was_invoked_from_cargo(){;diag.note(fluent::codegen_ssa_use_cargo_directive);;}} +diag}}#[derive(Diagnostic)]#[diag(codegen_ssa_link_exe_unexpected_error)]pub//3; +struct LinkExeUnexpectedError;#[derive(Diagnostic)]#[diag(//if true{};if true{}; +codegen_ssa_repair_vs_build_tools)]pub struct RepairVSBuildTools;#[derive(//{;}; +Diagnostic)]#[diag(codegen_ssa_missing_cpp_build_tool_component)]pub struct//(); +MissingCppBuildToolComponent;#[derive(Diagnostic)]#[diag(//if true{};let _=||(); +codegen_ssa_select_cpp_build_tool_workload)]pub struct//loop{break};loop{break}; +SelectCppBuildToolWorkload;#[derive(Diagnostic)]#[diag(//let _=||();loop{break}; +codegen_ssa_visual_studio_not_installed)]pub struct VisualStudioNotInstalled;#[ +derive(Diagnostic)]#[diag(codegen_ssa_linker_not_found)]#[note]pub struct//({}); +LinkerNotFound{pub linker_path:PathBuf,pub error: Error,}#[derive(Diagnostic)]#[ +diag(codegen_ssa_unable_to_exe_linker)]#[note ]#[note(codegen_ssa_command_note)] +pub struct UnableToExeLinker{pub linker_path:PathBuf,pub error:Error,pub//{();}; +command_formatted:String,}#[derive(Diagnostic)]#[diag(//loop{break};loop{break}; +codegen_ssa_msvc_missing_linker)]pub struct MsvcMissingLinker;#[derive(//*&*&(); +Diagnostic)]#[diag(codegen_ssa_check_installed_visual_studio)]pub struct//{();}; +CheckInstalledVisualStudio;#[derive(Diagnostic)]#[diag(//let _=||();loop{break}; +codegen_ssa_insufficient_vs_code_product)]pub struct InsufficientVSCodeProduct; +#[derive(Diagnostic)]#[diag(codegen_ssa_processing_dymutil_failed)]#[note]pub//; +struct ProcessingDymutilFailed{pub status:ExitStatus,pub output:String,}#[//{;}; +derive(Diagnostic)]#[diag( codegen_ssa_unable_to_run_dsymutil)]#[note]pub struct +UnableToRunDsymutil{pub error:Error,}#[derive(Diagnostic)]#[diag(//loop{break;}; +codegen_ssa_stripping_debug_info_failed)]#[note]pub struct//if true{};if true{}; +StrippingDebugInfoFailed<'a>{pub util:&'a str,pub status:ExitStatus,pub output: +String,}#[derive(Diagnostic)]#[diag(codegen_ssa_unable_to_run)]pub struct//({}); +UnableToRun<'a>{pub util:&'a str,pub error:Error,}#[derive(Diagnostic)]#[diag(// +codegen_ssa_linker_file_stem)]pub struct LinkerFileStem; #[derive(Diagnostic)]#[ +diag(codegen_ssa_static_library_native_artifacts)]pub struct//let _=();let _=(); +StaticLibraryNativeArtifacts;#[derive(Diagnostic)]#[diag(//if true{};let _=||(); +codegen_ssa_static_library_native_artifacts_to_file)]pub struct//*&*&();((),()); +StaticLibraryNativeArtifactsToFile<'a>{pub path:&'a Path,}#[derive(Diagnostic)] +#[diag(codegen_ssa_link_script_unavailable)] pub struct LinkScriptUnavailable;#[ +derive(Diagnostic)]#[diag(codegen_ssa_link_script_write_failure)]pub struct//(); +LinkScriptWriteFailure{pub path:PathBuf,pub error :Error,}#[derive(Diagnostic)]# +[diag(codegen_ssa_failed_to_write)]pub struct FailedToWrite{pub path:PathBuf,//; +pub error:Error,}#[derive(Diagnostic)]#[diag(//((),());((),());((),());let _=(); +codegen_ssa_unable_to_write_debugger_visualizer)]pub struct//let _=();if true{}; +UnableToWriteDebuggerVisualizer{pub path:PathBuf,pub error:Error,}#[derive(//(); +Diagnostic)]#[diag(codegen_ssa_rlib_archive_build_failure)]pub struct//let _=(); +RlibArchiveBuildFailure{pub error:Error,}#[derive(Diagnostic)]pub enum//((),()); +ExtractBundledLibsError<'a>{# [diag(codegen_ssa_extract_bundled_libs_open_file)] +OpenFile{rlib:&'a Path,error:Box},#[diag(//if let _=(){}; +codegen_ssa_extract_bundled_libs_mmap_file)]MmapFile{rlib:&'a Path,error:Box },#[diag(codegen_ssa_extract_bundled_libs_parse_archive)] +ParseArchive{rlib:&'a Path,error:Box},#[diag(//if true{}; +codegen_ssa_extract_bundled_libs_read_entry)]ReadEntry{rlib:& 'a Path,error:Box< +dyn std::error::Error> },#[diag(codegen_ssa_extract_bundled_libs_archive_member) +]ArchiveMember{rlib:&'a Path,error:Box},#[diag(//((),()); +codegen_ssa_extract_bundled_libs_convert_name)]ConvertName{rlib: &'a Path,error: +Box},#[diag(codegen_ssa_extract_bundled_libs_write_file) +]WriteFile{rlib:&'a Path,error:Box},#[diag(//loop{break}; +codegen_ssa_extract_bundled_libs_write_file)]ExtractSection{rlib :&'a Path,error +:Box},}#[derive(Diagnostic)]#[diag(//if true{};if true{}; +codegen_ssa_unsupported_arch)]pub struct UnsupportedArch<'a>{pub arch:&'a str,// +pub os:&'a str,}#[derive(Diagnostic)]pub enum AppleSdkRootError<'a>{#[diag(//(); +codegen_ssa_apple_sdk_error_sdk_path)]SdkPath{sdk_name:&'a str,error:Error},}#[ +derive(Diagnostic)]#[diag(codegen_ssa_read_file)]pub struct ReadFileError{pub//; +message:std::io::Error,}#[derive(Diagnostic)]#[diag(//loop{break;};loop{break;}; +codegen_ssa_unsupported_link_self_contained)]pub struct//let _=||();loop{break}; +UnsupportedLinkSelfContained;#[derive(Diagnostic)]#[diag(//if true{};let _=||(); +codegen_ssa_archive_build_failure)]pub struct ArchiveBuildFailure{pub error:std +::io::Error,}#[derive(Diagnostic)]#[diag(codegen_ssa_unknown_archive_kind)]pub// +struct UnknownArchiveKind<'a>{pub kind:&'a str,}#[derive(Diagnostic)]#[diag(//3; +codegen_ssa_expected_coverage_symbol)]pub struct ExpectedCoverageSymbol{#[//{;}; +primary_span]pub span:Span,}#[derive(Diagnostic)]#[diag(//let _=||();let _=||(); +codegen_ssa_expected_used_symbol)]pub struct ExpectedUsedSymbol{#[primary_span] +pub span:Span,}#[derive (Diagnostic)]#[diag(codegen_ssa_multiple_main_functions) +]#[help]pub struct MultipleMainFunctions{# [primary_span]pub span:Span,}#[derive +(Diagnostic)]#[diag(codegen_ssa_metadata_object_file_write)]pub struct//((),()); +MetadataObjectFileWrite{pub error:Error,}#[derive(Diagnostic)]#[diag(//let _=(); +codegen_ssa_invalid_windows_subsystem)]pub struct InvalidWindowsSubsystem{pub//; +subsystem:Symbol,}#[derive(Diagnostic)]#[diag(//((),());((),());((),());((),()); +codegen_ssa_shuffle_indices_evaluation)]pub struct ShuffleIndicesEvaluation{#[// +primary_span]pub span:Span,}#[derive(Diagnostic)]#[diag(//let _=||();let _=||(); +codegen_ssa_missing_memory_ordering)]pub struct MissingMemoryOrdering;#[derive( +Diagnostic)]#[diag(codegen_ssa_unknown_atomic_ordering)]pub struct//loop{break}; +UnknownAtomicOrdering;#[derive(Diagnostic)]#[diag(//if let _=(){};if let _=(){}; +codegen_ssa_atomic_compare_exchange)]pub struct AtomicCompareExchange;#[derive( +Diagnostic)]#[diag(codegen_ssa_unknown_atomic_operation)]pub struct//let _=||(); +UnknownAtomicOperation;#[derive(Diagnostic)]pub enum InvalidMonomorphization{#[diag (codegen_ssa_invalid_monomorphization_basic_integer_type,code=E0511 +)]BasicIntegerType{#[primary_span]span:Span,name:Symbol,ty:Ty<'tcx>,},#[diag(//; +codegen_ssa_invalid_monomorphization_basic_float_type,code=E0511)]//loop{break}; +BasicFloatType{#[primary_span]span:Span,name:Symbol,ty:Ty<'tcx>,},#[diag(//({}); +codegen_ssa_invalid_monomorphization_float_to_int_unchecked,code=E0511)]//{();}; +FloatToIntUnchecked{#[primary_span]span:Span,ty:Ty<'tcx>,},#[diag(//loop{break}; +codegen_ssa_invalid_monomorphization_floating_point_vector,code=E0511)]//*&*&(); +FloatingPointVector{#[primary_span]span:Span,name :Symbol,f_ty:FloatTy,in_ty:Ty< +'tcx>,},#[diag(codegen_ssa_invalid_monomorphization_floating_point_type,code=//; +E0511)]FloatingPointType{#[primary_span]span:Span, name:Symbol,in_ty:Ty<'tcx>,}, +#[diag(codegen_ssa_invalid_monomorphization_unrecognized_intrinsic ,code=E0511)] +UnrecognizedIntrinsic{#[primary_span]span:Span,name:Symbol,},#[diag(//if true{}; +codegen_ssa_invalid_monomorphization_simd_argument,code=E0511)]SimdArgument{#[// +primary_span]span:Span,name:Symbol,ty:Ty<'tcx>,},#[diag(//let _=||();let _=||(); +codegen_ssa_invalid_monomorphization_simd_input,code=E0511)]SimdInput{#[//{();}; +primary_span]span:Span,name:Symbol,ty:Ty<'tcx>,},#[diag(//let _=||();let _=||(); +codegen_ssa_invalid_monomorphization_simd_first,code=E0511)]SimdFirst{#[//{();}; +primary_span]span:Span,name:Symbol,ty:Ty<'tcx>,},#[diag(//let _=||();let _=||(); +codegen_ssa_invalid_monomorphization_simd_second,code=E0511)]SimdSecond{#[//{;}; +primary_span]span:Span,name:Symbol,ty:Ty<'tcx>,},#[diag(//let _=||();let _=||(); +codegen_ssa_invalid_monomorphization_simd_third,code=E0511)]SimdThird{#[//{();}; +primary_span]span:Span,name:Symbol,ty:Ty<'tcx>,},#[diag(//let _=||();let _=||(); +codegen_ssa_invalid_monomorphization_simd_return,code=E0511)]SimdReturn{#[//{;}; +primary_span]span:Span,name:Symbol,ty:Ty<'tcx>,},#[diag(//let _=||();let _=||(); +codegen_ssa_invalid_monomorphization_invalid_bitmask,code= E0511)]InvalidBitmask +{#[primary_span]span:Span,name:Symbol,mask_ty:Ty<'tcx>,expected_int_bits:u64,//; +expected_bytes:u64,},#[diag(//loop{break};loop{break;};loop{break};loop{break;}; +codegen_ssa_invalid_monomorphization_return_length_input_type,code=E0511)]//{;}; +ReturnLengthInputType{#[primary_span]span:Span,name :Symbol,in_len:u64,in_ty:Ty< +'tcx>,ret_ty:Ty<'tcx>,out_len:u64,},#[diag(//((),());let _=();let _=();let _=(); +codegen_ssa_invalid_monomorphization_second_argument_length,code=E0511)]//{();}; +SecondArgumentLength{#[primary_span]span:Span,name:Symbol,in_len:u64,in_ty:Ty,arg_ty:Ty<'tcx>,out_len:u64,},#[diag(//((),());let _=();let _=();let _=(); +codegen_ssa_invalid_monomorphization_third_argument_length,code=E0511)]//*&*&(); +ThirdArgumentLength{#[primary_span]span:Span,name:Symbol,in_len:u64,in_ty:Ty,arg_ty:Ty<'tcx>,out_len:u64,},#[diag(//((),());let _=();let _=();let _=(); +codegen_ssa_invalid_monomorphization_return_integer_type,code=E0511)]//let _=(); +ReturnIntegerType{#[primary_span]span:Span,name:Symbol,ret_ty:Ty<'tcx>,out_ty:// +Ty<'tcx>,},# [diag(codegen_ssa_invalid_monomorphization_simd_shuffle,code=E0511) +]SimdShuffle{#[primary_span]span:Span,name:Symbol,ty:Ty<'tcx>,},#[diag(//*&*&(); +codegen_ssa_invalid_monomorphization_return_length,code=E0511)]ReturnLength{#[// +primary_span]span:Span,name:Symbol,in_len:u64,ret_ty:Ty<'tcx>,out_len:u64,},#[// +diag(codegen_ssa_invalid_monomorphization_return_element,code=E0511)]//let _=(); +ReturnElement{#[primary_span]span:Span,name:Symbol,in_elem:Ty<'tcx>,in_ty:Ty,ret_ty:Ty<'tcx>,out_ty:Ty<'tcx>,},#[diag(//*&*&();((),());((),());((),()); +codegen_ssa_invalid_monomorphization_simd_index_out_of_bounds,code=E0511)]//{;}; +SimdIndexOutOfBounds{#[primary_span]span:Span ,name:Symbol,arg_idx:u64,total_len +:u128,},#[diag(codegen_ssa_invalid_monomorphization_inserted_type,code=E0511)]// +InsertedType{#[primary_span]span:Span,name:Symbol,in_elem:Ty<'tcx>,in_ty:Ty,out_ty:Ty<'tcx >,},#[diag(codegen_ssa_invalid_monomorphization_return_type +,code=E0511)]ReturnType{#[primary_span]span:Span,name:Symbol,in_elem:Ty<'tcx>,// +in_ty:Ty<'tcx>,ret_ty:Ty<'tcx>,},#[diag(//let _=();if true{};let _=();if true{}; +codegen_ssa_invalid_monomorphization_expected_return_type,code=E0511)]//((),()); +ExpectedReturnType{#[primary_span]span:Span,name:Symbol,in_ty:Ty<'tcx>,ret_ty:// +Ty<'tcx>,}, #[diag(codegen_ssa_invalid_monomorphization_mismatched_lengths,code= +E0511)]MismatchedLengths{#[primary_span]span:Span,name:Symbol,m_len:u64,v_len:// +u64,},#[diag(codegen_ssa_invalid_monomorphization_mask_type,code=E0511)]//{();}; +MaskType{#[primary_span]span:Span,name:Symbol,ty:Ty<'tcx>,},#[diag(//let _=||(); +codegen_ssa_invalid_monomorphization_vector_argument,code= E0511)]VectorArgument +{#[primary_span]span:Span,name:Symbol,in_ty:Ty <'tcx>,in_elem:Ty<'tcx>,},#[diag( +codegen_ssa_invalid_monomorphization_cannot_return,code=E0511)]CannotReturn{#[// +primary_span]span:Span,name:Symbol,ret_ty:Ty<'tcx>,expected_int_bits:u64,//({}); +expected_bytes:u64,},#[diag(//loop{break};loop{break;};loop{break};loop{break;}; +codegen_ssa_invalid_monomorphization_expected_element_type,code=E0511)]//*&*&(); +ExpectedElementType{#[primary_span]span:Span,name:Symbol,expected_element:Ty,second_arg:Ty<'tcx>,in_elem:Ty<'tcx>,in_ty:Ty<'tcx>,mutability://let _=(); +ExpectedPointerMutability,},#[diag(//if true{};let _=||();let _=||();let _=||(); +codegen_ssa_invalid_monomorphization_third_arg_element_type,code=E0511)]//{();}; +ThirdArgElementType{#[primary_span]span:Span,name:Symbol,expected_element:Ty,third_arg:Ty<'tcx>,},#[diag(//let _=||();let _=||();let _=||();let _=||(); +codegen_ssa_invalid_monomorphization_unsupported_symbol_of_size,code=E0511)]//3; +UnsupportedSymbolOfSize{#[primary_span]span:Span,name:Symbol,symbol:Symbol,//(); +in_ty:Ty<'tcx>,in_elem:Ty<'tcx>,size:u64,ret_ty:Ty<'tcx>,},#[diag(//loop{break}; +codegen_ssa_invalid_monomorphization_unsupported_symbol,code=E0511)]//if true{}; +UnsupportedSymbol{#[primary_span]span:Span,name:Symbol,symbol:Symbol,in_ty:Ty,in_elem:Ty<'tcx>,ret_ty:Ty<'tcx>,},#[diag(//*&*&();((),());*&*&();((),()); +codegen_ssa_invalid_monomorphization_cast_fat_pointer,code=E0511)]//loop{break}; +CastFatPointer{#[primary_span]span:Span,name:Symbol,ty:Ty<'tcx>,},#[diag(//({}); +codegen_ssa_invalid_monomorphization_expected_pointer,code=E0511)]//loop{break}; +ExpectedPointer{#[primary_span]span:Span,name:Symbol,ty:Ty<'tcx>,},#[diag(//{;}; +codegen_ssa_invalid_monomorphization_expected_usize,code=E0511 )]ExpectedUsize{# +[primary_span]span:Span,name:Symbol,ty:Ty<'tcx>,},#[diag(//if true{};let _=||(); +codegen_ssa_invalid_monomorphization_unsupported_cast,code=E0511)]//loop{break}; +UnsupportedCast{#[primary_span]span:Span,name: Symbol,in_ty:Ty<'tcx>,in_elem:Ty< +'tcx>,ret_ty:Ty<'tcx>,out_elem:Ty<'tcx>,},#[diag(//if let _=(){};*&*&();((),()); +codegen_ssa_invalid_monomorphization_unsupported_operation,code=E0511)]//*&*&(); +UnsupportedOperation{#[primary_span]span:Span,name:Symbol,in_ty:Ty<'tcx>,//({}); +in_elem:Ty<'tcx>,},#[diag(//loop{break;};loop{break;};loop{break;};loop{break;}; +codegen_ssa_invalid_monomorphization_expected_vector_element_type,code=E0511)]// +ExpectedVectorElementType{#[primary_span]span :Span,name:Symbol,expected_element +:Ty<'tcx>,vector_type:Ty<'tcx>,},}pub enum ExpectedPointerMutability{Mut,Not,}// +impl IntoDiagArg for ExpectedPointerMutability{fn into_diag_arg(self)->//*&*&(); +DiagArgValue{match self{ExpectedPointerMutability::Mut =>DiagArgValue::Str(Cow:: +Borrowed(((("*mut"))))),ExpectedPointerMutability ::Not=>DiagArgValue::Str(Cow:: +Borrowed("*_")),}}} #[derive(Diagnostic)]#[diag(codegen_ssa_invalid_no_sanitize) +]#[note]pub struct InvalidNoSanitize{#[primary_span]pub span:Span,}#[derive(//3; +Diagnostic)]#[diag(codegen_ssa_invalid_link_ordinal_nargs)]#[note]pub struct//3; +InvalidLinkOrdinalNargs{#[primary_span]pub span:Span,}#[derive(Diagnostic)]#[//; +diag(codegen_ssa_illegal_link_ordinal_format)]#[note]pub struct//*&*&();((),()); +InvalidLinkOrdinalFormat{#[primary_span]pub span:Span,}#[derive(Diagnostic)]#[// +diag(codegen_ssa_target_feature_safe_trait)]pub struct TargetFeatureSafeTrait{# +[primary_span]#[label]pub span:Span ,#[label(codegen_ssa_label_def)]pub def:Span +,}#[derive(Diagnostic)]#[diag(codegen_ssa_failed_to_get_layout)]pub struct//{;}; +FailedToGetLayout<'tcx>{#[primary_span]pub span:Span,pub ty:Ty<'tcx>,pub err://; +LayoutError<'tcx>,}#[derive(Diagnostic)]#[diag(//*&*&();((),());((),());((),()); +codegen_ssa_error_creating_remark_dir)]pub struct ErrorCreatingRemarkDir{pub//3; +error:std::io::Error,}#[derive(Diagnostic)]#[diag(//if let _=(){};if let _=(){}; +codegen_ssa_compiler_builtins_cannot_call)]pub struct//loop{break};loop{break;}; +CompilerBuiltinsCannotCall{pub caller:String,pub callee:String,}//if let _=(){}; diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 9be8dcf166d40..1049e383bf6f4 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -1,269 +1,85 @@ -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] -#![doc(rust_logo)] -#![feature(rustdoc_internals)] -#![allow(internal_features)] -#![allow(rustc::diagnostic_outside_of_impl)] -#![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(bootstrap, feature(associated_type_bounds))] -#![feature(box_patterns)] -#![feature(if_let_guard)] -#![feature(let_chains)] -#![feature(negative_impls)] -#![feature(strict_provenance)] -#![feature(try_blocks)] - -//! This crate contains codegen code that is used by all codegen backends (LLVM and others). -//! The backend-agnostic functions of this crate use functions defined in various traits that -//! have to be implemented by each backend. - -#[macro_use] -extern crate rustc_macros; -#[macro_use] -extern crate tracing; -#[macro_use] -extern crate rustc_middle; - -use rustc_ast as ast; -use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::fx::FxIndexMap; -use rustc_data_structures::sync::Lrc; -use rustc_data_structures::unord::UnordMap; -use rustc_hir::def_id::CrateNum; -use rustc_middle::dep_graph::WorkProduct; -use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; -use rustc_middle::middle::dependency_format::Dependencies; -use rustc_middle::middle::exported_symbols::SymbolExportKind; -use rustc_middle::util::Providers; -use rustc_serialize::opaque::{FileEncoder, MemDecoder}; -use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; -use rustc_session::config::{CrateType, OutputFilenames, OutputType, RUST_CGU_EXT}; -use rustc_session::cstore::{self, CrateSource}; -use rustc_session::utils::NativeLibKind; -use rustc_session::Session; -use rustc_span::symbol::Symbol; -use std::collections::BTreeSet; -use std::io; -use std::path::{Path, PathBuf}; - -pub mod assert_module_sources; -pub mod back; -pub mod base; -pub mod codegen_attrs; -pub mod common; -pub mod debuginfo; -pub mod errors; -pub mod meth; -pub mod mir; -pub mod mono_item; -pub mod size_of_val; -pub mod target_features; -pub mod traits; - -rustc_fluent_macro::fluent_messages! { "../messages.ftl" } - -pub struct ModuleCodegen { - /// The name of the module. When the crate may be saved between - /// compilations, incremental compilation requires that name be - /// unique amongst **all** crates. Therefore, it should contain - /// something unique to this crate (e.g., a module path) as well - /// as the crate name and disambiguator. - /// We currently generate these names via CodegenUnit::build_cgu_name(). - pub name: String, - pub module_llvm: M, - pub kind: ModuleKind, -} - -impl ModuleCodegen { - pub fn into_compiled_module( - self, - emit_obj: bool, - emit_dwarf_obj: bool, - emit_bc: bool, - outputs: &OutputFilenames, - ) -> CompiledModule { - let object = emit_obj.then(|| outputs.temp_path(OutputType::Object, Some(&self.name))); - let dwarf_object = emit_dwarf_obj.then(|| outputs.temp_path_dwo(Some(&self.name))); - let bytecode = emit_bc.then(|| outputs.temp_path(OutputType::Bitcode, Some(&self.name))); - - CompiledModule { name: self.name.clone(), kind: self.kind, object, dwarf_object, bytecode } - } -} - -#[derive(Debug, Encodable, Decodable)] -pub struct CompiledModule { - pub name: String, - pub kind: ModuleKind, - pub object: Option, - pub dwarf_object: Option, - pub bytecode: Option, -} - -pub struct CachedModuleCodegen { - pub name: String, - pub source: WorkProduct, -} - -#[derive(Copy, Clone, Debug, PartialEq, Encodable, Decodable)] -pub enum ModuleKind { - Regular, - Metadata, - Allocator, -} - -bitflags::bitflags! { - #[derive(Debug, Clone, Copy, PartialEq, Eq)] - pub struct MemFlags: u8 { - const VOLATILE = 1 << 0; - const NONTEMPORAL = 1 << 1; - const UNALIGNED = 1 << 2; - } -} - -#[derive(Clone, Debug, Encodable, Decodable, HashStable)] -pub struct NativeLib { - pub kind: NativeLibKind, - pub name: Symbol, - pub filename: Option, - pub cfg: Option, - pub verbatim: bool, - pub dll_imports: Vec, -} - -impl From<&cstore::NativeLib> for NativeLib { - fn from(lib: &cstore::NativeLib) -> Self { - NativeLib { - kind: lib.kind, - filename: lib.filename, - name: lib.name, - cfg: lib.cfg.clone(), - verbatim: lib.verbatim.unwrap_or(false), - dll_imports: lib.dll_imports.clone(), - } - } -} - -/// Misc info we load from metadata to persist beyond the tcx. -/// -/// Note: though `CrateNum` is only meaningful within the same tcx, information within `CrateInfo` -/// is self-contained. `CrateNum` can be viewed as a unique identifier within a `CrateInfo`, where -/// `used_crate_source` contains all `CrateSource` of the dependents, and maintains a mapping from -/// identifiers (`CrateNum`) to `CrateSource`. The other fields map `CrateNum` to the crate's own -/// additional properties, so that effectively we can retrieve each dependent crate's `CrateSource` -/// and the corresponding properties without referencing information outside of a `CrateInfo`. -#[derive(Debug, Encodable, Decodable)] -pub struct CrateInfo { - pub target_cpu: String, - pub crate_types: Vec, - pub exported_symbols: UnordMap>, - pub linked_symbols: FxIndexMap>, - pub local_crate_name: Symbol, - pub compiler_builtins: Option, - pub profiler_runtime: Option, - pub is_no_builtins: FxHashSet, - pub native_libraries: FxIndexMap>, - pub crate_name: UnordMap, - pub used_libraries: Vec, - pub used_crate_source: UnordMap>, - pub used_crates: Vec, - pub dependency_formats: Lrc, - pub windows_subsystem: Option, - pub natvis_debugger_visualizers: BTreeSet, -} - -#[derive(Encodable, Decodable)] -pub struct CodegenResults { - pub modules: Vec, - pub allocator_module: Option, - pub metadata_module: Option, - pub metadata: rustc_metadata::EncodedMetadata, - pub crate_info: CrateInfo, -} - -pub enum CodegenErrors { - WrongFileType, - EmptyVersionNumber, - EncodingVersionMismatch { version_array: String, rlink_version: u32 }, - RustcVersionMismatch { rustc_version: String }, -} - -pub fn provide(providers: &mut Providers) { - crate::back::symbol_export::provide(providers); - crate::base::provide(providers); - crate::target_features::provide(providers); - crate::codegen_attrs::provide(providers); -} - -/// Checks if the given filename ends with the `.rcgu.o` extension that `rustc` -/// uses for the object files it generates. -pub fn looks_like_rust_object_file(filename: &str) -> bool { - let path = Path::new(filename); - let ext = path.extension().and_then(|s| s.to_str()); - if ext != Some(OutputType::Object.extension()) { - // The file name does not end with ".o", so it can't be an object file. - return false; - } - - // Strip the ".o" at the end - let ext2 = path.file_stem().and_then(|s| Path::new(s).extension()).and_then(|s| s.to_str()); - - // Check if the "inner" extension - ext2 == Some(RUST_CGU_EXT) -} - -const RLINK_VERSION: u32 = 1; -const RLINK_MAGIC: &[u8] = b"rustlink"; - -impl CodegenResults { - pub fn serialize_rlink( - sess: &Session, - rlink_file: &Path, - codegen_results: &CodegenResults, - outputs: &OutputFilenames, - ) -> Result { - let mut encoder = FileEncoder::new(rlink_file)?; - encoder.emit_raw_bytes(RLINK_MAGIC); - // `emit_raw_bytes` is used to make sure that the version representation does not depend on - // Encoder's inner representation of `u32`. - encoder.emit_raw_bytes(&RLINK_VERSION.to_be_bytes()); - encoder.emit_str(sess.cfg_version); - Encodable::encode(codegen_results, &mut encoder); - Encodable::encode(outputs, &mut encoder); - encoder.finish().map_err(|(_path, err)| err) - } - - pub fn deserialize_rlink( - sess: &Session, - data: Vec, - ) -> Result<(Self, OutputFilenames), CodegenErrors> { - // The Decodable machinery is not used here because it panics if the input data is invalid - // and because its internal representation may change. - if !data.starts_with(RLINK_MAGIC) { - return Err(CodegenErrors::WrongFileType); - } - let data = &data[RLINK_MAGIC.len()..]; - if data.len() < 4 { - return Err(CodegenErrors::EmptyVersionNumber); - } - - let mut version_array: [u8; 4] = Default::default(); - version_array.copy_from_slice(&data[..4]); - if u32::from_be_bytes(version_array) != RLINK_VERSION { - return Err(CodegenErrors::EncodingVersionMismatch { - version_array: String::from_utf8_lossy(&version_array).to_string(), - rlink_version: RLINK_VERSION, - }); - } - - let mut decoder = MemDecoder::new(&data[4..], 0); - let rustc_version = decoder.read_str(); - if rustc_version != sess.cfg_version { - return Err(CodegenErrors::RustcVersionMismatch { - rustc_version: rustc_version.to_string(), - }); - } - - let codegen_results = CodegenResults::decode(&mut decoder); - let outputs = OutputFilenames::decode(&mut decoder); - Ok((codegen_results, outputs)) - } -} +#![doc(html_root_url= "https://doc.rust-lang.org/nightly/nightly-rustc/")]#![doc +(rust_logo)]#![feature(rustdoc_internals)] #![allow(internal_features)]#![allow( +rustc::diagnostic_outside_of_impl)]#![ allow(rustc::untranslatable_diagnostic)]# +![cfg_attr(bootstrap,feature(associated_type_bounds) )]#![feature(box_patterns)] +#![feature(if_let_guard)]#![feature(let_chains)]#![feature(negative_impls)]#![// +feature(strict_provenance)]#![feature(try_blocks)]#[macro_use]extern crate//{;}; +rustc_macros;#[macro_use]extern crate tracing;#[macro_use]extern crate//((),()); +rustc_middle;use rustc_ast as ast;use rustc_data_structures::fx::FxHashSet;use// +rustc_data_structures::fx::FxIndexMap;use rustc_data_structures::sync::Lrc;use// +rustc_data_structures::unord::UnordMap;use rustc_hir::def_id::CrateNum;use//{;}; +rustc_middle::dep_graph::WorkProduct;use rustc_middle::middle:://*&*&();((),()); +debugger_visualizer::DebuggerVisualizerFile;use rustc_middle::middle:://((),()); +dependency_format::Dependencies;use rustc_middle::middle::exported_symbols:://3; +SymbolExportKind;use rustc_middle::util::Providers;use rustc_serialize::opaque// +::{FileEncoder,MemDecoder};use rustc_serialize::{Decodable,Decoder,Encodable,//; +Encoder};use rustc_session::config::{CrateType,OutputFilenames,OutputType,//{;}; +RUST_CGU_EXT};use rustc_session::cstore:: {self,CrateSource};use rustc_session:: +utils::NativeLibKind;use rustc_session::Session ;use rustc_span::symbol::Symbol; +use std::collections::BTreeSet;use std::io;use std::path::{Path,PathBuf};pub//3; +mod assert_module_sources;pub mod back;pub mod base;pub mod codegen_attrs;pub//; +mod common;pub mod debuginfo;pub mod errors;pub mod meth;pub mod mir;pub mod//3; +mono_item;pub mod size_of_val;pub mod target_features;pub mod traits;//let _=(); +rustc_fluent_macro::fluent_messages!{"../messages.ftl" }pub struct ModuleCodegen +{pub name:String,pub module_llvm: M,pub kind:ModuleKind,}implModuleCodegen +{pub fn into_compiled_module(self ,emit_obj:bool,emit_dwarf_obj:bool,emit_bc: +bool,outputs:&OutputFilenames,)->CompiledModule{({});let object=emit_obj.then(|| +outputs.temp_path(OutputType::Object,Some(&self.name)));{;};();let dwarf_object= +emit_dwarf_obj.then(||outputs.temp_path_dwo(Some(&self.name)));3;3;let bytecode= +emit_bc.then(||outputs.temp_path(OutputType::Bitcode,Some(&self.name)));((),()); +CompiledModule{name:(((self.name.clone() ))),kind:self.kind,object,dwarf_object, +bytecode}}}#[derive(Debug,Encodable,Decodable)]pub struct CompiledModule{pub//3; +name:String,pub kind:ModuleKind,pub object:Option,pub dwarf_object://3; +Option,pub bytecode:Option,}pub struct CachedModuleCodegen{//; +pub name:String,pub source:WorkProduct,}#[derive(Copy,Clone,Debug,PartialEq,//3; +Encodable,Decodable)]pub enum ModuleKind {Regular,Metadata,Allocator,}bitflags:: +bitflags!{#[derive(Debug,Clone,Copy,PartialEq,Eq)]pub struct MemFlags:u8{const// +VOLATILE=1<<0;const NONTEMPORAL=1<<1;const UNALIGNED=1<<2;}}#[derive(Clone,//(); +Debug,Encodable,Decodable,HashStable)]pub struct NativeLib{pub kind://if true{}; +NativeLibKind,pub name:Symbol,pub filename:Option,pub cfg:Option,pub verbatim:bool,pub dll_imports: Vec,}impl From<& +cstore::NativeLib>for NativeLib{fn from( lib:&cstore::NativeLib)->Self{NativeLib +{kind:lib.kind,filename:lib.filename,name:lib .name,cfg:lib.cfg.clone(),verbatim +:lib.verbatim.unwrap_or(false),dll_imports: lib.dll_imports.clone(),}}}#[derive( +Debug,Encodable,Decodable)]pub struct CrateInfo{pub target_cpu:String,pub//({}); +crate_types:Vec,pub exported_symbols:UnordMap> +,pub linked_symbols:FxIndexMap>,pub//3; +local_crate_name:Symbol,pub compiler_builtins:Option,pub//loop{break}; +profiler_runtime:Option,pub is_no_builtins:FxHashSet,pub//3; +native_libraries:FxIndexMap>,pub crate_name:UnordMap,pub used_libraries:Vec,pub used_crate_source://({}); +UnordMap>,pub used_crates:Vec,pub//let _=(); +dependency_formats:Lrc,pub windows_subsystem:Option,pub//; +natvis_debugger_visualizers:BTreeSet,}#[derive(//*&*&(); +Encodable,Decodable)]pub struct CodegenResults {pub modules:Vec, +pub allocator_module:Option,pub metadata_module:Option,pub metadata:rustc_metadata::EncodedMetadata,pub crate_info://3; +CrateInfo,}pub enum CodegenErrors{WrongFileType,EmptyVersionNumber,//let _=||(); +EncodingVersionMismatch{version_array:String,rlink_version:u32},//if let _=(){}; +RustcVersionMismatch{rustc_version:String},}pub fn provide(providers:&mut//({}); +Providers){;crate::back::symbol_export::provide(providers);crate::base::provide( +providers);;;crate::target_features::provide(providers);;;crate::codegen_attrs:: +provide(providers);;}pub fn looks_like_rust_object_file(filename:&str)->bool{let +path=Path::new(filename);;;let ext=path.extension().and_then(|s|s.to_str());;if +ext!=Some(OutputType::Object.extension()){;return false;}let ext2=path.file_stem +().and_then(|s|Path::new(s).extension()).and_then(|s|s.to_str());{;};ext2==Some( +RUST_CGU_EXT)}const RLINK_VERSION:u32=(1);const RLINK_MAGIC:&[u8]=(b"rustlink"); +impl CodegenResults{pub fn serialize_rlink(sess:&Session,rlink_file:&Path,//{;}; +codegen_results:&CodegenResults,outputs:&OutputFilenames,)->Result{3;let mut encoder=FileEncoder::new(rlink_file)?;;;encoder.emit_raw_bytes( +RLINK_MAGIC);3;3;encoder.emit_raw_bytes(&RLINK_VERSION.to_be_bytes());;;encoder. +emit_str(sess.cfg_version);3;;Encodable::encode(codegen_results,&mut encoder);;; +Encodable::encode(outputs,&mut encoder);3;encoder.finish().map_err(|(_path,err)| +err)}pub fn deserialize_rlink(sess:&Session,data:Vec,)->Result<(Self,//({}); +OutputFilenames),CodegenErrors>{if!data.starts_with(RLINK_MAGIC){{;};return Err( +CodegenErrors::WrongFileType);;}let data=&data[RLINK_MAGIC.len()..];if data.len( +)<4{;return Err(CodegenErrors::EmptyVersionNumber);}let mut version_array:[u8;4] +=Default::default();{;};();version_array.copy_from_slice(&data[..4]);();if u32:: +from_be_bytes(version_array)!=RLINK_VERSION{if true{};return Err(CodegenErrors:: +EncodingVersionMismatch{version_array:(String::from_utf8_lossy(&version_array)). +to_string(),rlink_version:RLINK_VERSION,});3;};let mut decoder=MemDecoder::new(& +data[4..],0);();3;let rustc_version=decoder.read_str();3;if rustc_version!=sess. +cfg_version{*&*&();return Err(CodegenErrors::RustcVersionMismatch{rustc_version: +rustc_version.to_string(),});3;};let codegen_results=CodegenResults::decode(&mut +decoder);;let outputs=OutputFilenames::decode(&mut decoder);Ok((codegen_results, +outputs))}}//((),());((),());((),());let _=();((),());let _=();((),());let _=(); diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs index 4f7dc9968a13c..7542cd091a4c9 100644 --- a/compiler/rustc_codegen_ssa/src/meth.rs +++ b/compiler/rustc_codegen_ssa/src/meth.rs @@ -1,114 +1,35 @@ -use crate::traits::*; - -use rustc_middle::ty::{self, GenericArgKind, Ty}; -use rustc_session::config::Lto; -use rustc_symbol_mangling::typeid_for_trait_ref; -use rustc_target::abi::call::FnAbi; - -#[derive(Copy, Clone, Debug)] -pub struct VirtualIndex(u64); - -impl<'a, 'tcx> VirtualIndex { - pub fn from_index(index: usize) -> Self { - VirtualIndex(index as u64) - } - - pub fn get_fn>( - self, - bx: &mut Bx, - llvtable: Bx::Value, - ty: Ty<'tcx>, - fn_abi: &FnAbi<'tcx, Ty<'tcx>>, - ) -> Bx::Value { - // Load the function pointer from the object. - debug!("get_fn({llvtable:?}, {ty:?}, {self:?})"); - - let llty = bx.fn_ptr_backend_type(fn_abi); - let ptr_size = bx.data_layout().pointer_size; - let ptr_align = bx.data_layout().pointer_align.abi; - let vtable_byte_offset = self.0 * ptr_size.bytes(); - - if bx.cx().sess().opts.unstable_opts.virtual_function_elimination - && bx.cx().sess().lto() == Lto::Fat - { - let typeid = bx - .typeid_metadata(typeid_for_trait_ref(bx.tcx(), expect_dyn_trait_in_self(ty))) - .unwrap(); - let func = bx.type_checked_load(llvtable, vtable_byte_offset, typeid); - func - } else { - let gep = bx.inbounds_ptradd(llvtable, bx.const_usize(vtable_byte_offset)); - let ptr = bx.load(llty, gep, ptr_align); - bx.nonnull_metadata(ptr); - // VTable loads are invariant. - bx.set_invariant_load(ptr); - ptr - } - } - - pub fn get_usize>( - self, - bx: &mut Bx, - llvtable: Bx::Value, - ) -> Bx::Value { - // Load the data pointer from the object. - debug!("get_int({:?}, {:?})", llvtable, self); - - let llty = bx.type_isize(); - let ptr_size = bx.data_layout().pointer_size; - let ptr_align = bx.data_layout().pointer_align.abi; - let vtable_byte_offset = self.0 * ptr_size.bytes(); - - let gep = bx.inbounds_ptradd(llvtable, bx.const_usize(vtable_byte_offset)); - let ptr = bx.load(llty, gep, ptr_align); - // VTable loads are invariant. - bx.set_invariant_load(ptr); - ptr - } -} - -/// This takes a valid `self` receiver type and extracts the principal trait -/// ref of the type. -fn expect_dyn_trait_in_self(ty: Ty<'_>) -> ty::PolyExistentialTraitRef<'_> { - for arg in ty.peel_refs().walk() { - if let GenericArgKind::Type(ty) = arg.unpack() - && let ty::Dynamic(data, _, _) = ty.kind() - { - return data.principal().expect("expected principal trait object"); - } - } - - bug!("expected a `dyn Trait` ty, found {ty:?}") -} - -/// Creates a dynamic vtable for the given type and vtable origin. -/// This is used only for objects. -/// -/// The vtables are cached instead of created on every call. -/// -/// The `trait_ref` encodes the erased self type. Hence if we are -/// making an object `Foo` from a value of type `Foo`, then -/// `trait_ref` would map `T: Trait`. -#[instrument(level = "debug", skip(cx))] -pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>( - cx: &Cx, - ty: Ty<'tcx>, - trait_ref: Option>, -) -> Cx::Value { - let tcx = cx.tcx(); - - // Check the cache. - if let Some(&val) = cx.vtables().borrow().get(&(ty, trait_ref)) { - return val; - } - - let vtable_alloc_id = tcx.vtable_allocation((ty, trait_ref)); - let vtable_allocation = tcx.global_alloc(vtable_alloc_id).unwrap_memory(); - let vtable_const = cx.const_data_from_alloc(vtable_allocation); - let align = cx.data_layout().pointer_align.abi; - let vtable = cx.static_addr_of(vtable_const, align, Some("vtable")); - - cx.create_vtable_debuginfo(ty, trait_ref, vtable); - cx.vtables().borrow_mut().insert((ty, trait_ref), vtable); - vtable -} +use crate::traits::*;use rustc_middle::ty::{self,GenericArgKind,Ty};use//*&*&(); +rustc_session::config::Lto;use rustc_symbol_mangling::typeid_for_trait_ref;use// +rustc_target::abi::call::FnAbi;#[derive(Copy,Clone,Debug)]pub struct//if true{}; +VirtualIndex(u64);impl<'a,'tcx>VirtualIndex{pub fn from_index(index:usize)->//3; +Self{VirtualIndex(index as u64)}pub fn get_fn>(self, +bx:&mut Bx,llvtable:Bx::Value,ty:Ty<'tcx>,fn_abi:&FnAbi<'tcx,Ty<'tcx>>,)->Bx::// +Value{({});debug!("get_fn({llvtable:?}, {ty:?}, {self:?})");{;};{;};let llty=bx. +fn_ptr_backend_type(fn_abi);3;3;let ptr_size=bx.data_layout().pointer_size;;;let +ptr_align=bx.data_layout().pointer_align.abi;();3;let vtable_byte_offset=self.0* +ptr_size.bytes();loop{break;};loop{break;};if bx.cx().sess().opts.unstable_opts. +virtual_function_elimination&&bx.cx().sess().lto()==Lto::Fat{({});let typeid=bx. +typeid_metadata((typeid_for_trait_ref(bx.tcx() ,expect_dyn_trait_in_self(ty)))). +unwrap();;let func=bx.type_checked_load(llvtable,vtable_byte_offset,typeid);func +}else{;let gep=bx.inbounds_ptradd(llvtable,bx.const_usize(vtable_byte_offset));; +let ptr=bx.load(llty,gep,ptr_align);{;};{;};bx.nonnull_metadata(ptr);{;};{;};bx. +set_invariant_load(ptr);;ptr}}pub fn get_usize>(self, +bx:&mut Bx,llvtable:Bx::Value,)->Bx::Value{((),());debug!("get_int({:?}, {:?})", +llvtable,self);();();let llty=bx.type_isize();3;3;let ptr_size=bx.data_layout(). +pointer_size;{;};{;};let ptr_align=bx.data_layout().pointer_align.abi;{;};();let +vtable_byte_offset=self.0*ptr_size.bytes();;let gep=bx.inbounds_ptradd(llvtable, +bx.const_usize(vtable_byte_offset));3;;let ptr=bx.load(llty,gep,ptr_align);;;bx. +set_invariant_load(ptr);*&*&();ptr}}fn expect_dyn_trait_in_self(ty:Ty<'_>)->ty:: +PolyExistentialTraitRef<'_>{for arg in ((((((ty .peel_refs()))).walk()))){if let +GenericArgKind::Type(ty)=arg.unpack()&&let ty::Dynamic(data,_,_)=ty.kind(){({}); +return data.principal().expect("expected principal trait object");*&*&();}}bug!( +"expected a `dyn Trait` ty, found {ty:?}")}#[instrument( level="debug",skip(cx)) +]pub fn get_vtable<'tcx,Cx:CodegenMethods<'tcx>>(cx:&Cx,ty:Ty<'tcx>,trait_ref:// +Option>,)->Cx::Value{;let tcx=cx.tcx();;if let +Some(&val)=cx.vtables().borrow().get(&(ty,trait_ref)){{;};return val;{;};}();let +vtable_alloc_id=tcx.vtable_allocation((ty,trait_ref));;let vtable_allocation=tcx +.global_alloc(vtable_alloc_id).unwrap_memory();*&*&();{();};let vtable_const=cx. +const_data_from_alloc(vtable_allocation);{();};{();};let align=cx.data_layout(). +pointer_align.abi;;let vtable=cx.static_addr_of(vtable_const,align,Some("vtable" +));;;cx.create_vtable_debuginfo(ty,trait_ref,vtable);;cx.vtables().borrow_mut(). +insert((ty,trait_ref),vtable);if true{};let _=||();let _=||();let _=||();vtable} diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index c1de9b76fe734..e8c4a0fcddd6f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -1,377 +1,110 @@ -//! An analysis to determine which locals require allocas and -//! which do not. - -use super::FunctionCx; -use crate::traits::*; -use rustc_data_structures::graph::dominators::Dominators; -use rustc_index::bit_set::BitSet; -use rustc_index::{IndexSlice, IndexVec}; -use rustc_middle::mir::traversal; -use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::{self, DefLocation, Location, TerminatorKind}; -use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; - -pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - fx: &FunctionCx<'a, 'tcx, Bx>, -) -> BitSet { - let mir = fx.mir; - let dominators = mir.basic_blocks.dominators(); - let locals = mir - .local_decls - .iter() - .map(|decl| { - let ty = fx.monomorphize(decl.ty); - let layout = fx.cx.spanned_layout_of(ty, decl.source_info.span); - if layout.is_zst() { - LocalKind::ZST - } else if fx.cx.is_backend_immediate(layout) || fx.cx.is_backend_scalar_pair(layout) { - LocalKind::Unused - } else { - LocalKind::Memory - } - }) - .collect(); - - let mut analyzer = LocalAnalyzer { fx, dominators, locals }; - - // Arguments get assigned to by means of the function being called - for arg in mir.args_iter() { - analyzer.define(arg, DefLocation::Argument); - } - - // If there exists a local definition that dominates all uses of that local, - // the definition should be visited first. Traverse blocks in an order that - // is a topological sort of dominance partial order. - for (bb, data) in traversal::reverse_postorder(mir) { - analyzer.visit_basic_block_data(bb, data); - } - - let mut non_ssa_locals = BitSet::new_empty(analyzer.locals.len()); - for (local, kind) in analyzer.locals.iter_enumerated() { - if matches!(kind, LocalKind::Memory) { - non_ssa_locals.insert(local); - } - } - - non_ssa_locals -} - -#[derive(Copy, Clone, PartialEq, Eq)] -enum LocalKind { - ZST, - /// A local that requires an alloca. - Memory, - /// A scalar or a scalar pair local that is neither defined nor used. - Unused, - /// A scalar or a scalar pair local with a single definition that dominates all uses. - SSA(DefLocation), -} - -struct LocalAnalyzer<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { - fx: &'mir FunctionCx<'a, 'tcx, Bx>, - dominators: &'mir Dominators, - locals: IndexVec, -} - -impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { - fn define(&mut self, local: mir::Local, location: DefLocation) { - let kind = &mut self.locals[local]; - match *kind { - LocalKind::ZST => {} - LocalKind::Memory => {} - LocalKind::Unused => *kind = LocalKind::SSA(location), - LocalKind::SSA(_) => *kind = LocalKind::Memory, - } - } - - fn process_place( - &mut self, - place_ref: &mir::PlaceRef<'tcx>, - context: PlaceContext, - location: Location, - ) { - let cx = self.fx.cx; - - if let Some((place_base, elem)) = place_ref.last_projection() { - let mut base_context = if context.is_mutating_use() { - PlaceContext::MutatingUse(MutatingUseContext::Projection) - } else { - PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) - }; - - // Allow uses of projections that are ZSTs or from scalar fields. - let is_consume = matches!( - context, - PlaceContext::NonMutatingUse( - NonMutatingUseContext::Copy | NonMutatingUseContext::Move, - ) - ); - if is_consume { - let base_ty = place_base.ty(self.fx.mir, cx.tcx()); - let base_ty = self.fx.monomorphize(base_ty); - - // ZSTs don't require any actual memory access. - let elem_ty = base_ty.projection_ty(cx.tcx(), self.fx.monomorphize(elem)).ty; - let span = self.fx.mir.local_decls[place_ref.local].source_info.span; - if cx.spanned_layout_of(elem_ty, span).is_zst() { - return; - } - - if let mir::ProjectionElem::Field(..) = elem { - let layout = cx.spanned_layout_of(base_ty.ty, span); - if cx.is_backend_immediate(layout) || cx.is_backend_scalar_pair(layout) { - // Recurse with the same context, instead of `Projection`, - // potentially stopping at non-operand projections, - // which would trigger `not_ssa` on locals. - base_context = context; - } - } - } - - if let mir::ProjectionElem::Deref = elem { - // Deref projections typically only read the pointer. - base_context = PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy); - } - - self.process_place(&place_base, base_context, location); - // HACK(eddyb) this emulates the old `visit_projection_elem`, this - // entire `visit_place`-like `process_place` method should be rewritten, - // now that we have moved to the "slice of projections" representation. - if let mir::ProjectionElem::Index(local) = elem { - self.visit_local( - local, - PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), - location, - ); - } - } else { - self.visit_local(place_ref.local, context, location); - } - } -} - -impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> - for LocalAnalyzer<'mir, 'a, 'tcx, Bx> -{ - fn visit_assign( - &mut self, - place: &mir::Place<'tcx>, - rvalue: &mir::Rvalue<'tcx>, - location: Location, - ) { - debug!("visit_assign(place={:?}, rvalue={:?})", place, rvalue); - - if let Some(local) = place.as_local() { - self.define(local, DefLocation::Assignment(location)); - if self.locals[local] != LocalKind::Memory { - let decl_span = self.fx.mir.local_decls[local].source_info.span; - if !self.fx.rvalue_creates_operand(rvalue, decl_span) { - self.locals[local] = LocalKind::Memory; - } - } - } else { - self.visit_place(place, PlaceContext::MutatingUse(MutatingUseContext::Store), location); - } - - self.visit_rvalue(rvalue, location); - } - - fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) { - debug!("visit_place(place={:?}, context={:?})", place, context); - self.process_place(&place.as_ref(), context, location); - } - - fn visit_local(&mut self, local: mir::Local, context: PlaceContext, location: Location) { - match context { - PlaceContext::MutatingUse(MutatingUseContext::Call) => { - let call = location.block; - let TerminatorKind::Call { target, .. } = - self.fx.mir.basic_blocks[call].terminator().kind - else { - bug!() - }; - self.define(local, DefLocation::CallReturn { call, target }); - } - - PlaceContext::NonUse(_) - | PlaceContext::NonMutatingUse(NonMutatingUseContext::PlaceMention) - | PlaceContext::MutatingUse(MutatingUseContext::Retag) => {} - - PlaceContext::NonMutatingUse( - NonMutatingUseContext::Copy | NonMutatingUseContext::Move, - ) => match &mut self.locals[local] { - LocalKind::ZST => {} - LocalKind::Memory => {} - LocalKind::SSA(def) if def.dominates(location, self.dominators) => {} - // Reads from uninitialized variables (e.g., in dead code, after - // optimizations) require locals to be in (uninitialized) memory. - // N.B., there can be uninitialized reads of a local visited after - // an assignment to that local, if they happen on disjoint paths. - kind @ (LocalKind::Unused | LocalKind::SSA(_)) => { - *kind = LocalKind::Memory; - } - }, - - PlaceContext::MutatingUse( - MutatingUseContext::Store - | MutatingUseContext::Deinit - | MutatingUseContext::SetDiscriminant - | MutatingUseContext::AsmOutput - | MutatingUseContext::Borrow - | MutatingUseContext::AddressOf - | MutatingUseContext::Projection, - ) - | PlaceContext::NonMutatingUse( - NonMutatingUseContext::Inspect - | NonMutatingUseContext::SharedBorrow - | NonMutatingUseContext::FakeBorrow - | NonMutatingUseContext::AddressOf - | NonMutatingUseContext::Projection, - ) => { - self.locals[local] = LocalKind::Memory; - } - - PlaceContext::MutatingUse(MutatingUseContext::Drop) => { - let kind = &mut self.locals[local]; - if *kind != LocalKind::Memory { - let ty = self.fx.mir.local_decls[local].ty; - let ty = self.fx.monomorphize(ty); - if self.fx.cx.type_needs_drop(ty) { - // Only need the place if we're actually dropping it. - *kind = LocalKind::Memory; - } - } - } - - PlaceContext::MutatingUse(MutatingUseContext::Yield) => bug!(), - } - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum CleanupKind { - NotCleanup, - Funclet, - Internal { funclet: mir::BasicBlock }, -} - -impl CleanupKind { - pub fn funclet_bb(self, for_bb: mir::BasicBlock) -> Option { - match self { - CleanupKind::NotCleanup => None, - CleanupKind::Funclet => Some(for_bb), - CleanupKind::Internal { funclet } => Some(funclet), - } - } -} - -/// MSVC requires unwinding code to be split to a tree of *funclets*, where each funclet can only -/// branch to itself or to its parent. Luckily, the code we generates matches this pattern. -/// Recover that structure in an analyze pass. -pub fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec { - fn discover_masters<'tcx>( - result: &mut IndexSlice, - mir: &mir::Body<'tcx>, - ) { - for (bb, data) in mir.basic_blocks.iter_enumerated() { - match data.terminator().kind { - TerminatorKind::Goto { .. } - | TerminatorKind::UnwindResume - | TerminatorKind::UnwindTerminate(_) - | TerminatorKind::Return - | TerminatorKind::CoroutineDrop - | TerminatorKind::Unreachable - | TerminatorKind::SwitchInt { .. } - | TerminatorKind::Yield { .. } - | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } => { /* nothing to do */ } - TerminatorKind::Call { unwind, .. } - | TerminatorKind::InlineAsm { unwind, .. } - | TerminatorKind::Assert { unwind, .. } - | TerminatorKind::Drop { unwind, .. } => { - if let mir::UnwindAction::Cleanup(unwind) = unwind { - debug!( - "cleanup_kinds: {:?}/{:?} registering {:?} as funclet", - bb, data, unwind - ); - result[unwind] = CleanupKind::Funclet; - } - } - } - } - } - - fn propagate<'tcx>( - result: &mut IndexSlice, - mir: &mir::Body<'tcx>, - ) { - let mut funclet_succs = IndexVec::from_elem(None, &mir.basic_blocks); - - let mut set_successor = |funclet: mir::BasicBlock, succ| match funclet_succs[funclet] { - ref mut s @ None => { - debug!("set_successor: updating successor of {:?} to {:?}", funclet, succ); - *s = Some(succ); - } - Some(s) => { - if s != succ { - span_bug!( - mir.span, - "funclet {:?} has 2 parents - {:?} and {:?}", - funclet, - s, - succ - ); - } - } - }; - - for (bb, data) in traversal::reverse_postorder(mir) { - let funclet = match result[bb] { - CleanupKind::NotCleanup => continue, - CleanupKind::Funclet => bb, - CleanupKind::Internal { funclet } => funclet, - }; - - debug!( - "cleanup_kinds: {:?}/{:?}/{:?} propagating funclet {:?}", - bb, data, result[bb], funclet - ); - - for succ in data.terminator().successors() { - let kind = result[succ]; - debug!("cleanup_kinds: propagating {:?} to {:?}/{:?}", funclet, succ, kind); - match kind { - CleanupKind::NotCleanup => { - result[succ] = CleanupKind::Internal { funclet }; - } - CleanupKind::Funclet => { - if funclet != succ { - set_successor(funclet, succ); - } - } - CleanupKind::Internal { funclet: succ_funclet } => { - if funclet != succ_funclet { - // `succ` has 2 different funclet going into it, so it must - // be a funclet by itself. - - debug!( - "promoting {:?} to a funclet and updating {:?}", - succ, succ_funclet - ); - result[succ] = CleanupKind::Funclet; - set_successor(succ_funclet, succ); - set_successor(funclet, succ); - } - } - } - } - } - } - - let mut result = IndexVec::from_elem(CleanupKind::NotCleanup, &mir.basic_blocks); - - discover_masters(&mut result, mir); - propagate(&mut result, mir); - debug!("cleanup_kinds: result={:?}", result); - result -} +use super::FunctionCx;use crate::traits::*;use rustc_data_structures::graph:://; +dominators::Dominators;use rustc_index::bit_set::BitSet;use rustc_index::{//{;}; +IndexSlice,IndexVec};use rustc_middle::mir::traversal;use rustc_middle::mir:://; +visit::{MutatingUseContext,NonMutatingUseContext,PlaceContext,Visitor};use//{;}; +rustc_middle::mir::{self,DefLocation,Location,TerminatorKind};use rustc_middle// +::ty::layout::{HasTyCtxt,LayoutOf};pub fn non_ssa_locals<'a,'tcx,Bx://if true{}; +BuilderMethods<'a,'tcx>>(fx:&FunctionCx<'a,'tcx,Bx>,)->BitSet{();let +mir=fx.mir;();3;let dominators=mir.basic_blocks.dominators();3;3;let locals=mir. +local_decls.iter().map(|decl|{;let ty=fx.monomorphize(decl.ty);let layout=fx.cx. +spanned_layout_of(ty,decl.source_info.span);3;if layout.is_zst(){LocalKind::ZST} +else if fx.cx.is_backend_immediate( layout)||fx.cx.is_backend_scalar_pair(layout +){LocalKind::Unused}else{LocalKind::Memory}}).collect();{;};();let mut analyzer= +LocalAnalyzer{fx,dominators,locals};;for arg in mir.args_iter(){analyzer.define( +arg,DefLocation::Argument);3;}for(bb,data)in traversal::reverse_postorder(mir){; +analyzer.visit_basic_block_data(bb,data);{;};}();let mut non_ssa_locals=BitSet:: +new_empty(analyzer.locals.len());loop{break;};for(local,kind)in analyzer.locals. +iter_enumerated(){if matches!(kind,LocalKind::Memory){{;};non_ssa_locals.insert( +local);();}}non_ssa_locals}#[derive(Copy,Clone,PartialEq,Eq)]enum LocalKind{ZST, +Memory,Unused,SSA(DefLocation),}struct LocalAnalyzer<'mir,'a,'tcx,Bx://let _=(); +BuilderMethods<'a,'tcx>>{fx:&'mir FunctionCx<'a,'tcx,Bx>,dominators:&'mir//({}); +Dominators,locals:IndexVec,}impl<'mir,'a +,'tcx,Bx:BuilderMethods<'a,'tcx>>LocalAnalyzer<'mir,'a,'tcx,Bx>{fn define(&mut// +self,local:mir::Local,location:DefLocation){3;let kind=&mut self.locals[local];; +match(*kind){LocalKind::ZST=>{}LocalKind:: Memory=>{}LocalKind::Unused=>(*kind)= +LocalKind::SSA(location),LocalKind::SSA(_)=>((((*kind))=LocalKind::Memory)),}}fn +process_place(&mut self,place_ref:&mir::PlaceRef<'tcx>,context:PlaceContext,//3; +location:Location,){;let cx=self.fx.cx;if let Some((place_base,elem))=place_ref. +last_projection(){loop{break};let mut base_context=if context.is_mutating_use(){ +PlaceContext::MutatingUse(MutatingUseContext::Projection)}else{PlaceContext:://; +NonMutatingUse(NonMutatingUseContext::Projection)};();3;let is_consume=matches!( +context,PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy|//loop{break;}; +NonMutatingUseContext::Move,));;if is_consume{let base_ty=place_base.ty(self.fx. +mir,cx.tcx());;;let base_ty=self.fx.monomorphize(base_ty);;;let elem_ty=base_ty. +projection_ty(cx.tcx(),self.fx.monomorphize(elem)).ty;();3;let span=self.fx.mir. +local_decls[place_ref.local].source_info.span;3;if cx.spanned_layout_of(elem_ty, +span).is_zst(){;return;}if let mir::ProjectionElem::Field(..)=elem{let layout=cx +.spanned_layout_of(base_ty.ty,span);({});if cx.is_backend_immediate(layout)||cx. +is_backend_scalar_pair(layout){*&*&();base_context=context;{();};}}}if let mir:: +ProjectionElem::Deref=elem{let _=||();base_context=PlaceContext::NonMutatingUse( +NonMutatingUseContext::Copy);();}();self.process_place(&place_base,base_context, +location);;if let mir::ProjectionElem::Index(local)=elem{self.visit_local(local, +PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),location,);3;}}else{3; +self.visit_local(place_ref.local,context,location);({});}}}impl<'mir,'a,'tcx,Bx: +BuilderMethods<'a,'tcx>>Visitor<'tcx>for LocalAnalyzer<'mir,'a,'tcx,Bx>{fn//{;}; +visit_assign(&mut self,place:&mir::Place<'tcx>,rvalue:&mir::Rvalue<'tcx>,//({}); +location:Location,){;debug!("visit_assign(place={:?}, rvalue={:?})",place,rvalue +);;if let Some(local)=place.as_local(){self.define(local,DefLocation::Assignment +(location));;if self.locals[local]!=LocalKind::Memory{let decl_span=self.fx.mir. +local_decls[local].source_info.span;();if!self.fx.rvalue_creates_operand(rvalue, +decl_span){;self.locals[local]=LocalKind::Memory;}}}else{self.visit_place(place, +PlaceContext::MutatingUse(MutatingUseContext::Store),location);{();};}({});self. +visit_rvalue(rvalue,location);;}fn visit_place(&mut self,place:&mir::Place<'tcx> +,context:PlaceContext,location:Location){((),());((),());((),());((),());debug!( +"visit_place(place={:?}, context={:?})",place,context);();3;self.process_place(& +place.as_ref(),context,location);{;};}fn visit_local(&mut self,local:mir::Local, +context:PlaceContext,location:Location) {match context{PlaceContext::MutatingUse +(MutatingUseContext::Call)=>{;let call=location.block;;let TerminatorKind::Call{ +target,..}=self.fx.mir.basic_blocks[call].terminator().kind else{bug!()};;;self. +define(local,DefLocation::CallReturn{call,target});{;};}PlaceContext::NonUse(_)| +PlaceContext::NonMutatingUse(NonMutatingUseContext::PlaceMention)|PlaceContext// +::MutatingUse(MutatingUseContext::Retag)=>{}PlaceContext::NonMutatingUse(//({}); +NonMutatingUseContext::Copy|NonMutatingUseContext::Move,)=>match&mut self.//{;}; +locals[local]{LocalKind::ZST=>{}LocalKind:: Memory=>{}LocalKind::SSA(def)if def. +dominates(location,self.dominators)=>{} kind@(LocalKind::Unused|LocalKind::SSA(_ +))=>{;*kind=LocalKind::Memory;;}},PlaceContext::MutatingUse(MutatingUseContext:: +Store|MutatingUseContext::Deinit|MutatingUseContext::SetDiscriminant|//let _=(); +MutatingUseContext::AsmOutput|MutatingUseContext::Borrow|MutatingUseContext:://; +AddressOf|MutatingUseContext::Projection,)|PlaceContext::NonMutatingUse(//{();}; +NonMutatingUseContext::Inspect|NonMutatingUseContext::SharedBorrow|//let _=||(); +NonMutatingUseContext::FakeBorrow|NonMutatingUseContext::AddressOf|//let _=||(); +NonMutatingUseContext::Projection,)=>{3;self.locals[local]=LocalKind::Memory;3;} +PlaceContext::MutatingUse(MutatingUseContext::Drop)=>{;let kind=&mut self.locals +[local];;if*kind!=LocalKind::Memory{let ty=self.fx.mir.local_decls[local].ty;let +ty=self.fx.monomorphize(ty);3;if self.fx.cx.type_needs_drop(ty){;*kind=LocalKind +::Memory;3;}}}PlaceContext::MutatingUse(MutatingUseContext::Yield)=>bug!(),}}}#[ +derive(Copy,Clone,Debug,PartialEq,Eq)]pub enum CleanupKind{NotCleanup,Funclet,// +Internal{funclet:mir::BasicBlock},}impl CleanupKind{pub fn funclet_bb(self,//(); +for_bb:mir::BasicBlock)->Option{match self{CleanupKind:://({}); +NotCleanup=>None,CleanupKind::Funclet=>(((Some(for_bb)))),CleanupKind::Internal{ +funclet}=>(Some(funclet)),}}}pub fn cleanup_kinds(mir:&mir::Body<'_>)->IndexVec< +mir::BasicBlock,CleanupKind>{3;fn discover_masters<'tcx>(result:&mut IndexSlice< +mir::BasicBlock,CleanupKind>,mir:&mir::Body<'tcx>,){for(bb,data)in mir.//*&*&(); +basic_blocks.iter_enumerated(){match ((data.terminator())).kind{TerminatorKind:: +Goto{..}|TerminatorKind::UnwindResume|TerminatorKind::UnwindTerminate(_)|//({}); +TerminatorKind::Return|TerminatorKind::CoroutineDrop|TerminatorKind:://let _=(); +Unreachable|TerminatorKind::SwitchInt{..}|TerminatorKind::Yield{..}|//if true{}; +TerminatorKind::FalseEdge{..}|TerminatorKind ::FalseUnwind{..}=>{}TerminatorKind +::Call{unwind,..}|TerminatorKind::InlineAsm{unwind,..}|TerminatorKind::Assert{// +unwind,..}|TerminatorKind::Drop{unwind,.. }=>{if let mir::UnwindAction::Cleanup( +unwind)=unwind{;debug!("cleanup_kinds: {:?}/{:?} registering {:?} as funclet",bb +,data,unwind);3;;result[unwind]=CleanupKind::Funclet;;}}}}};;fn propagate<'tcx>( +result:&mut IndexSlice,mir:&mir::Body<'tcx>,){3;let +mut funclet_succs=IndexVec::from_elem(None,&mir.basic_blocks);{();};({});let mut +set_successor=|funclet:mir::BasicBlock,succ|match ((funclet_succs[funclet])){ref +mut s@None=>{;debug!("set_successor: updating successor of {:?} to {:?}",funclet +,succ);({});({});*s=Some(succ);{;};}Some(s)=>{if s!=succ{{;};span_bug!(mir.span, +"funclet {:?} has 2 parents - {:?} and {:?}",funclet,s,succ);;}}};for(bb,data)in +traversal::reverse_postorder(mir){{;};let funclet=match result[bb]{CleanupKind:: +NotCleanup=>(continue),CleanupKind::Funclet=>bb,CleanupKind::Internal{funclet}=> +funclet,};3;;debug!("cleanup_kinds: {:?}/{:?}/{:?} propagating funclet {:?}",bb, +data,result[bb],funclet);3;for succ in data.terminator().successors(){;let kind= +result[succ];;debug!("cleanup_kinds: propagating {:?} to {:?}/{:?}",funclet,succ +,kind);;match kind{CleanupKind::NotCleanup=>{result[succ]=CleanupKind::Internal{ +funclet};;}CleanupKind::Funclet=>{if funclet!=succ{set_successor(funclet,succ);} +}CleanupKind::Internal{funclet:succ_funclet}=>{if funclet!=succ_funclet{;debug!( +"promoting {:?} to a funclet and updating {:?}",succ,succ_funclet);;result[succ] +=CleanupKind::Funclet;;;set_successor(succ_funclet,succ);;set_successor(funclet, +succ);3;}}}}}};;let mut result=IndexVec::from_elem(CleanupKind::NotCleanup,&mir. +basic_blocks);;;discover_masters(&mut result,mir);;;propagate(&mut result,mir);; +debug!("cleanup_kinds: result={:?}",result);if let _=(){};*&*&();((),());result} diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index d4123329f4481..7d361b2724aaa 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1,1850 +1,493 @@ -use super::operand::OperandRef; -use super::operand::OperandValue::{Immediate, Pair, Ref, ZeroSized}; -use super::place::PlaceRef; -use super::{CachedLlbb, FunctionCx, LocalRef}; - -use crate::base; -use crate::common::{self, IntPredicate}; -use crate::errors::CompilerBuiltinsCannotCall; -use crate::meth; -use crate::traits::*; -use crate::MemFlags; - -use rustc_ast as ast; -use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; -use rustc_hir::lang_items::LangItem; -use rustc_middle::mir::{self, AssertKind, BasicBlock, SwitchTargets, UnwindTerminateReason}; -use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement}; -use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; -use rustc_middle::ty::{self, Instance, Ty}; -use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization; -use rustc_session::config::OptLevel; -use rustc_span::{source_map::Spanned, sym, Span}; -use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode, Reg}; -use rustc_target::abi::{self, HasDataLayout, WrappingRange}; -use rustc_target::spec::abi::Abi; - -use std::cmp; - -// Indicates if we are in the middle of merging a BB's successor into it. This -// can happen when BB jumps directly to its successor and the successor has no -// other predecessors. -#[derive(Debug, PartialEq)] -enum MergingSucc { - False, - True, -} - -/// Used by `FunctionCx::codegen_terminator` for emitting common patterns -/// e.g., creating a basic block, calling a function, etc. -struct TerminatorCodegenHelper<'tcx> { - bb: mir::BasicBlock, - terminator: &'tcx mir::Terminator<'tcx>, -} - -impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { - /// Returns the appropriate `Funclet` for the current funclet, if on MSVC, - /// either already previously cached, or newly created, by `landing_pad_for`. - fn funclet<'b, Bx: BuilderMethods<'a, 'tcx>>( - &self, - fx: &'b mut FunctionCx<'a, 'tcx, Bx>, - ) -> Option<&'b Bx::Funclet> { - let cleanup_kinds = fx.cleanup_kinds.as_ref()?; - let funclet_bb = cleanup_kinds[self.bb].funclet_bb(self.bb)?; - // If `landing_pad_for` hasn't been called yet to create the `Funclet`, - // it has to be now. This may not seem necessary, as RPO should lead - // to all the unwind edges being visited (and so to `landing_pad_for` - // getting called for them), before building any of the blocks inside - // the funclet itself - however, if MIR contains edges that end up not - // being needed in the LLVM IR after monomorphization, the funclet may - // be unreachable, and we don't have yet a way to skip building it in - // such an eventuality (which may be a better solution than this). - if fx.funclets[funclet_bb].is_none() { - fx.landing_pad_for(funclet_bb); - } - Some( - fx.funclets[funclet_bb] - .as_ref() - .expect("landing_pad_for didn't also create funclets entry"), - ) - } - - /// Get a basic block (creating it if necessary), possibly with cleanup - /// stuff in it or next to it. - fn llbb_with_cleanup>( - &self, - fx: &mut FunctionCx<'a, 'tcx, Bx>, - target: mir::BasicBlock, - ) -> Bx::BasicBlock { - let (needs_landing_pad, is_cleanupret) = self.llbb_characteristics(fx, target); - let mut lltarget = fx.llbb(target); - if needs_landing_pad { - lltarget = fx.landing_pad_for(target); - } - if is_cleanupret { - // Cross-funclet jump - need a trampoline - debug_assert!(base::wants_new_eh_instructions(fx.cx.tcx().sess)); - debug!("llbb_with_cleanup: creating cleanup trampoline for {:?}", target); - let name = &format!("{:?}_cleanup_trampoline_{:?}", self.bb, target); - 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_llbb - } else { - lltarget - } - } - - fn llbb_characteristics>( - &self, - fx: &mut FunctionCx<'a, 'tcx, Bx>, - target: mir::BasicBlock, - ) -> (bool, bool) { - if let Some(ref cleanup_kinds) = fx.cleanup_kinds { - let funclet_bb = cleanup_kinds[self.bb].funclet_bb(self.bb); - let target_funclet = cleanup_kinds[target].funclet_bb(target); - let (needs_landing_pad, is_cleanupret) = match (funclet_bb, target_funclet) { - (None, None) => (false, false), - (None, Some(_)) => (true, false), - (Some(f), Some(t_f)) => (f != t_f, f != t_f), - (Some(_), None) => { - let span = self.terminator.source_info.span; - span_bug!(span, "{:?} - jump out of cleanup?", self.terminator); - } - }; - (needs_landing_pad, is_cleanupret) - } else { - let needs_landing_pad = !fx.mir[self.bb].is_cleanup && fx.mir[target].is_cleanup; - let is_cleanupret = false; - (needs_landing_pad, is_cleanupret) - } - } - - fn funclet_br>( - &self, - fx: &mut FunctionCx<'a, 'tcx, Bx>, - bx: &mut Bx, - target: mir::BasicBlock, - mergeable_succ: bool, - ) -> MergingSucc { - let (needs_landing_pad, is_cleanupret) = self.llbb_characteristics(fx, target); - if mergeable_succ && !needs_landing_pad && !is_cleanupret { - // We can merge the successor into this bb, so no need for a `br`. - MergingSucc::True - } else { - let mut lltarget = fx.llbb(target); - if needs_landing_pad { - lltarget = fx.landing_pad_for(target); - } - if is_cleanupret { - // micro-optimization: generate a `ret` rather than a jump - // to a trampoline. - bx.cleanup_ret(self.funclet(fx).unwrap(), Some(lltarget)); - } else { - bx.br(lltarget); - } - MergingSucc::False - } - } - - /// Call `fn_ptr` of `fn_abi` with the arguments `llargs`, the optional - /// return destination `destination` and the unwind action `unwind`. - fn do_call>( - &self, - fx: &mut FunctionCx<'a, 'tcx, Bx>, - bx: &mut Bx, - fn_abi: &'tcx FnAbi<'tcx, Ty<'tcx>>, - fn_ptr: Bx::Value, - llargs: &[Bx::Value], - destination: Option<(ReturnDest<'tcx, Bx::Value>, mir::BasicBlock)>, - mut unwind: mir::UnwindAction, - copied_constant_arguments: &[PlaceRef<'tcx, ::Value>], - instance: Option>, - mergeable_succ: bool, - ) -> MergingSucc { - let tcx = bx.tcx(); - if let Some(instance) = instance { - if is_call_from_compiler_builtins_to_upstream_monomorphization(tcx, instance) { - if destination.is_some() { - let caller = with_no_trimmed_paths!(tcx.def_path_str(fx.instance.def_id())); - let callee = with_no_trimmed_paths!(tcx.def_path_str(instance.def_id())); - tcx.dcx().emit_err(CompilerBuiltinsCannotCall { caller, callee }); - } else { - info!( - "compiler_builtins call to diverging function {:?} replaced with abort", - instance.def_id() - ); - bx.abort(); - bx.unreachable(); - return MergingSucc::False; - } - } - } - - // If there is a cleanup block and the function we're calling can unwind, then - // do an invoke, otherwise do a call. - let fn_ty = bx.fn_decl_backend_type(fn_abi); - - let fn_attrs = if bx.tcx().def_kind(fx.instance.def_id()).has_codegen_attrs() { - Some(bx.tcx().codegen_fn_attrs(fx.instance.def_id())) - } else { - None - }; - - if !fn_abi.can_unwind { - unwind = mir::UnwindAction::Unreachable; - } - - let unwind_block = match unwind { - mir::UnwindAction::Cleanup(cleanup) => Some(self.llbb_with_cleanup(fx, cleanup)), - mir::UnwindAction::Continue => None, - mir::UnwindAction::Unreachable => None, - mir::UnwindAction::Terminate(reason) => { - if fx.mir[self.bb].is_cleanup && base::wants_new_eh_instructions(fx.cx.tcx().sess) { - // MSVC SEH will abort automatically if an exception tries to - // propagate out from cleanup. - - // FIXME(@mirkootter): For wasm, we currently do not support terminate during - // cleanup, because this requires a few more changes: The current code - // caches the `terminate_block` for each function; funclet based code - however - - // requires a different terminate_block for each funclet - // Until this is implemented, we just do not unwind inside cleanup blocks - - None - } else { - Some(fx.terminate_block(reason)) - } - } - }; - - if let Some(unwind_block) = unwind_block { - let ret_llbb = if let Some((_, target)) = destination { - fx.llbb(target) - } else { - fx.unreachable_block() - }; - let invokeret = bx.invoke( - fn_ty, - fn_attrs, - Some(fn_abi), - fn_ptr, - llargs, - ret_llbb, - unwind_block, - self.funclet(fx), - instance, - ); - if fx.mir[self.bb].is_cleanup { - bx.apply_attrs_to_cleanup_callsite(invokeret); - } - - if let Some((ret_dest, target)) = destination { - bx.switch_to_block(fx.llbb(target)); - fx.set_debug_loc(bx, self.terminator.source_info); - for tmp in copied_constant_arguments { - bx.lifetime_end(tmp.llval, tmp.layout.size); - } - fx.store_return(bx, ret_dest, &fn_abi.ret, invokeret); - } - MergingSucc::False - } else { - let llret = - bx.call(fn_ty, fn_attrs, Some(fn_abi), fn_ptr, llargs, self.funclet(fx), instance); - if fx.mir[self.bb].is_cleanup { - bx.apply_attrs_to_cleanup_callsite(llret); - } - - if let Some((ret_dest, target)) = destination { - for tmp in copied_constant_arguments { - bx.lifetime_end(tmp.llval, tmp.layout.size); - } - fx.store_return(bx, ret_dest, &fn_abi.ret, llret); - self.funclet_br(fx, bx, target, mergeable_succ) - } else { - bx.unreachable(); - MergingSucc::False - } - } - } - - /// Generates inline assembly with optional `destination` and `unwind`. - fn do_inlineasm>( - &self, - fx: &mut FunctionCx<'a, 'tcx, Bx>, - bx: &mut Bx, - template: &[InlineAsmTemplatePiece], - operands: &[InlineAsmOperandRef<'tcx, Bx>], - options: InlineAsmOptions, - line_spans: &[Span], - destination: Option, - unwind: mir::UnwindAction, - instance: Instance<'_>, - mergeable_succ: bool, - ) -> MergingSucc { - let unwind_target = match unwind { - mir::UnwindAction::Cleanup(cleanup) => Some(self.llbb_with_cleanup(fx, cleanup)), - mir::UnwindAction::Terminate(reason) => Some(fx.terminate_block(reason)), - mir::UnwindAction::Continue => None, - mir::UnwindAction::Unreachable => None, - }; - - if operands.iter().any(|x| matches!(x, InlineAsmOperandRef::Label { .. })) { - assert!(unwind_target.is_none()); - let ret_llbb = if let Some(target) = destination { - fx.llbb(target) - } else { - fx.unreachable_block() - }; - - bx.codegen_inline_asm( - template, - operands, - options, - line_spans, - instance, - Some(ret_llbb), - None, - ); - MergingSucc::False - } else if let Some(cleanup) = unwind_target { - let ret_llbb = if let Some(target) = destination { - fx.llbb(target) - } else { - fx.unreachable_block() - }; - - bx.codegen_inline_asm( - template, - operands, - options, - line_spans, - instance, - Some(ret_llbb), - Some((cleanup, self.funclet(fx))), - ); - MergingSucc::False - } else { - bx.codegen_inline_asm(template, operands, options, line_spans, instance, None, None); - - if let Some(target) = destination { - self.funclet_br(fx, bx, target, mergeable_succ) - } else { - bx.unreachable(); - MergingSucc::False - } - } - } -} - -/// Codegen implementations for some terminator variants. -impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { - /// Generates code for a `Resume` terminator. - fn codegen_resume_terminator(&mut self, helper: TerminatorCodegenHelper<'tcx>, bx: &mut Bx) { - if let Some(funclet) = helper.funclet(self) { - bx.cleanup_ret(funclet, None); - } else { - let slot = self.get_personality_slot(bx); - let exn0 = slot.project_field(bx, 0); - let exn0 = bx.load_operand(exn0).immediate(); - let exn1 = slot.project_field(bx, 1); - let exn1 = bx.load_operand(exn1).immediate(); - slot.storage_dead(bx); - - bx.resume(exn0, exn1); - } - } - - fn codegen_switchint_terminator( - &mut self, - helper: TerminatorCodegenHelper<'tcx>, - bx: &mut Bx, - discr: &mir::Operand<'tcx>, - targets: &SwitchTargets, - ) { - let discr = self.codegen_operand(bx, discr); - let discr_value = discr.immediate(); - let switch_ty = discr.layout.ty; - // If our discriminant is a constant we can branch directly - if let Some(const_discr) = bx.const_to_opt_u128(discr_value, false) { - let target = targets.target_for_value(const_discr); - bx.br(helper.llbb_with_cleanup(self, target)); - return; - }; - - let mut target_iter = targets.iter(); - 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.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 { - 0 => bx.cond_br(discr_value, llfalse, lltrue), - 1 => bx.cond_br(discr_value, lltrue, llfalse), - _ => bug!(), - } - } else { - let switch_llty = bx.immediate_backend_type(bx.layout_of(switch_ty)); - let llval = bx.const_uint_big(switch_llty, test_value); - let cmp = bx.icmp(IntPredicate::IntEQ, discr_value, llval); - bx.cond_br(cmp, lltrue, llfalse); - } - } else if self.cx.sess().opts.optimize == OptLevel::No - && target_iter.len() == 2 - && self.mir[targets.otherwise()].is_empty_unreachable() - { - // In unoptimized builds, if there are two normal targets and the `otherwise` target is - // an unreachable BB, emit `br` instead of `switch`. This leaves behind the unreachable - // BB, which will usually (but not always) be dead code. - // - // Why only in unoptimized builds? - // - In unoptimized builds LLVM uses FastISel which does not support switches, so it - // must fall back to the to the slower SelectionDAG isel. Therefore, using `br` gives - // significant compile time speedups for unoptimized builds. - // - In optimized builds the above doesn't hold, and using `br` sometimes results in - // worse generated code because LLVM can no longer tell that the value being switched - // on can only have two values, e.g. 0 and 1. - // - let (test_value1, target1) = target_iter.next().unwrap(); - let (_test_value2, target2) = target_iter.next().unwrap(); - let ll1 = helper.llbb_with_cleanup(self, target1); - let ll2 = helper.llbb_with_cleanup(self, target2); - let switch_llty = bx.immediate_backend_type(bx.layout_of(switch_ty)); - let llval = bx.const_uint_big(switch_llty, test_value1); - let cmp = bx.icmp(IntPredicate::IntEQ, discr_value, llval); - bx.cond_br(cmp, ll1, ll2); - } else { - bx.switch( - discr_value, - helper.llbb_with_cleanup(self, targets.otherwise()), - target_iter.map(|(value, target)| (value, helper.llbb_with_cleanup(self, target))), - ); - } - } - - fn codegen_return_terminator(&mut self, bx: &mut Bx) { - // Call `va_end` if this is the definition of a C-variadic function. - if self.fn_abi.c_variadic { - // The `VaList` "spoofed" argument is just after all the real arguments. - let va_list_arg_idx = self.fn_abi.args.len(); - match self.locals[mir::Local::from_usize(1 + va_list_arg_idx)] { - LocalRef::Place(va_list) => { - bx.va_end(va_list.llval); - } - _ => bug!("C-variadic function must have a `VaList` place"), - } - } - if self.fn_abi.ret.layout.abi.is_uninhabited() { - // Functions with uninhabited return values are marked `noreturn`, - // so we should make sure that we never actually do. - // We play it safe by using a well-defined `abort`, but we could go for immediate UB - // if that turns out to be helpful. - bx.abort(); - // `abort` does not terminate the block, so we still need to generate - // an `unreachable` terminator after it. - bx.unreachable(); - return; - } - let llval = match &self.fn_abi.ret.mode { - PassMode::Ignore | PassMode::Indirect { .. } => { - bx.ret_void(); - return; - } - - PassMode::Direct(_) | PassMode::Pair(..) => { - let op = self.codegen_consume(bx, mir::Place::return_place().as_ref()); - if let Ref(llval, _, align) = op.val { - bx.load(bx.backend_type(op.layout), llval, align) - } else { - op.immediate_or_packed_pair(bx) - } - } - - PassMode::Cast { cast: cast_ty, pad_i32: _ } => { - let op = match self.locals[mir::RETURN_PLACE] { - LocalRef::Operand(op) => op, - LocalRef::PendingOperand => bug!("use of return before def"), - LocalRef::Place(cg_place) => OperandRef { - val: Ref(cg_place.llval, None, cg_place.align), - layout: cg_place.layout, - }, - LocalRef::UnsizedPlace(_) => bug!("return type must be sized"), - }; - let llslot = match op.val { - Immediate(_) | Pair(..) => { - let scratch = PlaceRef::alloca(bx, self.fn_abi.ret.layout); - op.val.store(bx, scratch); - scratch.llval - } - Ref(llval, _, align) => { - assert_eq!(align, op.layout.align.abi, "return place is unaligned!"); - llval - } - ZeroSized => bug!("ZST return value shouldn't be in PassMode::Cast"), - }; - let ty = bx.cast_backend_type(cast_ty); - bx.load(ty, llslot, self.fn_abi.ret.layout.align.abi) - } - }; - bx.ret(llval); - } - - #[tracing::instrument(level = "trace", skip(self, helper, bx))] - fn codegen_drop_terminator( - &mut self, - helper: TerminatorCodegenHelper<'tcx>, - bx: &mut Bx, - location: mir::Place<'tcx>, - target: mir::BasicBlock, - unwind: mir::UnwindAction, - mergeable_succ: bool, - ) -> MergingSucc { - let ty = location.ty(self.mir, bx.tcx()).ty; - let ty = self.monomorphize(ty); - let drop_fn = Instance::resolve_drop_in_place(bx.tcx(), ty); - - if let ty::InstanceDef::DropGlue(_, None) = drop_fn.def { - // we don't actually need to drop anything. - return helper.funclet_br(self, bx, target, mergeable_succ); - } - - let place = self.codegen_place(bx, location.as_ref()); - let (args1, args2); - let mut args = if let Some(llextra) = place.llextra { - args2 = [place.llval, llextra]; - &args2[..] - } else { - args1 = [place.llval]; - &args1[..] - }; - let (drop_fn, fn_abi, drop_instance) = - match ty.kind() { - // FIXME(eddyb) perhaps move some of this logic into - // `Instance::resolve_drop_in_place`? - ty::Dynamic(_, _, ty::Dyn) => { - // IN THIS ARM, WE HAVE: - // ty = *mut (dyn Trait) - // which is: exists ( *mut T, Vtable ) - // args[0] args[1] - // - // args = ( Data, Vtable ) - // | - // v - // /-------\ - // | ... | - // \-------/ - // - let virtual_drop = Instance { - def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0), - args: drop_fn.args, - }; - debug!("ty = {:?}", ty); - debug!("drop_fn = {:?}", drop_fn); - debug!("args = {:?}", args); - let fn_abi = bx.fn_abi_of_instance(virtual_drop, ty::List::empty()); - let vtable = args[1]; - // Truncate vtable off of args list - args = &args[..1]; - ( - meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE) - .get_fn(bx, vtable, ty, fn_abi), - fn_abi, - virtual_drop, - ) - } - ty::Dynamic(_, _, ty::DynStar) => { - // IN THIS ARM, WE HAVE: - // ty = *mut (dyn* Trait) - // which is: *mut exists (T, Vtable) - // - // 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 virtual_drop = Instance { - def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0), - args: drop_fn.args, - }; - debug!("ty = {:?}", ty); - debug!("drop_fn = {:?}", drop_fn); - debug!("args = {:?}", args); - let fn_abi = bx.fn_abi_of_instance(virtual_drop, ty::List::empty()); - let meta_ptr = place.project_field(bx, 1); - let meta = bx.load_operand(meta_ptr); - // Truncate vtable off of args list - args = &args[..1]; - debug!("args' = {:?}", args); - ( - meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE) - .get_fn(bx, meta.immediate(), ty, fn_abi), - fn_abi, - virtual_drop, - ) - } - _ => ( - bx.get_fn_addr(drop_fn), - bx.fn_abi_of_instance(drop_fn, ty::List::empty()), - drop_fn, - ), - }; - helper.do_call( - self, - bx, - fn_abi, - drop_fn, - args, - Some((ReturnDest::Nothing, target)), - unwind, - &[], - Some(drop_instance), - mergeable_succ, - ) - } - - fn codegen_assert_terminator( - &mut self, - helper: TerminatorCodegenHelper<'tcx>, - bx: &mut Bx, - terminator: &mir::Terminator<'tcx>, - cond: &mir::Operand<'tcx>, - expected: bool, - msg: &mir::AssertMessage<'tcx>, - target: mir::BasicBlock, - unwind: mir::UnwindAction, - mergeable_succ: bool, - ) -> MergingSucc { - let span = terminator.source_info.span; - let cond = self.codegen_operand(bx, cond).immediate(); - let mut const_cond = bx.const_to_opt_u128(cond, false).map(|c| c == 1); - - // This case can currently arise only from functions marked - // with #[rustc_inherit_overflow_checks] and inlined from - // another crate (mostly core::num generic/#[inline] fns), - // while the current crate doesn't use overflow checks. - if !bx.cx().check_overflow() && msg.is_optional_overflow_check() { - const_cond = Some(expected); - } - - // Don't codegen the panic block if success if known. - if const_cond == Some(expected) { - return helper.funclet_br(self, bx, target, mergeable_succ); - } - - // Pass the condition through llvm.expect for branch hinting. - let cond = bx.expect(cond, expected); - - // Create the failure block and the conditional branch to it. - 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); - } else { - bx.cond_br(cond, panic_block, lltarget); - } - - // After this point, bx is the block for the call to panic. - bx.switch_to_block(panic_block); - self.set_debug_loc(bx, terminator.source_info); - - // Get the location information. - let location = self.get_caller_location(bx, terminator.source_info).immediate(); - - // Put together the arguments to the panic entry point. - let (lang_item, args) = match msg { - AssertKind::BoundsCheck { ref len, ref index } => { - let len = self.codegen_operand(bx, len).immediate(); - let index = self.codegen_operand(bx, index).immediate(); - // It's `fn panic_bounds_check(index: usize, len: usize)`, - // and `#[track_caller]` adds an implicit third argument. - (LangItem::PanicBoundsCheck, vec![index, len, location]) - } - AssertKind::MisalignedPointerDereference { ref required, ref found } => { - let required = self.codegen_operand(bx, required).immediate(); - let found = self.codegen_operand(bx, found).immediate(); - // It's `fn panic_misaligned_pointer_dereference(required: usize, found: usize)`, - // and `#[track_caller]` adds an implicit third argument. - (LangItem::PanicMisalignedPointerDereference, vec![required, found, location]) - } - _ => { - // It's `pub fn panic_...()` and `#[track_caller]` adds an implicit argument. - (msg.panic_function(), vec![location]) - } - }; - - let (fn_abi, llfn, instance) = common::build_langcall(bx, Some(span), lang_item); - - // Codegen the actual panic invoke/call. - let merging_succ = - helper.do_call(self, bx, fn_abi, llfn, &args, None, unwind, &[], Some(instance), false); - assert_eq!(merging_succ, MergingSucc::False); - MergingSucc::False - } - - fn codegen_terminate_terminator( - &mut self, - helper: TerminatorCodegenHelper<'tcx>, - bx: &mut Bx, - terminator: &mir::Terminator<'tcx>, - reason: UnwindTerminateReason, - ) { - let span = terminator.source_info.span; - self.set_debug_loc(bx, terminator.source_info); - - // Obtain the panic entry point. - let (fn_abi, llfn, instance) = common::build_langcall(bx, Some(span), reason.lang_item()); - - // Codegen the actual panic invoke/call. - let merging_succ = helper.do_call( - self, - bx, - fn_abi, - llfn, - &[], - None, - mir::UnwindAction::Unreachable, - &[], - Some(instance), - false, - ); - assert_eq!(merging_succ, MergingSucc::False); - } - - /// Returns `Some` if this is indeed a panic intrinsic and codegen is done. - fn codegen_panic_intrinsic( - &mut self, - helper: &TerminatorCodegenHelper<'tcx>, - bx: &mut Bx, - intrinsic: Option, - instance: Option>, - source_info: mir::SourceInfo, - target: Option, - unwind: mir::UnwindAction, - mergeable_succ: bool, - ) -> Option { - // Emit a panic or a no-op for `assert_*` intrinsics. - // These are intrinsics that compile to panics so that we can get a message - // which mentions the offending type, even from a const context. - let panic_intrinsic = intrinsic.and_then(|i| ValidityRequirement::from_intrinsic(i.name)); - if let Some(requirement) = panic_intrinsic { - let ty = instance.unwrap().args.type_at(0); - - let do_panic = !bx - .tcx() - .check_validity_requirement((requirement, bx.param_env().and(ty))) - .expect("expect to have layout during codegen"); - - let layout = bx.layout_of(ty); - - Some(if do_panic { - let msg_str = with_no_visible_paths!({ - with_no_trimmed_paths!({ - if layout.abi.is_uninhabited() { - // Use this error even for the other intrinsics as it is more precise. - format!("attempted to instantiate uninhabited type `{ty}`") - } else if requirement == ValidityRequirement::Zero { - format!("attempted to zero-initialize type `{ty}`, which is invalid") - } else { - format!( - "attempted to leave type `{ty}` uninitialized, which is invalid" - ) - } - }) - }); - let msg = bx.const_str(&msg_str); - - // Obtain the panic entry point. - let (fn_abi, llfn, instance) = - common::build_langcall(bx, Some(source_info.span), LangItem::PanicNounwind); - - // Codegen the actual panic invoke/call. - helper.do_call( - self, - bx, - fn_abi, - llfn, - &[msg.0, msg.1], - target.as_ref().map(|bb| (ReturnDest::Nothing, *bb)), - unwind, - &[], - Some(instance), - mergeable_succ, - ) - } else { - // a NOP - let target = target.unwrap(); - helper.funclet_br(self, bx, target, mergeable_succ) - }) - } else { - None - } - } - - fn codegen_call_terminator( - &mut self, - helper: TerminatorCodegenHelper<'tcx>, - bx: &mut Bx, - terminator: &mir::Terminator<'tcx>, - func: &mir::Operand<'tcx>, - args: &[Spanned>], - destination: mir::Place<'tcx>, - target: Option, - unwind: mir::UnwindAction, - fn_span: Span, - mergeable_succ: bool, - ) -> MergingSucc { - let source_info = terminator.source_info; - let span = source_info.span; - - // Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar. - let callee = self.codegen_operand(bx, func); - - let (instance, mut llfn) = match *callee.layout.ty.kind() { - ty::FnDef(def_id, args) => ( - Some( - ty::Instance::expect_resolve( - bx.tcx(), - ty::ParamEnv::reveal_all(), - def_id, - args, - ) - .polymorphize(bx.tcx()), - ), - None, - ), - ty::FnPtr(_) => (None, Some(callee.immediate())), - _ => bug!("{} is not callable", callee.layout.ty), - }; - - let def = instance.map(|i| i.def); - - if let Some(ty::InstanceDef::DropGlue(_, None)) = def { - // Empty drop glue; a no-op. - let target = target.unwrap(); - return helper.funclet_br(self, bx, target, mergeable_succ); - } - - // FIXME(eddyb) avoid computing this if possible, when `instance` is - // available - right now `sig` is only needed for getting the `abi` - // and figuring out how many extra args were passed to a C-variadic `fn`. - let sig = callee.layout.ty.fn_sig(bx.tcx()); - let abi = sig.abi(); - - // Handle intrinsics old codegen wants Expr's for, ourselves. - let intrinsic = match def { - Some(ty::InstanceDef::Intrinsic(def_id)) => Some(bx.tcx().intrinsic(def_id).unwrap()), - _ => None, - }; - - let extra_args = &args[sig.inputs().skip_binder().len()..]; - let extra_args = bx.tcx().mk_type_list_from_iter(extra_args.iter().map(|op_arg| { - let op_ty = op_arg.node.ty(self.mir, bx.tcx()); - self.monomorphize(op_ty) - })); - - let fn_abi = match instance { - Some(instance) => bx.fn_abi_of_instance(instance, extra_args), - None => bx.fn_abi_of_fn_ptr(sig, extra_args), - }; - - if let Some(merging_succ) = self.codegen_panic_intrinsic( - &helper, - bx, - intrinsic, - instance, - source_info, - target, - unwind, - mergeable_succ, - ) { - return merging_succ; - } - - // The arguments we'll be passing. Plus one to account for outptr, if used. - let arg_count = fn_abi.args.len() + fn_abi.ret.is_indirect() as usize; - - if matches!(intrinsic, Some(ty::IntrinsicDef { name: sym::caller_location, .. })) { - return if let Some(target) = target { - let location = - self.get_caller_location(bx, mir::SourceInfo { span: fn_span, ..source_info }); - - let mut llargs = Vec::with_capacity(arg_count); - let ret_dest = self.make_return_dest( - bx, - destination, - &fn_abi.ret, - &mut llargs, - intrinsic, - Some(target), - ); - assert_eq!(llargs, []); - if let ReturnDest::IndirectOperand(tmp, _) = ret_dest { - location.val.store(bx, tmp); - } - self.store_return(bx, ret_dest, &fn_abi.ret, location.immediate()); - helper.funclet_br(self, bx, target, mergeable_succ) - } else { - MergingSucc::False - }; - } - - let instance = match intrinsic { - None => instance, - Some(intrinsic) => { - let mut llargs = Vec::with_capacity(1); - let ret_dest = self.make_return_dest( - bx, - destination, - &fn_abi.ret, - &mut llargs, - Some(intrinsic), - target, - ); - let dest = match ret_dest { - _ if fn_abi.ret.is_indirect() => llargs[0], - ReturnDest::Nothing => bx.const_undef(bx.type_ptr()), - ReturnDest::IndirectOperand(dst, _) | ReturnDest::Store(dst) => dst.llval, - ReturnDest::DirectOperand(_) => { - bug!("Cannot use direct operand with an intrinsic call") - } - }; - - let args: Vec<_> = args - .iter() - .enumerate() - .map(|(i, arg)| { - // The indices passed to simd_shuffle in the - // third argument must be constant. This is - // checked by the type-checker. - if i == 2 && intrinsic.name == sym::simd_shuffle { - if let mir::Operand::Constant(constant) = &arg.node { - let (llval, ty) = self.simd_shuffle_indices(bx, constant); - return OperandRef { - val: Immediate(llval), - layout: bx.layout_of(ty), - }; - } else { - span_bug!(span, "shuffle indices must be constant"); - } - } - - self.codegen_operand(bx, &arg.node) - }) - .collect(); - - let instance = *instance.as_ref().unwrap(); - match Self::codegen_intrinsic_call(bx, instance, fn_abi, &args, dest, span) { - Ok(()) => { - if let ReturnDest::IndirectOperand(dst, _) = ret_dest { - self.store_return(bx, ret_dest, &fn_abi.ret, dst.llval); - } - - return if let Some(target) = target { - helper.funclet_br(self, bx, target, mergeable_succ) - } else { - bx.unreachable(); - MergingSucc::False - }; - } - Err(instance) => { - if intrinsic.must_be_overridden { - span_bug!( - span, - "intrinsic {} must be overridden by codegen backend, but isn't", - intrinsic.name, - ); - } - Some(instance) - } - } - } - }; - - let mut llargs = Vec::with_capacity(arg_count); - let destination = target.as_ref().map(|&target| { - ( - self.make_return_dest( - bx, - destination, - &fn_abi.ret, - &mut llargs, - None, - Some(target), - ), - target, - ) - }); - - // Split the rust-call tupled arguments off. - let (first_args, untuple) = if abi == Abi::RustCall && !args.is_empty() { - let (tup, args) = args.split_last().unwrap(); - (args, Some(tup)) - } else { - (args, None) - }; - - let mut copied_constant_arguments = vec![]; - 'make_args: for (i, arg) in first_args.iter().enumerate() { - let mut op = self.codegen_operand(bx, &arg.node); - - if let (0, Some(ty::InstanceDef::Virtual(_, idx))) = (i, def) { - match op.val { - Pair(data_ptr, meta) => { - // In the case of Rc, we need to explicitly pass a - // *mut RcBox with a Scalar (not ScalarPair) ABI. This is a hack - // that is understood elsewhere in the compiler as a method on - // `dyn Trait`. - // To get a `*mut RcBox`, we just keep unwrapping newtypes until - // we get a value of a built-in pointer type. - // - // This is also relevant for `Pin<&mut Self>`, where we need to peel the `Pin`. - while !op.layout.ty.is_unsafe_ptr() && !op.layout.ty.is_ref() { - let (idx, _) = op.layout.non_1zst_field(bx).expect( - "not exactly one non-1-ZST field in a `DispatchFromDyn` type", - ); - op = op.extract_field(bx, idx); - } - - // now that we have `*dyn Trait` or `&dyn Trait`, split it up into its - // data pointer and vtable. Look up the method in the vtable, and pass - // the data pointer as the first argument - llfn = Some(meth::VirtualIndex::from_index(idx).get_fn( - bx, - meta, - op.layout.ty, - fn_abi, - )); - llargs.push(data_ptr); - continue 'make_args; - } - Ref(data_ptr, Some(meta), _) => { - // by-value dynamic dispatch - llfn = Some(meth::VirtualIndex::from_index(idx).get_fn( - bx, - meta, - op.layout.ty, - fn_abi, - )); - llargs.push(data_ptr); - continue; - } - Immediate(_) => { - // See comment above explaining why we peel these newtypes - while !op.layout.ty.is_unsafe_ptr() && !op.layout.ty.is_ref() { - let (idx, _) = op.layout.non_1zst_field(bx).expect( - "not exactly one non-1-ZST field in a `DispatchFromDyn` type", - ); - op = op.extract_field(bx, idx); - } - - // Make sure that we've actually unwrapped the rcvr down - // to a pointer or ref to `dyn* Trait`. - if !op.layout.ty.builtin_deref(true).unwrap().ty.is_dyn_star() { - span_bug!(span, "can't codegen a virtual call on {:#?}", op); - } - let place = op.deref(bx.cx()); - let data_ptr = place.project_field(bx, 0); - let meta_ptr = place.project_field(bx, 1); - let meta = bx.load_operand(meta_ptr); - llfn = Some(meth::VirtualIndex::from_index(idx).get_fn( - bx, - meta.immediate(), - op.layout.ty, - fn_abi, - )); - llargs.push(data_ptr.llval); - continue; - } - _ => { - span_bug!(span, "can't codegen a virtual call on {:#?}", op); - } - } - } - - // The callee needs to own the argument memory if we pass it - // by-ref, so make a local copy of non-immediate constants. - match (&arg.node, op.val) { - (&mir::Operand::Copy(_), Ref(_, None, _)) - | (&mir::Operand::Constant(_), Ref(_, None, _)) => { - let tmp = PlaceRef::alloca(bx, op.layout); - bx.lifetime_start(tmp.llval, tmp.layout.size); - op.val.store(bx, tmp); - op.val = Ref(tmp.llval, None, tmp.align); - copied_constant_arguments.push(tmp); - } - _ => {} - } - - self.codegen_argument(bx, op, &mut llargs, &fn_abi.args[i]); - } - let num_untupled = untuple.map(|tup| { - self.codegen_arguments_untupled( - bx, - &tup.node, - &mut llargs, - &fn_abi.args[first_args.len()..], - ) - }); - - let needs_location = - instance.is_some_and(|i| i.def.requires_caller_location(self.cx.tcx())); - if needs_location { - let mir_args = if let Some(num_untupled) = num_untupled { - first_args.len() + num_untupled - } else { - args.len() - }; - assert_eq!( - fn_abi.args.len(), - mir_args + 1, - "#[track_caller] fn's must have 1 more argument in their ABI than in their MIR: {instance:?} {fn_span:?} {fn_abi:?}", - ); - let location = - self.get_caller_location(bx, mir::SourceInfo { span: fn_span, ..source_info }); - debug!( - "codegen_call_terminator({:?}): location={:?} (fn_span {:?})", - terminator, location, fn_span - ); - - let last_arg = fn_abi.args.last().unwrap(); - self.codegen_argument(bx, location, &mut llargs, last_arg); - } - - let fn_ptr = match (instance, llfn) { - (Some(instance), None) => bx.get_fn_addr(instance), - (_, Some(llfn)) => llfn, - _ => span_bug!(span, "no instance or llfn for call"), - }; - helper.do_call( - self, - bx, - fn_abi, - fn_ptr, - &llargs, - destination, - unwind, - &copied_constant_arguments, - instance, - mergeable_succ, - ) - } - - fn codegen_asm_terminator( - &mut self, - helper: TerminatorCodegenHelper<'tcx>, - bx: &mut Bx, - terminator: &mir::Terminator<'tcx>, - template: &[ast::InlineAsmTemplatePiece], - operands: &[mir::InlineAsmOperand<'tcx>], - options: ast::InlineAsmOptions, - line_spans: &[Span], - targets: &[mir::BasicBlock], - unwind: mir::UnwindAction, - instance: Instance<'_>, - mergeable_succ: bool, - ) -> MergingSucc { - let span = terminator.source_info.span; - - let operands: Vec<_> = operands - .iter() - .map(|op| match *op { - mir::InlineAsmOperand::In { reg, ref value } => { - let value = self.codegen_operand(bx, value); - InlineAsmOperandRef::In { reg, value } - } - mir::InlineAsmOperand::Out { reg, late, ref place } => { - let place = place.map(|place| self.codegen_place(bx, place.as_ref())); - InlineAsmOperandRef::Out { reg, late, place } - } - mir::InlineAsmOperand::InOut { reg, late, ref in_value, ref out_place } => { - let in_value = self.codegen_operand(bx, in_value); - let out_place = - out_place.map(|out_place| self.codegen_place(bx, out_place.as_ref())); - InlineAsmOperandRef::InOut { reg, late, in_value, out_place } - } - mir::InlineAsmOperand::Const { ref value } => { - let const_value = self.eval_mir_constant(value); - let string = common::asm_const_to_str( - bx.tcx(), - span, - const_value, - bx.layout_of(value.ty()), - ); - InlineAsmOperandRef::Const { string } - } - mir::InlineAsmOperand::SymFn { ref value } => { - let const_ = self.monomorphize(value.const_); - if let ty::FnDef(def_id, args) = *const_.ty().kind() { - let instance = ty::Instance::resolve_for_fn_ptr( - bx.tcx(), - ty::ParamEnv::reveal_all(), - def_id, - args, - ) - .unwrap(); - InlineAsmOperandRef::SymFn { instance } - } else { - span_bug!(span, "invalid type for asm sym (fn)"); - } - } - mir::InlineAsmOperand::SymStatic { def_id } => { - InlineAsmOperandRef::SymStatic { def_id } - } - mir::InlineAsmOperand::Label { target_index } => { - InlineAsmOperandRef::Label { label: self.llbb(targets[target_index]) } - } - }) - .collect(); - - helper.do_inlineasm( - self, - bx, - template, - &operands, - options, - line_spans, - if options.contains(InlineAsmOptions::NORETURN) { - None - } else { - targets.get(0).copied() - }, - unwind, - instance, - mergeable_succ, - ) - } -} - -impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { - pub fn codegen_block(&mut self, mut bb: mir::BasicBlock) { - let llbb = match self.try_llbb(bb) { - Some(llbb) => llbb, - None => return, - }; - let bx = &mut Bx::build(self.cx, llbb); - let mir = self.mir; - - // MIR basic blocks stop at any function call. This may not be the case - // for the backend's basic blocks, in which case we might be able to - // combine multiple MIR basic blocks into a single backend basic block. - loop { - let data = &mir[bb]; - - debug!("codegen_block({:?}={:?})", bb, data); - - for statement in &data.statements { - self.codegen_statement(bx, statement); - } - - let merging_succ = self.codegen_terminator(bx, bb, data.terminator()); - if let MergingSucc::False = merging_succ { - break; - } - - // We are merging the successor into the produced backend basic - // block. Record that the successor should be skipped when it is - // reached. - // - // Note: we must not have already generated code for the successor. - // This is implicitly ensured by the reverse postorder traversal, - // and the assertion explicitly guarantees that. - let mut successors = data.terminator().successors(); - let succ = successors.next().unwrap(); - assert!(matches!(self.cached_llbbs[succ], CachedLlbb::None)); - self.cached_llbbs[succ] = CachedLlbb::Skip; - bb = succ; - } - } - - pub fn codegen_block_as_unreachable(&mut self, bb: mir::BasicBlock) { - let llbb = match self.try_llbb(bb) { - Some(llbb) => llbb, - None => return, - }; - let bx = &mut Bx::build(self.cx, llbb); - debug!("codegen_block_as_unreachable({:?})", bb); - bx.unreachable(); - } - - fn codegen_terminator( - &mut self, - bx: &mut Bx, - bb: mir::BasicBlock, - terminator: &'tcx mir::Terminator<'tcx>, - ) -> MergingSucc { - debug!("codegen_terminator: {:?}", terminator); - - let helper = TerminatorCodegenHelper { bb, terminator }; - - let mergeable_succ = || { - // Note: any call to `switch_to_block` will invalidate a `true` value - // of `mergeable_succ`. - let mut successors = terminator.successors(); - if let Some(succ) = successors.next() - && successors.next().is_none() - && let &[succ_pred] = self.mir.basic_blocks.predecessors()[succ].as_slice() - { - // bb has a single successor, and bb is its only predecessor. This - // makes it a candidate for merging. - assert_eq!(succ_pred, bb); - true - } else { - false - } - }; - - self.set_debug_loc(bx, terminator.source_info); - match terminator.kind { - mir::TerminatorKind::UnwindResume => { - self.codegen_resume_terminator(helper, bx); - MergingSucc::False - } - - mir::TerminatorKind::UnwindTerminate(reason) => { - self.codegen_terminate_terminator(helper, bx, terminator, reason); - MergingSucc::False - } - - mir::TerminatorKind::Goto { target } => { - helper.funclet_br(self, bx, target, mergeable_succ()) - } - - mir::TerminatorKind::SwitchInt { ref discr, ref targets } => { - self.codegen_switchint_terminator(helper, bx, discr, targets); - MergingSucc::False - } - - mir::TerminatorKind::Return => { - self.codegen_return_terminator(bx); - MergingSucc::False - } - - mir::TerminatorKind::Unreachable => { - bx.unreachable(); - MergingSucc::False - } - - mir::TerminatorKind::Drop { place, target, unwind, replace: _ } => { - self.codegen_drop_terminator(helper, bx, place, target, unwind, mergeable_succ()) - } - - mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, unwind } => self - .codegen_assert_terminator( - helper, - bx, - terminator, - cond, - expected, - msg, - target, - unwind, - mergeable_succ(), - ), - - mir::TerminatorKind::Call { - ref func, - ref args, - destination, - target, - unwind, - call_source: _, - fn_span, - } => self.codegen_call_terminator( - helper, - bx, - terminator, - func, - args, - destination, - target, - unwind, - fn_span, - mergeable_succ(), - ), - mir::TerminatorKind::CoroutineDrop | mir::TerminatorKind::Yield { .. } => { - bug!("coroutine ops in codegen") - } - mir::TerminatorKind::FalseEdge { .. } | mir::TerminatorKind::FalseUnwind { .. } => { - bug!("borrowck false edges in codegen") - } - - mir::TerminatorKind::InlineAsm { - template, - ref operands, - options, - line_spans, - ref targets, - unwind, - } => self.codegen_asm_terminator( - helper, - bx, - terminator, - template, - operands, - options, - line_spans, - targets, - unwind, - self.instance, - mergeable_succ(), - ), - } - } - - fn codegen_argument( - &mut self, - bx: &mut Bx, - op: OperandRef<'tcx, Bx::Value>, - llargs: &mut Vec, - arg: &ArgAbi<'tcx, Ty<'tcx>>, - ) { - match arg.mode { - PassMode::Ignore => return, - PassMode::Cast { pad_i32: true, .. } => { - // Fill padding with undef value, where applicable. - llargs.push(bx.const_undef(bx.reg_backend_type(&Reg::i32()))); - } - PassMode::Pair(..) => match op.val { - Pair(a, b) => { - llargs.push(a); - llargs.push(b); - return; - } - _ => bug!("codegen_argument: {:?} invalid for pair argument", op), - }, - PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => match op.val { - Ref(a, Some(b), _) => { - llargs.push(a); - llargs.push(b); - return; - } - _ => bug!("codegen_argument: {:?} invalid for unsized indirect argument", op), - }, - _ => {} - } - - // Force by-ref if we have to load through a cast pointer. - let (mut llval, align, by_ref) = match op.val { - Immediate(_) | Pair(..) => match arg.mode { - PassMode::Indirect { attrs, .. } => { - // Indirect argument may have higher alignment requirements than the type's alignment. - // This can happen, e.g. when passing types with <4 byte alignment on the stack on x86. - let required_align = match attrs.pointee_align { - Some(pointee_align) => cmp::max(pointee_align, arg.layout.align.abi), - None => arg.layout.align.abi, - }; - let scratch = PlaceRef::alloca_aligned(bx, arg.layout, required_align); - op.val.store(bx, scratch); - (scratch.llval, scratch.align, true) - } - PassMode::Cast { .. } => { - let scratch = PlaceRef::alloca(bx, arg.layout); - op.val.store(bx, scratch); - (scratch.llval, scratch.align, true) - } - _ => (op.immediate_or_packed_pair(bx), arg.layout.align.abi, false), - }, - Ref(llval, _, align) => match arg.mode { - PassMode::Indirect { attrs, .. } => { - let required_align = match attrs.pointee_align { - Some(pointee_align) => cmp::max(pointee_align, arg.layout.align.abi), - None => arg.layout.align.abi, - }; - if align < required_align { - // For `foo(packed.large_field)`, and types with <4 byte alignment on x86, - // alignment requirements may be higher than the type's alignment, so copy - // to a higher-aligned alloca. - let scratch = PlaceRef::alloca_aligned(bx, arg.layout, required_align); - base::memcpy_ty( - bx, - scratch.llval, - scratch.align, - llval, - align, - op.layout, - MemFlags::empty(), - ); - (scratch.llval, scratch.align, true) - } else { - (llval, align, true) - } - } - _ => (llval, align, true), - }, - ZeroSized => match arg.mode { - PassMode::Indirect { on_stack, .. } => { - if on_stack { - // It doesn't seem like any target can have `byval` ZSTs, so this assert - // is here to replace a would-be untested codepath. - bug!("ZST {op:?} passed on stack with abi {arg:?}"); - } - // Though `extern "Rust"` doesn't pass ZSTs, some ABIs pass - // a pointer for `repr(C)` structs even when empty, so get - // one from an `alloca` (which can be left uninitialized). - let scratch = PlaceRef::alloca(bx, arg.layout); - (scratch.llval, scratch.align, true) - } - _ => bug!("ZST {op:?} wasn't ignored, but was passed with abi {arg:?}"), - }, - }; - - if by_ref && !arg.is_indirect() { - // Have to load the argument, maybe while casting it. - if let PassMode::Cast { cast: ty, .. } = &arg.mode { - let llty = bx.cast_backend_type(ty); - llval = bx.load(llty, llval, align.min(arg.layout.align.abi)); - } else { - // We can't use `PlaceRef::load` here because the argument - // may have a type we don't treat as immediate, but the ABI - // used for this call is passing it by-value. In that case, - // the load would just produce `OperandValue::Ref` instead - // of the `OperandValue::Immediate` we need for the call. - llval = bx.load(bx.backend_type(arg.layout), llval, align); - if let abi::Abi::Scalar(scalar) = arg.layout.abi { - if scalar.is_bool() { - bx.range_metadata(llval, WrappingRange { start: 0, end: 1 }); - } - } - // We store bools as `i8` so we need to truncate to `i1`. - llval = bx.to_immediate(llval, arg.layout); - } - } - - llargs.push(llval); - } - - fn codegen_arguments_untupled( - &mut self, - bx: &mut Bx, - operand: &mir::Operand<'tcx>, - llargs: &mut Vec, - args: &[ArgAbi<'tcx, Ty<'tcx>>], - ) -> usize { - let tuple = self.codegen_operand(bx, operand); - - // Handle both by-ref and immediate tuples. - if let Ref(llval, None, align) = tuple.val { - let tuple_ptr = PlaceRef::new_sized_aligned(llval, tuple.layout, align); - for i in 0..tuple.layout.fields.count() { - let field_ptr = tuple_ptr.project_field(bx, i); - let field = bx.load_operand(field_ptr); - self.codegen_argument(bx, field, llargs, &args[i]); - } - } else if let Ref(_, Some(_), _) = tuple.val { - bug!("closure arguments must be sized") - } else { - // If the tuple is immediate, the elements are as well. - for i in 0..tuple.layout.fields.count() { - let op = tuple.extract_field(bx, i); - self.codegen_argument(bx, op, llargs, &args[i]); - } - } - tuple.layout.fields.count() - } - - fn get_caller_location( - &mut self, - bx: &mut Bx, - source_info: mir::SourceInfo, - ) -> OperandRef<'tcx, Bx::Value> { - self.mir.caller_location_span(source_info, self.caller_location, bx.tcx(), |span: Span| { - let const_loc = bx.tcx().span_as_caller_location(span); - OperandRef::from_const(bx, const_loc, bx.tcx().caller_location_ty()) - }) - } - - fn get_personality_slot(&mut self, bx: &mut Bx) -> PlaceRef<'tcx, Bx::Value> { - let cx = bx.cx(); - if let Some(slot) = self.personality_slot { - slot - } else { - let layout = cx.layout_of(Ty::new_tup( - cx.tcx(), - &[Ty::new_mut_ptr(cx.tcx(), cx.tcx().types.u8), cx.tcx().types.i32], - )); - let slot = PlaceRef::alloca(bx, layout); - self.personality_slot = Some(slot); - slot - } - } - - /// Returns the landing/cleanup pad wrapper around the given basic block. - // FIXME(eddyb) rename this to `eh_pad_for`. - fn landing_pad_for(&mut self, bb: mir::BasicBlock) -> Bx::BasicBlock { - if let Some(landing_pad) = self.landing_pads[bb] { - return landing_pad; - } - - let landing_pad = self.landing_pad_for_uncached(bb); - self.landing_pads[bb] = Some(landing_pad); - landing_pad - } - - // FIXME(eddyb) rename this to `eh_pad_for_uncached`. - fn landing_pad_for_uncached(&mut self, bb: mir::BasicBlock) -> Bx::BasicBlock { - let llbb = self.llbb(bb); - if base::wants_new_eh_instructions(self.cx.sess()) { - let cleanup_bb = Bx::append_block(self.cx, self.llfn, &format!("funclet_{bb:?}")); - let mut cleanup_bx = Bx::build(self.cx, cleanup_bb); - let funclet = cleanup_bx.cleanup_pad(None, &[]); - cleanup_bx.br(llbb); - self.funclets[bb] = Some(funclet); - cleanup_bb - } else { - 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 (exn0, exn1) = cleanup_bx.cleanup_landing_pad(llpersonality); - - let slot = self.get_personality_slot(&mut cleanup_bx); - slot.storage_live(&mut cleanup_bx); - Pair(exn0, exn1).store(&mut cleanup_bx, slot); - - cleanup_bx.br(llbb); - cleanup_llbb - } - } - - fn unreachable_block(&mut self) -> Bx::BasicBlock { - self.unreachable_block.unwrap_or_else(|| { - let llbb = Bx::append_block(self.cx, self.llfn, "unreachable"); - let mut bx = Bx::build(self.cx, llbb); - bx.unreachable(); - self.unreachable_block = Some(llbb); - llbb - }) - } - - fn terminate_block(&mut self, reason: UnwindTerminateReason) -> Bx::BasicBlock { - if let Some((cached_bb, cached_reason)) = self.terminate_block - && reason == cached_reason - { - return cached_bb; - } - - let funclet; - let llbb; - let mut bx; - if base::wants_new_eh_instructions(self.cx.sess()) { - // This is a basic block that we're aborting the program for, - // notably in an `extern` function. These basic blocks are inserted - // so that we assert that `extern` functions do indeed not panic, - // and if they do we abort the process. - // - // On MSVC these are tricky though (where we're doing funclets). If - // we were to do a cleanuppad (like below) the normal functions like - // `longjmp` would trigger the abort logic, terminating the - // program. Instead we insert the equivalent of `catch(...)` for C++ - // which magically doesn't trigger when `longjmp` files over this - // frame. - // - // Lots more discussion can be found on #48251 but this codegen is - // modeled after clang's for: - // - // try { - // foo(); - // } catch (...) { - // bar(); - // } - // - // which creates an IR snippet like - // - // cs_terminate: - // %cs = catchswitch within none [%cp_terminate] unwind to caller - // cp_terminate: - // %cp = catchpad within %cs [null, i32 64, null] - // ... - - llbb = Bx::append_block(self.cx, self.llfn, "cs_terminate"); - let cp_llbb = Bx::append_block(self.cx, self.llfn, "cp_terminate"); - - let mut cs_bx = Bx::build(self.cx, 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. - bx = Bx::build(self.cx, cp_llbb); - let null = - bx.const_null(bx.type_ptr_ext(bx.cx().data_layout().instruction_address_space)); - let sixty_four = bx.const_i32(64); - funclet = Some(bx.catch_pad(cs, &[null, sixty_four, null])); - } else { - llbb = Bx::append_block(self.cx, self.llfn, "terminate"); - bx = Bx::build(self.cx, llbb); - - let llpersonality = self.cx.eh_personality(); - bx.filter_landing_pad(llpersonality); - - funclet = None; - } - - self.set_debug_loc(&mut bx, mir::SourceInfo::outermost(self.mir.span)); - - let (fn_abi, fn_ptr, instance) = common::build_langcall(&bx, None, reason.lang_item()); - if is_call_from_compiler_builtins_to_upstream_monomorphization(bx.tcx(), instance) { - bx.abort(); - } else { - let fn_ty = bx.fn_decl_backend_type(fn_abi); - - let llret = bx.call(fn_ty, None, Some(fn_abi), fn_ptr, &[], funclet.as_ref(), None); - bx.apply_attrs_to_cleanup_callsite(llret); - } - - bx.unreachable(); - - self.terminate_block = Some((llbb, reason)); - llbb - } - - /// Get the backend `BasicBlock` for a MIR `BasicBlock`, either already - /// cached in `self.cached_llbbs`, or created on demand (and cached). - // FIXME(eddyb) rename `llbb` and other `ll`-prefixed things to use a - // more backend-agnostic prefix such as `cg` (i.e. this would be `cgbb`). - pub fn llbb(&mut self, bb: mir::BasicBlock) -> Bx::BasicBlock { - self.try_llbb(bb).unwrap() - } - - /// Like `llbb`, but may fail if the basic block should be skipped. - pub fn try_llbb(&mut self, bb: mir::BasicBlock) -> Option { - match self.cached_llbbs[bb] { - CachedLlbb::None => { - let llbb = Bx::append_block(self.cx, self.llfn, &format!("{bb:?}")); - self.cached_llbbs[bb] = CachedLlbb::Some(llbb); - Some(llbb) - } - CachedLlbb::Some(llbb) => Some(llbb), - CachedLlbb::Skip => None, - } - } - - fn make_return_dest( - &mut self, - bx: &mut Bx, - dest: mir::Place<'tcx>, - fn_ret: &ArgAbi<'tcx, Ty<'tcx>>, - llargs: &mut Vec, - intrinsic: Option, - target: Option, - ) -> ReturnDest<'tcx, Bx::Value> { - if target.is_none() { - return ReturnDest::Nothing; - } - // If the return is ignored, we can just return a do-nothing `ReturnDest`. - if fn_ret.is_ignore() { - return ReturnDest::Nothing; - } - let dest = if let Some(index) = dest.as_local() { - match self.locals[index] { - LocalRef::Place(dest) => dest, - LocalRef::UnsizedPlace(_) => bug!("return type must be sized"), - LocalRef::PendingOperand => { - // Handle temporary places, specifically `Operand` ones, as - // they don't have `alloca`s. - return if fn_ret.is_indirect() { - // Odd, but possible, case, we have an operand temporary, - // but the calling convention has an indirect return. - let tmp = PlaceRef::alloca(bx, fn_ret.layout); - tmp.storage_live(bx); - llargs.push(tmp.llval); - ReturnDest::IndirectOperand(tmp, index) - } else if intrinsic.is_some() { - // Currently, intrinsics always need a location to store - // the result, so we create a temporary `alloca` for the - // result. - let tmp = PlaceRef::alloca(bx, fn_ret.layout); - tmp.storage_live(bx); - ReturnDest::IndirectOperand(tmp, index) - } else { - ReturnDest::DirectOperand(index) - }; - } - LocalRef::Operand(_) => { - bug!("place local already assigned to"); - } - } - } else { - self.codegen_place(bx, mir::PlaceRef { local: dest.local, projection: dest.projection }) - }; - if fn_ret.is_indirect() { - if dest.align < dest.layout.align.abi { - // Currently, MIR code generation does not create calls - // that store directly to fields of packed structs (in - // fact, the calls it creates write only to temps). - // - // If someone changes that, please update this code path - // to create a temporary. - span_bug!(self.mir.span, "can't directly store to unaligned value"); - } - llargs.push(dest.llval); - ReturnDest::Nothing - } else { - ReturnDest::Store(dest) - } - } - - // Stores the return value of a function call into it's final location. - fn store_return( - &mut self, - bx: &mut Bx, - dest: ReturnDest<'tcx, Bx::Value>, - ret_abi: &ArgAbi<'tcx, Ty<'tcx>>, - llval: Bx::Value, - ) { - use self::ReturnDest::*; - - match dest { - Nothing => (), - Store(dst) => bx.store_arg(ret_abi, llval, dst), - IndirectOperand(tmp, index) => { - let op = bx.load_operand(tmp); - tmp.storage_dead(bx); - self.overwrite_local(index, LocalRef::Operand(op)); - self.debug_introduce_local(bx, index); - } - DirectOperand(index) => { - // If there is a cast, we have to store and reload. - let op = if let PassMode::Cast { .. } = ret_abi.mode { - let tmp = PlaceRef::alloca(bx, ret_abi.layout); - tmp.storage_live(bx); - bx.store_arg(ret_abi, llval, tmp); - let op = bx.load_operand(tmp); - tmp.storage_dead(bx); - op - } else { - OperandRef::from_immediate_or_packed_pair(bx, llval, ret_abi.layout) - }; - self.overwrite_local(index, LocalRef::Operand(op)); - self.debug_introduce_local(bx, index); - } - } - } -} - -enum ReturnDest<'tcx, V> { - // Do nothing; the return value is indirect or ignored. - Nothing, - // Store the return value to the pointer. - Store(PlaceRef<'tcx, V>), - // Store an indirect return value to an operand local place. - IndirectOperand(PlaceRef<'tcx, V>, mir::Local), - // Store a direct return value to an operand local place. - DirectOperand(mir::Local), -} +use super::operand::OperandRef;use super::operand::OperandValue::{Immediate,//3; +Pair,Ref,ZeroSized};use super::place::PlaceRef;use super::{CachedLlbb,//((),()); +FunctionCx,LocalRef};use crate::base;use crate::common::{self,IntPredicate};use +crate::errors::CompilerBuiltinsCannotCall;use crate::meth;use crate::traits::*// +;use crate::MemFlags;use rustc_ast as ast;use rustc_ast::{InlineAsmOptions,//(); +InlineAsmTemplatePiece};use rustc_hir::lang_items::LangItem;use rustc_middle::// +mir::{self,AssertKind,BasicBlock,SwitchTargets,UnwindTerminateReason};use//({}); +rustc_middle::ty::layout::{HasTyCtxt,LayoutOf,ValidityRequirement};use//((),()); +rustc_middle::ty::print::{with_no_trimmed_paths,with_no_visible_paths};use//{;}; +rustc_middle::ty::{self,Instance,Ty};use rustc_monomorphize:://((),());let _=(); +is_call_from_compiler_builtins_to_upstream_monomorphization;use rustc_session:: +config::OptLevel;use rustc_span::{source_map::Spanned,sym,Span};use//let _=||(); +rustc_target::abi::call::{ArgAbi,FnAbi,PassMode,Reg};use rustc_target::abi::{//; +self,HasDataLayout,WrappingRange};use rustc_target:: spec::abi::Abi;use std::cmp +;#[derive(Debug,PartialEq)]enum MergingSucc{False,True,}struct//((),());((),()); +TerminatorCodegenHelper<'tcx>{bb:mir::BasicBlock,terminator:&'tcx mir:://*&*&(); +Terminator<'tcx>,}impl<'a,'tcx>TerminatorCodegenHelper<'tcx>{fn funclet<'b,Bx:// +BuilderMethods<'a,'tcx>>(&self,fx:&'b mut FunctionCx<'a,'tcx,Bx>,)->Option<&'b// +Bx::Funclet>{();let cleanup_kinds=fx.cleanup_kinds.as_ref()?;3;3;let funclet_bb= +cleanup_kinds[self.bb].funclet_bb(self.bb)?;;if fx.funclets[funclet_bb].is_none( +){;fx.landing_pad_for(funclet_bb);}Some(fx.funclets[funclet_bb].as_ref().expect( +"landing_pad_for didn't also create funclets entry"),)} fn llbb_with_cleanup>(&self,fx:&mut FunctionCx<'a,'tcx,Bx>,target:mir:://{;}; +BasicBlock,)->Bx::BasicBlock{let _=();let(needs_landing_pad,is_cleanupret)=self. +llbb_characteristics(fx,target);({});{;};let mut lltarget=fx.llbb(target);{;};if +needs_landing_pad{();lltarget=fx.landing_pad_for(target);();}if is_cleanupret{3; +debug_assert!(base::wants_new_eh_instructions(fx.cx.tcx().sess));{;};{;};debug!( +"llbb_with_cleanup: creating cleanup trampoline for {:?}",target);3;3;let name=& +format!("{:?}_cleanup_trampoline_{:?}",self.bb,target);;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));let _=||();trampoline_llbb}else{lltarget}}fn llbb_characteristics>(&self,fx:&mut FunctionCx<'a,'tcx,Bx>,target:mir:://{;}; +BasicBlock,)->(bool,bool){if let Some(ref cleanup_kinds)=fx.cleanup_kinds{();let +funclet_bb=cleanup_kinds[self.bb].funclet_bb(self.bb);{;};();let target_funclet= +cleanup_kinds[target].funclet_bb(target);;;let(needs_landing_pad,is_cleanupret)= +match(funclet_bb,target_funclet){(None,None)=>(false,false),(None,Some(_))=>(//; +true,false),(Some(f),Some(t_f))=>(f!=t_f,f!=t_f),(Some(_),None)=>{;let span=self +.terminator.source_info.span;;span_bug!(span,"{:?} - jump out of cleanup?",self. +terminator);;}};(needs_landing_pad,is_cleanupret)}else{let needs_landing_pad=!fx +.mir[self.bb].is_cleanup&&fx.mir[target].is_cleanup;;;let is_cleanupret=false;;( +needs_landing_pad,is_cleanupret)}}fn funclet_br>(&//; +self,fx:&mut FunctionCx<'a,'tcx,Bx>,bx:&mut Bx,target:mir::BasicBlock,//((),()); +mergeable_succ:bool,)->MergingSucc{();let(needs_landing_pad,is_cleanupret)=self. +llbb_characteristics(fx,target);((),());if mergeable_succ&&!needs_landing_pad&&! +is_cleanupret{MergingSucc::True}else{{;};let mut lltarget=fx.llbb(target);{;};if +needs_landing_pad{3;lltarget=fx.landing_pad_for(target);3;}if is_cleanupret{;bx. +cleanup_ret(self.funclet(fx).unwrap(),Some(lltarget));;}else{;bx.br(lltarget);;} +MergingSucc::False}}fn do_call>(&self,fx:&mut//{();}; +FunctionCx<'a,'tcx,Bx>,bx:&mut Bx,fn_abi :&'tcx FnAbi<'tcx,Ty<'tcx>>,fn_ptr:Bx:: +Value,llargs:&[Bx::Value],destination:Option<(ReturnDest<'tcx,Bx::Value>,mir::// +BasicBlock)>,mut unwind:mir ::UnwindAction,copied_constant_arguments:&[PlaceRef< +'tcx,::Value>],instance:Option>,//let _=||(); +mergeable_succ:bool,)->MergingSucc{();let tcx=bx.tcx();();if let Some(instance)= +instance{if is_call_from_compiler_builtins_to_upstream_monomorphization(tcx,//3; +instance){if destination.is_some(){*&*&();let caller=with_no_trimmed_paths!(tcx. +def_path_str(fx.instance.def_id()));();();let callee=with_no_trimmed_paths!(tcx. +def_path_str(instance.def_id()));;tcx.dcx().emit_err(CompilerBuiltinsCannotCall{ +caller,callee});loop{break;};loop{break;};}else{loop{break;};loop{break;};info!( +"compiler_builtins call to diverging function {:?} replaced with abort",//{();}; +instance.def_id());;bx.abort();bx.unreachable();return MergingSucc::False;}}}let +fn_ty=bx.fn_decl_backend_type(fn_abi);();3;let fn_attrs=if bx.tcx().def_kind(fx. +instance.def_id()).has_codegen_attrs(){Some(bx.tcx().codegen_fn_attrs(fx.//({}); +instance.def_id()))}else{None};;if!fn_abi.can_unwind{;unwind=mir::UnwindAction:: +Unreachable;;};let unwind_block=match unwind{mir::UnwindAction::Cleanup(cleanup) +=>Some(self.llbb_with_cleanup(fx,cleanup)),mir::UnwindAction::Continue=>None,//; +mir::UnwindAction::Unreachable=>None,mir::UnwindAction::Terminate(reason)=>{if// +fx.mir[self.bb].is_cleanup&&base::wants_new_eh_instructions(fx.cx.tcx().sess){// +None}else{Some(fx.terminate_block(reason))}}};((),());if let Some(unwind_block)= +unwind_block{3;let ret_llbb=if let Some((_,target))=destination{fx.llbb(target)} +else{fx.unreachable_block()};;let invokeret=bx.invoke(fn_ty,fn_attrs,Some(fn_abi +),fn_ptr,llargs,ret_llbb,unwind_block,self.funclet(fx),instance,);{;};if fx.mir[ +self.bb].is_cleanup{;bx.apply_attrs_to_cleanup_callsite(invokeret);}if let Some( +(ret_dest,target))=destination{{;};bx.switch_to_block(fx.llbb(target));();();fx. +set_debug_loc(bx,self.terminator.source_info);loop{break};loop{break};for tmp in +copied_constant_arguments{();bx.lifetime_end(tmp.llval,tmp.layout.size);3;}3;fx. +store_return(bx,ret_dest,&fn_abi.ret,invokeret);3;}MergingSucc::False}else{3;let +llret=bx.call(fn_ty,fn_attrs,Some(fn_abi),fn_ptr,llargs,self.funclet(fx),//({}); +instance);();if fx.mir[self.bb].is_cleanup{3;bx.apply_attrs_to_cleanup_callsite( +llret);let _=();if true{};}if let Some((ret_dest,target))=destination{for tmp in +copied_constant_arguments{();bx.lifetime_end(tmp.llval,tmp.layout.size);3;}3;fx. +store_return(bx,ret_dest,&fn_abi.ret,llret);*&*&();self.funclet_br(fx,bx,target, +mergeable_succ)}else{;bx.unreachable();;MergingSucc::False}}}fn do_inlineasm>(&self,fx:&mut FunctionCx<'a,'tcx,Bx>,bx:&mut Bx,//({}); +template:&[InlineAsmTemplatePiece],operands:&[InlineAsmOperandRef<'tcx,Bx>],//3; +options:InlineAsmOptions,line_spans:&[Span ],destination:Option +,unwind:mir::UnwindAction,instance:Instance<'_>,mergeable_succ:bool,)->//*&*&(); +MergingSucc{3;let unwind_target=match unwind{mir::UnwindAction::Cleanup(cleanup) +=>Some(self.llbb_with_cleanup(fx,cleanup )),mir::UnwindAction::Terminate(reason) +=>Some(fx.terminate_block(reason)),mir::UnwindAction::Continue=>None,mir:://{;}; +UnwindAction::Unreachable=>None,};let _=();if operands.iter().any(|x|matches!(x, +InlineAsmOperandRef::Label{..})){;assert!(unwind_target.is_none());let ret_llbb= +if let Some(target)=destination{fx.llbb(target)}else{fx.unreachable_block()};;bx +.codegen_inline_asm(template,operands,options ,line_spans,instance,Some(ret_llbb +),None,);({});MergingSucc::False}else if let Some(cleanup)=unwind_target{{;};let +ret_llbb=if let Some(target)=destination{fx.llbb(target)}else{fx.//loop{break;}; +unreachable_block()};;bx.codegen_inline_asm(template,operands,options,line_spans +,instance,Some(ret_llbb),Some((cleanup,self.funclet(fx))),);;MergingSucc::False} +else{3;bx.codegen_inline_asm(template,operands,options,line_spans,instance,None, +None);loop{break;};if let Some(target)=destination{self.funclet_br(fx,bx,target, +mergeable_succ)}else{3;bx.unreachable();3;MergingSucc::False}}}}impl<'a,'tcx,Bx: +BuilderMethods<'a,'tcx>>FunctionCx<'a,'tcx,Bx>{fn codegen_resume_terminator(&//; +mut self,helper:TerminatorCodegenHelper<'tcx>,bx:& mut Bx){if let Some(funclet)= +helper.funclet(self){{;};bx.cleanup_ret(funclet,None);();}else{();let slot=self. +get_personality_slot(bx);();3;let exn0=slot.project_field(bx,0);3;3;let exn0=bx. +load_operand(exn0).immediate();;;let exn1=slot.project_field(bx,1);;let exn1=bx. +load_operand(exn1).immediate();;;slot.storage_dead(bx);bx.resume(exn0,exn1);}}fn +codegen_switchint_terminator(&mut self,helper :TerminatorCodegenHelper<'tcx>,bx: +&mut Bx,discr:&mir::Operand<'tcx>,targets:&SwitchTargets,){{();};let discr=self. +codegen_operand(bx,discr);;let discr_value=discr.immediate();let switch_ty=discr +.layout.ty;;if let Some(const_discr)=bx.const_to_opt_u128(discr_value,false){let +target=targets.target_for_value(const_discr);3;3;bx.br(helper.llbb_with_cleanup( +self,target));;;return;};let mut target_iter=targets.iter();if target_iter.len() +==1{();let(test_value,target)=target_iter.next().unwrap();3;3;let lltrue=helper. +llbb_with_cleanup(self,target);{;};();let llfalse=helper.llbb_with_cleanup(self, +targets.otherwise());3;if switch_ty==bx.tcx().types.bool{match test_value{0=>bx. +cond_br(discr_value,llfalse,lltrue),1=> bx.cond_br(discr_value,lltrue,llfalse),_ +=>bug!(),}}else{let _=();let switch_llty=bx.immediate_backend_type(bx.layout_of( +switch_ty));;let llval=bx.const_uint_big(switch_llty,test_value);let cmp=bx.icmp +(IntPredicate::IntEQ,discr_value,llval);;;bx.cond_br(cmp,lltrue,llfalse);;}}else +if self.cx.sess().opts.optimize==OptLevel::No&&target_iter.len()==2&&self.mir[// +targets.otherwise()].is_empty_unreachable(){let _=||();let(test_value1,target1)= +target_iter.next().unwrap();;let(_test_value2,target2)=target_iter.next().unwrap +();{;};{;};let ll1=helper.llbb_with_cleanup(self,target1);{;};();let ll2=helper. +llbb_with_cleanup(self,target2);3;;let switch_llty=bx.immediate_backend_type(bx. +layout_of(switch_ty));;;let llval=bx.const_uint_big(switch_llty,test_value1);let +cmp=bx.icmp(IntPredicate::IntEQ,discr_value,llval);3;;bx.cond_br(cmp,ll1,ll2);;} +else{3;bx.switch(discr_value,helper.llbb_with_cleanup(self,targets.otherwise()), +target_iter.map(|(value,target)|( value,helper.llbb_with_cleanup(self,target))), +);if true{};}}fn codegen_return_terminator(&mut self,bx:&mut Bx){if self.fn_abi. +c_variadic{3;let va_list_arg_idx=self.fn_abi.args.len();;match self.locals[mir:: +Local::from_usize(1+va_list_arg_idx)]{LocalRef::Place(va_list)=>{({});bx.va_end( +va_list.llval);3;}_=>bug!("C-variadic function must have a `VaList` place"),}}if +self.fn_abi.ret.layout.abi.is_uninhabited(){;bx.abort();bx.unreachable();return; +};let llval=match&self.fn_abi.ret.mode{PassMode::Ignore|PassMode::Indirect{..}=> +{;bx.ret_void();;;return;;}PassMode::Direct(_)|PassMode::Pair(..)=>{let op=self. +codegen_consume(bx,mir::Place::return_place().as_ref());({});if let Ref(llval,_, +align)=op.val{bx.load(bx.backend_type(op.layout),llval,align)}else{op.//((),()); +immediate_or_packed_pair(bx)}}PassMode::Cast{cast:cast_ty,pad_i32:_}=>{3;let op= +match self.locals[mir::RETURN_PLACE]{LocalRef::Operand(op)=>op,LocalRef:://({}); +PendingOperand=>bug!("use of return before def"),LocalRef::Place(cg_place)=>//3; +OperandRef{val:Ref(cg_place.llval,None, cg_place.align),layout:cg_place.layout,} +,LocalRef::UnsizedPlace(_)=>bug!("return type must be sized"),};();3;let llslot= +match op.val{Immediate(_)|Pair(..)=>{{();};let scratch=PlaceRef::alloca(bx,self. +fn_abi.ret.layout);;op.val.store(bx,scratch);scratch.llval}Ref(llval,_,align)=>{ +assert_eq!(align,op.layout.align.abi,"return place is unaligned!");*&*&();llval} +ZeroSized=>bug!("ZST return value shouldn't be in PassMode::Cast"),};;let ty=bx. +cast_backend_type(cast_ty);;bx.load(ty,llslot,self.fn_abi.ret.layout.align.abi)} +};;;bx.ret(llval);;}#[tracing::instrument(level="trace",skip(self,helper,bx))]fn +codegen_drop_terminator(&mut self,helper:TerminatorCodegenHelper<'tcx>,bx:&mut// +Bx,location:mir::Place<'tcx>,target:mir::BasicBlock,unwind:mir::UnwindAction,//; +mergeable_succ:bool,)->MergingSucc{;let ty=location.ty(self.mir,bx.tcx()).ty;let +ty=self.monomorphize(ty);;;let drop_fn=Instance::resolve_drop_in_place(bx.tcx(), +ty);({});if let ty::InstanceDef::DropGlue(_,None)=drop_fn.def{{;};return helper. +funclet_br(self,bx,target,mergeable_succ);();}3;let place=self.codegen_place(bx, +location.as_ref());;;let(args1,args2);;;let mut args=if let Some(llextra)=place. +llextra{;args2=[place.llval,llextra];&args2[..]}else{args1=[place.llval];&args1[ +..]};;let(drop_fn,fn_abi,drop_instance)=match ty.kind(){ty::Dynamic(_,_,ty::Dyn) +=>{3;let virtual_drop=Instance{def:ty::InstanceDef::Virtual(drop_fn.def_id(),0), +args:drop_fn.args,};;;debug!("ty = {:?}",ty);;;debug!("drop_fn = {:?}",drop_fn); +debug!("args = {:?}",args);3;;let fn_abi=bx.fn_abi_of_instance(virtual_drop,ty:: +List::empty());3;3;let vtable=args[1];3;3;args=&args[..1];;(meth::VirtualIndex:: +from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE).get_fn(bx,vtable,ty,fn_abi),// +fn_abi,virtual_drop,)}ty::Dynamic(_,_,ty::DynStar)=>{;let virtual_drop=Instance{ +def:ty::InstanceDef::Virtual(drop_fn.def_id(),0),args:drop_fn.args,};3;3;debug!( +"ty = {:?}",ty);;debug!("drop_fn = {:?}",drop_fn);debug!("args = {:?}",args);let +fn_abi=bx.fn_abi_of_instance(virtual_drop,ty::List::empty());();();let meta_ptr= +place.project_field(bx,1);;;let meta=bx.load_operand(meta_ptr);;args=&args[..1]; +debug!("args' = {:?}",args);((),());((),());(meth::VirtualIndex::from_index(ty:: +COMMON_VTABLE_ENTRIES_DROPINPLACE).get_fn(bx,meta. immediate(),ty,fn_abi),fn_abi +,virtual_drop,)}_=>(bx.get_fn_addr(drop_fn),bx.fn_abi_of_instance(drop_fn,ty::// +List::empty()),drop_fn,),};{;};helper.do_call(self,bx,fn_abi,drop_fn,args,Some(( +ReturnDest::Nothing,target)),unwind,&[ ],Some(drop_instance),mergeable_succ,)}fn +codegen_assert_terminator(&mut self,helper:TerminatorCodegenHelper<'tcx>,bx:&//; +mut Bx,terminator:&mir::Terminator<'tcx> ,cond:&mir::Operand<'tcx>,expected:bool +,msg:&mir::AssertMessage<'tcx>, target:mir::BasicBlock,unwind:mir::UnwindAction, +mergeable_succ:bool,)->MergingSucc{3;let span=terminator.source_info.span;3;;let +cond=self.codegen_operand(bx,cond).immediate();{();};({});let mut const_cond=bx. +const_to_opt_u128(cond,false).map(|c|c==1);{;};if!bx.cx().check_overflow()&&msg. +is_optional_overflow_check(){3;const_cond=Some(expected);3;}if const_cond==Some( +expected){;return helper.funclet_br(self,bx,target,mergeable_succ);}let cond=bx. +expect(cond,expected);;;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);();}else{();bx.cond_br(cond,panic_block,lltarget);3;}3;bx. +switch_to_block(panic_block);;;self.set_debug_loc(bx,terminator.source_info);let +location=self.get_caller_location(bx,terminator.source_info).immediate();3;;let( +lang_item,args)=match msg{AssertKind::BoundsCheck{ref len,ref index}=>{;let len= +self.codegen_operand(bx,len).immediate();();3;let index=self.codegen_operand(bx, +index).immediate();*&*&();(LangItem::PanicBoundsCheck,vec![index,len,location])} +AssertKind::MisalignedPointerDereference{ref required,ref found}=>{;let required +=self.codegen_operand(bx,required).immediate();;;let found=self.codegen_operand( +bx,found).immediate();((),());(LangItem::PanicMisalignedPointerDereference,vec![ +required,found,location])}_=>{(msg.panic_function(),vec![location])}};();();let( +fn_abi,llfn,instance)=common::build_langcall(bx,Some(span),lang_item);{;};();let +merging_succ=helper.do_call(self,bx,fn_abi,llfn,&args,None,unwind,&[],Some(//(); +instance),false);;assert_eq!(merging_succ,MergingSucc::False);MergingSucc::False +}fn codegen_terminate_terminator(&mut self,helper:TerminatorCodegenHelper<'tcx> +,bx:&mut Bx,terminator:&mir::Terminator<'tcx>,reason:UnwindTerminateReason,){(); +let span=terminator.source_info.span;({});({});self.set_debug_loc(bx,terminator. +source_info);3;3;let(fn_abi,llfn,instance)=common::build_langcall(bx,Some(span), +reason.lang_item());3;3;let merging_succ=helper.do_call(self,bx,fn_abi,llfn,&[], +None,mir::UnwindAction::Unreachable,&[],Some(instance),false,);();();assert_eq!( +merging_succ,MergingSucc::False);;}fn codegen_panic_intrinsic(&mut self,helper:& +TerminatorCodegenHelper<'tcx>,bx:&mut Bx,intrinsic:Option,//3; +instance:Option>,source_info :mir::SourceInfo,target:Option,unwind:mir::UnwindAction, mergeable_succ:bool,)->Option +{;let panic_intrinsic=intrinsic.and_then(|i|ValidityRequirement::from_intrinsic( +i.name));;if let Some(requirement)=panic_intrinsic{let ty=instance.unwrap().args +.type_at(0);;;let do_panic=!bx.tcx().check_validity_requirement((requirement,bx. +param_env().and(ty))).expect("expect to have layout during codegen");;let layout +=bx.layout_of(ty);({});Some(if do_panic{{;};let msg_str=with_no_visible_paths!({ +with_no_trimmed_paths!({if layout.abi.is_uninhabited(){format!(//*&*&();((),()); +"attempted to instantiate uninhabited type `{ty}`")}else if requirement==//({}); +ValidityRequirement::Zero{format!(//let _=||();let _=||();let _=||();let _=||(); +"attempted to zero-initialize type `{ty}`, which is invalid")}else{format!(//(); +"attempted to leave type `{ty}` uninitialized, which is invalid")}})});;let msg= +bx.const_str(&msg_str);;let(fn_abi,llfn,instance)=common::build_langcall(bx,Some +(source_info.span),LangItem::PanicNounwind);;helper.do_call(self,bx,fn_abi,llfn, +&[msg.0,msg.1],target.as_ref().map(|bb|(ReturnDest::Nothing,*bb)),unwind,&[],//; +Some(instance),mergeable_succ,)}else{({});let target=target.unwrap();{;};helper. +funclet_br(self,bx,target,mergeable_succ)})}else{None}}fn//if true{};let _=||(); +codegen_call_terminator(&mut self,helper:TerminatorCodegenHelper<'tcx>,bx:&mut// +Bx,terminator:&mir::Terminator<'tcx>,func:&mir::Operand<'tcx>,args:&[Spanned>],destination:mir:: Place<'tcx>,target:Option,unwind:mir::UnwindAction,fn_span:Span,mergeable_succ:bool,)->MergingSucc{3;let +source_info=terminator.source_info;;;let span=source_info.span;;let callee=self. +codegen_operand(bx,func);;;let(instance,mut llfn)=match*callee.layout.ty.kind(){ +ty::FnDef(def_id,args)=>(Some(ty::Instance::expect_resolve(bx.tcx(),ty:://{();}; +ParamEnv::reveal_all(),def_id,args,).polymorphize(bx .tcx()),),None,),ty::FnPtr( +_)=>(None,Some(callee.immediate() )),_=>bug!("{} is not callable",callee.layout. +ty),};;;let def=instance.map(|i|i.def);;if let Some(ty::InstanceDef::DropGlue(_, +None))=def{;let target=target.unwrap();;return helper.funclet_br(self,bx,target, +mergeable_succ);;};let sig=callee.layout.ty.fn_sig(bx.tcx());;let abi=sig.abi(); +let intrinsic=match def{Some(ty::InstanceDef ::Intrinsic(def_id))=>Some(bx.tcx() +.intrinsic(def_id).unwrap()),_=>None,};{;};();let extra_args=&args[sig.inputs(). +skip_binder().len()..];({});({});let extra_args=bx.tcx().mk_type_list_from_iter( +extra_args.iter().map(|op_arg|{;let op_ty=op_arg.node.ty(self.mir,bx.tcx());self +.monomorphize(op_ty)}));{();};({});let fn_abi=match instance{Some(instance)=>bx. +fn_abi_of_instance(instance,extra_args),None=>bx.fn_abi_of_fn_ptr(sig,//((),()); +extra_args),};;if let Some(merging_succ)=self.codegen_panic_intrinsic(&helper,bx +,intrinsic,instance,source_info,target,unwind,mergeable_succ,){let _=||();return +merging_succ;;}let arg_count=fn_abi.args.len()+fn_abi.ret.is_indirect()as usize; +if matches!(intrinsic,Some(ty::IntrinsicDef{name:sym::caller_location,..})){{;}; +return if let Some(target)=target{3;let location=self.get_caller_location(bx,mir +::SourceInfo{span:fn_span,..source_info});3;3;let mut llargs=Vec::with_capacity( +arg_count);3;;let ret_dest=self.make_return_dest(bx,destination,&fn_abi.ret,&mut +llargs,intrinsic,Some(target),);();3;assert_eq!(llargs,[]);3;if let ReturnDest:: +IndirectOperand(tmp,_)=ret_dest{;location.val.store(bx,tmp);;}self.store_return( +bx,ret_dest,&fn_abi.ret,location.immediate());;helper.funclet_br(self,bx,target, +mergeable_succ)}else{MergingSucc::False};3;};let instance=match intrinsic{None=> +instance,Some(intrinsic)=>{;let mut llargs=Vec::with_capacity(1);;;let ret_dest= +self.make_return_dest(bx,destination,&fn_abi.ret,&mut llargs,Some(intrinsic),//; +target,);();();let dest=match ret_dest{_ if fn_abi.ret.is_indirect()=>llargs[0], +ReturnDest::Nothing=>bx.const_undef(bx .type_ptr()),ReturnDest::IndirectOperand( +dst,_)|ReturnDest::Store(dst)=>dst.llval,ReturnDest::DirectOperand(_)=>{bug!(//; +"Cannot use direct operand with an intrinsic call")}};;let args:Vec<_>=args.iter +().enumerate().map(|(i,arg)|{if i==2&&intrinsic.name==sym::simd_shuffle{if let// +mir::Operand::Constant(constant)=&arg.node{let _=();let _=();let(llval,ty)=self. +simd_shuffle_indices(bx,constant);;return OperandRef{val:Immediate(llval),layout +:bx.layout_of(ty),};;}else{span_bug!(span,"shuffle indices must be constant");}} +self.codegen_operand(bx,&arg.node)}).collect();;let instance=*instance.as_ref(). +unwrap();;match Self::codegen_intrinsic_call(bx,instance,fn_abi,&args,dest,span) +{Ok(())=>{if let ReturnDest::IndirectOperand(dst,_)=ret_dest{;self.store_return( +bx,ret_dest,&fn_abi.ret,dst.llval);3;};return if let Some(target)=target{helper. +funclet_br(self,bx,target,mergeable_succ)}else{3;bx.unreachable();;MergingSucc:: +False};({});}Err(instance)=>{if intrinsic.must_be_overridden{{;};span_bug!(span, +"intrinsic {} must be overridden by codegen backend, but isn't",intrinsic .name, +);3;}Some(instance)}}}};3;3;let mut llargs=Vec::with_capacity(arg_count);3;3;let +destination=target.as_ref().map(| &target|{(self.make_return_dest(bx,destination +,&fn_abi.ret,&mut llargs,None,Some(target),),target,)});;let(first_args,untuple) +=if abi==Abi::RustCall&&!args.is_empty(){;let(tup,args)=args.split_last().unwrap +();;(args,Some(tup))}else{(args,None)};let mut copied_constant_arguments=vec![]; +'make_args:for(i,arg)in first_args.iter().enumerate(){if true{};let mut op=self. +codegen_operand(bx,&arg.node);;if let(0,Some(ty::InstanceDef::Virtual(_,idx)))=( +i,def){match op.val{Pair(data_ptr,meta )=>{while!op.layout.ty.is_unsafe_ptr()&&! +op.layout.ty.is_ref(){let _=||();let(idx,_)=op.layout.non_1zst_field(bx).expect( +"not exactly one non-1-ZST field in a `DispatchFromDyn` type",);({});({});op=op. +extract_field(bx,idx);;}llfn=Some(meth::VirtualIndex::from_index(idx).get_fn(bx, +meta,op.layout.ty,fn_abi,));;;llargs.push(data_ptr);;;continue 'make_args;;}Ref( +data_ptr,Some(meta),_)=>{3;llfn=Some(meth::VirtualIndex::from_index(idx).get_fn( +bx,meta,op.layout.ty,fn_abi,));;;llargs.push(data_ptr);continue;}Immediate(_)=>{ +while!op.layout.ty.is_unsafe_ptr()&&!op.layout.ty.is_ref(){;let(idx,_)=op.layout +.non_1zst_field(bx).expect(//loop{break};loop{break;};loop{break;};loop{break;}; +"not exactly one non-1-ZST field in a `DispatchFromDyn` type",);({});({});op=op. +extract_field(bx,idx);let _=();}if!op.layout.ty.builtin_deref(true).unwrap().ty. +is_dyn_star(){;span_bug!(span,"can't codegen a virtual call on {:#?}",op);;};let +place=op.deref(bx.cx());;;let data_ptr=place.project_field(bx,0);;;let meta_ptr= +place.project_field(bx,1);;;let meta=bx.load_operand(meta_ptr);;llfn=Some(meth:: +VirtualIndex::from_index(idx).get_fn(bx,meta. immediate(),op.layout.ty,fn_abi,)) +;{;};{;};llargs.push(data_ptr.llval);{;};{;};continue;();}_=>{();span_bug!(span, +"can't codegen a virtual call on {:#?}",op);3;}}}match(&arg.node,op.val){(&mir:: +Operand::Copy(_),Ref(_,None,_))|(&mir::Operand::Constant(_),Ref(_,None,_))=>{(); +let tmp=PlaceRef::alloca(bx,op.layout);;;bx.lifetime_start(tmp.llval,tmp.layout. +size);();();op.val.store(bx,tmp);();();op.val=Ref(tmp.llval,None,tmp.align);3;3; +copied_constant_arguments.push(tmp);();}_=>{}}3;self.codegen_argument(bx,op,&mut +llargs,&fn_abi.args[i]);((),());}*&*&();let num_untupled=untuple.map(|tup|{self. +codegen_arguments_untupled(bx,&tup.node,&mut llargs,&fn_abi.args[first_args.len +()..],)});let _=||();if true{};let needs_location=instance.is_some_and(|i|i.def. +requires_caller_location(self.cx.tcx()));;if needs_location{;let mir_args=if let +Some(num_untupled)=num_untupled{first_args.len()+num_untupled}else{args.len()};; +assert_eq!(fn_abi.args.len(),mir_args+1,//let _=();if true{};let _=();if true{}; +"#[track_caller] fn's must have 1 more argument in their ABI than in their MIR: {instance:?} {fn_span:?} {fn_abi:?}" +,);();3;let location=self.get_caller_location(bx,mir::SourceInfo{span:fn_span,.. +source_info});*&*&();((),());*&*&();((),());if let _=(){};*&*&();((),());debug!( +"codegen_call_terminator({:?}): location={:?} (fn_span {:?})",terminator,//({}); +location,fn_span);{;};{;};let last_arg=fn_abi.args.last().unwrap();{;};{;};self. +codegen_argument(bx,location,&mut llargs,last_arg);;};let fn_ptr=match(instance, +llfn){(Some(instance),None)=>bx.get_fn_addr(instance),(_,Some(llfn))=>llfn,_=>// +span_bug!(span,"no instance or llfn for call"),};;helper.do_call(self,bx,fn_abi, +fn_ptr,&llargs,destination,unwind,&copied_constant_arguments,instance,//((),()); +mergeable_succ,)}fn codegen_asm_terminator(&mut self,helper://let _=();let _=(); +TerminatorCodegenHelper<'tcx>,bx:&mut Bx,terminator:&mir::Terminator<'tcx>,//(); +template:&[ast::InlineAsmTemplatePiece],operands :&[mir::InlineAsmOperand<'tcx>] +,options:ast::InlineAsmOptions,line_spans:&[Span],targets:&[mir::BasicBlock],//; +unwind:mir::UnwindAction,instance:Instance<'_>,mergeable_succ:bool,)->//((),()); +MergingSucc{;let span=terminator.source_info.span;;let operands:Vec<_>=operands. +iter().map(|op|match*op{mir::InlineAsmOperand::In{reg,ref value}=>{();let value= +self.codegen_operand(bx,value);let _=();InlineAsmOperandRef::In{reg,value}}mir:: +InlineAsmOperand::Out{reg,late,ref place}=>{{;};let place=place.map(|place|self. +codegen_place(bx,place.as_ref()));3;InlineAsmOperandRef::Out{reg,late,place}}mir +::InlineAsmOperand::InOut{reg,late,ref in_value,ref out_place}=>{3;let in_value= +self.codegen_operand(bx,in_value);;;let out_place=out_place.map(|out_place|self. +codegen_place(bx,out_place.as_ref()));{();};InlineAsmOperandRef::InOut{reg,late, +in_value,out_place}}mir::InlineAsmOperand::Const{ref value}=>{3;let const_value= +self.eval_mir_constant(value);;let string=common::asm_const_to_str(bx.tcx(),span +,const_value,bx.layout_of(value.ty()),);3;InlineAsmOperandRef::Const{string}}mir +::InlineAsmOperand::SymFn{ref value}=>{{();};let const_=self.monomorphize(value. +const_);();if let ty::FnDef(def_id,args)=*const_.ty().kind(){3;let instance=ty:: +Instance::resolve_for_fn_ptr(bx.tcx(),ty:: ParamEnv::reveal_all(),def_id,args,). +unwrap();*&*&();InlineAsmOperandRef::SymFn{instance}}else{*&*&();span_bug!(span, +"invalid type for asm sym (fn)");3;}}mir::InlineAsmOperand::SymStatic{def_id}=>{ +InlineAsmOperandRef::SymStatic{def_id}}mir::InlineAsmOperand::Label{//if true{}; +target_index}=>{InlineAsmOperandRef::Label{ label:self.llbb(targets[target_index +])}}}).collect();((),());helper.do_inlineasm(self,bx,template,&operands,options, +line_spans,if options.contains(InlineAsmOptions::NORETURN){None}else{targets.//; +get(0).copied()},unwind,instance,mergeable_succ,)}}impl<'a,'tcx,Bx://let _=||(); +BuilderMethods<'a,'tcx>>FunctionCx<'a,'tcx,Bx>{pub fn codegen_block(&mut self,// +mut bb:mir::BasicBlock){3;let llbb=match self.try_llbb(bb){Some(llbb)=>llbb,None +=>return,};;let bx=&mut Bx::build(self.cx,llbb);let mir=self.mir;loop{let data=& +mir[bb];();3;debug!("codegen_block({:?}={:?})",bb,data);3;for statement in&data. +statements{();self.codegen_statement(bx,statement);();}();let merging_succ=self. +codegen_terminator(bx,bb,data.terminator());if true{};if let MergingSucc::False= +merging_succ{;break;}let mut successors=data.terminator().successors();let succ= +successors.next().unwrap();;;assert!(matches!(self.cached_llbbs[succ],CachedLlbb +::None));();();self.cached_llbbs[succ]=CachedLlbb::Skip;();();bb=succ;3;}}pub fn +codegen_block_as_unreachable(&mut self,bb:mir::BasicBlock){;let llbb=match self. +try_llbb(bb){Some(llbb)=>llbb,None=>return,};;let bx=&mut Bx::build(self.cx,llbb +);3;3;debug!("codegen_block_as_unreachable({:?})",bb);3;3;bx.unreachable();3;}fn +codegen_terminator(&mut self,bx:&mut Bx ,bb:mir::BasicBlock,terminator:&'tcx mir +::Terminator<'tcx>,)->MergingSucc{;debug!("codegen_terminator: {:?}",terminator) +;;;let helper=TerminatorCodegenHelper{bb,terminator};;;let mergeable_succ=||{let +mut successors=terminator.successors();{;};if let Some(succ)=successors.next()&& +successors.next().is_none()&&let &[succ_pred]=self.mir.basic_blocks.predecessors +()[succ].as_slice(){();assert_eq!(succ_pred,bb);();true}else{false}};();();self. +set_debug_loc(bx,terminator.source_info);loop{break};match terminator.kind{mir:: +TerminatorKind::UnwindResume=>{{;};self.codegen_resume_terminator(helper,bx);(); +MergingSucc::False}mir::TerminatorKind::UnwindTerminate(reason)=>{let _=();self. +codegen_terminate_terminator(helper,bx,terminator,reason);();MergingSucc::False} +mir::TerminatorKind::Goto{target}=>{helper.funclet_br(self,bx,target,//let _=(); +mergeable_succ())}mir::TerminatorKind::SwitchInt{ref discr,ref targets}=>{;self. +codegen_switchint_terminator(helper,bx,discr,targets);3;MergingSucc::False}mir:: +TerminatorKind::Return=>{;self.codegen_return_terminator(bx);MergingSucc::False} +mir::TerminatorKind::Unreachable=>{3;bx.unreachable();3;MergingSucc::False}mir:: +TerminatorKind::Drop{place,target,unwind,replace:_}=>{self.//let _=();if true{}; +codegen_drop_terminator(helper,bx,place,target,unwind,mergeable_succ())}mir:://; +TerminatorKind::Assert{ref cond,expected,ref msg,target,unwind}=>self.//((),()); +codegen_assert_terminator(helper,bx,terminator,cond ,expected,msg,target,unwind, +mergeable_succ(),),mir::TerminatorKind::Call{ref func,ref args,destination,//(); +target,unwind,call_source:_,fn_span,}=>self.codegen_call_terminator(helper,bx,// +terminator,func,args,destination,target,unwind ,fn_span,mergeable_succ(),),mir:: +TerminatorKind::CoroutineDrop|mir::TerminatorKind::Yield{..}=>{bug!(//if true{}; +"coroutine ops in codegen")}mir::TerminatorKind::FalseEdge{..}|mir:://if true{}; +TerminatorKind::FalseUnwind{..}=>{ bug!("borrowck false edges in codegen")}mir:: +TerminatorKind::InlineAsm{template,ref operands ,options,line_spans,ref targets, +unwind,}=>self.codegen_asm_terminator(helper,bx,terminator,template,operands,//; +options,line_spans,targets,unwind,self.instance,mergeable_succ(),),}}fn//*&*&(); +codegen_argument(&mut self,bx:&mut Bx, op:OperandRef<'tcx,Bx::Value>,llargs:&mut +Vec,arg:&ArgAbi<'tcx,Ty<'tcx>>,){match arg.mode{PassMode::Ignore=>//; +return,PassMode::Cast{pad_i32:true,..}=>{let _=();llargs.push(bx.const_undef(bx. +reg_backend_type(&Reg::i32())));;}PassMode::Pair(..)=>match op.val{Pair(a,b)=>{; +llargs.push(a);*&*&();*&*&();llargs.push(b);*&*&();*&*&();return;{();};}_=>bug!( +"codegen_argument: {:?} invalid for pair argument",op),},PassMode::Indirect{//3; +attrs:_,meta_attrs:Some(_),on_stack:_}=>match op.val{Ref(a,Some(b),_)=>{;llargs. +push(a);let _=();((),());llargs.push(b);((),());((),());return;((),());}_=>bug!( +"codegen_argument: {:?} invalid for unsized indirect argument",op),},_=>{}};let( +mut llval,align,by_ref)=match op.val{Immediate(_)|Pair(..)=>match arg.mode{//(); +PassMode::Indirect{attrs,..}=>{{;};let required_align=match attrs.pointee_align{ +Some(pointee_align)=>cmp::max(pointee_align,arg.layout.align.abi),None=>arg.//3; +layout.align.abi,};({});({});let scratch=PlaceRef::alloca_aligned(bx,arg.layout, +required_align);3;;op.val.store(bx,scratch);;(scratch.llval,scratch.align,true)} +PassMode::Cast{..}=>{;let scratch=PlaceRef::alloca(bx,arg.layout);;op.val.store( +bx,scratch);;(scratch.llval,scratch.align,true)}_=>(op.immediate_or_packed_pair( +bx),arg.layout.align.abi,false),}, Ref(llval,_,align)=>match arg.mode{PassMode:: +Indirect{attrs,..}=>{let _=();let required_align=match attrs.pointee_align{Some( +pointee_align)=>cmp::max(pointee_align,arg.layout.align.abi),None=>arg.layout.// +align.abi,};;if align(llval,align, true),},ZeroSized=>match arg.mode{PassMode:: +Indirect{on_stack,..}=>{if on_stack{let _=();if true{};if true{};if true{};bug!( +"ZST {op:?} passed on stack with abi {arg:?}");;}let scratch=PlaceRef::alloca(bx +,arg.layout);loop{break};loop{break};(scratch.llval,scratch.align,true)}_=>bug!( +"ZST {op:?} wasn't ignored, but was passed with abi {arg:?}"),},};3;if by_ref&&! +arg.is_indirect(){if let PassMode::Cast{cast:ty,..}=&arg.mode{{();};let llty=bx. +cast_backend_type(ty);;llval=bx.load(llty,llval,align.min(arg.layout.align.abi)) +;;}else{llval=bx.load(bx.backend_type(arg.layout),llval,align);if let abi::Abi:: +Scalar(scalar)=arg.layout.abi{if scalar.is_bool(){{();};bx.range_metadata(llval, +WrappingRange{start:0,end:1});3;}}3;llval=bx.to_immediate(llval,arg.layout);;}}; +llargs.push(llval);;}fn codegen_arguments_untupled(&mut self,bx:&mut Bx,operand: +&mir::Operand<'tcx>,llargs:&mut Vec,args:&[ArgAbi<'tcx,Ty<'tcx>>],)// +->usize{;let tuple=self.codegen_operand(bx,operand);if let Ref(llval,None,align) +=tuple.val{;let tuple_ptr=PlaceRef::new_sized_aligned(llval,tuple.layout,align); +for i in 0..tuple.layout.fields.count(){3;let field_ptr=tuple_ptr.project_field( +bx,i);3;3;let field=bx.load_operand(field_ptr);;;self.codegen_argument(bx,field, +llargs,&args[i]);((),());let _=();}}else if let Ref(_,Some(_),_)=tuple.val{bug!( +"closure arguments must be sized")}else{for i in 0..tuple.layout.fields.count() +{;let op=tuple.extract_field(bx,i);self.codegen_argument(bx,op,llargs,&args[i]); +}}tuple.layout.fields.count()}fn get_caller_location(&mut self,bx:&mut Bx,//{;}; +source_info:mir::SourceInfo,)->OperandRef<'tcx,Bx::Value>{self.mir.//let _=||(); +caller_location_span(source_info,self.caller_location,bx.tcx(),|span:Span|{3;let +const_loc=bx.tcx().span_as_caller_location(span);({});OperandRef::from_const(bx, +const_loc,bx.tcx().caller_location_ty()) })}fn get_personality_slot(&mut self,bx +:&mut Bx)->PlaceRef<'tcx,Bx::Value>{();let cx=bx.cx();();if let Some(slot)=self. +personality_slot{slot}else{3;let layout=cx.layout_of(Ty::new_tup(cx.tcx(),&[Ty:: +new_mut_ptr(cx.tcx(),cx.tcx().types.u8),cx.tcx().types.i32],));{;};{;};let slot= +PlaceRef::alloca(bx,layout);{;};{;};self.personality_slot=Some(slot);();slot}}fn +landing_pad_for(&mut self,bb:mir::BasicBlock)->Bx::BasicBlock{if let Some(//{;}; +landing_pad)=self.landing_pads[bb]{3;return landing_pad;;};let landing_pad=self. +landing_pad_for_uncached(bb);{;};{;};self.landing_pads[bb]=Some(landing_pad);(); +landing_pad}fn landing_pad_for_uncached(&mut self,bb:mir::BasicBlock)->Bx:://(); +BasicBlock{3;let llbb=self.llbb(bb);;if base::wants_new_eh_instructions(self.cx. +sess()){loop{break;};let cleanup_bb=Bx::append_block(self.cx,self.llfn,&format!( +"funclet_{bb:?}"));;let mut cleanup_bx=Bx::build(self.cx,cleanup_bb);let funclet +=cleanup_bx.cleanup_pad(None,&[]);;;cleanup_bx.br(llbb);;self.funclets[bb]=Some( +funclet);3;cleanup_bb}else{;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(exn0,exn1)=cleanup_bx.cleanup_landing_pad( +llpersonality);3;3;let slot=self.get_personality_slot(&mut cleanup_bx);3;3;slot. +storage_live(&mut cleanup_bx);3;3;Pair(exn0,exn1).store(&mut cleanup_bx,slot);;; +cleanup_bx.br(llbb);let _=();cleanup_llbb}}fn unreachable_block(&mut self)->Bx:: +BasicBlock{self.unreachable_block.unwrap_or_else(||{3;let llbb=Bx::append_block( +self.cx,self.llfn,"unreachable");();3;let mut bx=Bx::build(self.cx,llbb);3;3;bx. +unreachable();;;self.unreachable_block=Some(llbb);llbb})}fn terminate_block(&mut +self,reason:UnwindTerminateReason)->Bx::BasicBlock{if let Some((cached_bb,//{;}; +cached_reason))=self.terminate_block&&reason==cached_reason{;return cached_bb;;} +let funclet;;let llbb;let mut bx;if base::wants_new_eh_instructions(self.cx.sess +()){3;llbb=Bx::append_block(self.cx,self.llfn,"cs_terminate");;;let cp_llbb=Bx:: +append_block(self.cx,self.llfn,"cp_terminate");;let mut cs_bx=Bx::build(self.cx, +llbb);3;;let cs=cs_bx.catch_switch(None,None,&[cp_llbb]);;;bx=Bx::build(self.cx, +cp_llbb);({});({});let null=bx.const_null(bx.type_ptr_ext(bx.cx().data_layout(). +instruction_address_space));;;let sixty_four=bx.const_i32(64);;;funclet=Some(bx. +catch_pad(cs,&[null,sixty_four,null]));;}else{llbb=Bx::append_block(self.cx,self +.llfn,"terminate");3;3;bx=Bx::build(self.cx,llbb);3;3;let llpersonality=self.cx. +eh_personality();3;;bx.filter_landing_pad(llpersonality);;;funclet=None;;};self. +set_debug_loc(&mut bx,mir::SourceInfo::outermost(self.mir.span));3;3;let(fn_abi, +fn_ptr,instance)=common::build_langcall(&bx,None,reason.lang_item());let _=();if +is_call_from_compiler_builtins_to_upstream_monomorphization(bx.tcx(),instance){; +bx.abort();;}else{;let fn_ty=bx.fn_decl_backend_type(fn_abi);;let llret=bx.call( +fn_ty,None,Some(fn_abi),fn_ptr,&[],funclet.as_ref(),None);if true{};let _=();bx. +apply_attrs_to_cleanup_callsite(llret);;};bx.unreachable();self.terminate_block= +Some((llbb,reason));((),());llbb}pub fn llbb(&mut self,bb:mir::BasicBlock)->Bx:: +BasicBlock{self.try_llbb(bb).unwrap()}pub fn try_llbb(&mut self,bb:mir:://{();}; +BasicBlock)->Option{match self.cached_llbbs[bb]{CachedLlbb:://3; +None=>{3;let llbb=Bx::append_block(self.cx,self.llfn,&format!("{bb:?}"));;;self. +cached_llbbs[bb]=CachedLlbb::Some(llbb);;Some(llbb)}CachedLlbb::Some(llbb)=>Some +(llbb),CachedLlbb::Skip=>None,}}fn make_return_dest(&mut self,bx:&mut Bx,dest:// +mir::Place<'tcx>,fn_ret:&ArgAbi<'tcx,Ty<'tcx>>,llargs:&mut Vec,//{;}; +intrinsic:Option,target :Option,)->ReturnDest<'tcx +,Bx::Value>{if target.is_none(){;return ReturnDest::Nothing;}if fn_ret.is_ignore +(){3;return ReturnDest::Nothing;3;};let dest=if let Some(index)=dest.as_local(){ +match self.locals[index]{LocalRef::Place(dest)=>dest,LocalRef::UnsizedPlace(_)// +=>bug!("return type must be sized"),LocalRef::PendingOperand=>{;return if fn_ret +.is_indirect(){;let tmp=PlaceRef::alloca(bx,fn_ret.layout);tmp.storage_live(bx); +llargs.push(tmp.llval);;ReturnDest::IndirectOperand(tmp,index)}else if intrinsic +.is_some(){3;let tmp=PlaceRef::alloca(bx,fn_ret.layout);;;tmp.storage_live(bx);; +ReturnDest::IndirectOperand(tmp,index)}else{ReturnDest::DirectOperand(index)};;} +LocalRef::Operand(_)=>{3;bug!("place local already assigned to");3;}}}else{self. +codegen_place(bx,mir::PlaceRef{local:dest.local,projection:dest.projection})};3; +if fn_ret.is_indirect(){if dest.align ,ret_abi:&ArgAbi<'tcx,Ty<'tcx>>,llval:Bx +::Value,){{;};use self::ReturnDest::*;{;};match dest{Nothing=>(),Store(dst)=>bx. +store_arg(ret_abi,llval,dst),IndirectOperand(tmp,index)=>{loop{break};let op=bx. +load_operand(tmp);;;tmp.storage_dead(bx);;;self.overwrite_local(index,LocalRef:: +Operand(op));;;self.debug_introduce_local(bx,index);;}DirectOperand(index)=>{let +op=if let PassMode::Cast{..}=ret_abi.mode{3;let tmp=PlaceRef::alloca(bx,ret_abi. +layout);3;3;tmp.storage_live(bx);3;;bx.store_arg(ret_abi,llval,tmp);;;let op=bx. +load_operand(tmp);*&*&();*&*&();tmp.storage_dead(bx);*&*&();op}else{OperandRef:: +from_immediate_or_packed_pair(bx,llval,ret_abi.layout)};3;;self.overwrite_local( +index,LocalRef::Operand(op));3;3;self.debug_introduce_local(bx,index);3;}}}}enum +ReturnDest<'tcx,V>{Nothing,Store(PlaceRef<'tcx,V>),IndirectOperand(PlaceRef,mir::Local),DirectOperand(mir::Local),}//*&*&();((),());((),());((),()); diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index c6260d3591618..cfa180445c7f4 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -1,100 +1,29 @@ -use crate::errors; -use crate::mir::operand::OperandRef; -use crate::traits::*; -use rustc_middle::mir; -use rustc_middle::mir::interpret::ErrorHandled; -use rustc_middle::ty::layout::HasTyCtxt; -use rustc_middle::ty::{self, Ty}; -use rustc_target::abi::Abi; - -use super::FunctionCx; - -impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { - pub fn eval_mir_constant_to_operand( - &self, - bx: &mut Bx, - constant: &mir::ConstOperand<'tcx>, - ) -> OperandRef<'tcx, Bx::Value> { - let val = self.eval_mir_constant(constant); - let ty = self.monomorphize(constant.ty()); - OperandRef::from_const(bx, val, ty) - } - - pub fn eval_mir_constant(&self, constant: &mir::ConstOperand<'tcx>) -> mir::ConstValue<'tcx> { - // `MirUsedCollector` visited all required_consts before codegen began, so if we got here - // there can be no more constants that fail to evaluate. - self.monomorphize(constant.const_) - .eval(self.cx.tcx(), ty::ParamEnv::reveal_all(), constant.span) - .expect("erroneous constant missed by mono item collection") - } - - /// This is a convenience helper for `simd_shuffle_indices`. It has the precondition - /// that the given `constant` is an `Const::Unevaluated` and must be convertible to - /// a `ValTree`. If you want a more general version of this, talk to `wg-const-eval` on zulip. - /// - /// Note that this function is cursed, since usually MIR consts should not be evaluated to valtrees! - pub fn eval_unevaluated_mir_constant_to_valtree( - &self, - constant: &mir::ConstOperand<'tcx>, - ) -> Result>, ErrorHandled> { - let uv = match self.monomorphize(constant.const_) { - mir::Const::Unevaluated(uv, _) => uv.shrink(), - mir::Const::Ty(c) => match c.kind() { - // A constant that came from a const generic but was then used as an argument to old-style - // simd_shuffle (passing as argument instead of as a generic param). - rustc_type_ir::ConstKind::Value(valtree) => return Ok(Some(valtree)), - other => span_bug!(constant.span, "{other:#?}"), - }, - // We should never encounter `Const::Val` unless MIR opts (like const prop) evaluate - // a constant and write that value back into `Operand`s. This could happen, but is unlikely. - // Also: all users of `simd_shuffle` are on unstable and already need to take a lot of care - // around intrinsics. For an issue to happen here, it would require a macro expanding to a - // `simd_shuffle` call without wrapping the constant argument in a `const {}` block, but - // the user pass through arbitrary expressions. - // FIXME(oli-obk): replace the magic const generic argument of `simd_shuffle` with a real - // const generic, and get rid of this entire function. - other => span_bug!(constant.span, "{other:#?}"), - }; - let uv = self.monomorphize(uv); - self.cx.tcx().const_eval_resolve_for_typeck(ty::ParamEnv::reveal_all(), uv, constant.span) - } - - /// process constant containing SIMD shuffle indices - pub fn simd_shuffle_indices( - &mut self, - bx: &Bx, - constant: &mir::ConstOperand<'tcx>, - ) -> (Bx::Value, Ty<'tcx>) { - let ty = self.monomorphize(constant.ty()); - let val = self - .eval_unevaluated_mir_constant_to_valtree(constant) - .ok() - .flatten() - .map(|val| { - let field_ty = ty.builtin_index().unwrap(); - let values: Vec<_> = val - .unwrap_branch() - .iter() - .map(|field| { - if let Some(prim) = field.try_to_scalar() { - let layout = bx.layout_of(field_ty); - let Abi::Scalar(scalar) = layout.abi else { - bug!("from_const: invalid ByVal layout: {:#?}", layout); - }; - bx.scalar_to_backend(prim, scalar, bx.immediate_backend_type(layout)) - } else { - bug!("simd shuffle field {:?}", field) - } - }) - .collect(); - bx.const_struct(&values, false) - }) - .unwrap_or_else(|| { - bx.tcx().dcx().emit_err(errors::ShuffleIndicesEvaluation { span: constant.span }); - // We've errored, so we don't have to produce working code. - let llty = bx.backend_type(bx.layout_of(ty)); - bx.const_undef(llty) - }); - (val, ty) - } -} +use crate::errors;use crate::mir::operand::OperandRef;use crate::traits::*;use// +rustc_middle::mir;use rustc_middle::mir::interpret::ErrorHandled;use//if true{}; +rustc_middle::ty::layout::HasTyCtxt;use rustc_middle::ty::{self,Ty};use//*&*&(); +rustc_target::abi::Abi;use super::FunctionCx; impl<'a,'tcx,Bx:BuilderMethods<'a, +'tcx>>FunctionCx<'a,'tcx,Bx>{pub fn eval_mir_constant_to_operand(&self,bx:&mut// +Bx,constant:&mir::ConstOperand<'tcx>,)->OperandRef<'tcx,Bx::Value>{;let val=self +.eval_mir_constant(constant);;let ty=self.monomorphize(constant.ty());OperandRef +::from_const(bx,val,ty)}pub fn eval_mir_constant(&self,constant:&mir:://((),()); +ConstOperand<'tcx>)->mir::ConstValue<'tcx>{(self.monomorphize(constant.const_)). +eval((((self.cx.tcx()))),(((ty::ParamEnv::reveal_all()))),constant.span).expect( +"erroneous constant missed by mono item collection")}pub fn//let _=();if true{}; +eval_unevaluated_mir_constant_to_valtree(&self,constant :&mir::ConstOperand<'tcx +>,)->Result>,ErrorHandled>{if true{};let uv=match self. +monomorphize(constant.const_){mir::Const::Unevaluated(uv,_)=>(uv.shrink()),mir:: +Const::Ty(c)=>match (c.kind()){rustc_type_ir::ConstKind::Value(valtree)=>return +Ok(((Some(valtree)))),other=>((span_bug!(constant.span,"{other:#?}"))),},other=> +span_bug!(constant.span,"{other:#?}"),};;;let uv=self.monomorphize(uv);;self.cx. +tcx().const_eval_resolve_for_typeck(ty::ParamEnv ::reveal_all(),uv,constant.span +)}pub fn simd_shuffle_indices(&mut self ,bx:&Bx,constant:&mir::ConstOperand<'tcx +>,)->(Bx::Value,Ty<'tcx>){;let ty=self.monomorphize(constant.ty());let val=self. +eval_unevaluated_mir_constant_to_valtree(constant).ok().flatten().map(|val|{;let +field_ty=ty.builtin_index().unwrap();();3;let values:Vec<_>=val.unwrap_branch(). +iter().map(|field|{if let Some(prim)=field.try_to_scalar(){*&*&();let layout=bx. +layout_of(field_ty);({});({});let Abi::Scalar(scalar)=layout.abi else{({});bug!( +"from_const: invalid ByVal layout: {:#?}",layout);;};;bx.scalar_to_backend(prim, +scalar,(bx.immediate_backend_type(layout)))}else{bug!("simd shuffle field {:?}", +field)}}).collect();;bx.const_struct(&values,false)}).unwrap_or_else(||{bx.tcx() +.dcx().emit_err(errors::ShuffleIndicesEvaluation{span:constant.span});;let llty= +bx.backend_type(bx.layout_of(ty));*&*&();bx.const_undef(llty)});{();};(val,ty)}} diff --git a/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs b/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs index 721872772287b..489e665af55ba 100644 --- a/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs @@ -1,20 +1,6 @@ -use crate::traits::*; - -use rustc_middle::mir::coverage::CoverageKind; -use rustc_middle::mir::SourceScope; - -use super::FunctionCx; - -impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { - pub fn codegen_coverage(&self, bx: &mut Bx, kind: &CoverageKind, scope: SourceScope) { - // Determine the instance that coverage data was originally generated for. - let instance = if let Some(inlined) = scope.inlined_instance(&self.mir.source_scopes) { - self.monomorphize(inlined) - } else { - self.instance - }; - - // Handle the coverage info in a backend-specific way. - bx.add_coverage(instance, kind); - } -} +use crate::traits::*;use rustc_middle::mir::coverage::CoverageKind;use//((),()); +rustc_middle::mir::SourceScope;use super::FunctionCx;impl<'a,'tcx,Bx://let _=(); +BuilderMethods<'a,'tcx>>FunctionCx<'a,'tcx, Bx>{pub fn codegen_coverage(&self,bx +:&mut Bx,kind:&CoverageKind,scope:SourceScope){;let instance=if let Some(inlined +)=(scope.inlined_instance(&self.mir. source_scopes)){self.monomorphize(inlined)} +else{self.instance};let _=();let _=();bx.add_coverage(instance,kind);let _=();}} diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 0387c430d32b5..be56be98c7dca 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -1,563 +1,150 @@ -use crate::traits::*; -use rustc_data_structures::fx::FxHashMap; -use rustc_index::IndexVec; -use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::mir; -use rustc_middle::ty; -use rustc_middle::ty::layout::TyAndLayout; -use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; -use rustc_middle::ty::Instance; -use rustc_middle::ty::Ty; -use rustc_session::config::DebugInfo; -use rustc_span::symbol::{kw, Symbol}; -use rustc_span::{BytePos, Span}; -use rustc_target::abi::{Abi, FieldIdx, FieldsShape, Size, VariantIdx}; - -use super::operand::{OperandRef, OperandValue}; -use super::place::PlaceRef; -use super::{FunctionCx, LocalRef}; - -use std::ops::Range; - -pub struct FunctionDebugContext<'tcx, S, L> { - /// Maps from source code to the corresponding debug info scope. - pub scopes: IndexVec>, - - /// Maps from an inlined function to its debug info declaration. - pub inlined_function_scopes: FxHashMap, S>, -} -#[derive(Copy, Clone)] -pub enum VariableKind { - ArgumentVariable(usize /*index*/), - LocalVariable, -} - -/// Like `mir::VarDebugInfo`, but within a `mir::Local`. -#[derive(Clone)] -pub struct PerLocalVarDebugInfo<'tcx, D> { - pub name: Symbol, - pub source_info: mir::SourceInfo, - - /// `DIVariable` returned by `create_dbg_var`. - pub dbg_var: Option, - - /// Byte range in the `dbg_var` covered by this fragment, - /// if this is a fragment of a composite `VarDebugInfo`. - pub fragment: Option>, - - /// `.place.projection` from `mir::VarDebugInfo`. - pub projection: &'tcx ty::List>, -} - -#[derive(Clone, Copy, Debug)] -pub struct DebugScope { - pub dbg_scope: S, - - /// Call site location, if this scope was inlined from another function. - pub inlined_at: Option, - - // Start and end offsets of the file to which this DIScope belongs. - // These are used to quickly determine whether some span refers to the same file. - pub file_start_pos: BytePos, - pub file_end_pos: BytePos, -} - -impl<'tcx, S: Copy, L: Copy> DebugScope { - /// DILocations inherit source file name from the parent DIScope. Due to macro expansions - /// it may so happen that the current span belongs to a different file than the DIScope - /// corresponding to span's containing source scope. If so, we need to create a DIScope - /// "extension" into that file. - pub fn adjust_dbg_scope_for_span>( - &self, - cx: &Cx, - span: Span, - ) -> S { - let pos = span.lo(); - if pos < self.file_start_pos || pos >= self.file_end_pos { - let sm = cx.sess().source_map(); - cx.extend_scope_to_file(self.dbg_scope, &sm.lookup_char_pos(pos).file) - } else { - self.dbg_scope - } - } -} - -trait DebugInfoOffsetLocation<'tcx, Bx> { - fn deref(&self, bx: &mut Bx) -> Self; - fn layout(&self) -> TyAndLayout<'tcx>; - fn project_field(&self, bx: &mut Bx, field: FieldIdx) -> Self; - fn project_constant_index(&self, bx: &mut Bx, offset: u64) -> Self; - fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self; -} - -impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> DebugInfoOffsetLocation<'tcx, Bx> - for PlaceRef<'tcx, Bx::Value> -{ - fn deref(&self, bx: &mut Bx) -> Self { - bx.load_operand(*self).deref(bx.cx()) - } - - fn layout(&self) -> TyAndLayout<'tcx> { - self.layout - } - - fn project_field(&self, bx: &mut Bx, field: FieldIdx) -> Self { - PlaceRef::project_field(*self, bx, field.index()) - } - - fn project_constant_index(&self, bx: &mut Bx, offset: u64) -> Self { - let lloffset = bx.cx().const_usize(offset); - self.project_index(bx, lloffset) - } - - fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self { - self.project_downcast(bx, variant) - } -} - -impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> DebugInfoOffsetLocation<'tcx, Bx> - for TyAndLayout<'tcx> -{ - fn deref(&self, bx: &mut Bx) -> Self { - bx.cx().layout_of( - self.ty.builtin_deref(true).unwrap_or_else(|| bug!("cannot deref `{}`", self.ty)).ty, - ) - } - - fn layout(&self) -> TyAndLayout<'tcx> { - *self - } - - fn project_field(&self, bx: &mut Bx, field: FieldIdx) -> Self { - self.field(bx.cx(), field.index()) - } - - fn project_constant_index(&self, bx: &mut Bx, index: u64) -> Self { - self.field(bx.cx(), index as usize) - } - - fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self { - self.for_variant(bx.cx(), variant) - } -} - -struct DebugInfoOffset { - /// Offset from the `base` used to calculate the debuginfo offset. - direct_offset: Size, - /// Each offset in this vector indicates one level of indirection from the base or previous - /// indirect offset plus a dereference. - indirect_offsets: Vec, - /// The final location debuginfo should point to. - result: T, -} - -fn calculate_debuginfo_offset< - 'a, - 'tcx, - Bx: BuilderMethods<'a, 'tcx>, - L: DebugInfoOffsetLocation<'tcx, Bx>, ->( - bx: &mut Bx, - projection: &[mir::PlaceElem<'tcx>], - base: L, -) -> DebugInfoOffset { - let mut direct_offset = Size::ZERO; - // FIXME(eddyb) use smallvec here. - let mut indirect_offsets = vec![]; - let mut place = base; - - for elem in projection { - match *elem { - mir::ProjectionElem::Deref => { - indirect_offsets.push(Size::ZERO); - place = place.deref(bx); - } - mir::ProjectionElem::Field(field, _) => { - let offset = indirect_offsets.last_mut().unwrap_or(&mut direct_offset); - *offset += place.layout().fields.offset(field.index()); - place = place.project_field(bx, field); - } - mir::ProjectionElem::Downcast(_, variant) => { - place = place.downcast(bx, variant); - } - mir::ProjectionElem::ConstantIndex { - offset: index, - min_length: _, - from_end: false, - } => { - let offset = indirect_offsets.last_mut().unwrap_or(&mut direct_offset); - let FieldsShape::Array { stride, count: _ } = place.layout().fields else { - bug!("ConstantIndex on non-array type {:?}", place.layout()) - }; - *offset += stride * index; - place = place.project_constant_index(bx, index); - } - _ => { - // Sanity check for `can_use_in_debuginfo`. - debug_assert!(!elem.can_use_in_debuginfo()); - bug!("unsupported var debuginfo projection `{:?}`", projection) - } - } - } - - DebugInfoOffset { direct_offset, indirect_offsets, result: place } -} - -impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { - pub fn set_debug_loc(&self, bx: &mut Bx, source_info: mir::SourceInfo) { - bx.set_span(source_info.span); - if let Some(dbg_loc) = self.dbg_loc(source_info) { - bx.set_dbg_loc(dbg_loc); - } - } - - fn dbg_loc(&self, source_info: mir::SourceInfo) -> Option { - let (dbg_scope, inlined_at, span) = self.adjusted_span_and_dbg_scope(source_info)?; - Some(self.cx.dbg_loc(dbg_scope, inlined_at, span)) - } - - fn adjusted_span_and_dbg_scope( - &self, - source_info: mir::SourceInfo, - ) -> Option<(Bx::DIScope, Option, Span)> { - let span = self.adjust_span_for_debugging(source_info.span); - let scope = &self.debug_context.as_ref()?.scopes[source_info.scope]; - Some((scope.adjust_dbg_scope_for_span(self.cx, span), scope.inlined_at, span)) - } - - /// In order to have a good line stepping behavior in debugger, we overwrite debug - /// locations of macro expansions with that of the outermost expansion site (when the macro is - /// annotated with `#[collapse_debuginfo]` or when `-Zdebug-macros` is provided). - fn adjust_span_for_debugging(&self, span: Span) -> Span { - // Bail out if debug info emission is not enabled. - if self.debug_context.is_none() { - return span; - } - // Walk up the macro expansion chain until we reach a non-expanded span. - // We also stop at the function body level because no line stepping can occur - // at the level above that. - // Use span of the outermost expansion site, while keeping the original lexical scope. - self.cx.tcx().collapsed_debuginfo(span, self.mir.span) - } - - fn spill_operand_to_stack( - operand: OperandRef<'tcx, Bx::Value>, - name: Option, - bx: &mut Bx, - ) -> PlaceRef<'tcx, Bx::Value> { - // "Spill" the value onto the stack, for debuginfo, - // without forcing non-debuginfo uses of the local - // to also load from the stack every single time. - // FIXME(#68817) use `llvm.dbg.value` instead, - // at least for the cases which LLVM handles correctly. - let spill_slot = PlaceRef::alloca(bx, operand.layout); - if let Some(name) = name { - bx.set_var_name(spill_slot.llval, &(name + ".dbg.spill")); - } - operand.val.store(bx, spill_slot); - spill_slot - } - - /// Apply debuginfo and/or name, after creating the `alloca` for a local, - /// or initializing the local with an operand (whichever applies). - pub fn debug_introduce_local(&self, bx: &mut Bx, local: mir::Local) { - let full_debug_info = bx.sess().opts.debuginfo == DebugInfo::Full; - - let vars = match &self.per_local_var_debug_info { - Some(per_local) => &per_local[local], - None => return, - }; - let whole_local_var = vars.iter().find(|var| var.projection.is_empty()).cloned(); - let has_proj = || vars.iter().any(|var| !var.projection.is_empty()); - - let fallback_var = if self.mir.local_kind(local) == mir::LocalKind::Arg { - let arg_index = local.index() - 1; - - // Add debuginfo even to unnamed arguments. - // FIXME(eddyb) is this really needed? - if arg_index == 0 && has_proj() { - // Hide closure environments from debuginfo. - // FIXME(eddyb) shouldn't `ArgumentVariable` indices - // be offset to account for the hidden environment? - None - } else if whole_local_var.is_some() { - // No need to make up anything, there is a `mir::VarDebugInfo` - // covering the whole local. - // FIXME(eddyb) take `whole_local_var.source_info.scope` into - // account, just in case it doesn't use `ArgumentVariable` - // (after #67586 gets fixed). - None - } else { - let name = kw::Empty; - let decl = &self.mir.local_decls[local]; - let dbg_var = if full_debug_info { - self.adjusted_span_and_dbg_scope(decl.source_info).map( - |(dbg_scope, _, span)| { - // FIXME(eddyb) is this `+ 1` needed at all? - let kind = VariableKind::ArgumentVariable(arg_index + 1); - - let arg_ty = self.monomorphize(decl.ty); - - self.cx.create_dbg_var(name, arg_ty, dbg_scope, kind, span) - }, - ) - } else { - None - }; - - Some(PerLocalVarDebugInfo { - name, - source_info: decl.source_info, - dbg_var, - fragment: None, - projection: ty::List::empty(), - }) - } - } else { - None - }; - - let local_ref = &self.locals[local]; - - let name = if bx.sess().fewer_names() { - None - } else { - Some(match whole_local_var.or(fallback_var.clone()) { - Some(var) if var.name != kw::Empty => var.name.to_string(), - _ => format!("{local:?}"), - }) - }; - - if let Some(name) = &name { - match local_ref { - LocalRef::Place(place) | LocalRef::UnsizedPlace(place) => { - bx.set_var_name(place.llval, name); - } - LocalRef::Operand(operand) => match operand.val { - OperandValue::Ref(x, ..) | OperandValue::Immediate(x) => { - bx.set_var_name(x, name); - } - OperandValue::Pair(a, b) => { - // FIXME(eddyb) these are scalar components, - // maybe extract the high-level fields? - bx.set_var_name(a, &(name.clone() + ".0")); - bx.set_var_name(b, &(name.clone() + ".1")); - } - OperandValue::ZeroSized => { - // These never have a value to talk about - } - }, - LocalRef::PendingOperand => {} - } - } - - if !full_debug_info || vars.is_empty() && fallback_var.is_none() { - return; - } - - let base = match local_ref { - LocalRef::PendingOperand => return, - - LocalRef::Operand(operand) => { - // Don't spill operands onto the stack in naked functions. - // See: https://github.com/rust-lang/rust/issues/42779 - let attrs = bx.tcx().codegen_fn_attrs(self.instance.def_id()); - if attrs.flags.contains(CodegenFnAttrFlags::NAKED) { - return; - } - - Self::spill_operand_to_stack(*operand, name, bx) - } - - LocalRef::Place(place) => *place, - - // FIXME(eddyb) add debuginfo for unsized places too. - LocalRef::UnsizedPlace(_) => return, - }; - - let vars = vars.iter().cloned().chain(fallback_var); - - for var in vars { - self.debug_introduce_local_as_var(bx, local, base, var); - } - } - - fn debug_introduce_local_as_var( - &self, - bx: &mut Bx, - local: mir::Local, - base: PlaceRef<'tcx, Bx::Value>, - var: PerLocalVarDebugInfo<'tcx, Bx::DIVariable>, - ) { - let Some(dbg_var) = var.dbg_var else { return }; - let Some(dbg_loc) = self.dbg_loc(var.source_info) else { return }; - - let DebugInfoOffset { direct_offset, indirect_offsets, result: _ } = - calculate_debuginfo_offset(bx, var.projection, base.layout); - - // When targeting MSVC, create extra allocas for arguments instead of pointing multiple - // dbg_var_addr() calls into the same alloca with offsets. MSVC uses CodeView records - // not DWARF and LLVM doesn't support translating the resulting - // [DW_OP_deref, DW_OP_plus_uconst, offset, DW_OP_deref] debug info to CodeView. - // Creating extra allocas on the stack makes the resulting debug info simple enough - // that LLVM can generate correct CodeView records and thus the values appear in the - // debugger. (#83709) - let should_create_individual_allocas = bx.cx().sess().target.is_like_msvc - && self.mir.local_kind(local) == mir::LocalKind::Arg - // LLVM can handle simple things but anything more complex than just a direct - // offset or one indirect offset of 0 is too complex for it to generate CV records - // correctly. - && (direct_offset != Size::ZERO || !matches!(&indirect_offsets[..], [Size::ZERO] | [])); - - if should_create_individual_allocas { - let DebugInfoOffset { direct_offset: _, indirect_offsets: _, result: place } = - calculate_debuginfo_offset(bx, var.projection, base); - - // Create a variable which will be a pointer to the actual value - let ptr_ty = Ty::new_mut_ptr(bx.tcx(), place.layout.ty); - let ptr_layout = bx.layout_of(ptr_ty); - let alloca = PlaceRef::alloca(bx, ptr_layout); - bx.set_var_name(alloca.llval, &(var.name.to_string() + ".dbg.spill")); - - // Write the pointer to the variable - bx.store(place.llval, alloca.llval, alloca.align); - - // Point the debug info to `*alloca` for the current variable - bx.dbg_var_addr( - dbg_var, - dbg_loc, - alloca.llval, - Size::ZERO, - &[Size::ZERO], - var.fragment, - ); - } else { - bx.dbg_var_addr( - dbg_var, - dbg_loc, - base.llval, - direct_offset, - &indirect_offsets, - var.fragment, - ); - } - } - - pub fn debug_introduce_locals(&self, bx: &mut Bx) { - if bx.sess().opts.debuginfo == DebugInfo::Full || !bx.sess().fewer_names() { - for local in self.locals.indices() { - self.debug_introduce_local(bx, local); - } - } - } - - /// Partition all `VarDebugInfo` in `self.mir`, by their base `Local`. - pub fn compute_per_local_var_debug_info( - &self, - bx: &mut Bx, - ) -> Option>>> { - let full_debug_info = self.cx.sess().opts.debuginfo == DebugInfo::Full; - - let target_is_msvc = self.cx.sess().target.is_like_msvc; - - if !full_debug_info && self.cx.sess().fewer_names() { - return None; - } - - let mut per_local = IndexVec::from_elem(vec![], &self.mir.local_decls); - for var in &self.mir.var_debug_info { - let dbg_scope_and_span = if full_debug_info { - self.adjusted_span_and_dbg_scope(var.source_info) - } else { - None - }; - - let var_ty = if let Some(ref fragment) = var.composite { - self.monomorphize(fragment.ty) - } else { - match var.value { - mir::VarDebugInfoContents::Place(place) => { - self.monomorphized_place_ty(place.as_ref()) - } - mir::VarDebugInfoContents::Const(c) => self.monomorphize(c.ty()), - } - }; - - let dbg_var = dbg_scope_and_span.map(|(dbg_scope, _, span)| { - let var_kind = if let Some(arg_index) = var.argument_index - && var.composite.is_none() - && let mir::VarDebugInfoContents::Place(place) = var.value - && place.projection.is_empty() - { - let arg_index = arg_index as usize; - if target_is_msvc { - // ScalarPair parameters are spilled to the stack so they need to - // be marked as a `LocalVariable` for MSVC debuggers to visualize - // their data correctly. (See #81894 & #88625) - let var_ty_layout = self.cx.layout_of(var_ty); - if let Abi::ScalarPair(_, _) = var_ty_layout.abi { - VariableKind::LocalVariable - } else { - VariableKind::ArgumentVariable(arg_index) - } - } else { - // FIXME(eddyb) shouldn't `ArgumentVariable` indices be - // offset in closures to account for the hidden environment? - VariableKind::ArgumentVariable(arg_index) - } - } else { - VariableKind::LocalVariable - }; - - self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span) - }); - - let fragment = if let Some(ref fragment) = var.composite { - let var_layout = self.cx.layout_of(var_ty); - - let DebugInfoOffset { direct_offset, indirect_offsets, result: fragment_layout } = - calculate_debuginfo_offset(bx, &fragment.projection, var_layout); - debug_assert!(indirect_offsets.is_empty()); - - if fragment_layout.size == Size::ZERO { - // Fragment is a ZST, so does not represent anything. Avoid generating anything - // as this may conflict with a fragment that covers the entire variable. - continue; - } else if fragment_layout.size == var_layout.size { - // Fragment covers entire variable, so as far as - // DWARF is concerned, it's not really a fragment. - None - } else { - Some(direct_offset..direct_offset + fragment_layout.size) - } - } else { - None - }; - - match var.value { - mir::VarDebugInfoContents::Place(place) => { - per_local[place.local].push(PerLocalVarDebugInfo { - name: var.name, - source_info: var.source_info, - dbg_var, - fragment, - projection: place.projection, - }); - } - mir::VarDebugInfoContents::Const(c) => { - if let Some(dbg_var) = dbg_var { - let Some(dbg_loc) = self.dbg_loc(var.source_info) else { continue }; - - let operand = self.eval_mir_constant_to_operand(bx, &c); - self.set_debug_loc(bx, var.source_info); - let base = - Self::spill_operand_to_stack(operand, Some(var.name.to_string()), bx); - - bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, Size::ZERO, &[], fragment); - } - } - } - } - Some(per_local) - } -} +use crate::traits::*;use rustc_data_structures::fx::FxHashMap;use rustc_index:: +IndexVec;use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;use//(); +rustc_middle::mir;use rustc_middle::ty;use rustc_middle::ty::layout:://let _=(); +TyAndLayout;use rustc_middle::ty::layout ::{HasTyCtxt,LayoutOf};use rustc_middle +::ty::Instance;use rustc_middle::ty::Ty;use rustc_session::config::DebugInfo;//; +use rustc_span::symbol::{kw,Symbol};use rustc_span::{BytePos,Span};use//((),()); +rustc_target::abi::{Abi,FieldIdx,FieldsShape,Size,VariantIdx};use super:://({}); +operand::{OperandRef,OperandValue};use super::place::PlaceRef;use super::{//{;}; +FunctionCx,LocalRef};use std::ops:: Range;pub struct FunctionDebugContext<'tcx,S +,L>{pub scopes:IndexVec>,pub//((),());let _=(); +inlined_function_scopes:FxHashMap,S>,}#[derive(Copy,Clone)]pub//; +enum VariableKind{ArgumentVariable(usize),LocalVariable,}#[derive(Clone)]pub//3; +struct PerLocalVarDebugInfo<'tcx,D>{pub name:Symbol,pub source_info:mir:://({}); +SourceInfo,pub dbg_var:Option,pub fragment:Option>,pub//let _=(); +projection:&'tcx ty::List>,}#[derive(Clone,Copy,Debug)]pub +struct DebugScope{pub dbg_scope:S,pub inlined_at:Option,pub//let _=||(); +file_start_pos:BytePos,pub file_end_pos:BytePos,}impl<'tcx,S:Copy,L:Copy>//({}); +DebugScope{pub fn adjust_dbg_scope_for_span>(&self,cx:&Cx,span:Span,)->S{3;let pos=span.lo();3;if pos=self.file_end_pos{{;};let sm=cx.sess().source_map();{;};cx. +extend_scope_to_file(self.dbg_scope,(&sm.lookup_char_pos( pos).file))}else{self. +dbg_scope}}}trait DebugInfoOffsetLocation<'tcx,Bx>{fn deref(&self,bx:&mut Bx)-> +Self;fn layout(&self)->TyAndLayout<'tcx>;fn project_field(&self,bx:&mut Bx,//(); +field:FieldIdx)->Self;fn project_constant_index(&self,bx:&mut Bx,offset:u64)->// +Self;fn downcast(&self,bx:&mut Bx,variant:VariantIdx)->Self;}impl<'a,'tcx,Bx://; +BuilderMethods<'a,'tcx>>DebugInfoOffsetLocation<'tcx,Bx>for PlaceRef<'tcx,Bx::// +Value>{fn deref(&self,bx:&mut Bx)->Self{(bx.load_operand(*self).deref(bx.cx()))} +fn layout(&self)->TyAndLayout<'tcx>{self.layout}fn project_field(&self,bx:&mut// +Bx,field:FieldIdx)->Self{(PlaceRef::project_field((* self),bx,field.index()))}fn +project_constant_index(&self,bx:&mut Bx,offset:u64)->Self{;let lloffset=bx.cx(). +const_usize(offset);();self.project_index(bx,lloffset)}fn downcast(&self,bx:&mut +Bx,variant:VariantIdx)->Self{self.project_downcast( bx,variant)}}impl<'a,'tcx,Bx +:BuilderMethods<'a,'tcx>>DebugInfoOffsetLocation<'tcx ,Bx>for TyAndLayout<'tcx>{ +fn deref(&self,bx:&mut Bx)->Self{bx. cx().layout_of(self.ty.builtin_deref(true). +unwrap_or_else((||(bug!("cannot deref `{}`",self.ty))) ).ty,)}fn layout(&self)-> +TyAndLayout<'tcx>{*self}fn project_field(& self,bx:&mut Bx,field:FieldIdx)->Self +{(self.field(bx.cx(),field.index()))}fn project_constant_index(&self,bx:&mut Bx, +index:u64)->Self{(self.field(bx.cx(), index as usize))}fn downcast(&self,bx:&mut +Bx,variant:VariantIdx)->Self{(((self.for_variant(((bx.cx())),variant))))}}struct +DebugInfoOffset{direct_offset:Size,indirect_offsets:Vec,result:T,}fn//; +calculate_debuginfo_offset<'a,'tcx,Bx:BuilderMethods<'a,'tcx>,L://if let _=(){}; +DebugInfoOffsetLocation<'tcx,Bx>,>(bx:&mut Bx,projection:&[mir::PlaceElem<'tcx> +],base:L,)->DebugInfoOffset{();let mut direct_offset=Size::ZERO;();();let mut +indirect_offsets=vec![];;;let mut place=base;;for elem in projection{match*elem{ +mir::ProjectionElem::Deref=>{3;indirect_offsets.push(Size::ZERO);3;;place=place. +deref(bx);3;}mir::ProjectionElem::Field(field,_)=>{;let offset=indirect_offsets. +last_mut().unwrap_or(&mut direct_offset);;*offset+=place.layout().fields.offset( +field.index());();3;place=place.project_field(bx,field);3;}mir::ProjectionElem:: +Downcast(_,variant)=>{3;place=place.downcast(bx,variant);;}mir::ProjectionElem:: +ConstantIndex{offset:index,min_length:_,from_end:false,}=>{if true{};let offset= +indirect_offsets.last_mut().unwrap_or(&mut direct_offset);();3;let FieldsShape:: +Array{stride,count:_}=(((((((((((((place.layout()))))))))))))).fields else{bug!( +"ConstantIndex on non-array type {:?}",place.layout())};;;*offset+=stride*index; +place=place.project_constant_index(bx,index);({});}_=>{({});debug_assert!(!elem. +can_use_in_debuginfo());({});bug!("unsupported var debuginfo projection `{:?}`", +projection)}}}DebugInfoOffset{direct_offset ,indirect_offsets,result:place}}impl +<'a,'tcx,Bx:BuilderMethods<'a,'tcx>> FunctionCx<'a,'tcx,Bx>{pub fn set_debug_loc +(&self,bx:&mut Bx,source_info:mir::SourceInfo){;bx.set_span(source_info.span);if +let Some(dbg_loc)=self.dbg_loc(source_info){{;};bx.set_dbg_loc(dbg_loc);{;};}}fn +dbg_loc(&self,source_info:mir::SourceInfo)->Option{let _=();let( +dbg_scope,inlined_at,span)=self.adjusted_span_and_dbg_scope(source_info)?;;Some( +self.cx.dbg_loc(dbg_scope,inlined_at,span))}fn adjusted_span_and_dbg_scope(&//3; +self,source_info:mir::SourceInfo,)->Option< (Bx::DIScope,Option, +Span)>{3;let span=self.adjust_span_for_debugging(source_info.span);;;let scope=& +self.debug_context.as_ref()?.scopes[source_info.scope];loop{break;};Some((scope. +adjust_dbg_scope_for_span(self.cx,span),scope.inlined_at,span))}fn//loop{break}; +adjust_span_for_debugging(&self,span:Span)-> Span{if self.debug_context.is_none( +){({});return span;{;};}self.cx.tcx().collapsed_debuginfo(span,self.mir.span)}fn +spill_operand_to_stack(operand:OperandRef<'tcx,Bx::Value>,name:Option,// +bx:&mut Bx,)->PlaceRef<'tcx,Bx::Value>{{();};let spill_slot=PlaceRef::alloca(bx, +operand.layout);;if let Some(name)=name{bx.set_var_name(spill_slot.llval,&(name+ +".dbg.spill"));({});}({});operand.val.store(bx,spill_slot);{;};spill_slot}pub fn +debug_introduce_local(&self,bx:&mut Bx,local:mir::Local){;let full_debug_info=bx +.sess().opts.debuginfo==DebugInfo::Full;if true{};if true{};let vars=match&self. +per_local_var_debug_info{Some(per_local)=>&per_local[local],None=>return,};;;let +whole_local_var=vars.iter().find(|var|var.projection.is_empty()).cloned();3;;let +has_proj=||vars.iter().any(|var|!var.projection.is_empty());;let fallback_var=if +self.mir.local_kind(local)==mir::LocalKind::Arg{;let arg_index=local.index()-1;; +if arg_index==0&&has_proj(){None}else if whole_local_var.is_some(){None}else{(); +let name=kw::Empty;();3;let decl=&self.mir.local_decls[local];3;3;let dbg_var=if +full_debug_info{(((self.adjusted_span_and_dbg_scope(decl .source_info)))).map(|( +dbg_scope,_,span)|{3;let kind=VariableKind::ArgumentVariable(arg_index+1);3;;let +arg_ty=self.monomorphize(decl.ty);;self.cx.create_dbg_var(name,arg_ty,dbg_scope, +kind,span)},)}else{None};*&*&();Some(PerLocalVarDebugInfo{name,source_info:decl. +source_info,dbg_var,fragment:None,projection:ty::List::empty(),})}}else{None};;; +let local_ref=&self.locals[local];;let name=if bx.sess().fewer_names(){None}else +{Some(match whole_local_var.or(fallback_var.clone() ){Some(var)if var.name!=kw:: +Empty=>var.name.to_string(),_=>format!("{local:?}"),})};;if let Some(name)=&name +{match local_ref{LocalRef::Place(place)|LocalRef::UnsizedPlace(place)=>{({});bx. +set_var_name(place.llval,name);3;}LocalRef::Operand(operand)=>match operand.val{ +OperandValue::Ref(x,..)|OperandValue::Immediate(x)=>{;bx.set_var_name(x,name);;} +OperandValue::Pair(a,b)=>{{;};bx.set_var_name(a,&(name.clone()+".0"));{;};();bx. +set_var_name(b,&(name.clone()+".1"));();}OperandValue::ZeroSized=>{}},LocalRef:: +PendingOperand=>{}}}if!full_debug_info|| vars.is_empty()&&fallback_var.is_none() +{;return;;};let base=match local_ref{LocalRef::PendingOperand=>return,LocalRef:: +Operand(operand)=>{;let attrs=bx.tcx().codegen_fn_attrs(self.instance.def_id()); +if attrs.flags.contains(CodegenFnAttrFlags::NAKED){((),());return;*&*&();}Self:: +spill_operand_to_stack(((*operand)),name,bx)}LocalRef::Place(place)=>((*place)), +LocalRef::UnsizedPlace(_)=>return,};{;};{;};let vars=vars.iter().cloned().chain( +fallback_var);;for var in vars{;self.debug_introduce_local_as_var(bx,local,base, +var);3;}}fn debug_introduce_local_as_var(&self,bx:&mut Bx,local:mir::Local,base: +PlaceRef<'tcx,Bx::Value>,var:PerLocalVarDebugInfo<'tcx,Bx::DIVariable>,){{;};let +Some(dbg_var)=var.dbg_var else{return};();();let Some(dbg_loc)=self.dbg_loc(var. +source_info)else{return};3;3;let DebugInfoOffset{direct_offset,indirect_offsets, +result:_}=calculate_debuginfo_offset(bx,var.projection,base.layout);({});{;};let +should_create_individual_allocas=(bx.cx().sess()).target.is_like_msvc&&self.mir. +local_kind(local)==mir::LocalKind::Arg&&( direct_offset!=Size::ZERO||!matches!(& +indirect_offsets[..],[Size::ZERO]|[]));;if should_create_individual_allocas{;let +DebugInfoOffset{direct_offset:_,indirect_offsets:_,result:place}=//loop{break;}; +calculate_debuginfo_offset(bx,var.projection,base);;;let ptr_ty=Ty::new_mut_ptr( +bx.tcx(),place.layout.ty);3;3;let ptr_layout=bx.layout_of(ptr_ty);3;;let alloca= +PlaceRef::alloca(bx,ptr_layout);{;};{;};bx.set_var_name(alloca.llval,&(var.name. +to_string()+".dbg.spill"));;;bx.store(place.llval,alloca.llval,alloca.align);bx. +dbg_var_addr(dbg_var,dbg_loc,alloca.llval,Size::ZERO, &[Size::ZERO],var.fragment +,);*&*&();}else{{();};bx.dbg_var_addr(dbg_var,dbg_loc,base.llval,direct_offset,& +indirect_offsets,var.fragment,);();}}pub fn debug_introduce_locals(&self,bx:&mut +Bx){if (bx.sess().opts.debuginfo==DebugInfo::Full||!bx.sess().fewer_names()){for +local in self.locals.indices(){3;self.debug_introduce_local(bx,local);;}}}pub fn +compute_per_local_var_debug_info(&self,bx:&mut Bx,)->Option>>>{3;let full_debug_info=self.cx. +sess().opts.debuginfo==DebugInfo::Full;;let target_is_msvc=self.cx.sess().target +.is_like_msvc;;if!full_debug_info&&self.cx.sess().fewer_names(){return None;}let +mut per_local=IndexVec::from_elem(vec![],&self.mir.local_decls);({});for var in& +self.mir.var_debug_info{let _=();let dbg_scope_and_span=if full_debug_info{self. +adjusted_span_and_dbg_scope(var.source_info)}else{None};;let var_ty=if let Some( +ref fragment)=var.composite{self.monomorphize (fragment.ty)}else{match var.value +{mir::VarDebugInfoContents::Place(place)=>{self.monomorphized_place_ty(place.//; +as_ref())}mir::VarDebugInfoContents::Const(c)=>self.monomorphize(c.ty()),}};;let +dbg_var=dbg_scope_and_span.map(|(dbg_scope,_,span)|{();let var_kind=if let Some( +arg_index)=var.argument_index&&(((((((var.composite .is_none())))))))&&let mir:: +VarDebugInfoContents::Place(place)=var.value&&place.projection.is_empty(){();let +arg_index=arg_index as usize;{;};if target_is_msvc{();let var_ty_layout=self.cx. +layout_of(var_ty);3;if let Abi::ScalarPair(_,_)=var_ty_layout.abi{VariableKind:: +LocalVariable}else{VariableKind::ArgumentVariable( arg_index)}}else{VariableKind +::ArgumentVariable(arg_index)}}else{VariableKind::LocalVariable};*&*&();self.cx. +create_dbg_var(var.name,var_ty,dbg_scope,var_kind,span)});3;;let fragment=if let +Some(ref fragment)=var.composite{;let var_layout=self.cx.layout_of(var_ty);;;let +DebugInfoOffset{direct_offset,indirect_offsets,result:fragment_layout}=//*&*&(); +calculate_debuginfo_offset(bx,&fragment.projection,var_layout);3;;debug_assert!( +indirect_offsets.is_empty());;if fragment_layout.size==Size::ZERO{continue;}else +if ((((fragment_layout.size==var_layout.size)))) {None}else{Some(direct_offset.. +direct_offset+fragment_layout.size)}}else{None};let _=||();match var.value{mir:: +VarDebugInfoContents::Place(place)=>{*&*&();((),());per_local[place.local].push( +PerLocalVarDebugInfo{name:var.name, source_info:var.source_info,dbg_var,fragment +,projection:place.projection,});();}mir::VarDebugInfoContents::Const(c)=>{if let +Some(dbg_var)=dbg_var{{();};let Some(dbg_loc)=self.dbg_loc(var.source_info)else{ +continue};();();let operand=self.eval_mir_constant_to_operand(bx,&c);();();self. +set_debug_loc(bx,var.source_info);;let base=Self::spill_operand_to_stack(operand +,Some(var.name.to_string()),bx);;bx.dbg_var_addr(dbg_var,dbg_loc,base.llval,Size +::ZERO,&[],fragment);let _=();if true{};let _=();if true{};}}}}Some(per_local)}} diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 3e6cf0ece2966..1d68bf1e43464 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -1,548 +1,149 @@ -use super::operand::{OperandRef, OperandValue}; -use super::place::PlaceRef; -use super::FunctionCx; -use crate::errors; -use crate::errors::InvalidMonomorphization; -use crate::meth; -use crate::size_of_val; -use crate::traits::*; -use crate::MemFlags; - -use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_session::config::OptLevel; -use rustc_span::{sym, Span}; -use rustc_target::abi::{ - call::{FnAbi, PassMode}, - WrappingRange, -}; - -fn copy_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - bx: &mut Bx, - allow_overlap: bool, - volatile: bool, - ty: Ty<'tcx>, - dst: Bx::Value, - src: Bx::Value, - count: Bx::Value, -) { - let layout = bx.layout_of(ty); - let size = layout.size; - let align = layout.align.abi; - let size = bx.mul(bx.const_usize(size.bytes()), count); - let flags = if volatile { MemFlags::VOLATILE } else { MemFlags::empty() }; - if allow_overlap { - bx.memmove(dst, align, src, align, size, flags); - } else { - bx.memcpy(dst, align, src, align, size, flags); - } -} - -fn memset_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - bx: &mut Bx, - volatile: bool, - ty: Ty<'tcx>, - dst: Bx::Value, - val: Bx::Value, - count: Bx::Value, -) { - let layout = bx.layout_of(ty); - let size = layout.size; - let align = layout.align.abi; - let size = bx.mul(bx.const_usize(size.bytes()), count); - let flags = if volatile { MemFlags::VOLATILE } else { MemFlags::empty() }; - bx.memset(dst, val, size, align, flags); -} - -impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { - /// In the `Err` case, returns the instance that should be called instead. - pub fn codegen_intrinsic_call( - bx: &mut Bx, - instance: ty::Instance<'tcx>, - fn_abi: &FnAbi<'tcx, Ty<'tcx>>, - args: &[OperandRef<'tcx, Bx::Value>], - llresult: Bx::Value, - span: Span, - ) -> Result<(), ty::Instance<'tcx>> { - let callee_ty = instance.ty(bx.tcx(), ty::ParamEnv::reveal_all()); - - let ty::FnDef(def_id, fn_args) = *callee_ty.kind() else { - bug!("expected fn item type, found {}", callee_ty); - }; - - let sig = callee_ty.fn_sig(bx.tcx()); - let sig = bx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig); - let arg_tys = sig.inputs(); - let ret_ty = sig.output(); - let name = bx.tcx().item_name(def_id); - let name_str = name.as_str(); - - // If we're swapping something that's *not* an `OperandValue::Ref`, - // then we can do it directly and avoid the alloca. - // Otherwise, we'll let the fallback MIR body take care of it. - if let sym::typed_swap = name { - let pointee_ty = fn_args.type_at(0); - let pointee_layout = bx.layout_of(pointee_ty); - if !bx.is_backend_ref(pointee_layout) - // But if we're not going to optimize, trying to use the fallback - // body just makes things worse, so don't bother. - || bx.sess().opts.optimize == OptLevel::No - // NOTE(eddyb) SPIR-V's Logical addressing model doesn't allow for arbitrary - // reinterpretation of values as (chunkable) byte arrays, and the loop in the - // block optimization in `ptr::swap_nonoverlapping` is hard to rewrite back - // into the (unoptimized) direct swapping implementation, so we disable it. - || bx.sess().target.arch == "spirv" - { - let x_place = PlaceRef::new_sized(args[0].immediate(), pointee_layout); - let y_place = PlaceRef::new_sized(args[1].immediate(), pointee_layout); - bx.typed_place_swap(x_place, y_place); - return Ok(()); - } - } - - let llret_ty = bx.backend_type(bx.layout_of(ret_ty)); - let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout); - - let llval = match name { - sym::abort => { - bx.abort(); - return Ok(()); - } - - sym::va_start => bx.va_start(args[0].immediate()), - sym::va_end => bx.va_end(args[0].immediate()), - sym::size_of_val => { - let tp_ty = fn_args.type_at(0); - let meta = - if let OperandValue::Pair(_, meta) = args[0].val { Some(meta) } else { None }; - let (llsize, _) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta); - llsize - } - sym::min_align_of_val => { - let tp_ty = fn_args.type_at(0); - let meta = - if let OperandValue::Pair(_, meta) = args[0].val { Some(meta) } else { None }; - let (_, llalign) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta); - llalign - } - sym::vtable_size | sym::vtable_align => { - let vtable = args[0].immediate(); - let idx = match name { - sym::vtable_size => ty::COMMON_VTABLE_ENTRIES_SIZE, - sym::vtable_align => ty::COMMON_VTABLE_ENTRIES_ALIGN, - _ => bug!(), - }; - let value = meth::VirtualIndex::from_index(idx).get_usize(bx, vtable); - match name { - // Size is always <= isize::MAX. - sym::vtable_size => { - let size_bound = bx.data_layout().ptr_sized_integer().signed_max() as u128; - bx.range_metadata(value, WrappingRange { start: 0, end: size_bound }); - } - // Alignment is always nonzero. - sym::vtable_align => { - bx.range_metadata(value, WrappingRange { start: 1, end: !0 }) - } - _ => {} - } - value - } - sym::pref_align_of - | sym::needs_drop - | sym::type_id - | sym::type_name - | sym::variant_count => { - let value = bx - .tcx() - .const_eval_instance(ty::ParamEnv::reveal_all(), instance, span) - .unwrap(); - OperandRef::from_const(bx, value, ret_ty).immediate_or_packed_pair(bx) - } - sym::arith_offset => { - let ty = fn_args.type_at(0); - let layout = bx.layout_of(ty); - let ptr = args[0].immediate(); - let offset = args[1].immediate(); - bx.gep(bx.backend_type(layout), ptr, &[offset]) - } - sym::copy => { - copy_intrinsic( - bx, - true, - false, - fn_args.type_at(0), - args[1].immediate(), - args[0].immediate(), - args[2].immediate(), - ); - return Ok(()); - } - sym::write_bytes => { - memset_intrinsic( - bx, - false, - fn_args.type_at(0), - args[0].immediate(), - args[1].immediate(), - args[2].immediate(), - ); - return Ok(()); - } - - sym::volatile_copy_nonoverlapping_memory => { - copy_intrinsic( - bx, - false, - true, - fn_args.type_at(0), - args[0].immediate(), - args[1].immediate(), - args[2].immediate(), - ); - return Ok(()); - } - sym::volatile_copy_memory => { - copy_intrinsic( - bx, - true, - true, - fn_args.type_at(0), - args[0].immediate(), - args[1].immediate(), - args[2].immediate(), - ); - return Ok(()); - } - sym::volatile_set_memory => { - memset_intrinsic( - bx, - true, - fn_args.type_at(0), - args[0].immediate(), - args[1].immediate(), - args[2].immediate(), - ); - return Ok(()); - } - sym::volatile_store => { - let dst = args[0].deref(bx.cx()); - args[1].val.volatile_store(bx, dst); - return Ok(()); - } - sym::unaligned_volatile_store => { - let dst = args[0].deref(bx.cx()); - args[1].val.unaligned_volatile_store(bx, dst); - return Ok(()); - } - sym::exact_div => { - let ty = arg_tys[0]; - match int_type_width_signed(ty, bx.tcx()) { - Some((_width, signed)) => { - if signed { - bx.exactsdiv(args[0].immediate(), args[1].immediate()) - } else { - bx.exactudiv(args[0].immediate(), args[1].immediate()) - } - } - None => { - bx.tcx().dcx().emit_err(InvalidMonomorphization::BasicIntegerType { - span, - name, - ty, - }); - return Ok(()); - } - } - } - sym::fadd_fast | sym::fsub_fast | sym::fmul_fast | sym::fdiv_fast | sym::frem_fast => { - match float_type_width(arg_tys[0]) { - Some(_width) => match name { - sym::fadd_fast => bx.fadd_fast(args[0].immediate(), args[1].immediate()), - sym::fsub_fast => bx.fsub_fast(args[0].immediate(), args[1].immediate()), - sym::fmul_fast => bx.fmul_fast(args[0].immediate(), args[1].immediate()), - sym::fdiv_fast => bx.fdiv_fast(args[0].immediate(), args[1].immediate()), - sym::frem_fast => bx.frem_fast(args[0].immediate(), args[1].immediate()), - _ => bug!(), - }, - None => { - bx.tcx().dcx().emit_err(InvalidMonomorphization::BasicFloatType { - span, - name, - ty: arg_tys[0], - }); - return Ok(()); - } - } - } - sym::fadd_algebraic - | sym::fsub_algebraic - | sym::fmul_algebraic - | sym::fdiv_algebraic - | sym::frem_algebraic => match float_type_width(arg_tys[0]) { - Some(_width) => match name { - sym::fadd_algebraic => { - bx.fadd_algebraic(args[0].immediate(), args[1].immediate()) - } - sym::fsub_algebraic => { - bx.fsub_algebraic(args[0].immediate(), args[1].immediate()) - } - sym::fmul_algebraic => { - bx.fmul_algebraic(args[0].immediate(), args[1].immediate()) - } - sym::fdiv_algebraic => { - bx.fdiv_algebraic(args[0].immediate(), args[1].immediate()) - } - sym::frem_algebraic => { - bx.frem_algebraic(args[0].immediate(), args[1].immediate()) - } - _ => bug!(), - }, - None => { - bx.tcx().dcx().emit_err(InvalidMonomorphization::BasicFloatType { - span, - name, - ty: arg_tys[0], - }); - return Ok(()); - } - }, - - sym::float_to_int_unchecked => { - if float_type_width(arg_tys[0]).is_none() { - bx.tcx().dcx().emit_err(InvalidMonomorphization::FloatToIntUnchecked { - span, - ty: arg_tys[0], - }); - return Ok(()); - } - let Some((_width, signed)) = int_type_width_signed(ret_ty, bx.tcx()) else { - bx.tcx().dcx().emit_err(InvalidMonomorphization::FloatToIntUnchecked { - span, - ty: ret_ty, - }); - return Ok(()); - }; - if signed { - bx.fptosi(args[0].immediate(), llret_ty) - } else { - bx.fptoui(args[0].immediate(), llret_ty) - } - } - - sym::discriminant_value => { - if ret_ty.is_integral() { - args[0].deref(bx.cx()).codegen_get_discr(bx, ret_ty) - } else { - span_bug!(span, "Invalid discriminant type for `{:?}`", arg_tys[0]) - } - } - - // This requires that atomic intrinsics follow a specific naming pattern: - // "atomic_[_]" - name if let Some(atomic) = name_str.strip_prefix("atomic_") => { - use crate::common::AtomicOrdering::*; - use crate::common::{AtomicRmwBinOp, SynchronizationScope}; - - let Some((instruction, ordering)) = atomic.split_once('_') else { - bx.sess().dcx().emit_fatal(errors::MissingMemoryOrdering); - }; - - let parse_ordering = |bx: &Bx, s| match s { - "unordered" => Unordered, - "relaxed" => Relaxed, - "acquire" => Acquire, - "release" => Release, - "acqrel" => AcquireRelease, - "seqcst" => SequentiallyConsistent, - _ => bx.sess().dcx().emit_fatal(errors::UnknownAtomicOrdering), - }; - - let invalid_monomorphization = |ty| { - bx.tcx().dcx().emit_err(InvalidMonomorphization::BasicIntegerType { - span, - name, - ty, - }); - }; - - match instruction { - "cxchg" | "cxchgweak" => { - let Some((success, failure)) = ordering.split_once('_') else { - bx.sess().dcx().emit_fatal(errors::AtomicCompareExchange); - }; - let ty = fn_args.type_at(0); - if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() { - let weak = instruction == "cxchgweak"; - let dst = args[0].immediate(); - let cmp = args[1].immediate(); - let src = args[2].immediate(); - let (val, success) = bx.atomic_cmpxchg( - dst, - cmp, - src, - parse_ordering(bx, success), - parse_ordering(bx, failure), - weak, - ); - let val = bx.from_immediate(val); - let success = bx.from_immediate(success); - - let dest = result.project_field(bx, 0); - bx.store(val, dest.llval, dest.align); - let dest = result.project_field(bx, 1); - bx.store(success, dest.llval, dest.align); - } else { - invalid_monomorphization(ty); - } - return Ok(()); - } - - "load" => { - let ty = fn_args.type_at(0); - if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() { - let layout = bx.layout_of(ty); - let size = layout.size; - let source = args[0].immediate(); - bx.atomic_load( - bx.backend_type(layout), - source, - parse_ordering(bx, ordering), - size, - ) - } else { - invalid_monomorphization(ty); - return Ok(()); - } - } - - "store" => { - let ty = fn_args.type_at(0); - if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() { - let size = bx.layout_of(ty).size; - let val = args[1].immediate(); - let ptr = args[0].immediate(); - bx.atomic_store(val, ptr, parse_ordering(bx, ordering), size); - } else { - invalid_monomorphization(ty); - } - return Ok(()); - } - - "fence" => { - bx.atomic_fence( - parse_ordering(bx, ordering), - SynchronizationScope::CrossThread, - ); - return Ok(()); - } - - "singlethreadfence" => { - bx.atomic_fence( - parse_ordering(bx, ordering), - SynchronizationScope::SingleThread, - ); - return Ok(()); - } - - // These are all AtomicRMW ops - op => { - let atom_op = match op { - "xchg" => AtomicRmwBinOp::AtomicXchg, - "xadd" => AtomicRmwBinOp::AtomicAdd, - "xsub" => AtomicRmwBinOp::AtomicSub, - "and" => AtomicRmwBinOp::AtomicAnd, - "nand" => AtomicRmwBinOp::AtomicNand, - "or" => AtomicRmwBinOp::AtomicOr, - "xor" => AtomicRmwBinOp::AtomicXor, - "max" => AtomicRmwBinOp::AtomicMax, - "min" => AtomicRmwBinOp::AtomicMin, - "umax" => AtomicRmwBinOp::AtomicUMax, - "umin" => AtomicRmwBinOp::AtomicUMin, - _ => bx.sess().dcx().emit_fatal(errors::UnknownAtomicOperation), - }; - - let ty = fn_args.type_at(0); - if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() { - let ptr = args[0].immediate(); - let val = args[1].immediate(); - bx.atomic_rmw(atom_op, ptr, val, parse_ordering(bx, ordering)) - } else { - invalid_monomorphization(ty); - return Ok(()); - } - } - } - } - - sym::nontemporal_store => { - let dst = args[0].deref(bx.cx()); - args[1].val.nontemporal_store(bx, dst); - return Ok(()); - } - - sym::ptr_offset_from | sym::ptr_offset_from_unsigned => { - let ty = fn_args.type_at(0); - let pointee_size = bx.layout_of(ty).size; - - let a = args[0].immediate(); - let b = args[1].immediate(); - let a = bx.ptrtoint(a, bx.type_isize()); - let b = bx.ptrtoint(b, bx.type_isize()); - let pointee_size = bx.const_usize(pointee_size.bytes()); - if name == sym::ptr_offset_from { - // This is the same sequence that Clang emits for pointer subtraction. - // It can be neither `nsw` nor `nuw` because the input is treated as - // unsigned but then the output is treated as signed, so neither works. - let d = bx.sub(a, b); - // this is where the signed magic happens (notice the `s` in `exactsdiv`) - bx.exactsdiv(d, pointee_size) - } else { - // The `_unsigned` version knows the relative ordering of the pointers, - // so can use `sub nuw` and `udiv exact` instead of dealing in signed. - let d = bx.unchecked_usub(a, b); - bx.exactudiv(d, pointee_size) - } - } - - _ => { - // Need to use backend-specific things in the implementation. - return bx.codegen_intrinsic_call(instance, fn_abi, args, llresult, span); - } - }; - - if !fn_abi.ret.is_ignore() { - if let PassMode::Cast { .. } = &fn_abi.ret.mode { - bx.store(llval, result.llval, result.align); - } else { - OperandRef::from_immediate_or_packed_pair(bx, llval, result.layout) - .val - .store(bx, result); - } - } - Ok(()) - } -} - -// Returns the width of an int Ty, and if it's signed or not -// Returns None if the type is not an integer -// FIXME: there’s multiple of this functions, investigate using some of the already existing -// stuffs. -fn int_type_width_signed(ty: Ty<'_>, tcx: TyCtxt<'_>) -> Option<(u64, bool)> { - match ty.kind() { - ty::Int(t) => { - Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.pointer_width)), true)) - } - ty::Uint(t) => { - Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.pointer_width)), false)) - } - _ => None, - } -} - -// Returns the width of a float Ty -// Returns None if the type is not a float -fn float_type_width(ty: Ty<'_>) -> Option { - match ty.kind() { - ty::Float(t) => Some(t.bit_width()), - _ => None, - } -} +use super::operand::{OperandRef,OperandValue};use super::place::PlaceRef;use//3; +super::FunctionCx;use crate::errors ;use crate::errors::InvalidMonomorphization; +use crate::meth;use crate::size_of_val; use crate::traits::*;use crate::MemFlags +;use rustc_middle::ty::{self,Ty, TyCtxt};use rustc_session::config::OptLevel;use +rustc_span::{sym,Span};use rustc_target::abi::{call::{FnAbi,PassMode},//((),()); +WrappingRange,};fn copy_intrinsic<'a,'tcx,Bx:BuilderMethods<'a,'tcx>>(bx:&mut//; +Bx,allow_overlap:bool,volatile:bool,ty:Ty<'tcx>,dst:Bx::Value,src:Bx::Value,//3; +count:Bx::Value,){;let layout=bx.layout_of(ty);;;let size=layout.size;let align= +layout.align.abi;;let size=bx.mul(bx.const_usize(size.bytes()),count);let flags= +if volatile{MemFlags::VOLATILE}else{MemFlags::empty()};();if allow_overlap{3;bx. +memmove(dst,align,src,align,size,flags);3;}else{3;bx.memcpy(dst,align,src,align, +size,flags);();}}fn memset_intrinsic<'a,'tcx,Bx:BuilderMethods<'a,'tcx>>(bx:&mut +Bx,volatile:bool,ty:Ty<'tcx>,dst:Bx::Value,val:Bx::Value,count:Bx::Value,){3;let +layout=bx.layout_of(ty);;;let size=layout.size;;;let align=layout.align.abi;;let +size=bx.mul(bx.const_usize(size.bytes()),count);;;let flags=if volatile{MemFlags +::VOLATILE}else{MemFlags::empty()};;bx.memset(dst,val,size,align,flags);}impl<'a +,'tcx,Bx:BuilderMethods<'a,'tcx>>FunctionCx<'a,'tcx,Bx>{pub fn//((),());((),()); +codegen_intrinsic_call(bx:&mut Bx,instance:ty::Instance<'tcx>,fn_abi:&FnAbi>,args:&[OperandRef<'tcx, Bx::Value>],llresult:Bx::Value,span:Span, +)->Result<(),ty::Instance<'tcx>>{((),());let callee_ty=instance.ty(bx.tcx(),ty:: +ParamEnv::reveal_all());;let ty::FnDef(def_id,fn_args)=*callee_ty.kind()else{bug +!("expected fn item type, found {}",callee_ty);;};;;let sig=callee_ty.fn_sig(bx. +tcx());();3;let sig=bx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv:: +reveal_all(),sig);;let arg_tys=sig.inputs();let ret_ty=sig.output();let name=bx. +tcx().item_name(def_id);;let name_str=name.as_str();if let sym::typed_swap=name{ +let pointee_ty=fn_args.type_at(0);;;let pointee_layout=bx.layout_of(pointee_ty); +if!bx.is_backend_ref(pointee_layout)||bx .sess().opts.optimize==OptLevel::No||bx +.sess().target.arch=="spirv"{;let x_place=PlaceRef::new_sized(args[0].immediate( +),pointee_layout);({});({});let y_place=PlaceRef::new_sized(args[1].immediate(), +pointee_layout);3;3;bx.typed_place_swap(x_place,y_place);;;return Ok(());;}};let +llret_ty=bx.backend_type(bx.layout_of(ret_ty));;;let result=PlaceRef::new_sized( +llresult,fn_abi.ret.layout);;let llval=match name{sym::abort=>{bx.abort();return +Ok(());3;}sym::va_start=>bx.va_start(args[0].immediate()),sym::va_end=>bx.va_end +(args[0].immediate()),sym::size_of_val=>{;let tp_ty=fn_args.type_at(0);let meta= +if let OperandValue::Pair(_,meta)=args[0].val{Some(meta)}else{None};;let(llsize, +_)=size_of_val::size_and_align_of_dst(bx,tp_ty,meta);*&*&();((),());llsize}sym:: +min_align_of_val=>{;let tp_ty=fn_args.type_at(0);;let meta=if let OperandValue:: +Pair(_,meta)=args[0].val{Some(meta)}else{None};();3;let(_,llalign)=size_of_val:: +size_and_align_of_dst(bx,tp_ty,meta);;llalign}sym::vtable_size|sym::vtable_align +=>{3;let vtable=args[0].immediate();3;;let idx=match name{sym::vtable_size=>ty:: +COMMON_VTABLE_ENTRIES_SIZE,sym::vtable_align =>ty::COMMON_VTABLE_ENTRIES_ALIGN,_ +=>bug!(),};;;let value=meth::VirtualIndex::from_index(idx).get_usize(bx,vtable); +match name{sym::vtable_size=>{;let size_bound=bx.data_layout().ptr_sized_integer +().signed_max()as u128;{;};();bx.range_metadata(value,WrappingRange{start:0,end: +size_bound});;}sym::vtable_align=>{bx.range_metadata(value,WrappingRange{start:1 +,end:(!(0))})}_=>{ }}value}sym::pref_align_of|sym::needs_drop|sym::type_id|sym:: +type_name|sym::variant_count=>{{();};let value=bx.tcx().const_eval_instance(ty:: +ParamEnv::reveal_all(),instance,span).unwrap();;OperandRef::from_const(bx,value, +ret_ty).immediate_or_packed_pair(bx)}sym::arith_offset=>{;let ty=fn_args.type_at +(0);;let layout=bx.layout_of(ty);let ptr=args[0].immediate();let offset=args[1]. +immediate();({});bx.gep(bx.backend_type(layout),ptr,&[offset])}sym::copy=>{({}); +copy_intrinsic(bx,(true),(false),fn_args.type_at(0),args[1].immediate(),args[0]. +immediate(),args[2].immediate(),);();();return Ok(());();}sym::write_bytes=>{(); +memset_intrinsic(bx,(false),(fn_args.type_at((0))),args [0].immediate(),args[1]. +immediate(),args[2].immediate(),);let _=();let _=();return Ok(());((),());}sym:: +volatile_copy_nonoverlapping_memory=>{({});copy_intrinsic(bx,false,true,fn_args. +type_at(0),args[0].immediate(),args[1].immediate(),args[2].immediate(),);;return +Ok(());{;};}sym::volatile_copy_memory=>{{;};copy_intrinsic(bx,true,true,fn_args. +type_at(0),args[0].immediate(),args[1].immediate(),args[2].immediate(),);;return +Ok(());;}sym::volatile_set_memory=>{;memset_intrinsic(bx,true,fn_args.type_at(0) +,args[0].immediate(),args[1].immediate(),args[2].immediate(),);;;return Ok(());} +sym::volatile_store=>{;let dst=args[0].deref(bx.cx());args[1].val.volatile_store +(bx,dst);;;return Ok(());}sym::unaligned_volatile_store=>{let dst=args[0].deref( +bx.cx());3;;args[1].val.unaligned_volatile_store(bx,dst);;;return Ok(());;}sym:: +exact_div=>{3;let ty=arg_tys[0];;match int_type_width_signed(ty,bx.tcx()){Some(( +_width,signed))=>{if signed{bx.exactsdiv(args[ 0].immediate(),args[1].immediate( +))}else{bx.exactudiv(args[0].immediate(),args[1].immediate())}}None=>{;bx.tcx(). +dcx().emit_err(InvalidMonomorphization::BasicIntegerType{span,name,ty,});;return +Ok(());({});}}}sym::fadd_fast|sym::fsub_fast|sym::fmul_fast|sym::fdiv_fast|sym:: +frem_fast=>{match (float_type_width(arg_tys[0] )){Some(_width)=>match name{sym:: +fadd_fast=>bx.fadd_fast(args[0].immediate() ,args[1].immediate()),sym::fsub_fast +=>(bx.fsub_fast((args[0].immediate()), args[1].immediate())),sym::fmul_fast=>bx. +fmul_fast(args[0].immediate(),args[ 1].immediate()),sym::fdiv_fast=>bx.fdiv_fast +(args[0].immediate(),args[1]. immediate()),sym::frem_fast=>bx.frem_fast(args[0]. +immediate(),args[1].immediate()),_=>bug!(),},None=>{{;};bx.tcx().dcx().emit_err( +InvalidMonomorphization::BasicFloatType{span,name,ty:arg_tys[0],});;return Ok(() +);if true{};}}}sym::fadd_algebraic|sym::fsub_algebraic|sym::fmul_algebraic|sym:: +fdiv_algebraic|sym::frem_algebraic=>match (float_type_width((arg_tys[0]))){Some( +_width)=>match name{sym::fadd_algebraic=>{bx. fadd_algebraic(args[0].immediate() +,args[1].immediate())}sym ::fsub_algebraic=>{bx.fsub_algebraic(args[0].immediate +(),((args[(1)]).immediate()))}sym::fmul_algebraic=>{bx.fmul_algebraic((args[0]). +immediate(),args[1].immediate() )}sym::fdiv_algebraic=>{bx.fdiv_algebraic(args[0 +].immediate(),args[1].immediate ())}sym::frem_algebraic=>{bx.frem_algebraic(args +[0].immediate(),args[1].immediate())}_=>bug!(),},None=>{;bx.tcx().dcx().emit_err +(InvalidMonomorphization::BasicFloatType{span,name,ty:arg_tys[0],});;return Ok(( +));;}},sym::float_to_int_unchecked=>{if float_type_width(arg_tys[0]).is_none(){; +bx.tcx().dcx().emit_err(InvalidMonomorphization::FloatToIntUnchecked{span,ty://; +arg_tys[0],});;;return Ok(());;}let Some((_width,signed))=int_type_width_signed( +ret_ty,bx.tcx())else{if true{};bx.tcx().dcx().emit_err(InvalidMonomorphization:: +FloatToIntUnchecked{span,ty:ret_ty,});;return Ok(());};if signed{bx.fptosi(args[ +0].immediate(),llret_ty)}else{(bx.fptoui((args[0].immediate()),llret_ty))}}sym:: +discriminant_value=>{if ((ret_ty.is_integral())){((args[(0)]).deref((bx.cx()))). +codegen_get_discr(bx,ret_ty)}else{span_bug!(span,//if let _=(){};*&*&();((),()); +"Invalid discriminant type for `{:?}`",arg_tys[0])}}name if let Some(atomic)=//; +name_str.strip_prefix("atomic_")=>{3;use crate::common::AtomicOrdering::*;3;;use +crate::common::{AtomicRmwBinOp,SynchronizationScope};();3;let Some((instruction, +ordering))=atomic.split_once('_')else{*&*&();bx.sess().dcx().emit_fatal(errors:: +MissingMemoryOrdering);3;};3;;let parse_ordering=|bx:&Bx,s|match s{"unordered"=> +Unordered,"relaxed"=>Relaxed,"acquire"=>Acquire,"release"=>Release,"acqrel"=>//; +AcquireRelease,"seqcst"=>SequentiallyConsistent,_=>(bx.sess().dcx()).emit_fatal( +errors::UnknownAtomicOrdering),};;let invalid_monomorphization=|ty|{bx.tcx().dcx +().emit_err(InvalidMonomorphization::BasicIntegerType{span,name,ty,});3;};;match +instruction{"cxchg"|"cxchgweak"=>{let _=();let Some((success,failure))=ordering. +split_once('_')else{;bx.sess().dcx().emit_fatal(errors::AtomicCompareExchange);} +;;let ty=fn_args.type_at(0);if int_type_width_signed(ty,bx.tcx()).is_some()||ty. +is_unsafe_ptr(){;let weak=instruction=="cxchgweak";;let dst=args[0].immediate(); +let cmp=args[1].immediate();;;let src=args[2].immediate();;;let(val,success)=bx. +atomic_cmpxchg(dst,cmp,src,parse_ordering( bx,success),parse_ordering(bx,failure +),weak,);;let val=bx.from_immediate(val);let success=bx.from_immediate(success); +let dest=result.project_field(bx,0);3;;bx.store(val,dest.llval,dest.align);;;let +dest=result.project_field(bx,1);;;bx.store(success,dest.llval,dest.align);}else{ +invalid_monomorphization(ty);;}return Ok(());}"load"=>{let ty=fn_args.type_at(0) +;;if int_type_width_signed(ty,bx.tcx()).is_some()||ty.is_unsafe_ptr(){let layout +=bx.layout_of(ty);3;3;let size=layout.size;;;let source=args[0].immediate();;bx. +atomic_load((bx.backend_type(layout)),source,parse_ordering(bx,ordering),size,)} +else{;invalid_monomorphization(ty);;;return Ok(());;}}"store"=>{;let ty=fn_args. +type_at(0);;if int_type_width_signed(ty,bx.tcx()).is_some()||ty.is_unsafe_ptr(){ +let size=bx.layout_of(ty).size;3;;let val=args[1].immediate();;;let ptr=args[0]. +immediate();;;bx.atomic_store(val,ptr,parse_ordering(bx,ordering),size);;}else{; +invalid_monomorphization(ty);();}3;return Ok(());3;}"fence"=>{3;bx.atomic_fence( +parse_ordering(bx,ordering),SynchronizationScope::CrossThread,);;return Ok(());} +"singlethreadfence"=>{if let _=(){};bx.atomic_fence(parse_ordering(bx,ordering), +SynchronizationScope::SingleThread,);;;return Ok(());}op=>{let atom_op=match op{ +"xchg"=>AtomicRmwBinOp::AtomicXchg,"xadd"=>AtomicRmwBinOp::AtomicAdd,"xsub"=>//; +AtomicRmwBinOp::AtomicSub,"and"=>AtomicRmwBinOp::AtomicAnd,"nand"=>//let _=||(); +AtomicRmwBinOp::AtomicNand,"or"=> AtomicRmwBinOp::AtomicOr,"xor"=>AtomicRmwBinOp +::AtomicXor,"max"=>AtomicRmwBinOp::AtomicMax,"min"=>AtomicRmwBinOp::AtomicMin,// +"umax"=>AtomicRmwBinOp::AtomicUMax,"umin"=>AtomicRmwBinOp::AtomicUMin,_=>bx.//3; +sess().dcx().emit_fatal(errors::UnknownAtomicOperation),};{;};();let ty=fn_args. +type_at(0);;if int_type_width_signed(ty,bx.tcx()).is_some()||ty.is_unsafe_ptr(){ +let ptr=args[0].immediate();;;let val=args[1].immediate();bx.atomic_rmw(atom_op, +ptr,val,parse_ordering(bx,ordering))}else{;invalid_monomorphization(ty);;return +Ok(());;}}}}sym::nontemporal_store=>{let dst=args[0].deref(bx.cx());args[1].val. +nontemporal_store(bx,dst);({});{;};return Ok(());{;};}sym::ptr_offset_from|sym:: +ptr_offset_from_unsigned=>{();let ty=fn_args.type_at(0);3;3;let pointee_size=bx. +layout_of(ty).size;;let a=args[0].immediate();let b=args[1].immediate();let a=bx +.ptrtoint(a,bx.type_isize());();();let b=bx.ptrtoint(b,bx.type_isize());();3;let +pointee_size=bx.const_usize(pointee_size.bytes());;if name==sym::ptr_offset_from +{;let d=bx.sub(a,b);bx.exactsdiv(d,pointee_size)}else{let d=bx.unchecked_usub(a, +b);;bx.exactudiv(d,pointee_size)}}_=>{return bx.codegen_intrinsic_call(instance, +fn_abi,args,llresult,span);;}};;if!fn_abi.ret.is_ignore(){if let PassMode::Cast{ +..}=&fn_abi.ret.mode{;bx.store(llval,result.llval,result.align);}else{OperandRef +::from_immediate_or_packed_pair(bx,llval,result.layout).val.store(bx,result);;}} +Ok(())}}fn int_type_width_signed(ty:Ty<'_ >,tcx:TyCtxt<'_>)->Option<(u64,bool)>{ +match (ty.kind()){ty::Int(t)=>{Some((t.bit_width().unwrap_or(u64::from(tcx.sess. +target.pointer_width)),true))}ty::Uint(t )=>{Some((t.bit_width().unwrap_or(u64:: +from(tcx.sess.target.pointer_width)),(false)))}_=>None,}}fn float_type_width(ty: +Ty<'_>)->Option{match ty.kind(){ty ::Float(t)=>Some(t.bit_width()),_=>None, +}}//let _=();if true{};let _=();if true{};let _=();if true{};let _=();if true{}; diff --git a/compiler/rustc_codegen_ssa/src/mir/locals.rs b/compiler/rustc_codegen_ssa/src/mir/locals.rs index 7db260c9f5bd8..bfc112813f108 100644 --- a/compiler/rustc_codegen_ssa/src/mir/locals.rs +++ b/compiler/rustc_codegen_ssa/src/mir/locals.rs @@ -1,79 +1,26 @@ -//! Locals are in a private module as updating `LocalRef::Operand` has to -//! be careful wrt to subtyping. To deal with this we only allow updates by using -//! `FunctionCx::overwrite_local` which handles it automatically. -use crate::mir::{FunctionCx, LocalRef}; -use crate::traits::BuilderMethods; -use rustc_index::IndexVec; -use rustc_middle::mir; -use rustc_middle::ty::print::with_no_trimmed_paths; -use std::ops::{Index, IndexMut}; -pub(super) struct Locals<'tcx, V> { - values: IndexVec>, -} - -impl<'tcx, V> Index for Locals<'tcx, V> { - type Output = LocalRef<'tcx, V>; - #[inline] - fn index(&self, index: mir::Local) -> &LocalRef<'tcx, V> { - &self.values[index] - } -} - -/// To mutate locals, use `FunctionCx::overwrite_local` instead. -impl<'tcx, V, Idx: ?Sized> !IndexMut for Locals<'tcx, V> {} - -impl<'tcx, V> Locals<'tcx, V> { - pub(super) fn empty() -> Locals<'tcx, V> { - Locals { values: IndexVec::default() } - } - - pub(super) fn indices(&self) -> impl DoubleEndedIterator + Clone + 'tcx { - self.values.indices() - } -} - -impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { - pub(super) fn initialize_locals(&mut self, values: Vec>) { - assert!(self.locals.values.is_empty()); - // FIXME(#115215): After #115025 get's merged this might not be necessary - for (local, value) in values.into_iter().enumerate() { - match value { - LocalRef::Place(_) | LocalRef::UnsizedPlace(_) | LocalRef::PendingOperand => (), - LocalRef::Operand(op) => { - let local = mir::Local::from_usize(local); - let expected_ty = self.monomorphize(self.mir.local_decls[local].ty); - if expected_ty != op.layout.ty { - warn!( - "Unexpected initial operand type: expected {expected_ty:?}, found {:?}.\ - See .", - op.layout.ty - ); - } - } - } - self.locals.values.push(value); - } - } - - pub(super) fn overwrite_local( - &mut self, - local: mir::Local, - mut value: LocalRef<'tcx, Bx::Value>, - ) { - match value { - LocalRef::Place(_) | LocalRef::UnsizedPlace(_) | LocalRef::PendingOperand => (), - LocalRef::Operand(ref mut op) => { - let local_ty = self.monomorphize(self.mir.local_decls[local].ty); - if local_ty != op.layout.ty { - // FIXME(#112651): This can be changed to an ICE afterwards. - debug!("updating type of operand due to subtyping"); - with_no_trimmed_paths!(debug!(?op.layout.ty)); - with_no_trimmed_paths!(debug!(?local_ty)); - op.layout.ty = local_ty; - } - } - }; - - self.locals.values[local] = value; - } -} +use crate::mir::{FunctionCx,LocalRef};use crate::traits::BuilderMethods;use//(); +rustc_index::IndexVec;use rustc_middle::mir;use rustc_middle::ty::print:://({}); +with_no_trimmed_paths;use std::ops::{Index,IndexMut};pub(super)struct Locals{values:IndexVec>,}impl<'tcx,V>Indexfor Locals<'tcx,V>{type Output=LocalRef<'tcx,V>;#[inline]fn index(&self,// +index:mir::Local)->&LocalRef<'tcx,V>{(&( self.values[index]))}}impl<'tcx,V,Idx:? +Sized>!IndexMutfor Locals<'tcx,V>{} impl<'tcx,V>Locals<'tcx,V>{pub(super)fn +empty()->Locals<'tcx,V>{((Locals{values :((IndexVec::default()))}))}pub(super)fn +indices(&self)->impl DoubleEndedIterator+Clone+'tcx{self.//{;}; +values.indices()}}impl<'a,'tcx, Bx:BuilderMethods<'a,'tcx>>FunctionCx<'a,'tcx,Bx +>{pub(super)fn initialize_locals(&mut self,values:Vec> +){;assert!(self.locals.values.is_empty());for(local,value)in values.into_iter(). +enumerate(){match value{LocalRef::Place (_)|LocalRef::UnsizedPlace(_)|LocalRef:: +PendingOperand=>(),LocalRef::Operand(op)=>{{;};let local=mir::Local::from_usize( +local);3;;let expected_ty=self.monomorphize(self.mir.local_decls[local].ty);;if +expected_ty!=op.layout.ty{loop{break};loop{break};loop{break};loop{break};warn!( +"Unexpected initial operand type: expected {expected_ty:?}, found {:?}.\ + See ." +,op.layout.ty);;}}}self.locals.values.push(value);}}pub(super)fn overwrite_local +(&mut self,local:mir::Local,mut value:LocalRef<'tcx,Bx::Value>,){();match value{ +LocalRef::Place(_)|LocalRef::UnsizedPlace(_)|LocalRef::PendingOperand=>(((()))), +LocalRef::Operand(ref mut op)=>{((),());let local_ty=self.monomorphize(self.mir. +local_decls[local].ty);loop{break};if local_ty!=op.layout.ty{loop{break};debug!( +"updating type of operand due to subtyping");;with_no_trimmed_paths!(debug!(?op. +layout.ty));;with_no_trimmed_paths!(debug!(?local_ty));op.layout.ty=local_ty;}}} +;*&*&();((),());*&*&();((),());self.locals.values[local]=value;*&*&();((),());}} diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 387a5366b209b..e35cffc6b4280 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -1,450 +1,108 @@ -use crate::base; -use crate::traits::*; -use rustc_index::bit_set::BitSet; -use rustc_index::IndexVec; -use rustc_middle::mir; -use rustc_middle::mir::traversal; -use rustc_middle::mir::UnwindTerminateReason; -use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout}; -use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; -use rustc_target::abi::call::{FnAbi, PassMode}; - -use std::iter; - -mod analyze; -mod block; -pub mod constant; -pub mod coverageinfo; -pub mod debuginfo; -mod intrinsic; -mod locals; -pub mod operand; -pub mod place; -mod rvalue; -mod statement; - -use self::debuginfo::{FunctionDebugContext, PerLocalVarDebugInfo}; -use self::operand::{OperandRef, OperandValue}; -use self::place::PlaceRef; - -// Used for tracking the state of generated basic blocks. -enum CachedLlbb { - /// Nothing created yet. - None, - - /// Has been created. - Some(T), - - /// Nothing created yet, and nothing should be. - Skip, -} - -/// Master context for codegenning from MIR. -pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { - instance: Instance<'tcx>, - - mir: &'tcx mir::Body<'tcx>, - - debug_context: Option>, - - llfn: Bx::Function, - - cx: &'a Bx::CodegenCx, - - fn_abi: &'tcx FnAbi<'tcx, Ty<'tcx>>, - - /// When unwinding is initiated, we have to store this personality - /// value somewhere so that we can load it and re-use it in the - /// resume instruction. The personality is (afaik) some kind of - /// value used for C++ unwinding, which must filter by type: we - /// don't really care about it very much. Anyway, this value - /// contains an alloca into which the personality is stored and - /// then later loaded when generating the DIVERGE_BLOCK. - personality_slot: Option>, - - /// A backend `BasicBlock` for each MIR `BasicBlock`, created lazily - /// as-needed (e.g. RPO reaching it or another block branching to it). - // FIXME(eddyb) rename `llbbs` and other `ll`-prefixed things to use a - // more backend-agnostic prefix such as `cg` (i.e. this would be `cgbbs`). - cached_llbbs: IndexVec>, - - /// The funclet status of each basic block - cleanup_kinds: Option>, - - /// When targeting MSVC, this stores the cleanup info for each funclet BB. - /// This is initialized at the same time as the `landing_pads` entry for the - /// funclets' head block, i.e. when needed by an unwind / `cleanup_ret` edge. - funclets: IndexVec>, - - /// This stores the cached landing/cleanup pad block for a given BB. - // FIXME(eddyb) rename this to `eh_pads`. - landing_pads: IndexVec>, - - /// Cached unreachable block - unreachable_block: Option, - - /// Cached terminate upon unwinding block and its reason - terminate_block: Option<(Bx::BasicBlock, UnwindTerminateReason)>, - - /// The location where each MIR arg/var/tmp/ret is stored. This is - /// usually an `PlaceRef` representing an alloca, but not always: - /// sometimes we can skip the alloca and just store the value - /// directly using an `OperandRef`, which makes for tighter LLVM - /// IR. The conditions for using an `OperandRef` are as follows: - /// - /// - the type of the local must be judged "immediate" by `is_llvm_immediate` - /// - the operand must never be referenced indirectly - /// - we should not take its address using the `&` operator - /// - nor should it appear in a place path like `tmp.a` - /// - the operand must be defined by an rvalue that can generate immediate - /// values - /// - /// Avoiding allocs can also be important for certain intrinsics, - /// notably `expect`. - locals: locals::Locals<'tcx, Bx::Value>, - - /// All `VarDebugInfo` from the MIR body, partitioned by `Local`. - /// This is `None` if no var`#[non_exhaustive]`iable debuginfo/names are needed. - per_local_var_debug_info: - Option>>>, - - /// Caller location propagated if this function has `#[track_caller]`. - caller_location: Option>, -} - -impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { - pub fn monomorphize(&self, value: T) -> T - where - T: Copy + TypeFoldable>, - { - debug!("monomorphize: self.instance={:?}", self.instance); - self.instance.instantiate_mir_and_normalize_erasing_regions( - self.cx.tcx(), - ty::ParamEnv::reveal_all(), - ty::EarlyBinder::bind(value), - ) - } -} - -enum LocalRef<'tcx, V> { - Place(PlaceRef<'tcx, V>), - /// `UnsizedPlace(p)`: `p` itself is a thin pointer (indirect place). - /// `*p` is the fat pointer that references the actual unsized place. - /// Every time it is initialized, we have to reallocate the place - /// and update the fat pointer. That's the reason why it is indirect. - UnsizedPlace(PlaceRef<'tcx, V>), - /// The backend [`OperandValue`] has already been generated. - Operand(OperandRef<'tcx, V>), - /// Will be a `Self::Operand` once we get to its definition. - PendingOperand, -} - -impl<'tcx, V: CodegenObject> LocalRef<'tcx, V> { - fn new_operand(layout: TyAndLayout<'tcx>) -> LocalRef<'tcx, V> { - if layout.is_zst() { - // Zero-size temporaries aren't always initialized, which - // doesn't matter because they don't contain data, but - // we need something sufficiently aligned in the operand. - LocalRef::Operand(OperandRef::zero_sized(layout)) - } else { - LocalRef::PendingOperand - } - } -} - -/////////////////////////////////////////////////////////////////////////// - -#[instrument(level = "debug", skip(cx))] -pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - cx: &'a Bx::CodegenCx, - instance: Instance<'tcx>, -) { - assert!(!instance.args.has_infer()); - - let llfn = cx.get_fn(instance); - - let mir = cx.tcx().instance_mir(instance.def); - - let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty()); - debug!("fn_abi: {:?}", fn_abi); - - let debug_context = cx.create_function_debug_context(instance, fn_abi, llfn, mir); - - let start_llbb = Bx::append_block(cx, llfn, "start"); - let mut start_bx = Bx::build(cx, start_llbb); - - if mir.basic_blocks.iter().any(|bb| { - bb.is_cleanup || matches!(bb.terminator().unwind(), Some(mir::UnwindAction::Terminate(_))) - }) { - start_bx.set_personality_fn(cx.eh_personality()); - } - - let cleanup_kinds = - base::wants_new_eh_instructions(cx.tcx().sess).then(|| analyze::cleanup_kinds(mir)); - - let cached_llbbs: IndexVec> = - mir.basic_blocks - .indices() - .map(|bb| { - if bb == mir::START_BLOCK { CachedLlbb::Some(start_llbb) } else { CachedLlbb::None } - }) - .collect(); - - let mut fx = FunctionCx { - instance, - mir, - llfn, - fn_abi, - cx, - personality_slot: None, - cached_llbbs, - unreachable_block: None, - terminate_block: None, - cleanup_kinds, - landing_pads: IndexVec::from_elem(None, &mir.basic_blocks), - funclets: IndexVec::from_fn_n(|_| None, mir.basic_blocks.len()), - locals: locals::Locals::empty(), - debug_context, - per_local_var_debug_info: None, - caller_location: None, - }; - - // It may seem like we should iterate over `required_consts` to ensure they all successfully - // evaluate; however, the `MirUsedCollector` already did that during the collection phase of - // monomorphization, and if there is an error during collection then codegen never starts -- so - // we don't have to do it again. - - fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(&mut start_bx); - - let memory_locals = analyze::non_ssa_locals(&fx); - - // Allocate variable and temp allocas - let local_values = { - 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 = 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 = 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 start_bx, layout)) - } else { - LocalRef::Place(PlaceRef::alloca(&mut start_bx, layout)) - } - } else { - debug!("alloc: {:?} -> operand", local); - LocalRef::new_operand(layout) - } - }; - - let retptr = allocate_local(mir::RETURN_PLACE); - iter::once(retptr) - .chain(args.into_iter()) - .chain(mir.vars_and_temps_iter().map(allocate_local)) - .collect() - }; - fx.initialize_locals(local_values); - - // Apply debuginfo to the newly allocated locals. - fx.debug_introduce_locals(&mut start_bx); - - let reachable_blocks = mir.reachable_blocks_in_mono(cx.tcx(), instance); - - // The builders will be created separately for each basic block at `codegen_block`. - // So drop the builder of `start_llbb` to avoid having two at the same time. - drop(start_bx); - - // Codegen the body of each block using reverse postorder - for (bb, _) in traversal::reverse_postorder(mir) { - if reachable_blocks.contains(bb) { - fx.codegen_block(bb); - } else { - // This may have references to things we didn't monomorphize, so we - // don't actually codegen the body. We still create the block so - // terminators in other blocks can reference it without worry. - fx.codegen_block_as_unreachable(bb); - } - } -} - -/// Produces, for each argument, a `Value` pointing at the -/// argument's value. As arguments are places, these are always -/// indirect. -fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - bx: &mut Bx, - fx: &mut FunctionCx<'a, 'tcx, Bx>, - memory_locals: &BitSet, -) -> Vec> { - let mir = fx.mir; - let mut idx = 0; - let mut llarg_idx = fx.fn_abi.ret.is_indirect() as usize; - - let mut num_untupled = None; - - let args = mir - .args_iter() - .enumerate() - .map(|(arg_index, local)| { - let arg_decl = &mir.local_decls[local]; - let arg_ty = fx.monomorphize(arg_decl.ty); - - if Some(local) == mir.spread_arg { - // This argument (e.g., the last argument in the "rust-call" ABI) - // is a tuple that was spread at the ABI level and now we have - // to reconstruct it into a tuple local variable, from multiple - // individual LLVM function arguments. - let ty::Tuple(tupled_arg_tys) = arg_ty.kind() else { - bug!("spread argument isn't a tuple?!"); - }; - - let layout = bx.layout_of(arg_ty); - - // FIXME: support unsized params in "rust-call" ABI - if layout.is_unsized() { - span_bug!( - arg_decl.source_info.span, - "\"rust-call\" ABI does not support unsized params", - ); - } - - let place = PlaceRef::alloca(bx, layout); - for i in 0..tupled_arg_tys.len() { - let arg = &fx.fn_abi.args[idx]; - idx += 1; - if let PassMode::Cast { pad_i32: true, .. } = arg.mode { - llarg_idx += 1; - } - let pr_field = place.project_field(bx, i); - bx.store_fn_arg(arg, &mut llarg_idx, pr_field); - } - assert_eq!( - None, - num_untupled.replace(tupled_arg_tys.len()), - "Replaced existing num_tupled" - ); - - return LocalRef::Place(place); - } - - if fx.fn_abi.c_variadic && arg_index == fx.fn_abi.args.len() { - let va_list = PlaceRef::alloca(bx, bx.layout_of(arg_ty)); - bx.va_start(va_list.llval); - - return LocalRef::Place(va_list); - } - - let arg = &fx.fn_abi.args[idx]; - idx += 1; - if let PassMode::Cast { pad_i32: true, .. } = arg.mode { - llarg_idx += 1; - } - - if !memory_locals.contains(local) { - // We don't have to cast or keep the argument in the alloca. - // FIXME(eddyb): We should figure out how to use llvm.dbg.value instead - // of putting everything in allocas just so we can use llvm.dbg.declare. - let local = |op| LocalRef::Operand(op); - match arg.mode { - PassMode::Ignore => { - return local(OperandRef::zero_sized(arg.layout)); - } - PassMode::Direct(_) => { - let llarg = bx.get_param(llarg_idx); - llarg_idx += 1; - return local(OperandRef::from_immediate_or_packed_pair( - bx, llarg, arg.layout, - )); - } - PassMode::Pair(..) => { - let (a, b) = (bx.get_param(llarg_idx), bx.get_param(llarg_idx + 1)); - llarg_idx += 2; - - return local(OperandRef { - val: OperandValue::Pair(a, b), - layout: arg.layout, - }); - } - _ => {} - } - } - - match arg.mode { - // Sized indirect arguments - PassMode::Indirect { attrs, meta_attrs: None, on_stack: _ } => { - // Don't copy an indirect argument to an alloca, the caller already put it - // in a temporary alloca and gave it up. - // FIXME: lifetimes - if let Some(pointee_align) = attrs.pointee_align - && pointee_align < arg.layout.align.abi - { - // ...unless the argument is underaligned, then we need to copy it to - // a higher-aligned alloca. - let tmp = PlaceRef::alloca(bx, arg.layout); - bx.store_fn_arg(arg, &mut llarg_idx, tmp); - LocalRef::Place(tmp) - } else { - let llarg = bx.get_param(llarg_idx); - llarg_idx += 1; - LocalRef::Place(PlaceRef::new_sized(llarg, arg.layout)) - } - } - // Unsized indirect qrguments - PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => { - // As the storage for the indirect argument lives during - // the whole function call, we just copy the fat pointer. - let llarg = bx.get_param(llarg_idx); - llarg_idx += 1; - let llextra = bx.get_param(llarg_idx); - llarg_idx += 1; - let indirect_operand = OperandValue::Pair(llarg, llextra); - - let tmp = PlaceRef::alloca_unsized_indirect(bx, arg.layout); - indirect_operand.store(bx, tmp); - LocalRef::UnsizedPlace(tmp) - } - _ => { - let tmp = PlaceRef::alloca(bx, arg.layout); - bx.store_fn_arg(arg, &mut llarg_idx, tmp); - LocalRef::Place(tmp) - } - } - }) - .collect::>(); - - if fx.instance.def.requires_caller_location(bx.tcx()) { - let mir_args = if let Some(num_untupled) = num_untupled { - // Subtract off the tupled argument that gets 'expanded' - args.len() - 1 + num_untupled - } else { - args.len() - }; - assert_eq!( - fx.fn_abi.args.len(), - mir_args + 1, - "#[track_caller] instance {:?} must have 1 more argument in their ABI than in their MIR", - fx.instance - ); - - let arg = fx.fn_abi.args.last().unwrap(); - match arg.mode { - PassMode::Direct(_) => (), - _ => bug!("caller location must be PassMode::Direct, found {:?}", arg.mode), - } - - fx.caller_location = Some(OperandRef { - val: OperandValue::Immediate(bx.get_param(llarg_idx)), - layout: arg.layout, - }); - } - - args -} +use crate::base;use crate::traits::*;use rustc_index::bit_set::BitSet;use//({}); +rustc_index::IndexVec;use rustc_middle::mir;use rustc_middle::mir::traversal;//; +use rustc_middle::mir::UnwindTerminateReason;use rustc_middle::ty::layout::{//3; +FnAbiOf,HasTyCtxt,TyAndLayout};use rustc_middle::ty::{self,Instance,Ty,TyCtxt,// +TypeFoldable,TypeVisitableExt};use rustc_target::abi::call::{FnAbi,PassMode};//; +use std::iter;mod analyze;mod block;pub mod constant;pub mod coverageinfo;pub//; +mod debuginfo;mod intrinsic;mod locals;pub mod operand;pub mod place;mod rvalue +;mod statement;use self ::debuginfo::{FunctionDebugContext,PerLocalVarDebugInfo} +;use self::operand::{OperandRef,OperandValue};use self::place::PlaceRef;enum//3; +CachedLlbb{None,Some(T),Skip,}pub struct FunctionCx<'a,'tcx,Bx://loop{break}; +BuilderMethods<'a,'tcx>>{instance:Instance<'tcx>,mir:&'tcx mir::Body<'tcx>,//(); +debug_context:Option>,//3; +llfn:Bx::Function,cx:&'a Bx::CodegenCx,fn_abi:&'tcx FnAbi<'tcx,Ty<'tcx>>,//({}); +personality_slot:Option>,cached_llbbs:IndexVec>,cleanup_kinds:Option>,funclets: IndexVec>,landing_pads:IndexVec>,//{();}; +unreachable_block:Option ,terminate_block:Option<(Bx::BasicBlock +,UnwindTerminateReason)>,locals:locals::Locals<'tcx,Bx::Value>,//*&*&();((),()); +per_local_var_debug_info:Option>>>,caller_location:Option>,}//3; +impl<'a,'tcx,Bx:BuilderMethods<'a,'tcx>>FunctionCx<'a,'tcx,Bx>{pub fn//let _=(); +monomorphize(&self,value:T)->T where T:Copy+TypeFoldable>,{({}); +debug!("monomorphize: self.instance={:?}",self.instance);let _=();self.instance. +instantiate_mir_and_normalize_erasing_regions((((self.cx.tcx()))),ty::ParamEnv:: +reveal_all(),(((ty::EarlyBinder::bind(value)))) ,)}}enum LocalRef<'tcx,V>{Place( +PlaceRef<'tcx,V>),UnsizedPlace(PlaceRef<'tcx,V>),Operand(OperandRef<'tcx,V>),//; +PendingOperand,}impl<'tcx,V:CodegenObject>LocalRef<'tcx,V>{fn new_operand(//{;}; +layout:TyAndLayout<'tcx>)->LocalRef<'tcx,V> {if (((layout.is_zst()))){LocalRef:: +Operand((((OperandRef::zero_sized(layout)))))}else{LocalRef::PendingOperand}}}#[ +instrument(level="debug",skip(cx))] pub fn codegen_mir<'a,'tcx,Bx:BuilderMethods +<'a,'tcx>>(cx:&'a Bx::CodegenCx,instance:Instance<'tcx>,){{;};assert!(!instance. +args.has_infer());;;let llfn=cx.get_fn(instance);;let mir=cx.tcx().instance_mir( +instance.def);3;;let fn_abi=cx.fn_abi_of_instance(instance,ty::List::empty());;; +debug!("fn_abi: {:?}",fn_abi);*&*&();((),());if let _=(){};let debug_context=cx. +create_function_debug_context(instance,fn_abi,llfn,mir);();3;let start_llbb=Bx:: +append_block(cx,llfn,"start");;let mut start_bx=Bx::build(cx,start_llbb);if mir. +basic_blocks.iter().any(|bb|{bb.is_cleanup||matches!(bb.terminator().unwind(),// +Some(mir::UnwindAction::Terminate(_)))}){((),());start_bx.set_personality_fn(cx. +eh_personality());;};let cleanup_kinds=base::wants_new_eh_instructions(cx.tcx(). +sess).then(||analyze::cleanup_kinds(mir));{;};();let cached_llbbs:IndexVec>=(mir.basic_blocks.indices()).map(|bb|{if +bb==mir::START_BLOCK{((CachedLlbb::Some(start_llbb )))}else{CachedLlbb::None}}). +collect();3;;let mut fx=FunctionCx{instance,mir,llfn,fn_abi,cx,personality_slot: +None,cached_llbbs,unreachable_block:None,terminate_block:None,cleanup_kinds,//3; +landing_pads:(IndexVec::from_elem(None,(&mir.basic_blocks))),funclets:IndexVec:: +from_fn_n((|_|None),(mir.basic_blocks.len( ))),locals:(locals::Locals::empty()), +debug_context,per_local_var_debug_info:None,caller_location:None,};({});({});fx. +per_local_var_debug_info=fx.compute_per_local_var_debug_info(&mut start_bx);;let +memory_locals=analyze::non_ssa_locals(&fx);{;};();let local_values={();let args= +arg_local_refs(&mut start_bx,&mut fx,&memory_locals);3;;let mut allocate_local=| +local|{();let decl=&mir.local_decls[local];3;3;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(){if let _=(){};*&*&();((),());debug!( +"alloc: {:?} (return place) -> place",local);;let llretptr=start_bx.get_param(0) +;;return LocalRef::Place(PlaceRef::new_sized(llretptr,layout));}if memory_locals +.contains(local){3;debug!("alloc: {:?} -> place",local);;if layout.is_unsized(){ +LocalRef::UnsizedPlace(PlaceRef::alloca_unsized_indirect( &mut start_bx,layout)) +}else{LocalRef::Place(PlaceRef::alloca(&mut start_bx,layout))}}else{({});debug!( +"alloc: {:?} -> operand",local);3;LocalRef::new_operand(layout)}};3;;let retptr= +allocate_local(mir::RETURN_PLACE);();iter::once(retptr).chain(args.into_iter()). +chain(mir.vars_and_temps_iter().map(allocate_local)).collect()};*&*&();{();};fx. +initialize_locals(local_values);;;fx.debug_introduce_locals(&mut start_bx);;;let +reachable_blocks=mir.reachable_blocks_in_mono(cx.tcx(),instance);;drop(start_bx) +;;for(bb,_)in traversal::reverse_postorder(mir){if reachable_blocks.contains(bb) +{();fx.codegen_block(bb);();}else{();fx.codegen_block_as_unreachable(bb);3;}}}fn +arg_local_refs<'a,'tcx,Bx:BuilderMethods<'a,'tcx>>(bx:&mut Bx,fx:&mut//let _=(); +FunctionCx<'a,'tcx,Bx>,memory_locals:&BitSet,)->Vec>{3;let mir=fx.mir;3;;let mut idx=0;;;let mut llarg_idx=fx.fn_abi.ret. +is_indirect()as usize;3;3;let mut num_untupled=None;3;;let args=mir.args_iter(). +enumerate().map(|(arg_index,local)|{3;let arg_decl=&mir.local_decls[local];;;let +arg_ty=fx.monomorphize(arg_decl.ty);();if Some(local)==mir.spread_arg{3;let ty:: +Tuple(tupled_arg_tys)=arg_ty.kind()else{;bug!("spread argument isn't a tuple?!") +;;};;;let layout=bx.layout_of(arg_ty);if layout.is_unsized(){span_bug!(arg_decl. +source_info.span,"\"rust-call\" ABI does not support unsized params",);();}3;let +place=PlaceRef::alloca(bx,layout);;for i in 0..tupled_arg_tys.len(){let arg=&fx. +fn_abi.args[idx];3;3;idx+=1;3;if let PassMode::Cast{pad_i32:true,..}=arg.mode{3; +llarg_idx+=1;;};let pr_field=place.project_field(bx,i);;bx.store_fn_arg(arg,&mut +llarg_idx,pr_field);;}assert_eq!(None,num_untupled.replace(tupled_arg_tys.len()) +,"Replaced existing num_tupled");;;return LocalRef::Place(place);;}if fx.fn_abi. +c_variadic&&arg_index==fx.fn_abi.args.len(){;let va_list=PlaceRef::alloca(bx,bx. +layout_of(arg_ty));;bx.va_start(va_list.llval);return LocalRef::Place(va_list);} +let arg=&fx.fn_abi.args[idx];;idx+=1;if let PassMode::Cast{pad_i32:true,..}=arg. +mode{3;llarg_idx+=1;;}if!memory_locals.contains(local){;let local=|op|LocalRef:: +Operand(op);({});match arg.mode{PassMode::Ignore=>{{;};return local(OperandRef:: +zero_sized(arg.layout));;}PassMode::Direct(_)=>{let llarg=bx.get_param(llarg_idx +);;llarg_idx+=1;return local(OperandRef::from_immediate_or_packed_pair(bx,llarg, +arg.layout,));{;};}PassMode::Pair(..)=>{();let(a,b)=(bx.get_param(llarg_idx),bx. +get_param(llarg_idx+1));;llarg_idx+=2;return local(OperandRef{val:OperandValue:: +Pair(a,b),layout:arg.layout,});;}_=>{}}}match arg.mode{PassMode::Indirect{attrs, +meta_attrs:None,on_stack:_}=>{if let Some(pointee_align)=attrs.pointee_align&&// +pointee_align{{();};let +llarg=bx.get_param(llarg_idx);;llarg_idx+=1;let llextra=bx.get_param(llarg_idx); +llarg_idx+=1;;;let indirect_operand=OperandValue::Pair(llarg,llextra);;;let tmp= +PlaceRef::alloca_unsized_indirect(bx,arg.layout);;indirect_operand.store(bx,tmp) +;;LocalRef::UnsizedPlace(tmp)}_=>{;let tmp=PlaceRef::alloca(bx,arg.layout);;;bx. +store_fn_arg(arg,&mut llarg_idx,tmp);;LocalRef::Place(tmp)}}}).collect::> +();3;if fx.instance.def.requires_caller_location(bx.tcx()){3;let mir_args=if let +Some(num_untupled)=num_untupled{args.len()-1+num_untupled}else{args.len()};();3; +assert_eq!(fx.fn_abi.args.len(),mir_args+1,//((),());let _=();let _=();let _=(); +"#[track_caller] instance {:?} must have 1 more argument in their ABI than in their MIR" +,fx.instance);;;let arg=fx.fn_abi.args.last().unwrap();match arg.mode{PassMode:: +Direct(_)=>(()) ,_=>bug!("caller location must be PassMode::Direct, found {:?}", +arg.mode),}();fx.caller_location=Some(OperandRef{val:OperandValue::Immediate(bx. +get_param(llarg_idx)),layout:arg.layout,});*&*&();((),());((),());((),());}args} diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 932926976b58d..24ec396337de4 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -1,573 +1,162 @@ -use super::place::PlaceRef; -use super::{FunctionCx, LocalRef}; - -use crate::base; -use crate::size_of_val; -use crate::traits::*; -use crate::MemFlags; - -use rustc_middle::mir::interpret::{alloc_range, Pointer, Scalar}; -use rustc_middle::mir::{self, ConstValue}; -use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; -use rustc_middle::ty::Ty; -use rustc_target::abi::{self, Abi, Align, Size}; - -use std::fmt; - -/// The representation of a Rust value. The enum variant is in fact -/// uniquely determined by the value's type, but is kept as a -/// safety check. -#[derive(Copy, Clone, Debug)] -pub enum OperandValue { - /// A reference to the actual operand. The data is guaranteed - /// to be valid for the operand's lifetime. - /// The second value, if any, is the extra data (vtable or length) - /// which indicates that it refers to an unsized rvalue. - /// - /// An `OperandValue` has this variant for types which are neither - /// `Immediate` nor `Pair`s. The backend value in this variant must be a - /// pointer to the *non*-immediate backend type. That pointee type is the - /// one returned by [`LayoutTypeMethods::backend_type`]. - Ref(V, Option, Align), - /// A single LLVM immediate value. - /// - /// An `OperandValue` *must* be this variant for any type for which - /// [`LayoutTypeMethods::is_backend_immediate`] returns `true`. - /// The backend value in this variant must be the *immediate* backend type, - /// as returned by [`LayoutTypeMethods::immediate_backend_type`]. - Immediate(V), - /// A pair of immediate LLVM values. Used by fat pointers too. - /// - /// An `OperandValue` *must* be this variant for any type for which - /// [`LayoutTypeMethods::is_backend_scalar_pair`] returns `true`. - /// The backend values in this variant must be the *immediate* backend types, - /// as returned by [`LayoutTypeMethods::scalar_pair_element_backend_type`] - /// with `immediate: true`. - Pair(V, V), - /// A value taking no bytes, and which therefore needs no LLVM value at all. - /// - /// If you ever need a `V` to pass to something, get a fresh poison value - /// from [`ConstMethods::const_poison`]. - /// - /// An `OperandValue` *must* be this variant for any type for which - /// `is_zst` on its `Layout` returns `true`. Note however that - /// these values can still require alignment. - ZeroSized, -} - -/// An `OperandRef` is an "SSA" reference to a Rust value, along with -/// its type. -/// -/// NOTE: unless you know a value's type exactly, you should not -/// generate LLVM opcodes acting on it and instead act via methods, -/// to avoid nasty edge cases. In particular, using `Builder::store` -/// directly is sure to cause problems -- use `OperandRef::store` -/// instead. -#[derive(Copy, Clone)] -pub struct OperandRef<'tcx, V> { - /// The value. - pub val: OperandValue, - - /// The layout of value, based on its Rust type. - pub layout: TyAndLayout<'tcx>, -} - -impl fmt::Debug for OperandRef<'_, V> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "OperandRef({:?} @ {:?})", self.val, self.layout) - } -} - -impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { - pub fn zero_sized(layout: TyAndLayout<'tcx>) -> OperandRef<'tcx, V> { - assert!(layout.is_zst()); - OperandRef { val: OperandValue::ZeroSized, layout } - } - - pub fn from_const>( - bx: &mut Bx, - val: mir::ConstValue<'tcx>, - ty: Ty<'tcx>, - ) -> Self { - let layout = bx.layout_of(ty); - - let val = match val { - ConstValue::Scalar(x) => { - let Abi::Scalar(scalar) = layout.abi else { - bug!("from_const: invalid ByVal layout: {:#?}", layout); - }; - let llval = bx.scalar_to_backend(x, scalar, bx.immediate_backend_type(layout)); - OperandValue::Immediate(llval) - } - ConstValue::ZeroSized => return OperandRef::zero_sized(layout), - ConstValue::Slice { data, meta } => { - let Abi::ScalarPair(a_scalar, _) = layout.abi else { - bug!("from_const: invalid ScalarPair layout: {:#?}", layout); - }; - let a = Scalar::from_pointer( - Pointer::new(bx.tcx().reserve_and_set_memory_alloc(data).into(), Size::ZERO), - &bx.tcx(), - ); - let a_llval = bx.scalar_to_backend( - a, - a_scalar, - bx.scalar_pair_element_backend_type(layout, 0, true), - ); - let b_llval = bx.const_usize(meta); - OperandValue::Pair(a_llval, b_llval) - } - ConstValue::Indirect { alloc_id, offset } => { - let alloc = bx.tcx().global_alloc(alloc_id).unwrap_memory(); - return Self::from_const_alloc(bx, layout, alloc, offset); - } - }; - - OperandRef { val, layout } - } - - fn from_const_alloc>( - bx: &mut Bx, - layout: TyAndLayout<'tcx>, - alloc: rustc_middle::mir::interpret::ConstAllocation<'tcx>, - offset: Size, - ) -> Self { - let alloc_align = alloc.inner().align; - assert!(alloc_align >= layout.align.abi); - - let read_scalar = |start, size, s: abi::Scalar, ty| { - match alloc.0.read_scalar( - bx, - alloc_range(start, size), - /*read_provenance*/ matches!(s.primitive(), abi::Pointer(_)), - ) { - Ok(val) => bx.scalar_to_backend(val, s, ty), - Err(_) => bx.const_poison(ty), - } - }; - - // It may seem like all types with `Scalar` or `ScalarPair` ABI are fair game at this point. - // However, `MaybeUninit` is considered a `Scalar` as far as its layout is concerned -- - // and yet cannot be represented by an interpreter `Scalar`, since we have to handle the - // case where some of the bytes are initialized and others are not. So, we need an extra - // check that walks over the type of `mplace` to make sure it is truly correct to treat this - // like a `Scalar` (or `ScalarPair`). - match layout.abi { - Abi::Scalar(s @ abi::Scalar::Initialized { .. }) => { - let size = s.size(bx); - assert_eq!(size, layout.size, "abi::Scalar size does not match layout size"); - let val = read_scalar(offset, size, s, bx.immediate_backend_type(layout)); - OperandRef { val: OperandValue::Immediate(val), layout } - } - Abi::ScalarPair( - a @ abi::Scalar::Initialized { .. }, - b @ abi::Scalar::Initialized { .. }, - ) => { - let (a_size, b_size) = (a.size(bx), b.size(bx)); - let b_offset = (offset + a_size).align_to(b.align(bx).abi); - assert!(b_offset.bytes() > 0); - let a_val = read_scalar( - offset, - a_size, - a, - bx.scalar_pair_element_backend_type(layout, 0, true), - ); - let b_val = read_scalar( - b_offset, - b_size, - b, - bx.scalar_pair_element_backend_type(layout, 1, true), - ); - OperandRef { val: OperandValue::Pair(a_val, b_val), layout } - } - _ if layout.is_zst() => OperandRef::zero_sized(layout), - _ => { - // Neither a scalar nor scalar pair. Load from a place - // FIXME: should we cache `const_data_from_alloc` to avoid repeating this for the - // same `ConstAllocation`? - let init = bx.const_data_from_alloc(alloc); - let base_addr = bx.static_addr_of(init, alloc_align, None); - - let llval = bx.const_ptr_byte_offset(base_addr, offset); - bx.load_operand(PlaceRef::new_sized(llval, layout)) - } - } - } - - /// Asserts that this operand refers to a scalar and returns - /// a reference to its value. - pub fn immediate(self) -> V { - match self.val { - OperandValue::Immediate(s) => s, - _ => bug!("not immediate: {:?}", self), - } - } - - pub fn deref>(self, cx: &Cx) -> PlaceRef<'tcx, V> { - if self.layout.ty.is_box() { - // Derefer should have removed all Box derefs - bug!("dereferencing {:?} in codegen", self.layout.ty); - } - - let projected_ty = self - .layout - .ty - .builtin_deref(true) - .unwrap_or_else(|| bug!("deref of non-pointer {:?}", self)) - .ty; - - let (llptr, llextra) = match self.val { - OperandValue::Immediate(llptr) => (llptr, None), - OperandValue::Pair(llptr, llextra) => (llptr, Some(llextra)), - OperandValue::Ref(..) => bug!("Deref of by-Ref operand {:?}", self), - OperandValue::ZeroSized => bug!("Deref of ZST operand {:?}", self), - }; - let layout = cx.layout_of(projected_ty); - PlaceRef { llval: llptr, llextra, layout, align: layout.align.abi } - } - - /// If this operand is a `Pair`, we return an aggregate with the two values. - /// For other cases, see `immediate`. - pub fn immediate_or_packed_pair>( - self, - bx: &mut Bx, - ) -> V { - if let OperandValue::Pair(a, b) = self.val { - let llty = bx.cx().immediate_backend_type(self.layout); - debug!("Operand::immediate_or_packed_pair: packing {:?} into {:?}", self, llty); - // Reconstruct the immediate aggregate. - let mut llpair = bx.cx().const_poison(llty); - llpair = bx.insert_value(llpair, a, 0); - llpair = bx.insert_value(llpair, b, 1); - llpair - } else { - self.immediate() - } - } - - /// If the type is a pair, we return a `Pair`, otherwise, an `Immediate`. - pub fn from_immediate_or_packed_pair>( - bx: &mut Bx, - llval: V, - layout: TyAndLayout<'tcx>, - ) -> Self { - let val = if let Abi::ScalarPair(..) = layout.abi { - debug!("Operand::from_immediate_or_packed_pair: unpacking {:?} @ {:?}", llval, layout); - - // Deconstruct the immediate aggregate. - let a_llval = bx.extract_value(llval, 0); - let b_llval = bx.extract_value(llval, 1); - OperandValue::Pair(a_llval, b_llval) - } else { - OperandValue::Immediate(llval) - }; - OperandRef { val, layout } - } - - pub fn extract_field>( - &self, - bx: &mut Bx, - i: usize, - ) -> Self { - let field = self.layout.field(bx.cx(), i); - let offset = self.layout.fields.offset(i); - - let mut val = match (self.val, self.layout.abi) { - // If the field is ZST, it has no data. - _ if field.is_zst() => OperandValue::ZeroSized, - - // Newtype of a scalar, scalar pair or vector. - (OperandValue::Immediate(_) | OperandValue::Pair(..), _) - if field.size == self.layout.size => - { - assert_eq!(offset.bytes(), 0); - self.val - } - - // Extract a scalar component from a pair. - (OperandValue::Pair(a_llval, b_llval), Abi::ScalarPair(a, b)) => { - if offset.bytes() == 0 { - assert_eq!(field.size, a.size(bx.cx())); - OperandValue::Immediate(a_llval) - } else { - assert_eq!(offset, a.size(bx.cx()).align_to(b.align(bx.cx()).abi)); - assert_eq!(field.size, b.size(bx.cx())); - OperandValue::Immediate(b_llval) - } - } - - // `#[repr(simd)]` types are also immediate. - (OperandValue::Immediate(llval), Abi::Vector { .. }) => { - OperandValue::Immediate(bx.extract_element(llval, bx.cx().const_usize(i as u64))) - } - - _ => bug!("OperandRef::extract_field({:?}): not applicable", self), - }; - - match (&mut val, field.abi) { - (OperandValue::ZeroSized, _) => {} - ( - OperandValue::Immediate(llval), - Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. }, - ) => { - // Bools in union fields needs to be truncated. - *llval = bx.to_immediate(*llval, field); - } - (OperandValue::Pair(a, b), Abi::ScalarPair(a_abi, b_abi)) => { - // Bools in union fields needs to be truncated. - *a = bx.to_immediate_scalar(*a, a_abi); - *b = bx.to_immediate_scalar(*b, b_abi); - } - // Newtype vector of array, e.g. #[repr(simd)] struct S([i32; 4]); - (OperandValue::Immediate(llval), Abi::Aggregate { sized: true }) => { - assert!(matches!(self.layout.abi, Abi::Vector { .. })); - - let llfield_ty = bx.cx().backend_type(field); - - // Can't bitcast an aggregate, so round trip through memory. - let llptr = bx.alloca(llfield_ty, field.align.abi); - bx.store(*llval, llptr, field.align.abi); - *llval = bx.load(llfield_ty, llptr, field.align.abi); - } - (OperandValue::Immediate(_), Abi::Uninhabited | Abi::Aggregate { sized: false }) => { - bug!() - } - (OperandValue::Pair(..), _) => bug!(), - (OperandValue::Ref(..), _) => bug!(), - } - - OperandRef { val, layout: field } - } -} - -impl<'a, 'tcx, V: CodegenObject> OperandValue { - /// Returns an `OperandValue` that's generally UB to use in any way. - /// - /// Depending on the `layout`, returns `ZeroSized` for ZSTs, an `Immediate` or - /// `Pair` containing poison value(s), or a `Ref` containing a poison pointer. - /// - /// Supports sized types only. - pub fn poison>( - bx: &mut Bx, - layout: TyAndLayout<'tcx>, - ) -> OperandValue { - assert!(layout.is_sized()); - if layout.is_zst() { - OperandValue::ZeroSized - } else if bx.cx().is_backend_immediate(layout) { - let ibty = bx.cx().immediate_backend_type(layout); - OperandValue::Immediate(bx.const_poison(ibty)) - } else if bx.cx().is_backend_scalar_pair(layout) { - let ibty0 = bx.cx().scalar_pair_element_backend_type(layout, 0, true); - let ibty1 = bx.cx().scalar_pair_element_backend_type(layout, 1, true); - OperandValue::Pair(bx.const_poison(ibty0), bx.const_poison(ibty1)) - } else { - let ptr = bx.cx().type_ptr(); - OperandValue::Ref(bx.const_poison(ptr), None, layout.align.abi) - } - } - - pub fn store>( - self, - bx: &mut Bx, - dest: PlaceRef<'tcx, V>, - ) { - self.store_with_flags(bx, dest, MemFlags::empty()); - } - - pub fn volatile_store>( - self, - bx: &mut Bx, - dest: PlaceRef<'tcx, V>, - ) { - self.store_with_flags(bx, dest, MemFlags::VOLATILE); - } - - pub fn unaligned_volatile_store>( - self, - bx: &mut Bx, - dest: PlaceRef<'tcx, V>, - ) { - self.store_with_flags(bx, dest, MemFlags::VOLATILE | MemFlags::UNALIGNED); - } - - pub fn nontemporal_store>( - self, - bx: &mut Bx, - dest: PlaceRef<'tcx, V>, - ) { - self.store_with_flags(bx, dest, MemFlags::NONTEMPORAL); - } - - fn store_with_flags>( - self, - bx: &mut Bx, - dest: PlaceRef<'tcx, V>, - flags: MemFlags, - ) { - debug!("OperandRef::store: operand={:?}, dest={:?}", self, dest); - match self { - OperandValue::ZeroSized => { - // Avoid generating stores of zero-sized values, because the only way to have a zero-sized - // value is through `undef`/`poison`, and the store itself is useless. - } - OperandValue::Ref(r, None, source_align) => { - assert!(dest.layout.is_sized(), "cannot directly store unsized values"); - if flags.contains(MemFlags::NONTEMPORAL) { - // HACK(nox): This is inefficient but there is no nontemporal memcpy. - let ty = bx.backend_type(dest.layout); - let val = bx.load(ty, r, source_align); - bx.store_with_flags(val, dest.llval, dest.align, flags); - return; - } - base::memcpy_ty(bx, dest.llval, dest.align, r, source_align, dest.layout, flags) - } - OperandValue::Ref(_, Some(_), _) => { - bug!("cannot directly store unsized values"); - } - OperandValue::Immediate(s) => { - let val = bx.from_immediate(s); - bx.store_with_flags(val, dest.llval, dest.align, flags); - } - OperandValue::Pair(a, b) => { - let Abi::ScalarPair(a_scalar, b_scalar) = dest.layout.abi else { - bug!("store_with_flags: invalid ScalarPair layout: {:#?}", dest.layout); - }; - let b_offset = a_scalar.size(bx).align_to(b_scalar.align(bx).abi); - - let val = bx.from_immediate(a); - let align = dest.align; - bx.store_with_flags(val, dest.llval, align, flags); - - let llptr = bx.inbounds_ptradd(dest.llval, bx.const_usize(b_offset.bytes())); - let val = bx.from_immediate(b); - let align = dest.align.restrict_for_offset(b_offset); - bx.store_with_flags(val, llptr, align, flags); - } - } - } - - pub fn store_unsized>( - self, - bx: &mut Bx, - indirect_dest: PlaceRef<'tcx, V>, - ) { - debug!("OperandRef::store_unsized: operand={:?}, indirect_dest={:?}", self, indirect_dest); - // `indirect_dest` must have `*mut T` type. We extract `T` out of it. - let unsized_ty = indirect_dest - .layout - .ty - .builtin_deref(true) - .unwrap_or_else(|| bug!("indirect_dest has non-pointer type: {:?}", indirect_dest)) - .ty; - - let OperandValue::Ref(llptr, Some(llextra), _) = self else { - bug!("store_unsized called with a sized value (or with an extern type)") - }; - - // Allocate an appropriate region on the stack, and copy the value into it. Since alloca - // doesn't support dynamic alignment, we allocate an extra align - 1 bytes, and align the - // pointer manually. - let (size, align) = size_of_val::size_and_align_of_dst(bx, unsized_ty, Some(llextra)); - let one = bx.const_usize(1); - let align_minus_1 = bx.sub(align, one); - let size_extra = bx.add(size, align_minus_1); - let min_align = Align::ONE; - let alloca = bx.byte_array_alloca(size_extra, min_align); - let address = bx.ptrtoint(alloca, bx.type_isize()); - let neg_address = bx.neg(address); - let offset = bx.and(neg_address, align_minus_1); - let dst = bx.inbounds_ptradd(alloca, offset); - bx.memcpy(dst, min_align, llptr, min_align, size, MemFlags::empty()); - - // Store the allocated region and the extra to the indirect place. - let indirect_operand = OperandValue::Pair(dst, llextra); - indirect_operand.store(bx, indirect_dest); - } -} - -impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { - fn maybe_codegen_consume_direct( - &mut self, - bx: &mut Bx, - place_ref: mir::PlaceRef<'tcx>, - ) -> Option> { - debug!("maybe_codegen_consume_direct(place_ref={:?})", place_ref); - - match self.locals[place_ref.local] { - LocalRef::Operand(mut o) => { - // Moves out of scalar and scalar pair fields are trivial. - for elem in place_ref.projection.iter() { - match elem { - mir::ProjectionElem::Field(ref f, _) => { - o = o.extract_field(bx, f.index()); - } - mir::ProjectionElem::Index(_) - | mir::ProjectionElem::ConstantIndex { .. } => { - // ZSTs don't require any actual memory access. - // FIXME(eddyb) deduplicate this with the identical - // checks in `codegen_consume` and `extract_field`. - let elem = o.layout.field(bx.cx(), 0); - if elem.is_zst() { - o = OperandRef::zero_sized(elem); - } else { - return None; - } - } - _ => return None, - } - } - - Some(o) - } - LocalRef::PendingOperand => { - bug!("use of {:?} before def", place_ref); - } - LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => { - // watch out for locals that do not have an - // alloca; they are handled somewhat differently - None - } - } - } - - pub fn codegen_consume( - &mut self, - bx: &mut Bx, - place_ref: mir::PlaceRef<'tcx>, - ) -> OperandRef<'tcx, Bx::Value> { - debug!("codegen_consume(place_ref={:?})", place_ref); - - let ty = self.monomorphized_place_ty(place_ref); - let layout = bx.cx().layout_of(ty); - - // ZSTs don't require any actual memory access. - if layout.is_zst() { - return OperandRef::zero_sized(layout); - } - - if let Some(o) = self.maybe_codegen_consume_direct(bx, place_ref) { - return o; - } - - // for most places, to consume them we just load them - // out from their home - let place = self.codegen_place(bx, place_ref); - bx.load_operand(place) - } - - pub fn codegen_operand( - &mut self, - bx: &mut Bx, - operand: &mir::Operand<'tcx>, - ) -> OperandRef<'tcx, Bx::Value> { - debug!("codegen_operand(operand={:?})", operand); - - match *operand { - mir::Operand::Copy(ref place) | mir::Operand::Move(ref place) => { - self.codegen_consume(bx, place.as_ref()) - } - - mir::Operand::Constant(ref constant) => self.eval_mir_constant_to_operand(bx, constant), - } - } -} +use super::place::PlaceRef;use super:: {FunctionCx,LocalRef};use crate::base;use +crate::size_of_val;use crate::traits::*;use crate::MemFlags;use rustc_middle::// +mir::interpret::{alloc_range,Pointer,Scalar};use rustc_middle::mir::{self,//{;}; +ConstValue};use rustc_middle::ty::layout::{LayoutOf,TyAndLayout};use//if true{}; +rustc_middle::ty::Ty;use rustc_target::abi::{self ,Abi,Align,Size};use std::fmt; +#[derive(Copy,Clone,Debug)]pub enum OperandValue{Ref(V,Option,Align),//(); +Immediate(V),Pair(V,V),ZeroSized,}#[derive(Copy,Clone)]pub struct OperandRef{pub val:OperandValue,pub layout:TyAndLayout<'tcx>,}implfmt::Debug for OperandRef<'_,V>{fn fmt(&self,f:&mut fmt:://*&*&(); +Formatter<'_>)->fmt::Result{write!(f,"OperandRef({:?} @ {:?})",self.val,self.//; +layout)}}impl<'a,'tcx,V:CodegenObject>OperandRef<'tcx,V>{pub fn zero_sized(//(); +layout:TyAndLayout<'tcx>)->OperandRef<'tcx,V>{({});assert!(layout.is_zst());{;}; +OperandRef{val:OperandValue::ZeroSized,layout}}pub fn from_const>(bx:&mut Bx,val:mir::ConstValue<'tcx>,ty:Ty,)->Self{;let layout=bx.layout_of(ty);let val=match val{ConstValue::Scalar( +x)=>{*&*&();((),());let Abi::Scalar(scalar)=layout.abi else{*&*&();((),());bug!( +"from_const: invalid ByVal layout: {:#?}",layout);({});};({});({});let llval=bx. +scalar_to_backend(x,scalar,bx.immediate_backend_type(layout));{;};OperandValue:: +Immediate(llval)}ConstValue::ZeroSized=>(return OperandRef::zero_sized(layout)), +ConstValue::Slice{data,meta}=>{;let Abi::ScalarPair(a_scalar,_)=layout.abi else{ +bug!("from_const: invalid ScalarPair layout: {:#?}",layout);3;};;;let a=Scalar:: +from_pointer(Pointer::new((bx.tcx( ).reserve_and_set_memory_alloc(data).into()), +Size::ZERO),&bx.tcx(),);({});{;};let a_llval=bx.scalar_to_backend(a,a_scalar,bx. +scalar_pair_element_backend_type(layout,0,true),);3;;let b_llval=bx.const_usize( +meta);;OperandValue::Pair(a_llval,b_llval)}ConstValue::Indirect{alloc_id,offset} +=>{3;let alloc=bx.tcx().global_alloc(alloc_id).unwrap_memory();3;3;return Self:: +from_const_alloc(bx,layout,alloc,offset);{();};}};({});OperandRef{val,layout}}fn +from_const_alloc>(bx:&mut Bx,layout://*&*&(); +TyAndLayout<'tcx>,alloc:rustc_middle::mir::interpret::ConstAllocation<'tcx>,//3; +offset:Size,)->Self{;let alloc_align=alloc.inner().align;;;assert!(alloc_align>= +layout.align.abi);;;let read_scalar=|start,size,s:abi::Scalar,ty|{match alloc.0. +read_scalar(bx,alloc_range(start,size),matches! (s.primitive(),abi::Pointer(_)), +){Ok(val)=>bx.scalar_to_backend(val,s,ty),Err(_)=>bx.const_poison(ty),}};3;match +layout.abi{Abi::Scalar(s@abi::Scalar::Initialized{..})=>{;let size=s.size(bx);;; +assert_eq!(size,layout.size,"abi::Scalar size does not match layout size");;;let +val=read_scalar(offset,size,s,bx.immediate_backend_type(layout));;OperandRef{val +:(((((OperandValue::Immediate(val)))))),layout} }Abi::ScalarPair(a@abi::Scalar:: +Initialized{..},b@abi::Scalar::Initialized{..},)=>{3;let(a_size,b_size)=(a.size( +bx),b.size(bx));;let b_offset=(offset+a_size).align_to(b.align(bx).abi);assert!( +b_offset.bytes()>0);if true{};let _=();let a_val=read_scalar(offset,a_size,a,bx. +scalar_pair_element_backend_type(layout,0,true),);{;};{;};let b_val=read_scalar( +b_offset,b_size,b,bx.scalar_pair_element_backend_type(layout,1,true),);let _=(); +OperandRef{val:(OperandValue::Pair(a_val,b_val)),layout }}_ if layout.is_zst()=> +OperandRef::zero_sized(layout),_=>{;let init=bx.const_data_from_alloc(alloc);let +base_addr=bx.static_addr_of(init,alloc_align,None);((),());((),());let llval=bx. +const_ptr_byte_offset(base_addr,offset);{;};bx.load_operand(PlaceRef::new_sized( +llval,layout))}}}pub fn immediate(self)->V{match self.val{OperandValue:://{();}; +Immediate(s)=>s,_=>(((((bug!("not immediate: {:?}",self)))))),}}pub fn deref>(self,cx:&Cx)->PlaceRef<'tcx,V>{if self.layout.ty.//{;}; +is_box(){;bug!("dereferencing {:?} in codegen",self.layout.ty);}let projected_ty +=((((((self.layout.ty.builtin_deref((((((true)))))))))))).unwrap_or_else(||bug!( +"deref of non-pointer {:?}",self)).ty;{;};{;};let(llptr,llextra)=match self.val{ +OperandValue::Immediate(llptr)=>((llptr,None)),OperandValue::Pair(llptr,llextra) +=>((((((((llptr,(((((((Some(llextra)))))))))))))))),OperandValue::Ref(..)=>bug!( +"Deref of by-Ref operand {:?}",self),OperandValue::ZeroSized=>bug!(//let _=||(); +"Deref of ZST operand {:?}",self),};3;3;let layout=cx.layout_of(projected_ty);3; +PlaceRef{llval:llptr,llextra,layout,align:layout.align.abi}}pub fn//loop{break}; +immediate_or_packed_pair>(self,bx:&mut Bx,)// +->V{if let OperandValue::Pair(a,b)=self.val{let _=();if true{};let llty=bx.cx(). +immediate_backend_type(self.layout);let _=();if true{};let _=();let _=();debug!( +"Operand::immediate_or_packed_pair: packing {:?} into {:?}",self,llty);;;let mut +llpair=bx.cx().const_poison(llty);;llpair=bx.insert_value(llpair,a,0);llpair=bx. +insert_value(llpair,b,1);let _=();if true{};llpair}else{self.immediate()}}pub fn +from_immediate_or_packed_pair>(bx:&mut Bx,//; +llval:V,layout:TyAndLayout<'tcx>,)->Self{{;};let val=if let Abi::ScalarPair(..)= +layout.abi{*&*&();((),());((),());((),());*&*&();((),());((),());((),());debug!( +"Operand::from_immediate_or_packed_pair: unpacking {:?} @ {:?}",llval,layout);;; +let a_llval=bx.extract_value(llval,0);3;;let b_llval=bx.extract_value(llval,1);; +OperandValue::Pair(a_llval,b_llval)}else{OperandValue::Immediate(llval)};*&*&(); +OperandRef{val,layout}}pub fn extract_field > +(&self,bx:&mut Bx,i:usize,)->Self{3;let field=self.layout.field(bx.cx(),i);;;let +offset=self.layout.fields.offset(i);;let mut val=match(self.val,self.layout.abi) +{_ if (((field.is_zst())))=>OperandValue::ZeroSized,(OperandValue::Immediate(_)| +OperandValue::Pair(..),_)if field.size==self.layout.size=>{();assert_eq!(offset. +bytes(),0);3;self.val}(OperandValue::Pair(a_llval,b_llval),Abi::ScalarPair(a,b)) +=>{if offset.bytes()==0{3;assert_eq!(field.size,a.size(bx.cx()));;OperandValue:: +Immediate(a_llval)}else{3;assert_eq!(offset,a.size(bx.cx()).align_to(b.align(bx. +cx()).abi));3;3;assert_eq!(field.size,b.size(bx.cx()));;OperandValue::Immediate( +b_llval)}}(OperandValue::Immediate(llval),Abi::Vector{..})=>{OperandValue:://(); +Immediate((bx.extract_element(llval,(bx.cx().const_usize( i as u64)))))}_=>bug!( +"OperandRef::extract_field({:?}): not applicable",self),};;match(&mut val,field. +abi){(OperandValue::ZeroSized,_)=> {}(OperandValue::Immediate(llval),Abi::Scalar +(_)|Abi::ScalarPair(..)|Abi::Vector{..},)=>{;*llval=bx.to_immediate(*llval,field +);*&*&();}(OperandValue::Pair(a,b),Abi::ScalarPair(a_abi,b_abi))=>{*&*&();*a=bx. +to_immediate_scalar(*a,a_abi);{;};{;};*b=bx.to_immediate_scalar(*b,b_abi);{;};}( +OperandValue::Immediate(llval),Abi::Aggregate{sized:true})=>{3;assert!(matches!( +self.layout.abi,Abi::Vector{..}));;;let llfield_ty=bx.cx().backend_type(field);; +let llptr=bx.alloca(llfield_ty,field.align.abi);3;3;bx.store(*llval,llptr,field. +align.abi);3;;*llval=bx.load(llfield_ty,llptr,field.align.abi);;}(OperandValue:: +Immediate(_),Abi::Uninhabited|Abi::Aggregate{sized :false})=>{(((((bug!())))))}( +OperandValue::Pair(..),_)=>bug!(),(OperandValue ::Ref(..),_)=>bug!(),}OperandRef +{val,layout:field}}}impl<'a,'tcx ,V:CodegenObject>OperandValue{pub fn poison< +Bx:BuilderMethods<'a,'tcx,Value=V>>(bx:&mut Bx,layout:TyAndLayout<'tcx>,)->//(); +OperandValue{3;assert!(layout.is_sized());3;if layout.is_zst(){OperandValue:: +ZeroSized}else if bx.cx().is_backend_immediate(layout){((),());let ibty=bx.cx(). +immediate_backend_type(layout);3;OperandValue::Immediate(bx.const_poison(ibty))} +else if bx.cx().is_backend_scalar_pair(layout){*&*&();((),());let ibty0=bx.cx(). +scalar_pair_element_backend_type(layout,0,true);*&*&();*&*&();let ibty1=bx.cx(). +scalar_pair_element_backend_type(layout,1,true);if true{};OperandValue::Pair(bx. +const_poison(ibty0),bx.const_poison(ibty1))}else{3;let ptr=bx.cx().type_ptr();3; +OperandValue::Ref(bx.const_poison(ptr),None,layout .align.abi)}}pub fn store>(self,bx:&mut Bx,dest:PlaceRef<'tcx,V>,){3;self. +store_with_flags(bx,dest,MemFlags::empty());if true{};}pub fn volatile_store>(self,bx:&mut Bx,dest:PlaceRef<'tcx,V>,){3;self. +store_with_flags(bx,dest,MemFlags::VOLATILE);3;}pub fn unaligned_volatile_store< +Bx:BuilderMethods<'a,'tcx,Value=V>>(self,bx:&mut Bx,dest:PlaceRef<'tcx,V>,){{;}; +self.store_with_flags(bx,dest,MemFlags::VOLATILE|MemFlags::UNALIGNED);();}pub fn +nontemporal_store>(self,bx:&mut Bx,dest://(); +PlaceRef<'tcx,V>,){();self.store_with_flags(bx,dest,MemFlags::NONTEMPORAL);3;}fn +store_with_flags>(self,bx:&mut Bx,dest://{;}; +PlaceRef<'tcx,V>,flags:MemFlags,){let _=();if true{};if true{};if true{};debug!( +"OperandRef::store: operand={:?}, dest={:?}",self,dest);;match self{OperandValue +::ZeroSized=>{}OperandValue::Ref(r,None,source_align)=>{{;};assert!(dest.layout. +is_sized(),"cannot directly store unsized values");;if flags.contains(MemFlags:: +NONTEMPORAL){{;};let ty=bx.backend_type(dest.layout);();();let val=bx.load(ty,r, +source_align);;bx.store_with_flags(val,dest.llval,dest.align,flags);return;}base +::memcpy_ty(bx,dest.llval,dest.align,r,source_align,dest.layout,flags)}//*&*&(); +OperandValue::Ref(_,Some(_),_)=>{;bug!("cannot directly store unsized values");} +OperandValue::Immediate(s)=>{;let val=bx.from_immediate(s);;bx.store_with_flags( +val,dest.llval,dest.align,flags);;}OperandValue::Pair(a,b)=>{let Abi::ScalarPair +(a_scalar,b_scalar)=dest.layout.abi else{((),());let _=();((),());let _=();bug!( +"store_with_flags: invalid ScalarPair layout: {:#?}",dest.layout);();};();();let +b_offset=a_scalar.size(bx).align_to(b_scalar.align(bx).abi);({});{;};let val=bx. +from_immediate(a);;let align=dest.align;bx.store_with_flags(val,dest.llval,align +,flags);;let llptr=bx.inbounds_ptradd(dest.llval,bx.const_usize(b_offset.bytes() +));3;3;let val=bx.from_immediate(b);3;;let align=dest.align.restrict_for_offset( +b_offset);;bx.store_with_flags(val,llptr,align,flags);}}}pub fn store_unsized>(self, bx:&mut Bx,indirect_dest:PlaceRef<'tcx,V +>,){3;debug!("OperandRef::store_unsized: operand={:?}, indirect_dest={:?}",self, +indirect_dest);();();let unsized_ty=indirect_dest.layout.ty.builtin_deref(true). +unwrap_or_else(||bug! ("indirect_dest has non-pointer type: {:?}",indirect_dest) +).ty;((),());*&*&();let OperandValue::Ref(llptr,Some(llextra),_)=self else{bug!( +"store_unsized called with a sized value (or with an extern type)")};;;let(size, +align)=size_of_val::size_and_align_of_dst(bx,unsized_ty,Some(llextra));;let one= +bx.const_usize(1);;;let align_minus_1=bx.sub(align,one);;;let size_extra=bx.add( +size,align_minus_1);;;let min_align=Align::ONE;;let alloca=bx.byte_array_alloca( +size_extra,min_align);3;3;let address=bx.ptrtoint(alloca,bx.type_isize());3;;let +neg_address=bx.neg(address);;;let offset=bx.and(neg_address,align_minus_1);;;let +dst=bx.inbounds_ptradd(alloca,offset);;;bx.memcpy(dst,min_align,llptr,min_align, +size,MemFlags::empty());;;let indirect_operand=OperandValue::Pair(dst,llextra);; +indirect_operand.store(bx,indirect_dest);();}}impl<'a,'tcx,Bx:BuilderMethods<'a, +'tcx>>FunctionCx<'a,'tcx,Bx>{fn maybe_codegen_consume_direct(&mut self,bx:&mut// +Bx,place_ref:mir::PlaceRef<'tcx>,)->Option>{3;debug!( +"maybe_codegen_consume_direct(place_ref={:?})",place_ref);{;};match self.locals[ +place_ref.local]{LocalRef::Operand(mut o)=>{for elem in place_ref.projection.//; +iter(){match elem{mir::ProjectionElem::Field(ref f,_)=>{;o=o.extract_field(bx,f. +index());3;}mir::ProjectionElem::Index(_)|mir::ProjectionElem::ConstantIndex{..} +=>{;let elem=o.layout.field(bx.cx(),0);if elem.is_zst(){o=OperandRef::zero_sized +(elem);;}else{return None;}}_=>return None,}}Some(o)}LocalRef::PendingOperand=>{ +bug!("use of {:?} before def",place_ref);((),());}LocalRef::Place(..)|LocalRef:: +UnsizedPlace(..)=>{None}}}pub fn codegen_consume(&mut self,bx:&mut Bx,place_ref +:mir::PlaceRef<'tcx>,)->OperandRef<'tcx,Bx::Value>{let _=||();let _=||();debug!( +"codegen_consume(place_ref={:?})",place_ref);;let ty=self.monomorphized_place_ty +(place_ref);();3;let layout=bx.cx().layout_of(ty);3;if layout.is_zst(){3;return +OperandRef::zero_sized(layout);if let _=(){};if let _=(){};}if let Some(o)=self. +maybe_codegen_consume_direct(bx,place_ref){{;};return o;{;};}{;};let place=self. +codegen_place(bx,place_ref);3;bx.load_operand(place)}pub fn codegen_operand(&mut +self,bx:&mut Bx,operand:&mir::Operand<'tcx>,)->OperandRef<'tcx,Bx::Value>{;debug +!("codegen_operand(operand={:?})",operand);;match*operand{mir::Operand::Copy(ref +place)|mir::Operand::Move(ref place)=>{(self.codegen_consume(bx,place.as_ref())) +}mir::Operand::Constant(ref constant)=>self.eval_mir_constant_to_operand(bx,//3; +constant),}}}//((),());((),());((),());((),());((),());((),());((),());let _=(); diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 1ec6c351e2537..1c123072fa971 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -1,524 +1,137 @@ -use super::operand::OperandValue; -use super::{FunctionCx, LocalRef}; - -use crate::common::IntPredicate; -use crate::size_of_val; -use crate::traits::*; - -use rustc_middle::mir; -use rustc_middle::mir::tcx::PlaceTy; -use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; -use rustc_middle::ty::{self, Ty}; -use rustc_target::abi::{Align, FieldsShape, Int, Pointer, TagEncoding}; -use rustc_target::abi::{VariantIdx, Variants}; - -#[derive(Copy, Clone, Debug)] -pub struct PlaceRef<'tcx, V> { - /// A pointer to the contents of the place. - pub llval: V, - - /// This place's extra data if it is unsized, or `None` if null. - pub llextra: Option, - - /// The monomorphized type of this place, including variant information. - pub layout: TyAndLayout<'tcx>, - - /// The alignment we know for this place. - pub align: Align, -} - -impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { - pub fn new_sized(llval: V, layout: TyAndLayout<'tcx>) -> PlaceRef<'tcx, V> { - assert!(layout.is_sized()); - PlaceRef { llval, llextra: None, layout, align: layout.align.abi } - } - - pub fn new_sized_aligned( - llval: V, - layout: TyAndLayout<'tcx>, - align: Align, - ) -> PlaceRef<'tcx, V> { - assert!(layout.is_sized()); - PlaceRef { llval, llextra: None, layout, align } - } - - // FIXME(eddyb) pass something else for the name so no work is done - // unless LLVM IR names are turned on (e.g. for `--emit=llvm-ir`). - pub fn alloca>( - bx: &mut Bx, - layout: TyAndLayout<'tcx>, - ) -> Self { - Self::alloca_aligned(bx, layout, layout.align.abi) - } - - pub fn alloca_aligned>( - bx: &mut Bx, - layout: TyAndLayout<'tcx>, - align: Align, - ) -> Self { - assert!(layout.is_sized(), "tried to statically allocate unsized place"); - let tmp = bx.alloca(bx.cx().backend_type(layout), align); - Self::new_sized_aligned(tmp, layout, align) - } - - /// Returns a place for an indirect reference to an unsized place. - // FIXME(eddyb) pass something else for the name so no work is done - // unless LLVM IR names are turned on (e.g. for `--emit=llvm-ir`). - pub fn alloca_unsized_indirect>( - bx: &mut Bx, - layout: TyAndLayout<'tcx>, - ) -> Self { - assert!(layout.is_unsized(), "tried to allocate indirect place for sized values"); - let ptr_ty = Ty::new_mut_ptr(bx.cx().tcx(), layout.ty); - let ptr_layout = bx.cx().layout_of(ptr_ty); - Self::alloca(bx, ptr_layout) - } - - pub fn len>(&self, cx: &Cx) -> V { - if let FieldsShape::Array { count, .. } = self.layout.fields { - if self.layout.is_unsized() { - assert_eq!(count, 0); - self.llextra.unwrap() - } else { - cx.const_usize(count) - } - } else { - bug!("unexpected layout `{:#?}` in PlaceRef::len", self.layout) - } - } -} - -impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { - /// Access a field, at a point when the value's case is known. - pub fn project_field>( - self, - bx: &mut Bx, - ix: usize, - ) -> Self { - let field = self.layout.field(bx.cx(), ix); - let offset = self.layout.fields.offset(ix); - let effective_field_align = self.align.restrict_for_offset(offset); - - // `simple` is called when we don't need to adjust the offset to - // the dynamic alignment of the field. - let mut simple = || { - let llval = if offset.bytes() == 0 { - self.llval - } else { - bx.inbounds_ptradd(self.llval, bx.const_usize(offset.bytes())) - }; - PlaceRef { - llval, - llextra: if bx.cx().type_has_metadata(field.ty) { self.llextra } else { None }, - layout: field, - align: effective_field_align, - } - }; - - // Simple cases, which don't need DST adjustment: - // * known alignment - sized types, `[T]`, `str` - // * offset 0 -- rounding up to alignment cannot change the offset - // Note that looking at `field.align` is incorrect since that is not necessarily equal - // to the dynamic alignment of the type. - match field.ty.kind() { - _ if field.is_sized() => return simple(), - ty::Slice(..) | ty::Str => return simple(), - _ if offset.bytes() == 0 => return simple(), - _ => {} - } - - // We need to get the pointer manually now. - // We do this by casting to a `*i8`, then offsetting it by the appropriate amount. - // We do this instead of, say, simply adjusting the pointer from the result of a GEP - // because the field may have an arbitrary alignment in the LLVM representation. - // - // To demonstrate: - // - // struct Foo { - // x: u16, - // y: T - // } - // - // The type `Foo>` is represented in LLVM as `{ u16, { u16, u8 }}`, meaning that - // the `y` field has 16-bit alignment. - - let meta = self.llextra; - - let unaligned_offset = bx.cx().const_usize(offset.bytes()); - - // Get the alignment of the field - let (_, mut unsized_align) = size_of_val::size_and_align_of_dst(bx, field.ty, meta); - - // For packed types, we need to cap alignment. - if let ty::Adt(def, _) = self.layout.ty.kind() - && let Some(packed) = def.repr().pack - { - let packed = bx.const_usize(packed.bytes()); - let cmp = bx.icmp(IntPredicate::IntULT, unsized_align, packed); - unsized_align = bx.select(cmp, unsized_align, packed) - } - - // Bump the unaligned offset up to the appropriate alignment - let offset = round_up_const_value_to_alignment(bx, unaligned_offset, unsized_align); - - debug!("struct_field_ptr: DST field offset: {:?}", offset); - - // Adjust pointer. - let ptr = bx.inbounds_ptradd(self.llval, offset); - - PlaceRef { llval: ptr, llextra: self.llextra, layout: field, align: effective_field_align } - } - - /// Obtain the actual discriminant of a value. - #[instrument(level = "trace", skip(bx))] - pub fn codegen_get_discr>( - self, - bx: &mut Bx, - cast_to: Ty<'tcx>, - ) -> V { - let dl = &bx.tcx().data_layout; - let cast_to_layout = bx.cx().layout_of(cast_to); - let cast_to = bx.cx().immediate_backend_type(cast_to_layout); - if self.layout.abi.is_uninhabited() { - return bx.cx().const_poison(cast_to); - } - let (tag_scalar, tag_encoding, tag_field) = match self.layout.variants { - Variants::Single { index } => { - let discr_val = self - .layout - .ty - .discriminant_for_variant(bx.cx().tcx(), index) - .map_or(index.as_u32() as u128, |discr| discr.val); - return bx.cx().const_uint_big(cast_to, discr_val); - } - Variants::Multiple { tag, ref tag_encoding, tag_field, .. } => { - (tag, tag_encoding, tag_field) - } - }; - - // Read the tag/niche-encoded discriminant from memory. - let tag = self.project_field(bx, tag_field); - let tag_op = bx.load_operand(tag); - let tag_imm = tag_op.immediate(); - - // Decode the discriminant (specifically if it's niche-encoded). - match *tag_encoding { - TagEncoding::Direct => { - let signed = match tag_scalar.primitive() { - // We use `i1` for bytes that are always `0` or `1`, - // e.g., `#[repr(i8)] enum E { A, B }`, but we can't - // let LLVM interpret the `i1` as signed, because - // then `i1 1` (i.e., `E::B`) is effectively `i8 -1`. - Int(_, signed) => !tag_scalar.is_bool() && signed, - _ => false, - }; - bx.intcast(tag_imm, cast_to, signed) - } - TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start } => { - // Cast to an integer so we don't have to treat a pointer as a - // special case. - let (tag, tag_llty) = match tag_scalar.primitive() { - // FIXME(erikdesjardins): handle non-default addrspace ptr sizes - Pointer(_) => { - let t = bx.type_from_integer(dl.ptr_sized_integer()); - let tag = bx.ptrtoint(tag_imm, t); - (tag, t) - } - _ => (tag_imm, bx.cx().immediate_backend_type(tag_op.layout)), - }; - - let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32(); - - // We have a subrange `niche_start..=niche_end` inside `range`. - // If the value of the tag is inside this subrange, it's a - // "niche value", an increment of the discriminant. Otherwise it - // indicates the untagged variant. - // A general algorithm to extract the discriminant from the tag - // is: - // relative_tag = tag - niche_start - // is_niche = relative_tag <= (ule) relative_max - // discr = if is_niche { - // cast(relative_tag) + niche_variants.start() - // } else { - // untagged_variant - // } - // However, we will likely be able to emit simpler code. - let (is_niche, tagged_discr, delta) = if relative_max == 0 { - // Best case scenario: only one tagged variant. This will - // likely become just a comparison and a jump. - // The algorithm is: - // is_niche = tag == niche_start - // discr = if is_niche { - // niche_start - // } else { - // untagged_variant - // } - let niche_start = bx.cx().const_uint_big(tag_llty, niche_start); - let is_niche = bx.icmp(IntPredicate::IntEQ, tag, niche_start); - let tagged_discr = - bx.cx().const_uint(cast_to, niche_variants.start().as_u32() as u64); - (is_niche, tagged_discr, 0) - } else { - // The special cases don't apply, so we'll have to go with - // the general algorithm. - let relative_discr = bx.sub(tag, bx.cx().const_uint_big(tag_llty, niche_start)); - let cast_tag = bx.intcast(relative_discr, cast_to, false); - let is_niche = bx.icmp( - IntPredicate::IntULE, - relative_discr, - bx.cx().const_uint(tag_llty, relative_max as u64), - ); - (is_niche, cast_tag, niche_variants.start().as_u32() as u128) - }; - - let tagged_discr = if delta == 0 { - tagged_discr - } else { - bx.add(tagged_discr, bx.cx().const_uint_big(cast_to, delta)) - }; - - let discr = bx.select( - is_niche, - tagged_discr, - bx.cx().const_uint(cast_to, untagged_variant.as_u32() as u64), - ); - - // In principle we could insert assumes on the possible range of `discr`, but - // currently in LLVM this seems to be a pessimization. - - discr - } - } - } - - /// Sets the discriminant for a new value of the given case of the given - /// representation. - pub fn codegen_set_discr>( - &self, - bx: &mut Bx, - variant_index: VariantIdx, - ) { - if self.layout.for_variant(bx.cx(), variant_index).abi.is_uninhabited() { - // We play it safe by using a well-defined `abort`, but we could go for immediate UB - // if that turns out to be helpful. - bx.abort(); - return; - } - match self.layout.variants { - Variants::Single { index } => { - assert_eq!(index, variant_index); - } - Variants::Multiple { tag_encoding: TagEncoding::Direct, tag_field, .. } => { - let ptr = self.project_field(bx, tag_field); - let to = - self.layout.ty.discriminant_for_variant(bx.tcx(), variant_index).unwrap().val; - bx.store( - bx.cx().const_uint_big(bx.cx().backend_type(ptr.layout), to), - ptr.llval, - ptr.align, - ); - } - Variants::Multiple { - tag_encoding: - TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start }, - tag_field, - .. - } => { - if variant_index != untagged_variant { - let niche = self.project_field(bx, tag_field); - let niche_llty = bx.cx().immediate_backend_type(niche.layout); - let niche_value = variant_index.as_u32() - niche_variants.start().as_u32(); - let niche_value = (niche_value as u128).wrapping_add(niche_start); - // FIXME(eddyb): check the actual primitive type here. - let niche_llval = if niche_value == 0 { - // HACK(eddyb): using `c_null` as it works on all types. - bx.cx().const_null(niche_llty) - } else { - bx.cx().const_uint_big(niche_llty, niche_value) - }; - OperandValue::Immediate(niche_llval).store(bx, niche); - } - } - } - } - - pub fn project_index>( - &self, - bx: &mut Bx, - llindex: V, - ) -> Self { - // Statically compute the offset if we can, otherwise just use the element size, - // as this will yield the lowest alignment. - let layout = self.layout.field(bx, 0); - let offset = if let Some(llindex) = bx.const_to_opt_uint(llindex) { - layout.size.checked_mul(llindex, bx).unwrap_or(layout.size) - } else { - layout.size - }; - - PlaceRef { - llval: bx.inbounds_gep( - bx.cx().backend_type(self.layout), - self.llval, - &[bx.cx().const_usize(0), llindex], - ), - llextra: None, - layout, - align: self.align.restrict_for_offset(offset), - } - } - - pub fn project_downcast>( - &self, - bx: &mut Bx, - variant_index: VariantIdx, - ) -> Self { - let mut downcast = *self; - downcast.layout = self.layout.for_variant(bx.cx(), variant_index); - downcast - } - - pub fn project_type>( - &self, - bx: &mut Bx, - ty: Ty<'tcx>, - ) -> Self { - let mut downcast = *self; - downcast.layout = bx.cx().layout_of(ty); - downcast - } - - pub fn storage_live>(&self, bx: &mut Bx) { - bx.lifetime_start(self.llval, self.layout.size); - } - - pub fn storage_dead>(&self, bx: &mut Bx) { - bx.lifetime_end(self.llval, self.layout.size); - } -} - -impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { - #[instrument(level = "trace", skip(self, bx))] - pub fn codegen_place( - &mut self, - bx: &mut Bx, - place_ref: mir::PlaceRef<'tcx>, - ) -> PlaceRef<'tcx, Bx::Value> { - let cx = self.cx; - let tcx = self.cx.tcx(); - - let mut base = 0; - let mut cg_base = match self.locals[place_ref.local] { - LocalRef::Place(place) => place, - LocalRef::UnsizedPlace(place) => bx.load_operand(place).deref(cx), - LocalRef::Operand(..) => { - if place_ref.is_indirect_first_projection() { - base = 1; - let cg_base = self.codegen_consume( - bx, - mir::PlaceRef { projection: &place_ref.projection[..0], ..place_ref }, - ); - cg_base.deref(bx.cx()) - } else { - bug!("using operand local {:?} as place", place_ref); - } - } - LocalRef::PendingOperand => { - bug!("using still-pending operand local {:?} as place", place_ref); - } - }; - for elem in place_ref.projection[base..].iter() { - cg_base = match *elem { - mir::ProjectionElem::Deref => bx.load_operand(cg_base).deref(bx.cx()), - mir::ProjectionElem::Field(ref field, _) => { - cg_base.project_field(bx, field.index()) - } - mir::ProjectionElem::OpaqueCast(ty) => { - bug!("encountered OpaqueCast({ty}) in codegen") - } - mir::ProjectionElem::Subtype(ty) => cg_base.project_type(bx, self.monomorphize(ty)), - mir::ProjectionElem::Index(index) => { - let index = &mir::Operand::Copy(mir::Place::from(index)); - let index = self.codegen_operand(bx, index); - let llindex = index.immediate(); - cg_base.project_index(bx, llindex) - } - mir::ProjectionElem::ConstantIndex { offset, from_end: false, min_length: _ } => { - let lloffset = bx.cx().const_usize(offset); - cg_base.project_index(bx, lloffset) - } - mir::ProjectionElem::ConstantIndex { offset, from_end: true, min_length: _ } => { - let lloffset = bx.cx().const_usize(offset); - let lllen = cg_base.len(bx.cx()); - let llindex = bx.sub(lllen, lloffset); - cg_base.project_index(bx, llindex) - } - mir::ProjectionElem::Subslice { from, to, from_end } => { - let mut subslice = cg_base.project_index(bx, bx.cx().const_usize(from)); - let projected_ty = - PlaceTy::from_ty(cg_base.layout.ty).projection_ty(tcx, *elem).ty; - subslice.layout = bx.cx().layout_of(self.monomorphize(projected_ty)); - - if subslice.layout.is_unsized() { - assert!(from_end, "slice subslices should be `from_end`"); - subslice.llextra = - Some(bx.sub(cg_base.llextra.unwrap(), bx.cx().const_usize(from + to))); - } - - subslice - } - mir::ProjectionElem::Downcast(_, v) => cg_base.project_downcast(bx, v), - }; - } - debug!("codegen_place(place={:?}) => {:?}", place_ref, cg_base); - cg_base - } - - pub fn monomorphized_place_ty(&self, place_ref: mir::PlaceRef<'tcx>) -> Ty<'tcx> { - let tcx = self.cx.tcx(); - let place_ty = place_ref.ty(self.mir, tcx); - self.monomorphize(place_ty.ty) - } -} - -fn round_up_const_value_to_alignment<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - bx: &mut Bx, - value: Bx::Value, - align: Bx::Value, -) -> Bx::Value { - // In pseudo code: - // - // if value & (align - 1) == 0 { - // value - // } else { - // (value & !(align - 1)) + align - // } - // - // Usually this is written without branches as - // - // (value + align - 1) & !(align - 1) - // - // But this formula cannot take advantage of constant `value`. E.g. if `value` is known - // at compile time to be `1`, this expression should be optimized to `align`. However, - // optimization only holds if `align` is a power of two. Since the optimizer doesn't know - // that `align` is a power of two, it cannot perform this optimization. - // - // Instead we use - // - // value + (-value & (align - 1)) - // - // Since `align` is used only once, the expression can be optimized. For `value = 0` - // its optimized to `0` even in debug mode. - // - // NB: The previous version of this code used - // - // (value + align - 1) & -align - // - // Even though `-align == !(align - 1)`, LLVM failed to optimize this even for - // `value = 0`. Bug report: https://bugs.llvm.org/show_bug.cgi?id=48559 - let one = bx.const_usize(1); - let align_minus_1 = bx.sub(align, one); - let neg_value = bx.neg(value); - let offset = bx.and(neg_value, align_minus_1); - bx.add(value, offset) -} +use super::operand::OperandValue;use super::{FunctionCx,LocalRef};use crate:://; +common::IntPredicate;use crate::size_of_val;use crate::traits::*;use//if true{}; +rustc_middle::mir;use rustc_middle::mir::tcx::PlaceTy;use rustc_middle::ty:://3; +layout::{HasTyCtxt,LayoutOf,TyAndLayout};use rustc_middle::ty::{self,Ty};use//3; +rustc_target::abi::{Align,FieldsShape, Int,Pointer,TagEncoding};use rustc_target +::abi::{VariantIdx,Variants};#[derive(Copy,Clone,Debug)]pub struct PlaceRef{pub llval:V,pub llextra:Option,pub layout:TyAndLayout<'tcx>,pub//{;}; +align:Align,}impl<'a,'tcx,V:CodegenObject>PlaceRef<'tcx,V>{pub fn new_sized(//3; +llval:V,layout:TyAndLayout<'tcx>)->PlaceRef<'tcx,V>{;assert!(layout.is_sized()); +PlaceRef{llval,llextra:None,layout,align:layout.align.abi}}pub fn//loop{break;}; +new_sized_aligned(llval:V,layout:TyAndLayout<'tcx >,align:Align,)->PlaceRef<'tcx +,V>{;assert!(layout.is_sized());PlaceRef{llval,llextra:None,layout,align}}pub fn +alloca>(bx:&mut Bx,layout:TyAndLayout<'tcx>// +,)->Self{Self::alloca_aligned(bx,layout ,layout.align.abi)}pub fn alloca_aligned +>(bx :&mut Bx,layout:TyAndLayout<'tcx>,align: +Align,)->Self{if true{};if true{};if true{};if true{};assert!(layout.is_sized(), +"tried to statically allocate unsized place");{;};{;};let tmp=bx.alloca(bx.cx(). +backend_type(layout),align);{;};Self::new_sized_aligned(tmp,layout,align)}pub fn +alloca_unsized_indirect>(bx:&mut Bx,layout:// +TyAndLayout<'tcx>,)->Self{loop{break;};loop{break;};assert!(layout.is_unsized(), +"tried to allocate indirect place for sized values");;let ptr_ty=Ty::new_mut_ptr +(bx.cx().tcx(),layout.ty);;let ptr_layout=bx.cx().layout_of(ptr_ty);Self::alloca +(bx,ptr_layout)}pub fn len>(&self,cx:&Cx)->V{if//; +let FieldsShape::Array{count,..}=self.layout .fields{if self.layout.is_unsized() +{;assert_eq!(count,0);self.llextra.unwrap()}else{cx.const_usize(count)}}else{bug +!("unexpected layout `{:#?}` in PlaceRef::len",self.layout)}}}impl<'a,'tcx,V://; +CodegenObject>PlaceRef<'tcx,V>{pub fn project_field>(self,bx:&mut Bx,ix:usize,)->Self{;let field=self.layout.field(bx.cx(), +ix);;;let offset=self.layout.fields.offset(ix);;;let effective_field_align=self. +align.restrict_for_offset(offset);;let mut simple=||{let llval=if offset.bytes() +==0{self.llval}else{bx.inbounds_ptradd (self.llval,bx.const_usize(offset.bytes() +))};;PlaceRef{llval,llextra:if bx.cx().type_has_metadata(field.ty){self.llextra} +else{None},layout:field,align:effective_field_align,}};3;match field.ty.kind(){_ +if (field.is_sized())=>return simple(),ty ::Slice(..)|ty::Str=>return simple(),_ +if offset.bytes()==0=>return simple(),_=>{}}{;};let meta=self.llextra;{;};();let +unaligned_offset=bx.cx().const_usize(offset.bytes());;;let(_,mut unsized_align)= +size_of_val::size_and_align_of_dst(bx,field.ty,meta);;if let ty::Adt(def,_)=self +.layout.ty.kind()&&let Some(packed)=def.repr().pack{3;let packed=bx.const_usize( +packed.bytes());3;3;let cmp=bx.icmp(IntPredicate::IntULT,unsized_align,packed);; +unsized_align=bx.select(cmp,unsized_align,packed)}let _=();if true{};let offset= +round_up_const_value_to_alignment(bx,unaligned_offset,unsized_align);3;3;debug!( +"struct_field_ptr: DST field offset: {:?}",offset);;;let ptr=bx.inbounds_ptradd( +self.llval,offset);3;PlaceRef{llval:ptr,llextra:self.llextra,layout:field,align: +effective_field_align}}#[instrument(level="trace",skip(bx))]pub fn//loop{break}; +codegen_get_discr>(self,bx:&mut Bx,cast_to:// +Ty<'tcx>,)->V{;let dl=&bx.tcx().data_layout;let cast_to_layout=bx.cx().layout_of +(cast_to);;;let cast_to=bx.cx().immediate_backend_type(cast_to_layout);;if self. +layout.abi.is_uninhabited(){{;};return bx.cx().const_poison(cast_to);();}();let( +tag_scalar,tag_encoding,tag_field)=match self.layout.variants{Variants::Single{ +index}=>{();let discr_val=self.layout.ty.discriminant_for_variant(bx.cx().tcx(), +index).map_or(index.as_u32()as u128,|discr|discr.val);{();};({});return bx.cx(). +const_uint_big(cast_to,discr_val);({});}Variants::Multiple{tag,ref tag_encoding, +tag_field,..}=>{(tag,tag_encoding,tag_field)}};3;;let tag=self.project_field(bx, +tag_field);;let tag_op=bx.load_operand(tag);let tag_imm=tag_op.immediate();match +*tag_encoding{TagEncoding::Direct=>{;let signed=match tag_scalar.primitive(){Int +(_,signed)=>!tag_scalar.is_bool()&&signed,_=>false,};;bx.intcast(tag_imm,cast_to +,signed)}TagEncoding::Niche{untagged_variant,ref niche_variants,niche_start}=>{; +let(tag,tag_llty)=match tag_scalar.primitive(){Pointer(_)=>{let _=||();let t=bx. +type_from_integer(dl.ptr_sized_integer());;let tag=bx.ptrtoint(tag_imm,t);(tag,t +)}_=>(tag_imm,bx.cx().immediate_backend_type(tag_op.layout)),};;let relative_max +=niche_variants.end().as_u32()-niche_variants.start().as_u32();3;3;let(is_niche, +tagged_discr,delta)=if relative_max==0{3;let niche_start=bx.cx().const_uint_big( +tag_llty,niche_start);;let is_niche=bx.icmp(IntPredicate::IntEQ,tag,niche_start) +;;;let tagged_discr=bx.cx().const_uint(cast_to,niche_variants.start().as_u32()as +u64);();(is_niche,tagged_discr,0)}else{();let relative_discr=bx.sub(tag,bx.cx(). +const_uint_big(tag_llty,niche_start));3;;let cast_tag=bx.intcast(relative_discr, +cast_to,false);;let is_niche=bx.icmp(IntPredicate::IntULE,relative_discr,bx.cx() +.const_uint(tag_llty,relative_max as u64),);3;(is_niche,cast_tag,niche_variants. +start().as_u32()as u128)};;let tagged_discr=if delta==0{tagged_discr}else{bx.add +(tagged_discr,bx.cx().const_uint_big(cast_to,delta))};();();let discr=bx.select( +is_niche,tagged_discr,(bx.cx()).const_uint(cast_to,(untagged_variant.as_u32())as +u64),);();discr}}}pub fn codegen_set_discr>(& +self,bx:&mut Bx,variant_index:VariantIdx,){if self.layout.for_variant((bx.cx()), +variant_index).abi.is_uninhabited(){3;bx.abort();3;3;return;;}match self.layout. +variants{Variants::Single{index}=>{;assert_eq!(index,variant_index);;}Variants:: +Multiple{tag_encoding:TagEncoding::Direct,tag_field,..}=>{let _=();let ptr=self. +project_field(bx,tag_field);;;let to=self.layout.ty.discriminant_for_variant(bx. +tcx(),variant_index).unwrap().val;();();bx.store(bx.cx().const_uint_big(bx.cx(). +backend_type(ptr.layout),to),ptr.llval,ptr.align,);let _=();}Variants::Multiple{ +tag_encoding:TagEncoding::Niche{ untagged_variant,ref niche_variants,niche_start +},tag_field,..}=>{if variant_index!=untagged_variant{loop{break};let niche=self. +project_field(bx,tag_field);;let niche_llty=bx.cx().immediate_backend_type(niche +.layout);;let niche_value=variant_index.as_u32()-niche_variants.start().as_u32() +;();();let niche_value=(niche_value as u128).wrapping_add(niche_start);();();let +niche_llval=if (niche_value==(0)){(bx.cx().const_null(niche_llty))}else{bx.cx(). +const_uint_big(niche_llty,niche_value)};3;;OperandValue::Immediate(niche_llval). +store(bx,niche);3;}}}}pub fn project_index>(& +self,bx:&mut Bx,llindex:V,)->Self{;let layout=self.layout.field(bx,0);let offset +=if let Some(llindex)=((bx.const_to_opt_uint(llindex))){layout.size.checked_mul( +llindex,bx).unwrap_or(layout.size)}else{layout.size};let _=();PlaceRef{llval:bx. +inbounds_gep(bx.cx().backend_type(self.layout) ,self.llval,&[bx.cx().const_usize +(0),llindex],),llextra :None,layout,align:self.align.restrict_for_offset(offset) +,}}pub fn project_downcast>(&self,bx:&mut Bx +,variant_index:VariantIdx,)->Self{;let mut downcast=*self;;downcast.layout=self. +layout.for_variant(bx.cx(),variant_index);{();};downcast}pub fn project_type>(&self,bx:&mut Bx,ty:Ty<'tcx>,)->Self{();let mut +downcast=*self;{;};{;};downcast.layout=bx.cx().layout_of(ty);{;};downcast}pub fn +storage_live>(&self,bx:&mut Bx){if true{};bx. +lifetime_start(self.llval,self.layout.size);loop{break};}pub fn storage_dead>(&self,bx:&mut Bx){3;bx.lifetime_end(self.llval, +self.layout.size);;}}impl<'a,'tcx,Bx:BuilderMethods<'a,'tcx>>FunctionCx<'a,'tcx, +Bx>{#[instrument(level="trace",skip(self, bx))]pub fn codegen_place(&mut self,bx +:&mut Bx,place_ref:mir::PlaceRef<'tcx>,)->PlaceRef<'tcx,Bx::Value>{;let cx=self. +cx;;;let tcx=self.cx.tcx();;;let mut base=0;;;let mut cg_base=match self.locals[ +place_ref.local]{LocalRef::Place(place)=>place,LocalRef::UnsizedPlace(place)=>// +bx.load_operand(place).deref(cx),LocalRef::Operand(..)=>{if place_ref.//((),()); +is_indirect_first_projection(){;base=1;let cg_base=self.codegen_consume(bx,mir:: +PlaceRef{projection:&place_ref.projection[..0],..place_ref},);;cg_base.deref(bx. +cx())}else{();bug!("using operand local {:?} as place",place_ref);3;}}LocalRef:: +PendingOperand=>{((),());bug!("using still-pending operand local {:?} as place", +place_ref);3;}};;for elem in place_ref.projection[base..].iter(){;cg_base=match* +elem{mir::ProjectionElem::Deref=>(bx.load_operand(cg_base).deref(bx.cx())),mir:: +ProjectionElem::Field(ref field,_)=>{(cg_base .project_field(bx,field.index()))} +mir::ProjectionElem::OpaqueCast(ty)=>{bug!(//((),());let _=();let _=();let _=(); +"encountered OpaqueCast({ty}) in codegen")}mir::ProjectionElem::Subtype(ty)=>//; +cg_base.project_type(bx,self.monomorphize(ty )),mir::ProjectionElem::Index(index +)=>{3;let index=&mir::Operand::Copy(mir::Place::from(index));3;3;let index=self. +codegen_operand(bx,index);;;let llindex=index.immediate();cg_base.project_index( +bx,llindex)}mir::ProjectionElem ::ConstantIndex{offset,from_end:false,min_length +:_}=>{{;};let lloffset=bx.cx().const_usize(offset);{;};cg_base.project_index(bx, +lloffset)}mir::ProjectionElem::ConstantIndex{ offset,from_end:true,min_length:_} +=>{;let lloffset=bx.cx().const_usize(offset);;let lllen=cg_base.len(bx.cx());let +llindex=bx.sub(lllen,lloffset);if true{};cg_base.project_index(bx,llindex)}mir:: +ProjectionElem::Subslice{from,to,from_end}=>{if true{};let mut subslice=cg_base. +project_index(bx,bx.cx().const_usize(from));;;let projected_ty=PlaceTy::from_ty( +cg_base.layout.ty).projection_ty(tcx,*elem).ty;({});{;};subslice.layout=bx.cx(). +layout_of(self.monomorphize(projected_ty));();if subslice.layout.is_unsized(){3; +assert!(from_end,"slice subslices should be `from_end`");;subslice.llextra=Some( +bx.sub(cg_base.llextra.unwrap(),bx.cx().const_usize(from+to)));3;}subslice}mir:: +ProjectionElem::Downcast(_,v)=>cg_base.project_downcast(bx,v),};{;};}{;};debug!( +"codegen_place(place={:?}) => {:?}",place_ref,cg_base);let _=||();cg_base}pub fn +monomorphized_place_ty(&self,place_ref:mir::PlaceRef<'tcx>)->Ty<'tcx>{3;let tcx= +self.cx.tcx();();();let place_ty=place_ref.ty(self.mir,tcx);3;self.monomorphize( +place_ty.ty)}}fn round_up_const_value_to_alignment <'a,'tcx,Bx:BuilderMethods<'a +,'tcx>>(bx:&mut Bx,value:Bx::Value,align:Bx::Value,)->Bx::Value{({});let one=bx. +const_usize(1);;let align_minus_1=bx.sub(align,one);let neg_value=bx.neg(value); +let offset=bx.and(neg_value,align_minus_1);((),());((),());bx.add(value,offset)} diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 0af84ff067af4..d1fca40007e63 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -1,1050 +1,318 @@ -use super::operand::{OperandRef, OperandValue}; -use super::place::PlaceRef; -use super::{FunctionCx, LocalRef}; - -use crate::base; -use crate::common::{self, IntPredicate}; -use crate::traits::*; -use crate::MemFlags; - -use rustc_middle::mir; -use rustc_middle::mir::Operand; -use rustc_middle::ty::cast::{CastTy, IntTy}; -use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; -use rustc_middle::ty::{self, adjustment::PointerCoercion, Instance, Ty, TyCtxt}; -use rustc_session::config::OptLevel; -use rustc_span::{Span, DUMMY_SP}; -use rustc_target::abi::{self, FIRST_VARIANT}; - -impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { - #[instrument(level = "trace", skip(self, bx))] - pub fn codegen_rvalue( - &mut self, - bx: &mut Bx, - dest: PlaceRef<'tcx, Bx::Value>, - rvalue: &mir::Rvalue<'tcx>, - ) { - match *rvalue { - mir::Rvalue::Use(ref operand) => { - let cg_operand = self.codegen_operand(bx, operand); - // FIXME: consider not copying constants through stack. (Fixable by codegen'ing - // constants into `OperandValue::Ref`; why don’t we do that yet if we don’t?) - cg_operand.val.store(bx, dest); - } - - mir::Rvalue::Cast( - mir::CastKind::PointerCoercion(PointerCoercion::Unsize), - ref source, - _, - ) => { - // The destination necessarily contains a fat pointer, so if - // it's a scalar pair, it's a fat pointer or newtype thereof. - if bx.cx().is_backend_scalar_pair(dest.layout) { - // Into-coerce of a thin pointer to a fat pointer -- just - // use the operand path. - let temp = self.codegen_rvalue_operand(bx, rvalue); - temp.val.store(bx, dest); - return; - } - - // Unsize of a nontrivial struct. I would prefer for - // this to be eliminated by MIR building, but - // `CoerceUnsized` can be passed by a where-clause, - // so the (generic) MIR may not be able to expand it. - let operand = self.codegen_operand(bx, source); - match operand.val { - OperandValue::Pair(..) | OperandValue::Immediate(_) => { - // Unsize from an immediate structure. We don't - // really need a temporary alloca here, but - // avoiding it would require us to have - // `coerce_unsized_into` use `extractvalue` to - // index into the struct, and this case isn't - // important enough for it. - debug!("codegen_rvalue: creating ugly alloca"); - let scratch = PlaceRef::alloca(bx, operand.layout); - scratch.storage_live(bx); - operand.val.store(bx, scratch); - base::coerce_unsized_into(bx, scratch, dest); - scratch.storage_dead(bx); - } - OperandValue::Ref(llref, None, align) => { - let source = PlaceRef::new_sized_aligned(llref, operand.layout, align); - base::coerce_unsized_into(bx, source, dest); - } - OperandValue::Ref(_, Some(_), _) => { - bug!("unsized coercion on an unsized rvalue"); - } - OperandValue::ZeroSized => { - bug!("unsized coercion on a ZST rvalue"); - } - } - } - - mir::Rvalue::Cast(mir::CastKind::Transmute, ref operand, _ty) => { - let src = self.codegen_operand(bx, operand); - self.codegen_transmute(bx, src, dest); - } - - mir::Rvalue::Repeat(ref elem, count) => { - let cg_elem = self.codegen_operand(bx, elem); - - // Do not generate the loop for zero-sized elements or empty arrays. - if dest.layout.is_zst() { - return; - } - - if let OperandValue::Immediate(v) = cg_elem.val { - let start = dest.llval; - let size = bx.const_usize(dest.layout.size.bytes()); - - // Use llvm.memset.p0i8.* to initialize all zero arrays - if bx.cx().const_to_opt_u128(v, false) == Some(0) { - let fill = bx.cx().const_u8(0); - bx.memset(start, fill, size, dest.align, MemFlags::empty()); - return; - } - - // Use llvm.memset.p0i8.* to initialize byte arrays - let v = bx.from_immediate(v); - if bx.cx().val_ty(v) == bx.cx().type_i8() { - bx.memset(start, v, size, dest.align, MemFlags::empty()); - return; - } - } - - let count = self - .monomorphize(count) - .eval_target_usize(bx.cx().tcx(), ty::ParamEnv::reveal_all()); - - bx.write_operand_repeatedly(cg_elem, count, dest); - } - - mir::Rvalue::Aggregate(ref kind, ref operands) => { - let (variant_index, variant_dest, active_field_index) = match **kind { - mir::AggregateKind::Adt(_, variant_index, _, _, active_field_index) => { - let variant_dest = dest.project_downcast(bx, variant_index); - (variant_index, variant_dest, active_field_index) - } - _ => (FIRST_VARIANT, dest, None), - }; - if active_field_index.is_some() { - assert_eq!(operands.len(), 1); - } - for (i, operand) in operands.iter_enumerated() { - let op = self.codegen_operand(bx, operand); - // Do not generate stores and GEPis for zero-sized fields. - if !op.layout.is_zst() { - let field_index = active_field_index.unwrap_or(i); - let field = if let mir::AggregateKind::Array(_) = **kind { - let llindex = bx.cx().const_usize(field_index.as_u32().into()); - variant_dest.project_index(bx, llindex) - } else { - variant_dest.project_field(bx, field_index.as_usize()) - }; - op.val.store(bx, field); - } - } - dest.codegen_set_discr(bx, variant_index); - } - - _ => { - assert!(self.rvalue_creates_operand(rvalue, DUMMY_SP)); - let temp = self.codegen_rvalue_operand(bx, rvalue); - temp.val.store(bx, dest); - } - } - } - - fn codegen_transmute( - &mut self, - bx: &mut Bx, - src: OperandRef<'tcx, Bx::Value>, - dst: PlaceRef<'tcx, Bx::Value>, - ) { - // The MIR validator enforces no unsized transmutes. - debug_assert!(src.layout.is_sized()); - debug_assert!(dst.layout.is_sized()); - - if let Some(val) = self.codegen_transmute_operand(bx, src, dst.layout) { - val.store(bx, dst); - return; - } - - match src.val { - OperandValue::Ref(..) | OperandValue::ZeroSized => { - span_bug!( - self.mir.span, - "Operand path should have handled transmute \ +use super::operand::{OperandRef,OperandValue};use super::place::PlaceRef;use//3; +super::{FunctionCx,LocalRef};use crate::base;use crate::common::{self,//((),()); +IntPredicate};use crate::traits::*;use crate::MemFlags;use rustc_middle::mir;//; +use rustc_middle::mir::Operand;use rustc_middle::ty::cast::{CastTy,IntTy};use//; +rustc_middle::ty::layout::{HasTyCtxt, LayoutOf,TyAndLayout};use rustc_middle::ty +::{self,adjustment::PointerCoercion,Instance,Ty,TyCtxt};use rustc_session:://(); +config::OptLevel;use rustc_span::{Span,DUMMY_SP};use rustc_target::abi::{self,// +FIRST_VARIANT};impl<'a,'tcx,Bx:BuilderMethods< 'a,'tcx>>FunctionCx<'a,'tcx,Bx>{# +[instrument(level="trace",skip(self,bx))]pub fn codegen_rvalue(&mut self,bx:&//; +mut Bx,dest:PlaceRef<'tcx,Bx::Value>,rvalue:&mir::Rvalue<'tcx>,){match(*rvalue){ +mir::Rvalue::Use(ref operand)=>{;let cg_operand=self.codegen_operand(bx,operand) +;({});({});cg_operand.val.store(bx,dest);({});}mir::Rvalue::Cast(mir::CastKind:: +PointerCoercion(PointerCoercion::Unsize),ref source,_, )=>{if (((((bx.cx()))))). +is_backend_scalar_pair(dest.layout){{;};let temp=self.codegen_rvalue_operand(bx, +rvalue);;;temp.val.store(bx,dest);;;return;}let operand=self.codegen_operand(bx, +source);;match operand.val{OperandValue::Pair(..)|OperandValue::Immediate(_)=>{; +debug!("codegen_rvalue: creating ugly alloca");;let scratch=PlaceRef::alloca(bx, +operand.layout);;;scratch.storage_live(bx);;operand.val.store(bx,scratch);base:: +coerce_unsized_into(bx,scratch,dest);;;scratch.storage_dead(bx);;}OperandValue:: +Ref(llref,None,align)=>{();let source=PlaceRef::new_sized_aligned(llref,operand. +layout,align);;;base::coerce_unsized_into(bx,source,dest);;}OperandValue::Ref(_, +Some(_),_)=>{();bug!("unsized coercion on an unsized rvalue");();}OperandValue:: +ZeroSized=>{;bug!("unsized coercion on a ZST rvalue");}}}mir::Rvalue::Cast(mir:: +CastKind::Transmute,ref operand,_ty)=>{;let src=self.codegen_operand(bx,operand) +;;self.codegen_transmute(bx,src,dest);}mir::Rvalue::Repeat(ref elem,count)=>{let +cg_elem=self.codegen_operand(bx,elem);3;if dest.layout.is_zst(){;return;;}if let +OperandValue::Immediate(v)=cg_elem.val{();let start=dest.llval;();3;let size=bx. +const_usize(dest.layout.size.bytes());();if bx.cx().const_to_opt_u128(v,false)== +Some(0){3;let fill=bx.cx().const_u8(0);3;3;bx.memset(start,fill,size,dest.align, +MemFlags::empty());;return;}let v=bx.from_immediate(v);if bx.cx().val_ty(v)==bx. +cx().type_i8(){;bx.memset(start,v,size,dest.align,MemFlags::empty());;;return;}} +let count=self.monomorphize(count).eval_target_usize( bx.cx().tcx(),ty::ParamEnv +::reveal_all());;;bx.write_operand_repeatedly(cg_elem,count,dest);}mir::Rvalue:: +Aggregate(ref kind,ref operands)=>{if let _=(){};let(variant_index,variant_dest, +active_field_index)=match(*(*kind)){mir::AggregateKind::Adt(_,variant_index,_,_, +active_field_index)=>{;let variant_dest=dest.project_downcast(bx,variant_index); +(variant_index,variant_dest,active_field_index)}_=>(FIRST_VARIANT,dest,None),};; +if active_field_index.is_some(){;assert_eq!(operands.len(),1);}for(i,operand)in +operands.iter_enumerated(){;let op=self.codegen_operand(bx,operand);if!op.layout +.is_zst(){;let field_index=active_field_index.unwrap_or(i);;let field=if let mir +::AggregateKind::Array(_)=**kind{();let llindex=bx.cx().const_usize(field_index. +as_u32().into());{();};variant_dest.project_index(bx,llindex)}else{variant_dest. +project_field(bx,field_index.as_usize())};3;3;op.val.store(bx,field);3;}}3;dest. +codegen_set_discr(bx,variant_index);3;}_=>{;assert!(self.rvalue_creates_operand( +rvalue,DUMMY_SP));3;;let temp=self.codegen_rvalue_operand(bx,rvalue);;;temp.val. +store(bx,dest);;}}}fn codegen_transmute(&mut self,bx:&mut Bx,src:OperandRef<'tcx +,Bx::Value>,dst:PlaceRef<'tcx,Bx::Value>,){;debug_assert!(src.layout.is_sized()) +;*&*&();*&*&();debug_assert!(dst.layout.is_sized());{();};if let Some(val)=self. +codegen_transmute_operand(bx,src,dst.layout){;val.store(bx,dst);;;return;;}match +src.val{OperandValue::Ref(..)|OperandValue::ZeroSized=>{;span_bug!(self.mir.span +,//let _=();if true{};let _=();if true{};let _=();if true{};if true{};if true{}; +"Operand path should have handled transmute \ from {src:?} to place {dst:?}" - ); - } - OperandValue::Immediate(..) | OperandValue::Pair(..) => { - // When we have immediate(s), the alignment of the source is irrelevant, - // so we can store them using the destination's alignment. - src.val.store(bx, PlaceRef::new_sized_aligned(dst.llval, src.layout, dst.align)); - } - } - } - - /// Attempts to transmute an `OperandValue` to another `OperandValue`. - /// - /// Returns `None` for cases that can't work in that framework, such as for - /// `Immediate`->`Ref` that needs an `alloc` to get the location. - fn codegen_transmute_operand( - &mut self, - bx: &mut Bx, - operand: OperandRef<'tcx, Bx::Value>, - cast: TyAndLayout<'tcx>, - ) -> Option> { - // Check for transmutes that are always UB. - if operand.layout.size != cast.size - || operand.layout.abi.is_uninhabited() - || cast.abi.is_uninhabited() - { - if !operand.layout.abi.is_uninhabited() { - // Since this is known statically and the input could have existed - // without already having hit UB, might as well trap for it. - bx.abort(); - } - - // Because this transmute is UB, return something easy to generate, - // since it's fine that later uses of the value are probably UB. - return Some(OperandValue::poison(bx, cast)); - } - - let operand_kind = self.value_kind(operand.layout); - let cast_kind = self.value_kind(cast); - - match operand.val { - OperandValue::Ref(ptr, meta, align) => { - debug_assert_eq!(meta, None); - debug_assert!(matches!(operand_kind, OperandValueKind::Ref)); - let fake_place = PlaceRef::new_sized_aligned(ptr, cast, align); - Some(bx.load_operand(fake_place).val) - } - OperandValue::ZeroSized => { - let OperandValueKind::ZeroSized = operand_kind else { - bug!("Found {operand_kind:?} for operand {operand:?}"); - }; - if let OperandValueKind::ZeroSized = cast_kind { - Some(OperandValue::ZeroSized) - } else { - None - } - } - OperandValue::Immediate(imm) => { - let OperandValueKind::Immediate(in_scalar) = operand_kind else { - bug!("Found {operand_kind:?} for operand {operand:?}"); - }; - if let OperandValueKind::Immediate(out_scalar) = cast_kind - && in_scalar.size(self.cx) == out_scalar.size(self.cx) - { - let operand_bty = bx.backend_type(operand.layout); - let cast_bty = bx.backend_type(cast); - Some(OperandValue::Immediate(self.transmute_immediate( - bx, - imm, - in_scalar, - operand_bty, - out_scalar, - cast_bty, - ))) - } else { - None - } - } - OperandValue::Pair(imm_a, imm_b) => { - let OperandValueKind::Pair(in_a, in_b) = operand_kind else { - bug!("Found {operand_kind:?} for operand {operand:?}"); - }; - if let OperandValueKind::Pair(out_a, out_b) = cast_kind - && in_a.size(self.cx) == out_a.size(self.cx) - && in_b.size(self.cx) == out_b.size(self.cx) - { - let in_a_ibty = bx.scalar_pair_element_backend_type(operand.layout, 0, false); - let in_b_ibty = bx.scalar_pair_element_backend_type(operand.layout, 1, false); - let out_a_ibty = bx.scalar_pair_element_backend_type(cast, 0, false); - let out_b_ibty = bx.scalar_pair_element_backend_type(cast, 1, false); - Some(OperandValue::Pair( - self.transmute_immediate(bx, imm_a, in_a, in_a_ibty, out_a, out_a_ibty), - self.transmute_immediate(bx, imm_b, in_b, in_b_ibty, out_b, out_b_ibty), - )) - } else { - None - } - } - } - } - - /// Transmutes one of the immediates from an [`OperandValue::Immediate`] - /// or an [`OperandValue::Pair`] to an immediate of the target type. - /// - /// `to_backend_ty` must be the *non*-immediate backend type (so it will be - /// `i8`, not `i1`, for `bool`-like types.) - fn transmute_immediate( - &self, - bx: &mut Bx, - mut imm: Bx::Value, - from_scalar: abi::Scalar, - from_backend_ty: Bx::Type, - to_scalar: abi::Scalar, - to_backend_ty: Bx::Type, - ) -> Bx::Value { - debug_assert_eq!(from_scalar.size(self.cx), to_scalar.size(self.cx)); - - use abi::Primitive::*; - imm = bx.from_immediate(imm); - - // When scalars are passed by value, there's no metadata recording their - // valid ranges. For example, `char`s are passed as just `i32`, with no - // way for LLVM to know that they're 0x10FFFF at most. Thus we assume - // the range of the input value too, not just the output range. - self.assume_scalar_range(bx, imm, from_scalar, from_backend_ty); - - imm = match (from_scalar.primitive(), to_scalar.primitive()) { - (Int(..) | F16 | F32 | F64 | F128, Int(..) | F16 | F32 | F64 | F128) => { - bx.bitcast(imm, to_backend_ty) - } - (Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty), - (Int(..), Pointer(..)) => bx.ptradd(bx.const_null(bx.type_ptr()), imm), - (Pointer(..), Int(..)) => bx.ptrtoint(imm, to_backend_ty), - (F16 | F32 | F64 | F128, Pointer(..)) => { - let int_imm = bx.bitcast(imm, bx.cx().type_isize()); - bx.ptradd(bx.const_null(bx.type_ptr()), int_imm) - } - (Pointer(..), F16 | F32 | F64 | F128) => { - let int_imm = bx.ptrtoint(imm, bx.cx().type_isize()); - bx.bitcast(int_imm, to_backend_ty) - } - }; - self.assume_scalar_range(bx, imm, to_scalar, to_backend_ty); - imm = bx.to_immediate_scalar(imm, to_scalar); - imm - } - - fn assume_scalar_range( - &self, - bx: &mut Bx, - imm: Bx::Value, - scalar: abi::Scalar, - backend_ty: Bx::Type, - ) { - if matches!(self.cx.sess().opts.optimize, OptLevel::No | OptLevel::Less) - // For now, the critical niches are all over `Int`eger values. - // Should floating-point values or pointers ever get more complex - // niches, then this code will probably want to handle them too. - || !matches!(scalar.primitive(), abi::Primitive::Int(..)) - || scalar.is_always_valid(self.cx) - { - return; - } - - let abi::WrappingRange { start, end } = scalar.valid_range(self.cx); - - if start <= end { - if start > 0 { - let low = bx.const_uint_big(backend_ty, start); - let cmp = bx.icmp(IntPredicate::IntUGE, imm, low); - bx.assume(cmp); - } - - let type_max = scalar.size(self.cx).unsigned_int_max(); - if end < type_max { - let high = bx.const_uint_big(backend_ty, end); - let cmp = bx.icmp(IntPredicate::IntULE, imm, high); - bx.assume(cmp); - } - } else { - let low = bx.const_uint_big(backend_ty, start); - let cmp_low = bx.icmp(IntPredicate::IntUGE, imm, low); - - let high = bx.const_uint_big(backend_ty, end); - let cmp_high = bx.icmp(IntPredicate::IntULE, imm, high); - - let or = bx.or(cmp_low, cmp_high); - bx.assume(or); - } - } - - pub fn codegen_rvalue_unsized( - &mut self, - bx: &mut Bx, - indirect_dest: PlaceRef<'tcx, Bx::Value>, - rvalue: &mir::Rvalue<'tcx>, - ) { - debug!( - "codegen_rvalue_unsized(indirect_dest.llval={:?}, rvalue={:?})", - indirect_dest.llval, rvalue - ); - - match *rvalue { - mir::Rvalue::Use(ref operand) => { - let cg_operand = self.codegen_operand(bx, operand); - cg_operand.val.store_unsized(bx, indirect_dest); - } - - _ => bug!("unsized assignment other than `Rvalue::Use`"), - } - } - - pub fn codegen_rvalue_operand( - &mut self, - bx: &mut Bx, - rvalue: &mir::Rvalue<'tcx>, - ) -> OperandRef<'tcx, Bx::Value> { - assert!( - self.rvalue_creates_operand(rvalue, DUMMY_SP), - "cannot codegen {rvalue:?} to operand", - ); - - match *rvalue { - mir::Rvalue::Cast(ref kind, ref source, mir_cast_ty) => { - let operand = self.codegen_operand(bx, source); - debug!("cast operand is {:?}", operand); - let cast = bx.cx().layout_of(self.monomorphize(mir_cast_ty)); - - let val = match *kind { - mir::CastKind::PointerExposeAddress => { - assert!(bx.cx().is_backend_immediate(cast)); - let llptr = operand.immediate(); - let llcast_ty = bx.cx().immediate_backend_type(cast); - let lladdr = bx.ptrtoint(llptr, llcast_ty); - OperandValue::Immediate(lladdr) - } - mir::CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer) => { - match *operand.layout.ty.kind() { - ty::FnDef(def_id, args) => { - let instance = ty::Instance::resolve_for_fn_ptr( - bx.tcx(), - ty::ParamEnv::reveal_all(), - def_id, - args, - ) - .unwrap() - .polymorphize(bx.cx().tcx()); - OperandValue::Immediate(bx.get_fn_addr(instance)) - } - _ => bug!("{} cannot be reified to a fn ptr", operand.layout.ty), - } - } - mir::CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_)) => { - match *operand.layout.ty.kind() { - ty::Closure(def_id, args) => { - let instance = Instance::resolve_closure( - bx.cx().tcx(), - def_id, - args, - ty::ClosureKind::FnOnce, - ) - .polymorphize(bx.cx().tcx()); - OperandValue::Immediate(bx.cx().get_fn_addr(instance)) - } - _ => bug!("{} cannot be cast to a fn ptr", operand.layout.ty), - } - } - mir::CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer) => { - // This is a no-op at the LLVM level. - operand.val - } - mir::CastKind::PointerCoercion(PointerCoercion::Unsize) => { - assert!(bx.cx().is_backend_scalar_pair(cast)); - let (lldata, llextra) = match operand.val { - OperandValue::Pair(lldata, llextra) => { - // unsize from a fat pointer -- this is a - // "trait-object-to-supertrait" coercion. - (lldata, Some(llextra)) - } - OperandValue::Immediate(lldata) => { - // "standard" unsize - (lldata, None) - } - OperandValue::Ref(..) => { - bug!("by-ref operand {:?} in `codegen_rvalue_operand`", operand); - } - OperandValue::ZeroSized => { - bug!("zero-sized operand {:?} in `codegen_rvalue_operand`", operand); - } - }; - let (lldata, llextra) = - base::unsize_ptr(bx, lldata, operand.layout.ty, cast.ty, llextra); - OperandValue::Pair(lldata, llextra) - } - mir::CastKind::PointerCoercion(PointerCoercion::MutToConstPointer) - | mir::CastKind::PtrToPtr - if bx.cx().is_backend_scalar_pair(operand.layout) => - { - if let OperandValue::Pair(data_ptr, meta) = operand.val { - if bx.cx().is_backend_scalar_pair(cast) { - OperandValue::Pair(data_ptr, meta) - } else { - // Cast of fat-ptr to thin-ptr is an extraction of data-ptr. - OperandValue::Immediate(data_ptr) - } - } else { - bug!("unexpected non-pair operand"); - } - } - mir::CastKind::DynStar => { - let (lldata, llextra) = match operand.val { - OperandValue::Ref(_, _, _) => todo!(), - OperandValue::Immediate(v) => (v, None), - OperandValue::Pair(v, l) => (v, Some(l)), - OperandValue::ZeroSized => bug!("ZST -- which is not PointerLike -- in DynStar"), - }; - let (lldata, llextra) = - base::cast_to_dyn_star(bx, lldata, operand.layout, cast.ty, llextra); - OperandValue::Pair(lldata, llextra) - } - mir::CastKind::PointerCoercion( - PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer, - ) - | 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. - | mir::CastKind::PointerFromExposedAddress => { - assert!(bx.cx().is_backend_immediate(cast)); - let ll_t_out = bx.cx().immediate_backend_type(cast); - if operand.layout.abi.is_uninhabited() { - let val = OperandValue::Immediate(bx.cx().const_poison(ll_t_out)); - return OperandRef { val, layout: cast }; - } - let r_t_in = - CastTy::from_ty(operand.layout.ty).expect("bad input type for cast"); - let r_t_out = CastTy::from_ty(cast.ty).expect("bad output type for cast"); - let ll_t_in = bx.cx().immediate_backend_type(operand.layout); - let llval = operand.immediate(); - - let newval = match (r_t_in, r_t_out) { - (CastTy::Int(i), CastTy::Int(_)) => { - bx.intcast(llval, ll_t_out, i.is_signed()) - } - (CastTy::Float, CastTy::Float) => { - let srcsz = bx.cx().float_width(ll_t_in); - let dstsz = bx.cx().float_width(ll_t_out); - if dstsz > srcsz { - bx.fpext(llval, ll_t_out) - } else if srcsz > dstsz { - bx.fptrunc(llval, ll_t_out) - } else { - llval - } - } - (CastTy::Int(i), CastTy::Float) => { - if i.is_signed() { - bx.sitofp(llval, ll_t_out) - } else { - bx.uitofp(llval, ll_t_out) - } - } - (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Ptr(_)) => { - bx.pointercast(llval, ll_t_out) - } - (CastTy::Int(i), CastTy::Ptr(_)) => { - let usize_llval = - bx.intcast(llval, bx.cx().type_isize(), i.is_signed()); - bx.inttoptr(usize_llval, ll_t_out) - } - (CastTy::Float, CastTy::Int(IntTy::I)) => { - bx.cast_float_to_int(true, llval, ll_t_out) - } - (CastTy::Float, CastTy::Int(_)) => { - bx.cast_float_to_int(false, llval, ll_t_out) - } - _ => bug!("unsupported cast: {:?} to {:?}", operand.layout.ty, cast.ty), - }; - OperandValue::Immediate(newval) - } - mir::CastKind::Transmute => { - self.codegen_transmute_operand(bx, operand, cast).unwrap_or_else(|| { - bug!("Unsupported transmute-as-operand of {operand:?} to {cast:?}"); - }) - } - }; - OperandRef { val, layout: cast } - } - - mir::Rvalue::Ref(_, bk, place) => { - let mk_ref = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| { - Ty::new_ref(tcx, tcx.lifetimes.re_erased, ty, bk.to_mutbl_lossy()) - }; - self.codegen_place_to_pointer(bx, place, mk_ref) - } - - mir::Rvalue::CopyForDeref(place) => self.codegen_operand(bx, &Operand::Copy(place)), - mir::Rvalue::AddressOf(mutability, place) => { - let mk_ptr = - move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| Ty::new_ptr(tcx, ty, mutability); - self.codegen_place_to_pointer(bx, place, mk_ptr) - } - - mir::Rvalue::Len(place) => { - let size = self.evaluate_array_len(bx, place); - OperandRef { - val: OperandValue::Immediate(size), - layout: bx.cx().layout_of(bx.tcx().types.usize), - } - } - - mir::Rvalue::BinaryOp(op, box (ref lhs, ref rhs)) => { - let lhs = self.codegen_operand(bx, lhs); - let rhs = self.codegen_operand(bx, rhs); - let llresult = match (lhs.val, rhs.val) { - ( - OperandValue::Pair(lhs_addr, lhs_extra), - OperandValue::Pair(rhs_addr, rhs_extra), - ) => self.codegen_fat_ptr_binop( - bx, - op, - lhs_addr, - lhs_extra, - rhs_addr, - rhs_extra, - lhs.layout.ty, - ), - - (OperandValue::Immediate(lhs_val), OperandValue::Immediate(rhs_val)) => { - self.codegen_scalar_binop(bx, op, lhs_val, rhs_val, lhs.layout.ty) - } - - _ => bug!(), - }; - OperandRef { - val: OperandValue::Immediate(llresult), - layout: bx.cx().layout_of(op.ty(bx.tcx(), lhs.layout.ty, rhs.layout.ty)), - } - } - mir::Rvalue::CheckedBinaryOp(op, box (ref lhs, ref rhs)) => { - let lhs = self.codegen_operand(bx, lhs); - let rhs = self.codegen_operand(bx, rhs); - let result = self.codegen_scalar_checked_binop( - bx, - op, - lhs.immediate(), - rhs.immediate(), - lhs.layout.ty, - ); - let val_ty = op.ty(bx.tcx(), lhs.layout.ty, rhs.layout.ty); - let operand_ty = Ty::new_tup(bx.tcx(), &[val_ty, bx.tcx().types.bool]); - OperandRef { val: result, layout: bx.cx().layout_of(operand_ty) } - } - - mir::Rvalue::UnaryOp(op, ref operand) => { - let operand = self.codegen_operand(bx, operand); - let lloperand = operand.immediate(); - let is_float = operand.layout.ty.is_floating_point(); - let llval = match op { - mir::UnOp::Not => bx.not(lloperand), - mir::UnOp::Neg => { - if is_float { - bx.fneg(lloperand) - } else { - bx.neg(lloperand) - } - } - }; - OperandRef { val: OperandValue::Immediate(llval), layout: operand.layout } - } - - mir::Rvalue::Discriminant(ref place) => { - let discr_ty = rvalue.ty(self.mir, bx.tcx()); - let discr_ty = self.monomorphize(discr_ty); - let discr = self.codegen_place(bx, place.as_ref()).codegen_get_discr(bx, discr_ty); - OperandRef { - val: OperandValue::Immediate(discr), - layout: self.cx.layout_of(discr_ty), - } - } - - mir::Rvalue::NullaryOp(ref null_op, ty) => { - let ty = self.monomorphize(ty); - let layout = bx.cx().layout_of(ty); - let val = match null_op { - mir::NullOp::SizeOf => { - assert!(bx.cx().type_is_sized(ty)); - let val = layout.size.bytes(); - bx.cx().const_usize(val) - } - mir::NullOp::AlignOf => { - assert!(bx.cx().type_is_sized(ty)); - let val = layout.align.abi.bytes(); - bx.cx().const_usize(val) - } - mir::NullOp::OffsetOf(fields) => { - let val = layout.offset_of_subfield(bx.cx(), fields.iter()).bytes(); - bx.cx().const_usize(val) - } - mir::NullOp::UbChecks => { - let val = bx.tcx().sess.opts.debug_assertions; - bx.cx().const_bool(val) - } - }; - let tcx = self.cx.tcx(); - OperandRef { - val: OperandValue::Immediate(val), - layout: self.cx.layout_of(tcx.types.usize), - } - } - - mir::Rvalue::ThreadLocalRef(def_id) => { - assert!(bx.cx().tcx().is_static(def_id)); - let layout = bx.layout_of(bx.cx().tcx().static_ptr_ty(def_id)); - let static_ = if !def_id.is_local() && bx.cx().tcx().needs_thread_local_shim(def_id) - { - let instance = ty::Instance { - def: ty::InstanceDef::ThreadLocalShim(def_id), - args: ty::GenericArgs::empty(), - }; - let fn_ptr = bx.get_fn_addr(instance); - let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty()); - let fn_ty = bx.fn_decl_backend_type(fn_abi); - let fn_attrs = if bx.tcx().def_kind(instance.def_id()).has_codegen_attrs() { - Some(bx.tcx().codegen_fn_attrs(instance.def_id())) - } else { - None - }; - bx.call(fn_ty, fn_attrs, Some(fn_abi), fn_ptr, &[], None, Some(instance)) - } else { - bx.get_static(def_id) - }; - OperandRef { val: OperandValue::Immediate(static_), layout } - } - mir::Rvalue::Use(ref operand) => self.codegen_operand(bx, operand), - mir::Rvalue::Repeat(..) | mir::Rvalue::Aggregate(..) => { - // According to `rvalue_creates_operand`, only ZST - // aggregate rvalues are allowed to be operands. - let ty = rvalue.ty(self.mir, self.cx.tcx()); - OperandRef::zero_sized(self.cx.layout_of(self.monomorphize(ty))) - } - mir::Rvalue::ShallowInitBox(ref operand, content_ty) => { - let operand = self.codegen_operand(bx, operand); - let val = operand.immediate(); - - let content_ty = self.monomorphize(content_ty); - let box_layout = bx.cx().layout_of(Ty::new_box(bx.tcx(), content_ty)); - - OperandRef { val: OperandValue::Immediate(val), layout: box_layout } - } - } - } - - fn evaluate_array_len(&mut self, bx: &mut Bx, place: mir::Place<'tcx>) -> Bx::Value { - // ZST are passed as operands and require special handling - // because codegen_place() panics if Local is operand. - if let Some(index) = place.as_local() { - if let LocalRef::Operand(op) = self.locals[index] { - if let ty::Array(_, n) = op.layout.ty.kind() { - let n = n.eval_target_usize(bx.cx().tcx(), ty::ParamEnv::reveal_all()); - return bx.cx().const_usize(n); - } - } - } - // use common size calculation for non zero-sized types - let cg_value = self.codegen_place(bx, place.as_ref()); - cg_value.len(bx.cx()) - } - - /// Codegen an `Rvalue::AddressOf` or `Rvalue::Ref` - fn codegen_place_to_pointer( - &mut self, - bx: &mut Bx, - place: mir::Place<'tcx>, - mk_ptr_ty: impl FnOnce(TyCtxt<'tcx>, Ty<'tcx>) -> Ty<'tcx>, - ) -> OperandRef<'tcx, Bx::Value> { - let cg_place = self.codegen_place(bx, place.as_ref()); - - let ty = cg_place.layout.ty; - - // Note: places are indirect, so storing the `llval` into the - // destination effectively creates a reference. - let val = if !bx.cx().type_has_metadata(ty) { - OperandValue::Immediate(cg_place.llval) - } else { - OperandValue::Pair(cg_place.llval, cg_place.llextra.unwrap()) - }; - OperandRef { val, layout: self.cx.layout_of(mk_ptr_ty(self.cx.tcx(), ty)) } - } - - pub fn codegen_scalar_binop( - &mut self, - bx: &mut Bx, - op: mir::BinOp, - lhs: Bx::Value, - rhs: Bx::Value, - input_ty: Ty<'tcx>, - ) -> Bx::Value { - let is_float = input_ty.is_floating_point(); - let is_signed = input_ty.is_signed(); - match op { - mir::BinOp::Add => { - if is_float { - bx.fadd(lhs, rhs) - } else { - bx.add(lhs, rhs) - } - } - mir::BinOp::AddUnchecked => { - if is_signed { - bx.unchecked_sadd(lhs, rhs) - } else { - bx.unchecked_uadd(lhs, rhs) - } - } - mir::BinOp::Sub => { - if is_float { - bx.fsub(lhs, rhs) - } else { - bx.sub(lhs, rhs) - } - } - mir::BinOp::SubUnchecked => { - if is_signed { - bx.unchecked_ssub(lhs, rhs) - } else { - bx.unchecked_usub(lhs, rhs) - } - } - mir::BinOp::Mul => { - if is_float { - bx.fmul(lhs, rhs) - } else { - bx.mul(lhs, rhs) - } - } - mir::BinOp::MulUnchecked => { - if is_signed { - bx.unchecked_smul(lhs, rhs) - } else { - bx.unchecked_umul(lhs, rhs) - } - } - mir::BinOp::Div => { - if is_float { - bx.fdiv(lhs, rhs) - } else if is_signed { - bx.sdiv(lhs, rhs) - } else { - bx.udiv(lhs, rhs) - } - } - mir::BinOp::Rem => { - if is_float { - bx.frem(lhs, rhs) - } else if is_signed { - bx.srem(lhs, rhs) - } else { - bx.urem(lhs, rhs) - } - } - mir::BinOp::BitOr => bx.or(lhs, rhs), - mir::BinOp::BitAnd => bx.and(lhs, rhs), - mir::BinOp::BitXor => bx.xor(lhs, rhs), - mir::BinOp::Offset => { - let pointee_type = input_ty - .builtin_deref(true) - .unwrap_or_else(|| bug!("deref of non-pointer {:?}", input_ty)) - .ty; - let pointee_layout = bx.cx().layout_of(pointee_type); - if pointee_layout.is_zst() { - // `Offset` works in terms of the size of pointee, - // so offsetting a pointer to ZST is a noop. - lhs - } else { - let llty = bx.cx().backend_type(pointee_layout); - bx.inbounds_gep(llty, lhs, &[rhs]) - } - } - mir::BinOp::Shl => common::build_masked_lshift(bx, lhs, rhs), - mir::BinOp::ShlUnchecked => { - let rhs = base::cast_shift_expr_rhs(bx, lhs, rhs); - bx.shl(lhs, rhs) - } - mir::BinOp::Shr => common::build_masked_rshift(bx, input_ty, lhs, rhs), - mir::BinOp::ShrUnchecked => { - let rhs = base::cast_shift_expr_rhs(bx, lhs, rhs); - if is_signed { bx.ashr(lhs, rhs) } else { bx.lshr(lhs, rhs) } - } - mir::BinOp::Ne - | mir::BinOp::Lt - | mir::BinOp::Gt - | mir::BinOp::Eq - | mir::BinOp::Le - | mir::BinOp::Ge => { - if is_float { - bx.fcmp(base::bin_op_to_fcmp_predicate(op.to_hir_binop()), lhs, rhs) - } else { - bx.icmp(base::bin_op_to_icmp_predicate(op.to_hir_binop(), is_signed), lhs, rhs) - } - } - } - } - - pub fn codegen_fat_ptr_binop( - &mut self, - bx: &mut Bx, - op: mir::BinOp, - lhs_addr: Bx::Value, - lhs_extra: Bx::Value, - rhs_addr: Bx::Value, - rhs_extra: Bx::Value, - _input_ty: Ty<'tcx>, - ) -> Bx::Value { - match op { - mir::BinOp::Eq => { - let lhs = bx.icmp(IntPredicate::IntEQ, lhs_addr, rhs_addr); - let rhs = bx.icmp(IntPredicate::IntEQ, lhs_extra, rhs_extra); - bx.and(lhs, rhs) - } - mir::BinOp::Ne => { - let lhs = bx.icmp(IntPredicate::IntNE, lhs_addr, rhs_addr); - let rhs = bx.icmp(IntPredicate::IntNE, lhs_extra, rhs_extra); - bx.or(lhs, rhs) - } - mir::BinOp::Le | mir::BinOp::Lt | mir::BinOp::Ge | mir::BinOp::Gt => { - // a OP b ~ a.0 STRICT(OP) b.0 | (a.0 == b.0 && a.1 OP a.1) - let (op, strict_op) = match op { - mir::BinOp::Lt => (IntPredicate::IntULT, IntPredicate::IntULT), - mir::BinOp::Le => (IntPredicate::IntULE, IntPredicate::IntULT), - mir::BinOp::Gt => (IntPredicate::IntUGT, IntPredicate::IntUGT), - mir::BinOp::Ge => (IntPredicate::IntUGE, IntPredicate::IntUGT), - _ => bug!(), - }; - let lhs = bx.icmp(strict_op, lhs_addr, rhs_addr); - let and_lhs = bx.icmp(IntPredicate::IntEQ, lhs_addr, rhs_addr); - let and_rhs = bx.icmp(op, lhs_extra, rhs_extra); - let rhs = bx.and(and_lhs, and_rhs); - bx.or(lhs, rhs) - } - _ => { - bug!("unexpected fat ptr binop"); - } - } - } - - pub fn codegen_scalar_checked_binop( - &mut self, - bx: &mut Bx, - op: mir::BinOp, - lhs: Bx::Value, - rhs: Bx::Value, - input_ty: Ty<'tcx>, - ) -> OperandValue { - let (val, of) = match op { - // These are checked using intrinsics - mir::BinOp::Add | mir::BinOp::Sub | mir::BinOp::Mul => { - let oop = match op { - mir::BinOp::Add => OverflowOp::Add, - mir::BinOp::Sub => OverflowOp::Sub, - mir::BinOp::Mul => OverflowOp::Mul, - _ => unreachable!(), - }; - bx.checked_binop(oop, input_ty, lhs, rhs) - } - _ => bug!("Operator `{:?}` is not a checkable operator", op), - }; - - OperandValue::Pair(val, of) - } -} - -impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { - pub fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>, span: Span) -> bool { - match *rvalue { - mir::Rvalue::Cast(mir::CastKind::Transmute, ref operand, cast_ty) => { - let operand_ty = operand.ty(self.mir, self.cx.tcx()); - let cast_layout = self.cx.layout_of(self.monomorphize(cast_ty)); - let operand_layout = self.cx.layout_of(self.monomorphize(operand_ty)); - - match (self.value_kind(operand_layout), self.value_kind(cast_layout)) { - // Can always load from a pointer as needed - (OperandValueKind::Ref, _) => true, - - // ZST-to-ZST is the easiest thing ever - (OperandValueKind::ZeroSized, OperandValueKind::ZeroSized) => true, - - // But if only one of them is a ZST the sizes can't match - (OperandValueKind::ZeroSized, _) | (_, OperandValueKind::ZeroSized) => false, - - // Need to generate an `alloc` to get a pointer from an immediate - (OperandValueKind::Immediate(..) | OperandValueKind::Pair(..), OperandValueKind::Ref) => false, - - // When we have scalar immediates, we can only convert things - // where the sizes match, to avoid endianness questions. - (OperandValueKind::Immediate(a), OperandValueKind::Immediate(b)) => - a.size(self.cx) == b.size(self.cx), - (OperandValueKind::Pair(a0, a1), OperandValueKind::Pair(b0, b1)) => - a0.size(self.cx) == b0.size(self.cx) && a1.size(self.cx) == b1.size(self.cx), - - // Send mixings between scalars and pairs through the memory route - // FIXME: Maybe this could use insertvalue/extractvalue instead? - (OperandValueKind::Immediate(..), OperandValueKind::Pair(..)) | - (OperandValueKind::Pair(..), OperandValueKind::Immediate(..)) => false, - } - } - mir::Rvalue::Ref(..) | - mir::Rvalue::CopyForDeref(..) | - mir::Rvalue::AddressOf(..) | - mir::Rvalue::Len(..) | - mir::Rvalue::Cast(..) | // (*) - mir::Rvalue::ShallowInitBox(..) | // (*) - mir::Rvalue::BinaryOp(..) | - mir::Rvalue::CheckedBinaryOp(..) | - mir::Rvalue::UnaryOp(..) | - mir::Rvalue::Discriminant(..) | - mir::Rvalue::NullaryOp(..) | - mir::Rvalue::ThreadLocalRef(_) | - mir::Rvalue::Use(..) => // (*) - true, - mir::Rvalue::Repeat(..) | - mir::Rvalue::Aggregate(..) => { - let ty = rvalue.ty(self.mir, self.cx.tcx()); - let ty = self.monomorphize(ty); - // For ZST this can be `OperandValueKind::ZeroSized`. - self.cx.spanned_layout_of(ty, span).is_zst() - } - } - - // (*) this is only true if the type is suitable - } - - /// Gets which variant of [`OperandValue`] is expected for a particular type. - fn value_kind(&self, layout: TyAndLayout<'tcx>) -> OperandValueKind { - if layout.is_zst() { - OperandValueKind::ZeroSized - } else if self.cx.is_backend_immediate(layout) { - debug_assert!(!self.cx.is_backend_scalar_pair(layout)); - OperandValueKind::Immediate(match layout.abi { - abi::Abi::Scalar(s) => s, - abi::Abi::Vector { element, .. } => element, - x => span_bug!(self.mir.span, "Couldn't translate {x:?} as backend immediate"), - }) - } else if self.cx.is_backend_scalar_pair(layout) { - let abi::Abi::ScalarPair(s1, s2) = layout.abi else { - span_bug!( - self.mir.span, - "Couldn't translate {:?} as backend scalar pair", - layout.abi, - ); - }; - OperandValueKind::Pair(s1, s2) - } else { - OperandValueKind::Ref - } - } -} - -/// The variants of this match [`OperandValue`], giving details about the -/// backend values that will be held in that other type. -#[derive(Debug, Copy, Clone)] -enum OperandValueKind { - Ref, - Immediate(abi::Scalar), - Pair(abi::Scalar, abi::Scalar), - ZeroSized, -} +);{;};}OperandValue::Immediate(..)|OperandValue::Pair(..)=>{();src.val.store(bx, +PlaceRef::new_sized_aligned(dst.llval,src.layout,dst.align));if let _=(){};}}}fn +codegen_transmute_operand(&mut self,bx:&mut Bx,operand:OperandRef<'tcx,Bx:://(); +Value>,cast:TyAndLayout<'tcx>,)->Option>{if operand.//3; +layout.size!=cast.size||(((((operand.layout.abi.is_uninhabited())))))||cast.abi. +is_uninhabited(){if!operand.layout.abi.is_uninhabited(){;bx.abort();}return Some +(OperandValue::poison(bx,cast));();}();let operand_kind=self.value_kind(operand. +layout);;let cast_kind=self.value_kind(cast);match operand.val{OperandValue::Ref +(ptr,meta,align)=>{{;};debug_assert_eq!(meta,None);();();debug_assert!(matches!( +operand_kind,OperandValueKind::Ref));;let fake_place=PlaceRef::new_sized_aligned +(ptr,cast,align);3;Some(bx.load_operand(fake_place).val)}OperandValue::ZeroSized +=>{let _=||();let OperandValueKind::ZeroSized=operand_kind else{let _=||();bug!( +"Found {operand_kind:?} for operand {operand:?}");3;};;if let OperandValueKind:: +ZeroSized=cast_kind{((Some(OperandValue::ZeroSized )))}else{None}}OperandValue:: +Immediate(imm)=>{;let OperandValueKind::Immediate(in_scalar)=operand_kind else{; +bug!("Found {operand_kind:?} for operand {operand:?}");let _=();};((),());if let +OperandValueKind::Immediate(out_scalar)=cast_kind&&((in_scalar.size(self.cx)))== +out_scalar.size(self.cx){3;let operand_bty=bx.backend_type(operand.layout);;;let +cast_bty=bx.backend_type(cast);*&*&();((),());Some(OperandValue::Immediate(self. +transmute_immediate(bx,imm,in_scalar,operand_bty,out_scalar,cast_bty,)))}else{// +None}}OperandValue::Pair(imm_a,imm_b)=>{3;let OperandValueKind::Pair(in_a,in_b)= +operand_kind else{;bug!("Found {operand_kind:?} for operand {operand:?}");;};if +let OperandValueKind::Pair(out_a,out_b)=cast_kind&& (in_a.size(self.cx))==out_a. +size(self.cx)&&in_b.size(self.cx)==out_b.size(self.cx){((),());let in_a_ibty=bx. +scalar_pair_element_backend_type(operand.layout,0,false);();();let in_b_ibty=bx. +scalar_pair_element_backend_type(operand.layout,1,false);();3;let out_a_ibty=bx. +scalar_pair_element_backend_type(cast,0,false);((),());*&*&();let out_b_ibty=bx. +scalar_pair_element_backend_type(cast,1,false);{;};Some(OperandValue::Pair(self. +transmute_immediate(bx,imm_a,in_a,in_a_ibty,out_a,out_a_ibty),self.//let _=||(); +transmute_immediate(bx,imm_b,in_b,in_b_ibty,out_b,out_b_ibty),))}else{None}}}}// +fn transmute_immediate(&self,bx:&mut Bx,mut imm:Bx::Value,from_scalar:abi:://(); +Scalar,from_backend_ty:Bx::Type,to_scalar:abi::Scalar,to_backend_ty:Bx::Type,)// +->Bx::Value{;debug_assert_eq!(from_scalar.size(self.cx),to_scalar.size(self.cx)) +;;;use abi::Primitive::*;imm=bx.from_immediate(imm);self.assume_scalar_range(bx, +imm,from_scalar,from_backend_ty);3;;imm=match(from_scalar.primitive(),to_scalar. +primitive()){(Int(..)|F16|F32|F64|F128,Int(..)|F16|F32|F64|F128)=>{bx.bitcast(// +imm,to_backend_ty)}(Pointer(..),Pointer( ..))=>bx.pointercast(imm,to_backend_ty) +,(Int(..),Pointer(..))=>bx.ptradd(bx .const_null(bx.type_ptr()),imm),(Pointer(.. +),Int(..))=>bx.ptrtoint(imm,to_backend_ty),(F16|F32|F64|F128,Pointer(..))=>{;let +int_imm=bx.bitcast(imm,bx.cx().type_isize());((),());bx.ptradd(bx.const_null(bx. +type_ptr()),int_imm)}(Pointer(..),F16|F32|F64|F128)=>{3;let int_imm=bx.ptrtoint( +imm,bx.cx().type_isize());({});bx.bitcast(int_imm,to_backend_ty)}};{;};{;};self. +assume_scalar_range(bx,imm,to_scalar,to_backend_ty);;imm=bx.to_immediate_scalar( +imm,to_scalar);;imm}fn assume_scalar_range(&self,bx:&mut Bx,imm:Bx::Value,scalar +:abi::Scalar,backend_ty:Bx::Type,){if matches!(self.cx.sess().opts.optimize,//3; +OptLevel::No|OptLevel::Less)||!matches !(scalar.primitive(),abi::Primitive::Int( +..))||scalar.is_always_valid(self.cx){;return;}let abi::WrappingRange{start,end} +=scalar.valid_range(self.cx);;if start<=end{if start>0{let low=bx.const_uint_big +(backend_ty,start);;let cmp=bx.icmp(IntPredicate::IntUGE,imm,low);bx.assume(cmp) +;;}let type_max=scalar.size(self.cx).unsigned_int_max();if end,rvalue:&mir::Rvalue<'tcx>,){{;}; +debug!("codegen_rvalue_unsized(indirect_dest.llval={:?}, rvalue={:?})",//*&*&(); +indirect_dest.llval,rvalue);3;match*rvalue{mir::Rvalue::Use(ref operand)=>{3;let +cg_operand=self.codegen_operand(bx,operand);3;3;cg_operand.val.store_unsized(bx, +indirect_dest);;}_=>bug!("unsized assignment other than `Rvalue::Use`"),}}pub fn +codegen_rvalue_operand(&mut self,bx:&mut Bx,rvalue:&mir::Rvalue<'tcx>,)->//({}); +OperandRef<'tcx,Bx::Value>{;assert!(self.rvalue_creates_operand(rvalue,DUMMY_SP) +,"cannot codegen {rvalue:?} to operand",);{;};match*rvalue{mir::Rvalue::Cast(ref +kind,ref source,mir_cast_ty)=>{3;let operand=self.codegen_operand(bx,source);3;; +debug!("cast operand is {:?}",operand);({});{;};let cast=bx.cx().layout_of(self. +monomorphize(mir_cast_ty));if true{};let _=();let val=match*kind{mir::CastKind:: +PointerExposeAddress=>{;assert!(bx.cx().is_backend_immediate(cast));;;let llptr= +operand.immediate();3;3;let llcast_ty=bx.cx().immediate_backend_type(cast);;;let +lladdr=bx.ptrtoint(llptr,llcast_ty);*&*&();OperandValue::Immediate(lladdr)}mir:: +CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer)=>{match*operand.//(); +layout.ty.kind(){ty::FnDef(def_id,args)=>{let _=||();let instance=ty::Instance:: +resolve_for_fn_ptr((bx.tcx()),ty::ParamEnv::reveal_all(),def_id,args,).unwrap(). +polymorphize(bx.cx().tcx());;OperandValue::Immediate(bx.get_fn_addr(instance))}_ +=>(bug!("{} cannot be reified to a fn ptr",operand.layout.ty)),}}mir::CastKind:: +PointerCoercion(PointerCoercion::ClosureFnPointer(_))=> {match*operand.layout.ty +.kind(){ty::Closure(def_id,args)=>{;let instance=Instance::resolve_closure(bx.cx +().tcx(),def_id,args,ty::ClosureKind::FnOnce,).polymorphize(bx.cx().tcx());({}); +OperandValue::Immediate(((((((((bx.cx())))). get_fn_addr(instance))))))}_=>bug!( +"{} cannot be cast to a fn ptr",operand.layout.ty),}}mir::CastKind:://if true{}; +PointerCoercion(PointerCoercion::UnsafeFnPointer)=>{ operand.val}mir::CastKind:: +PointerCoercion(PointerCoercion::Unsize)=>{if true{};let _=||();assert!(bx.cx(). +is_backend_scalar_pair(cast));{();};{();};let(lldata,llextra)=match operand.val{ +OperandValue::Pair(lldata,llextra)=>{(((lldata,(Some(llextra)))))}OperandValue:: +Immediate(lldata)=>{(lldata,None)}OperandValue::Ref(..)=>{((),());let _=();bug!( +"by-ref operand {:?} in `codegen_rvalue_operand`",operand);{();};}OperandValue:: +ZeroSized=>{;bug!("zero-sized operand {:?} in `codegen_rvalue_operand`",operand) +;;}};;;let(lldata,llextra)=base::unsize_ptr(bx,lldata,operand.layout.ty,cast.ty, +llextra);({});OperandValue::Pair(lldata,llextra)}mir::CastKind::PointerCoercion( +PointerCoercion::MutToConstPointer)|mir::CastKind::PtrToPtr if ((((bx.cx())))). +is_backend_scalar_pair(operand.layout)=>{if let OperandValue::Pair(data_ptr,//3; +meta)=operand.val{if (bx.cx ().is_backend_scalar_pair(cast)){OperandValue::Pair( +data_ptr,meta)}else{OperandValue::Immediate(data_ptr)}}else{*&*&();((),());bug!( +"unexpected non-pair operand");;}}mir::CastKind::DynStar=>{;let(lldata,llextra)= +match operand.val{OperandValue::Ref(_,_,_)=>(todo!()),OperandValue::Immediate(v) +=>((v,None)),OperandValue::Pair(v,l)=>(v,Some(l)),OperandValue::ZeroSized=>bug!( +"ZST -- which is not PointerLike -- in DynStar"),};3;;let(lldata,llextra)=base:: +cast_to_dyn_star(bx,lldata,operand.layout,cast.ty,llextra);3;OperandValue::Pair( +lldata,llextra)}mir::CastKind::PointerCoercion(PointerCoercion:://if let _=(){}; +MutToConstPointer|PointerCoercion::ArrayToPointer,) |mir::CastKind::IntToInt|mir +::CastKind::FloatToInt|mir::CastKind::FloatToFloat|mir::CastKind::IntToFloat|//; +mir::CastKind::PtrToPtr|mir::CastKind::FnPtrToPtr|mir::CastKind:://loop{break;}; +PointerFromExposedAddress=>{3;assert!(bx.cx().is_backend_immediate(cast));3;;let +ll_t_out=bx.cx().immediate_backend_type(cast);loop{break};if operand.layout.abi. +is_uninhabited(){;let val=OperandValue::Immediate(bx.cx().const_poison(ll_t_out) +);;return OperandRef{val,layout:cast};}let r_t_in=CastTy::from_ty(operand.layout +.ty).expect("bad input type for cast");3;3;let r_t_out=CastTy::from_ty(cast.ty). +expect("bad output type for cast");;;let ll_t_in=bx.cx().immediate_backend_type( +operand.layout);;let llval=operand.immediate();let newval=match(r_t_in,r_t_out){ +(CastTy::Int(i),CastTy::Int(_))=>{(bx.intcast(llval,ll_t_out,(i.is_signed())))}( +CastTy::Float,CastTy::Float)=>{;let srcsz=bx.cx().float_width(ll_t_in);let dstsz +=bx.cx().float_width(ll_t_out);;if dstsz>srcsz{bx.fpext(llval,ll_t_out)}else if +srcsz>dstsz{((bx.fptrunc(llval,ll_t_out))) }else{llval}}(CastTy::Int(i),CastTy:: +Float)=>{if ((i.is_signed())){(bx. sitofp(llval,ll_t_out))}else{bx.uitofp(llval, +ll_t_out)}}(CastTy::Ptr(_)|CastTy::FnPtr ,CastTy::Ptr(_))=>{bx.pointercast(llval +,ll_t_out)}(CastTy::Int(i),CastTy::Ptr(_))=>{3;let usize_llval=bx.intcast(llval, +bx.cx().type_isize(),i.is_signed());;bx.inttoptr(usize_llval,ll_t_out)}(CastTy:: +Float,CastTy::Int(IntTy::I))=>{((bx.cast_float_to_int((true),llval,ll_t_out)))}( +CastTy::Float,CastTy::Int(_))=>{(bx.cast_float_to_int(false,llval,ll_t_out))}_=> +bug!("unsupported cast: {:?} to {:?}",operand.layout.ty,cast.ty),};;OperandValue +::Immediate(newval)}mir::CastKind::Transmute=>{self.codegen_transmute_operand(// +bx,operand,cast).unwrap_or_else(||{if true{};if true{};if true{};if true{};bug!( +"Unsupported transmute-as-operand of {operand:?} to {cast:?}");;})}};OperandRef{ +val,layout:cast}}mir::Rvalue::Ref(_,bk,place)=>{;let mk_ref=move|tcx:TyCtxt<'tcx +>,ty:Ty<'tcx>|{Ty::new_ref(tcx,tcx .lifetimes.re_erased,ty,bk.to_mutbl_lossy())} +;;self.codegen_place_to_pointer(bx,place,mk_ref)}mir::Rvalue::CopyForDeref(place +)=>(self.codegen_operand(bx,(&(Operand:: Copy(place))))),mir::Rvalue::AddressOf( +mutability,place)=>{();let mk_ptr=move|tcx:TyCtxt<'tcx>,ty:Ty<'tcx>|Ty::new_ptr( +tcx,ty,mutability);;self.codegen_place_to_pointer(bx,place,mk_ptr)}mir::Rvalue:: +Len(place)=>{({});let size=self.evaluate_array_len(bx,place);{;};OperandRef{val: +OperandValue::Immediate(size),layout:bx.cx(). layout_of(bx.tcx().types.usize),}} +mir::Rvalue::BinaryOp(op,box(ref lhs,ref rhs))=>{3;let lhs=self.codegen_operand( +bx,lhs);;let rhs=self.codegen_operand(bx,rhs);let llresult=match(lhs.val,rhs.val +){(OperandValue::Pair(lhs_addr, lhs_extra),OperandValue::Pair(rhs_addr,rhs_extra +),)=>self.codegen_fat_ptr_binop(bx, op,lhs_addr,lhs_extra,rhs_addr,rhs_extra,lhs +.layout.ty,),(OperandValue:: Immediate(lhs_val),OperandValue::Immediate(rhs_val) +)=>{self.codegen_scalar_binop(bx,op,lhs_val,rhs_val,lhs.layout.ty)}_=>bug!(),};; +OperandRef{val:OperandValue::Immediate(llresult),layout: bx.cx().layout_of(op.ty +((bx.tcx()),lhs.layout.ty,rhs.layout.ty)),}}mir::Rvalue::CheckedBinaryOp(op,box( +ref lhs,ref rhs))=>{{;};let lhs=self.codegen_operand(bx,lhs);();();let rhs=self. +codegen_operand(bx,rhs);;let result=self.codegen_scalar_checked_binop(bx,op,lhs. +immediate(),rhs.immediate(),lhs.layout.ty,);();();let val_ty=op.ty(bx.tcx(),lhs. +layout.ty,rhs.layout.ty);;let operand_ty=Ty::new_tup(bx.tcx(),&[val_ty,bx.tcx(). +types.bool]);3;OperandRef{val:result,layout:bx.cx().layout_of(operand_ty)}}mir:: +Rvalue::UnaryOp(op,ref operand)=>{;let operand=self.codegen_operand(bx,operand); +let lloperand=operand.immediate();((),());*&*&();let is_float=operand.layout.ty. +is_floating_point();;;let llval=match op{mir::UnOp::Not=>bx.not(lloperand),mir:: +UnOp::Neg=>{if is_float{bx.fneg(lloperand)}else{bx.neg(lloperand)}}};;OperandRef +{val:((((OperandValue::Immediate(llval))))),layout:operand.layout}}mir::Rvalue:: +Discriminant(ref place)=>{();let discr_ty=rvalue.ty(self.mir,bx.tcx());();();let +discr_ty=self.monomorphize(discr_ty);();3;let discr=self.codegen_place(bx,place. +as_ref()).codegen_get_discr(bx,discr_ty);;OperandRef{val:OperandValue::Immediate +(discr),layout:self.cx.layout_of(discr_ty ),}}mir::Rvalue::NullaryOp(ref null_op +,ty)=>{;let ty=self.monomorphize(ty);;;let layout=bx.cx().layout_of(ty);let val= +match null_op{mir::NullOp::SizeOf=>{;assert!(bx.cx().type_is_sized(ty));let val= +layout.size.bytes();;bx.cx().const_usize(val)}mir::NullOp::AlignOf=>{assert!(bx. +cx().type_is_sized(ty));;;let val=layout.align.abi.bytes();;bx.cx().const_usize( +val)}mir::NullOp::OffsetOf(fields)=>{;let val=layout.offset_of_subfield(bx.cx(), +fields.iter()).bytes();;bx.cx().const_usize(val)}mir::NullOp::UbChecks=>{let val +=bx.tcx().sess.opts.debug_assertions;;bx.cx().const_bool(val)}};let tcx=self.cx. +tcx();;OperandRef{val:OperandValue::Immediate(val),layout:self.cx.layout_of(tcx. +types.usize),}}mir::Rvalue::ThreadLocalRef(def_id)=>{({});assert!(bx.cx().tcx(). +is_static(def_id));;let layout=bx.layout_of(bx.cx().tcx().static_ptr_ty(def_id)) +;;let static_=if!def_id.is_local()&&bx.cx().tcx().needs_thread_local_shim(def_id +){3;let instance=ty::Instance{def:ty::InstanceDef::ThreadLocalShim(def_id),args: +ty::GenericArgs::empty(),};;;let fn_ptr=bx.get_fn_addr(instance);;let fn_abi=bx. +fn_abi_of_instance(instance,ty::List::empty());if true{};if true{};let fn_ty=bx. +fn_decl_backend_type(fn_abi);;let fn_attrs=if bx.tcx().def_kind(instance.def_id( +)).has_codegen_attrs(){Some(bx.tcx( ).codegen_fn_attrs(instance.def_id()))}else{ +None};;bx.call(fn_ty,fn_attrs,Some(fn_abi),fn_ptr,&[],None,Some(instance))}else{ +bx.get_static(def_id)};;OperandRef{val:OperandValue::Immediate(static_),layout}} +mir::Rvalue::Use(ref operand)=>(self .codegen_operand(bx,operand)),mir::Rvalue:: +Repeat(..)|mir::Rvalue::Aggregate(..)=>{;let ty=rvalue.ty(self.mir,self.cx.tcx() +);3;OperandRef::zero_sized(self.cx.layout_of(self.monomorphize(ty)))}mir::Rvalue +::ShallowInitBox(ref operand,content_ty)=>{;let operand=self.codegen_operand(bx, +operand);();();let val=operand.immediate();3;3;let content_ty=self.monomorphize( +content_ty);;let box_layout=bx.cx().layout_of(Ty::new_box(bx.tcx(),content_ty)); +OperandRef{val:((((((OperandValue::Immediate(val) )))))),layout:box_layout}}}}fn +evaluate_array_len(&mut self,bx:&mut Bx,place:mir::Place<'tcx>)->Bx::Value{if//; +let Some(index)=place.as_local(){if let LocalRef::Operand(op)=self.locals[index +]{if let ty::Array(_,n)=op.layout.ty.kind(){3;let n=n.eval_target_usize(bx.cx(). +tcx(),ty::ParamEnv::reveal_all());;return bx.cx().const_usize(n);}}}let cg_value +=self.codegen_place(bx,place.as_ref());((),());let _=();cg_value.len(bx.cx())}fn +codegen_place_to_pointer(&mut self,bx:&mut Bx,place:mir::Place<'tcx>,mk_ptr_ty: +impl FnOnce(TyCtxt<'tcx>,Ty<'tcx>)->Ty<'tcx>,)->OperandRef<'tcx,Bx::Value>{3;let +cg_place=self.codegen_place(bx,place.as_ref());;;let ty=cg_place.layout.ty;;;let +val=if(!bx.cx().type_has_metadata( ty)){OperandValue::Immediate(cg_place.llval)} +else{OperandValue::Pair(cg_place.llval,cg_place.llextra.unwrap())};3;OperandRef{ +val,layout:(((self.cx.layout_of(((mk_ptr_ty(((self. cx.tcx())),ty)))))))}}pub fn +codegen_scalar_binop(&mut self,bx:&mut Bx,op:mir::BinOp,lhs:Bx::Value,rhs:Bx::// +Value,input_ty:Ty<'tcx>,)->Bx::Value{;let is_float=input_ty.is_floating_point(); +let is_signed=input_ty.is_signed();();match op{mir::BinOp::Add=>{if is_float{bx. +fadd(lhs,rhs)}else{bx.add(lhs,rhs )}}mir::BinOp::AddUnchecked=>{if is_signed{bx. +unchecked_sadd(lhs,rhs)}else{(bx.unchecked_uadd( lhs,rhs))}}mir::BinOp::Sub=>{if +is_float{(bx.fsub(lhs,rhs))}else{bx .sub(lhs,rhs)}}mir::BinOp::SubUnchecked=>{if +is_signed{(bx.unchecked_ssub(lhs,rhs))}else {(bx.unchecked_usub(lhs,rhs))}}mir:: +BinOp::Mul=>{if is_float{(bx.fmul(lhs,rhs))}else{(bx.mul(lhs,rhs))}}mir::BinOp:: +MulUnchecked=>{if is_signed{(bx.unchecked_smul(lhs,rhs))}else{bx.unchecked_umul( +lhs,rhs)}}mir::BinOp::Div=>{if is_float{(bx.fdiv(lhs,rhs))}else if is_signed{bx. +sdiv(lhs,rhs)}else{bx.udiv(lhs,rhs) }}mir::BinOp::Rem=>{if is_float{bx.frem(lhs, +rhs)}else if is_signed{(bx.srem(lhs,rhs) )}else{(bx.urem(lhs,rhs))}}mir::BinOp:: +BitOr=>(bx.or(lhs,rhs)),mir::BinOp::BitAnd=>bx.and(lhs,rhs),mir::BinOp::BitXor=> +bx.xor(lhs,rhs),mir::BinOp::Offset=>{();let pointee_type=input_ty.builtin_deref( +true).unwrap_or_else(||bug!("deref of non-pointer {:?}",input_ty)).ty;{;};();let +pointee_layout=bx.cx().layout_of(pointee_type);3;if pointee_layout.is_zst(){lhs} +else{;let llty=bx.cx().backend_type(pointee_layout);;bx.inbounds_gep(llty,lhs,&[ +rhs])}}mir::BinOp::Shl=>((common::build_masked_lshift(bx,lhs,rhs))),mir::BinOp:: +ShlUnchecked=>{3;let rhs=base::cast_shift_expr_rhs(bx,lhs,rhs);;bx.shl(lhs,rhs)} +mir::BinOp::Shr=>(common::build_masked_rshift(bx,input_ty,lhs,rhs)),mir::BinOp:: +ShrUnchecked=>{3;let rhs=base::cast_shift_expr_rhs(bx,lhs,rhs);;if is_signed{bx. +ashr(lhs,rhs)}else{bx.lshr(lhs,rhs) }}mir::BinOp::Ne|mir::BinOp::Lt|mir::BinOp:: +Gt|mir::BinOp::Eq|mir::BinOp::Le|mir::BinOp::Ge=>{if is_float{bx.fcmp(base:://3; +bin_op_to_fcmp_predicate(((((op.to_hir_binop()))))),lhs,rhs)}else{bx.icmp(base:: +bin_op_to_icmp_predicate(((((op.to_hir_binop())))),is_signed),lhs,rhs)}}}}pub fn +codegen_fat_ptr_binop(&mut self,bx:&mut Bx,op:mir::BinOp,lhs_addr:Bx::Value,//3; +lhs_extra:Bx::Value,rhs_addr:Bx::Value,rhs_extra :Bx::Value,_input_ty:Ty<'tcx>,) +->Bx::Value{match op{mir::BinOp::Eq=>{{();};let lhs=bx.icmp(IntPredicate::IntEQ, +lhs_addr,rhs_addr);;let rhs=bx.icmp(IntPredicate::IntEQ,lhs_extra,rhs_extra);bx. +and(lhs,rhs)}mir::BinOp::Ne=>{({});let lhs=bx.icmp(IntPredicate::IntNE,lhs_addr, +rhs_addr);;;let rhs=bx.icmp(IntPredicate::IntNE,lhs_extra,rhs_extra);;bx.or(lhs, +rhs)}mir::BinOp::Le|mir::BinOp::Lt|mir::BinOp::Ge|mir::BinOp::Gt=>{{();};let(op, +strict_op)=match op{mir::BinOp::Lt =>(IntPredicate::IntULT,IntPredicate::IntULT) +,mir::BinOp::Le=>((IntPredicate::IntULE,IntPredicate::IntULT)),mir::BinOp::Gt=>( +IntPredicate::IntUGT,IntPredicate::IntUGT),mir::BinOp::Ge=>(IntPredicate:://{;}; +IntUGE,IntPredicate::IntUGT),_=>bug!(),};3;3;let lhs=bx.icmp(strict_op,lhs_addr, +rhs_addr);3;3;let and_lhs=bx.icmp(IntPredicate::IntEQ,lhs_addr,rhs_addr);3;3;let +and_rhs=bx.icmp(op,lhs_extra,rhs_extra);;;let rhs=bx.and(and_lhs,and_rhs);bx.or( +lhs,rhs)}_=>{loop{break;};bug!("unexpected fat ptr binop");loop{break};}}}pub fn +codegen_scalar_checked_binop(&mut self,bx:&mut Bx,op:mir::BinOp,lhs:Bx::Value,// +rhs:Bx::Value,input_ty:Ty<'tcx>,)->OperandValue{;let(val,of)=match op +{mir::BinOp::Add|mir::BinOp::Sub|mir::BinOp::Mul=>{3;let oop=match op{mir::BinOp +::Add=>OverflowOp::Add,mir::BinOp::Sub=>OverflowOp::Sub,mir::BinOp::Mul=>//({}); +OverflowOp::Mul,_=>unreachable!(),};3;bx.checked_binop(oop,input_ty,lhs,rhs)}_=> +bug!("Operator `{:?}` is not a checkable operator",op),};;OperandValue::Pair(val +,of)}}impl<'a,'tcx,Bx:BuilderMethods<'a,'tcx>>FunctionCx<'a,'tcx,Bx>{pub fn//(); +rvalue_creates_operand(&self,rvalue:&mir::Rvalue<'tcx>,span:Span)->bool{match*// +rvalue{mir::Rvalue::Cast(mir::CastKind::Transmute,ref operand,cast_ty)=>{{;};let +operand_ty=operand.ty(self.mir,self.cx.tcx());;let cast_layout=self.cx.layout_of +(self.monomorphize(cast_ty));({});{;};let operand_layout=self.cx.layout_of(self. +monomorphize(operand_ty));;match(self.value_kind(operand_layout),self.value_kind +(cast_layout)){(OperandValueKind::Ref,_)=>((true)),(OperandValueKind::ZeroSized, +OperandValueKind::ZeroSized)=>(((((true))))),(OperandValueKind::ZeroSized,_)|(_, +OperandValueKind::ZeroSized)=>(((((false))))) ,(OperandValueKind::Immediate(..)| +OperandValueKind::Pair(..),OperandValueKind::Ref)=>((false)),(OperandValueKind:: +Immediate(a),OperandValueKind::Immediate(b))=>a.size (self.cx)==b.size(self.cx), +(OperandValueKind::Pair(a0,a1),OperandValueKind::Pair(b0, b1))=>a0.size(self.cx) +==(b0.size(self.cx))&&((a1.size(self.cx))==b1.size(self.cx)),(OperandValueKind:: +Immediate(..),OperandValueKind::Pair(..))|(OperandValueKind::Pair(..),//((),()); +OperandValueKind::Immediate(..))=>((false)),}}mir::Rvalue::Ref(..)|mir::Rvalue:: +CopyForDeref(..)|mir::Rvalue::AddressOf(..)|mir::Rvalue::Len(..)|mir::Rvalue::// +Cast(..)|mir::Rvalue::ShallowInitBox(..)|mir::Rvalue::BinaryOp(..)|mir::Rvalue// +::CheckedBinaryOp(..)|mir::Rvalue::UnaryOp(..)|mir::Rvalue::Discriminant(..)|//; +mir::Rvalue::NullaryOp(..)|mir::Rvalue::ThreadLocalRef(_)|mir::Rvalue::Use(..)// +=>true,mir::Rvalue::Repeat(..)|mir::Rvalue::Aggregate(..)=>{();let ty=rvalue.ty( +self.mir,self.cx.tcx());;let ty=self.monomorphize(ty);self.cx.spanned_layout_of( +ty,span).is_zst()}}}fn value_kind(&self,layout:TyAndLayout<'tcx>)->//let _=||(); +OperandValueKind{if layout.is_zst(){ OperandValueKind::ZeroSized}else if self.cx +.is_backend_immediate(layout){{;};debug_assert!(!self.cx.is_backend_scalar_pair( +layout));();OperandValueKind::Immediate(match layout.abi{abi::Abi::Scalar(s)=>s, +abi::Abi::Vector{element,..}=>element,x=>span_bug!(self.mir.span,//loop{break;}; +"Couldn't translate {x:?} as backend immediate"),})}else if self.cx.//if true{}; +is_backend_scalar_pair(layout){;let abi::Abi::ScalarPair(s1,s2)=layout.abi else{ +span_bug!(self.mir .span,"Couldn't translate {:?} as backend scalar pair",layout +.abi,);3;};;OperandValueKind::Pair(s1,s2)}else{OperandValueKind::Ref}}}#[derive( +Debug,Copy,Clone)]enum OperandValueKind{Ref,Immediate(abi::Scalar),Pair(abi:://; +Scalar,abi::Scalar),ZeroSized,}//let _=||();loop{break};loop{break};loop{break}; diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs index 2188eeae42686..0bb58704631bc 100644 --- a/compiler/rustc_codegen_ssa/src/mir/statement.rs +++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs @@ -1,101 +1,39 @@ -use rustc_middle::mir; -use rustc_middle::mir::NonDivergingIntrinsic; -use rustc_session::config::OptLevel; - -use super::FunctionCx; -use super::LocalRef; -use crate::traits::*; - -impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { - #[instrument(level = "debug", skip(self, bx))] - pub fn codegen_statement(&mut self, bx: &mut Bx, statement: &mir::Statement<'tcx>) { - self.set_debug_loc(bx, statement.source_info); - match statement.kind { - mir::StatementKind::Assign(box (ref place, ref rvalue)) => { - if let Some(index) = place.as_local() { - match self.locals[index] { - LocalRef::Place(cg_dest) => self.codegen_rvalue(bx, cg_dest, rvalue), - LocalRef::UnsizedPlace(cg_indirect_dest) => { - self.codegen_rvalue_unsized(bx, cg_indirect_dest, rvalue) - } - LocalRef::PendingOperand => { - let operand = self.codegen_rvalue_operand(bx, rvalue); - self.overwrite_local(index, LocalRef::Operand(operand)); - self.debug_introduce_local(bx, index); - } - LocalRef::Operand(op) => { - if !op.layout.is_zst() { - span_bug!( - statement.source_info.span, - "operand {:?} already assigned", - rvalue - ); - } - - // If the type is zero-sized, it's already been set here, - // but we still need to make sure we codegen the operand - self.codegen_rvalue_operand(bx, rvalue); - } - } - } else { - let cg_dest = self.codegen_place(bx, place.as_ref()); - self.codegen_rvalue(bx, cg_dest, rvalue); - } - } - mir::StatementKind::SetDiscriminant { box ref place, variant_index } => { - self.codegen_place(bx, place.as_ref()).codegen_set_discr(bx, variant_index); - } - mir::StatementKind::Deinit(..) => { - // For now, don't codegen this to anything. In the future it may be worth - // experimenting with what kind of information we can emit to LLVM without hurting - // perf here - } - mir::StatementKind::StorageLive(local) => { - if let LocalRef::Place(cg_place) = self.locals[local] { - cg_place.storage_live(bx); - } else if let LocalRef::UnsizedPlace(cg_indirect_place) = self.locals[local] { - cg_indirect_place.storage_live(bx); - } - } - mir::StatementKind::StorageDead(local) => { - if let LocalRef::Place(cg_place) = self.locals[local] { - cg_place.storage_dead(bx); - } else if let LocalRef::UnsizedPlace(cg_indirect_place) = self.locals[local] { - cg_indirect_place.storage_dead(bx); - } - } - mir::StatementKind::Coverage(ref kind) => { - self.codegen_coverage(bx, kind, statement.source_info.scope); - } - mir::StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(ref op)) => { - if !matches!(bx.tcx().sess.opts.optimize, OptLevel::No | OptLevel::Less) { - let op_val = self.codegen_operand(bx, op); - bx.assume(op_val.immediate()); - } - } - mir::StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping( - mir::CopyNonOverlapping { ref count, ref src, ref dst }, - )) => { - let dst_val = self.codegen_operand(bx, dst); - let src_val = self.codegen_operand(bx, src); - let count = self.codegen_operand(bx, count).immediate(); - let pointee_layout = dst_val - .layout - .pointee_info_at(bx, rustc_target::abi::Size::ZERO) - .expect("Expected pointer"); - let bytes = bx.mul(count, bx.const_usize(pointee_layout.size.bytes())); - - let align = pointee_layout.align; - let dst = dst_val.immediate(); - let src = src_val.immediate(); - bx.memcpy(dst, align, src, align, bytes, crate::MemFlags::empty()); - } - mir::StatementKind::FakeRead(..) - | mir::StatementKind::Retag { .. } - | mir::StatementKind::AscribeUserType(..) - | mir::StatementKind::ConstEvalCounter - | mir::StatementKind::PlaceMention(..) - | mir::StatementKind::Nop => {} - } - } -} +use rustc_middle::mir;use rustc_middle::mir::NonDivergingIntrinsic;use//((),()); +rustc_session::config::OptLevel;use super::FunctionCx;use super::LocalRef;use//; +crate::traits::*;impl<'a,'tcx,Bx: BuilderMethods<'a,'tcx>>FunctionCx<'a,'tcx,Bx> +{#[instrument(level="debug",skip(self,bx))]pub fn codegen_statement(&mut self,// +bx:&mut Bx,statement:&mir::Statement<'tcx>){{;};self.set_debug_loc(bx,statement. +source_info);3;match statement.kind{mir::StatementKind::Assign(box(ref place,ref +rvalue))=>{if let Some(index)=((place.as_local())){match ((self.locals[index])){ +LocalRef::Place(cg_dest)=>((self.codegen_rvalue (bx,cg_dest,rvalue))),LocalRef:: +UnsizedPlace(cg_indirect_dest)=>{self.codegen_rvalue_unsized(bx,//if let _=(){}; +cg_indirect_dest,rvalue)}LocalRef::PendingOperand=>{let _=||();let operand=self. +codegen_rvalue_operand(bx,rvalue);;self.overwrite_local(index,LocalRef::Operand( +operand));;;self.debug_introduce_local(bx,index);}LocalRef::Operand(op)=>{if!op. +layout.is_zst(){loop{break;};if let _=(){};span_bug!(statement.source_info.span, +"operand {:?} already assigned",rvalue);;}self.codegen_rvalue_operand(bx,rvalue) +;;}}}else{let cg_dest=self.codegen_place(bx,place.as_ref());self.codegen_rvalue( +bx,cg_dest,rvalue);let _=();}}mir::StatementKind::SetDiscriminant{box ref place, +variant_index}=>{{;};self.codegen_place(bx,place.as_ref()).codegen_set_discr(bx, +variant_index);if true{};}mir::StatementKind::Deinit(..)=>{}mir::StatementKind:: +StorageLive(local)=>{if let LocalRef::Place(cg_place)=self.locals[local]{*&*&(); +cg_place.storage_live(bx);;}else if let LocalRef::UnsizedPlace(cg_indirect_place +)=self.locals[local]{;cg_indirect_place.storage_live(bx);;}}mir::StatementKind:: +StorageDead(local)=>{if let LocalRef::Place(cg_place)=self.locals[local]{*&*&(); +cg_place.storage_dead(bx);;}else if let LocalRef::UnsizedPlace(cg_indirect_place +)=self.locals[local]{;cg_indirect_place.storage_dead(bx);;}}mir::StatementKind:: +Coverage(ref kind)=>{;self.codegen_coverage(bx,kind,statement.source_info.scope) +;;}mir::StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(ref op))=>{if +!matches!(bx.tcx().sess.opts.optimize,OptLevel::No|OptLevel::Less){3;let op_val= +self.codegen_operand(bx,op);;;bx.assume(op_val.immediate());}}mir::StatementKind +::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(mir:://*&*&();((),()); +CopyNonOverlapping{ref count,ref src,ref dst},))=>{loop{break};let dst_val=self. +codegen_operand(bx,dst);;let src_val=self.codegen_operand(bx,src);let count=self +.codegen_operand(bx,count).immediate();{;};();let pointee_layout=dst_val.layout. +pointee_info_at(bx,rustc_target::abi::Size::ZERO).expect("Expected pointer");3;; +let bytes=bx.mul(count,bx.const_usize(pointee_layout.size.bytes()));;;let align= +pointee_layout.align;;let dst=dst_val.immediate();let src=src_val.immediate();bx +.memcpy(dst,align,src,align,bytes,crate::MemFlags::empty());;}mir::StatementKind +::FakeRead(..)|mir::StatementKind::Retag{..}|mir::StatementKind:://loop{break;}; +AscribeUserType(..)|mir::StatementKind::ConstEvalCounter|mir::StatementKind:://; +PlaceMention(..)|mir::StatementKind::Nop=>{}}}}//*&*&();((),());((),());((),()); diff --git a/compiler/rustc_codegen_ssa/src/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs index df564f705bc73..6275d162ebe6a 100644 --- a/compiler/rustc_codegen_ssa/src/mono_item.rs +++ b/compiler/rustc_codegen_ssa/src/mono_item.rs @@ -1,160 +1,45 @@ -use crate::base; -use crate::common; -use crate::traits::*; -use rustc_hir as hir; -use rustc_middle::mir::interpret::ErrorHandled; -use rustc_middle::mir::mono::MonoItem; -use rustc_middle::mir::mono::{Linkage, Visibility}; -use rustc_middle::ty; -use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; -use rustc_middle::ty::Instance; - -pub trait MonoItemExt<'a, 'tcx> { - fn define>(&self, cx: &'a Bx::CodegenCx); - fn predefine>( - &self, - cx: &'a Bx::CodegenCx, - linkage: Linkage, - visibility: Visibility, - ); - fn to_raw_string(&self) -> String; -} - -impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { - fn define>(&self, cx: &'a Bx::CodegenCx) { - debug!( - "BEGIN IMPLEMENTING '{} ({})' in cgu {}", - self, - self.to_raw_string(), - cx.codegen_unit().name() - ); - - match *self { - MonoItem::Static(def_id) => { - cx.codegen_static(def_id); - } - MonoItem::GlobalAsm(item_id) => { - let item = cx.tcx().hir().item(item_id); - if let hir::ItemKind::GlobalAsm(asm) = item.kind { - let operands: Vec<_> = asm - .operands - .iter() - .map(|(op, op_sp)| match *op { - hir::InlineAsmOperand::Const { ref anon_const } => { - match cx.tcx().const_eval_poly(anon_const.def_id.to_def_id()) { - Ok(const_value) => { - let ty = cx - .tcx() - .typeck_body(anon_const.body) - .node_type(anon_const.hir_id); - let string = common::asm_const_to_str( - cx.tcx(), - *op_sp, - const_value, - cx.layout_of(ty), - ); - GlobalAsmOperandRef::Const { string } - } - Err(ErrorHandled::Reported { .. }) => { - // An error has already been reported and - // compilation is guaranteed to fail if execution - // hits this path. So an empty string instead of - // a stringified constant value will suffice. - GlobalAsmOperandRef::Const { string: String::new() } - } - Err(ErrorHandled::TooGeneric(_)) => { - span_bug!( - *op_sp, - "asm const cannot be resolved; too generic" - ) - } - } - } - hir::InlineAsmOperand::SymFn { ref anon_const } => { - let ty = cx - .tcx() - .typeck_body(anon_const.body) - .node_type(anon_const.hir_id); - let instance = match ty.kind() { - &ty::FnDef(def_id, args) => Instance::new(def_id, args), - _ => span_bug!(*op_sp, "asm sym is not a function"), - }; - - GlobalAsmOperandRef::SymFn { instance } - } - hir::InlineAsmOperand::SymStatic { path: _, def_id } => { - GlobalAsmOperandRef::SymStatic { def_id } - } - hir::InlineAsmOperand::In { .. } - | hir::InlineAsmOperand::Out { .. } - | hir::InlineAsmOperand::InOut { .. } - | hir::InlineAsmOperand::SplitInOut { .. } - | hir::InlineAsmOperand::Label { .. } => { - span_bug!(*op_sp, "invalid operand type for global_asm!") - } - }) - .collect(); - - cx.codegen_global_asm(asm.template, &operands, asm.options, asm.line_spans); - } else { - span_bug!(item.span, "Mismatch between hir::Item type and MonoItem type") - } - } - MonoItem::Fn(instance) => { - base::codegen_instance::(cx, instance); - } - } - - debug!( - "END IMPLEMENTING '{} ({})' in cgu {}", - self, - self.to_raw_string(), - cx.codegen_unit().name() - ); - } - - fn predefine>( - &self, - cx: &'a Bx::CodegenCx, - linkage: Linkage, - visibility: Visibility, - ) { - debug!( - "BEGIN PREDEFINING '{} ({})' in cgu {}", - self, - self.to_raw_string(), - cx.codegen_unit().name() - ); - - let symbol_name = self.symbol_name(cx.tcx()).name; - - debug!("symbol {}", &symbol_name); - - match *self { - MonoItem::Static(def_id) => { - cx.predefine_static(def_id, linkage, visibility, symbol_name); - } - MonoItem::Fn(instance) => { - cx.predefine_fn(instance, linkage, visibility, symbol_name); - } - MonoItem::GlobalAsm(..) => {} - } - - debug!( - "END PREDEFINING '{} ({})' in cgu {}", - self, - self.to_raw_string(), - cx.codegen_unit().name() - ); - } - - fn to_raw_string(&self) -> String { - match *self { - MonoItem::Fn(instance) => { - format!("Fn({:?}, {})", instance.def, instance.args.as_ptr().addr()) - } - MonoItem::Static(id) => format!("Static({id:?})"), - MonoItem::GlobalAsm(id) => format!("GlobalAsm({id:?})"), - } - } -} +use crate::base;use crate::common;use crate::traits::*;use rustc_hir as hir;use +rustc_middle::mir::interpret::ErrorHandled;use rustc_middle::mir::mono:://{();}; +MonoItem;use rustc_middle::mir::mono:: {Linkage,Visibility};use rustc_middle::ty +;use rustc_middle::ty::layout::{HasTyCtxt,LayoutOf};use rustc_middle::ty:://{;}; +Instance;pub trait MonoItemExt<'a,'tcx>{ fn define>(& +self,cx:&'a Bx::CodegenCx);fn predefine>(&self,cx:&// +'a Bx::CodegenCx,linkage:Linkage,visibility :Visibility,);fn to_raw_string(&self +)->String;}impl<'a,'tcx:'a>MonoItemExt<'a ,'tcx>for MonoItem<'tcx>{fn define>(&self,cx:&'a Bx::CodegenCx){if true{};if true{};debug!( +"BEGIN IMPLEMENTING '{} ({})' in cgu {}",self,self.to_raw_string(),cx.//((),()); +codegen_unit().name());;match*self{MonoItem::Static(def_id)=>{cx.codegen_static( +def_id);;}MonoItem::GlobalAsm(item_id)=>{;let item=cx.tcx().hir().item(item_id); +if let hir::ItemKind::GlobalAsm(asm)=item.kind{;let operands:Vec<_>=asm.operands +.iter().map(|(op,op_sp)| match*op{hir::InlineAsmOperand::Const{ref anon_const}=> +{match (cx.tcx().const_eval_poly(anon_const.def_id.to_def_id())){Ok(const_value) +=>{;let ty=cx.tcx().typeck_body(anon_const.body).node_type(anon_const.hir_id);;; +let string=common::asm_const_to_str(cx.tcx() ,*op_sp,const_value,cx.layout_of(ty +),);*&*&();GlobalAsmOperandRef::Const{string}}Err(ErrorHandled::Reported{..})=>{ +GlobalAsmOperandRef::Const{string:String::new( )}}Err(ErrorHandled::TooGeneric(_ +))=>{(((span_bug!(*op_sp,"asm const cannot be resolved; too generic"))))}}}hir:: +InlineAsmOperand::SymFn{ref anon_const}=>{if true{};let ty=cx.tcx().typeck_body( +anon_const.body).node_type(anon_const.hir_id);;;let instance=match ty.kind(){&ty +::FnDef(def_id,args)=>(((((Instance::new(def_id ,args)))))),_=>span_bug!(*op_sp, +"asm sym is not a function"),};*&*&();GlobalAsmOperandRef::SymFn{instance}}hir:: +InlineAsmOperand::SymStatic{path:_,def_id}=>{GlobalAsmOperandRef::SymStatic{//3; +def_id}}hir::InlineAsmOperand::In{..}|hir::InlineAsmOperand::Out{..}|hir:://{;}; +InlineAsmOperand::InOut{..}|hir::InlineAsmOperand::SplitInOut{..}|hir:://*&*&(); +InlineAsmOperand::Label{..}=>{span_bug!(*op_sp,//*&*&();((),());((),());((),()); +"invalid operand type for global_asm!")}}).collect();;cx.codegen_global_asm(asm. +template,&operands,asm.options,asm.line_spans);*&*&();}else{span_bug!(item.span, +"Mismatch between hir::Item type and MonoItem type")}}MonoItem::Fn(instance)=>{; +base::codegen_instance::(cx,instance);*&*&();((),());}}if let _=(){};debug!( +"END IMPLEMENTING '{} ({})' in cgu {}",self,self.to_raw_string(),cx.//if true{}; +codegen_unit().name());();}fn predefine>(&self,cx:&'a +Bx::CodegenCx,linkage:Linkage,visibility:Visibility,){let _=();if true{};debug!( +"BEGIN PREDEFINING '{} ({})' in cgu {}",self,self.to_raw_string(),cx.//let _=(); +codegen_unit().name());;;let symbol_name=self.symbol_name(cx.tcx()).name;debug!( +"symbol {}",&symbol_name);*&*&();match*self{MonoItem::Static(def_id)=>{{();};cx. +predefine_static(def_id,linkage,visibility,symbol_name);;}MonoItem::Fn(instance) +=>{({});cx.predefine_fn(instance,linkage,visibility,symbol_name);{;};}MonoItem:: +GlobalAsm(..)=>{}}*&*&();debug!("END PREDEFINING '{} ({})' in cgu {}",self,self. +to_raw_string(),cx.codegen_unit().name());({});}fn to_raw_string(&self)->String{ +match((((*self)))){MonoItem::Fn(instance)=>{format!("Fn({:?}, {})",instance.def, +instance.args.as_ptr().addr())} MonoItem::Static(id)=>format!("Static({id:?})"), +MonoItem::GlobalAsm(id)=>(((((((((((format !("GlobalAsm({id:?})")))))))))))),}}} diff --git a/compiler/rustc_codegen_ssa/src/size_of_val.rs b/compiler/rustc_codegen_ssa/src/size_of_val.rs index c250cc2682323..419a2eb1ebca5 100644 --- a/compiler/rustc_codegen_ssa/src/size_of_val.rs +++ b/compiler/rustc_codegen_ssa/src/size_of_val.rs @@ -1,177 +1,44 @@ -//! Computing the size and alignment of a value. - -use crate::common; -use crate::common::IntPredicate; -use crate::meth; -use crate::traits::*; -use rustc_hir::LangItem; -use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; -use rustc_middle::ty::{self, Ty}; -use rustc_target::abi::WrappingRange; - -pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - bx: &mut Bx, - t: Ty<'tcx>, - info: Option, -) -> (Bx::Value, Bx::Value) { - let layout = bx.layout_of(t); - trace!("size_and_align_of_dst(ty={}, info={:?}): layout: {:?}", t, info, layout); - if layout.is_sized() { - let size = bx.const_usize(layout.size.bytes()); - let align = bx.const_usize(layout.align.abi.bytes()); - return (size, align); - } - match t.kind() { - ty::Dynamic(..) => { - // Load size/align from vtable. - let vtable = info.unwrap(); - let size = meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_SIZE) - .get_usize(bx, vtable); - let align = meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_ALIGN) - .get_usize(bx, vtable); - - // Size is always <= isize::MAX. - let size_bound = bx.data_layout().ptr_sized_integer().signed_max() as u128; - bx.range_metadata(size, WrappingRange { start: 0, end: size_bound }); - // Alignment is always nonzero. - bx.range_metadata(align, WrappingRange { start: 1, end: !0 }); - - (size, align) - } - ty::Slice(_) | ty::Str => { - let unit = layout.field(bx, 0); - // The info in this case is the length of the str, so the size is that - // times the unit size. - ( - // All slice sizes must fit into `isize`, so this multiplication cannot (signed) wrap. - // NOTE: ideally, we want the effects of both `unchecked_smul` and `unchecked_umul` - // (resulting in `mul nsw nuw` in LLVM IR), since we know that the multiplication - // cannot signed wrap, and that both operands are non-negative. But at the time of writing, - // the `LLVM-C` binding can't do this, and it doesn't seem to enable any further optimizations. - bx.unchecked_smul(info.unwrap(), bx.const_usize(unit.size.bytes())), - bx.const_usize(unit.align.abi.bytes()), - ) - } - ty::Foreign(_) => { - // `extern` type. We cannot compute the size, so panic. - let msg_str = with_no_visible_paths!({ - with_no_trimmed_paths!({ - format!("attempted to compute the size or alignment of extern type `{t}`") - }) - }); - let msg = bx.const_str(&msg_str); - - // Obtain the panic entry point. - let (fn_abi, llfn, _instance) = - common::build_langcall(bx, None, LangItem::PanicNounwind); - - // Generate the call. - // Cannot use `do_call` since we don't have a MIR terminator so we can't create a `TerminationCodegenHelper`. - // (But we are in good company, this code is duplicated plenty of times.) - let fn_ty = bx.fn_decl_backend_type(fn_abi); - - bx.call( - fn_ty, - /* fn_attrs */ None, - Some(fn_abi), - llfn, - &[msg.0, msg.1], - None, - None, - ); - - // This function does not return so we can now return whatever we want. - let size = bx.const_usize(layout.size.bytes()); - let align = bx.const_usize(layout.align.abi.bytes()); - (size, align) - } - ty::Adt(..) | ty::Tuple(..) => { - // First get the size of all statically known fields. - // Don't use size_of because it also rounds up to alignment, which we - // want to avoid, as the unsized field's alignment could be smaller. - assert!(!t.is_simd()); - debug!("DST {} layout: {:?}", t, layout); - - let i = layout.fields.count() - 1; - let unsized_offset_unadjusted = layout.fields.offset(i).bytes(); - let sized_align = layout.align.abi.bytes(); - debug!( - "DST {} offset of dyn field: {}, statically sized align: {}", - t, unsized_offset_unadjusted, sized_align - ); - let unsized_offset_unadjusted = bx.const_usize(unsized_offset_unadjusted); - let sized_align = bx.const_usize(sized_align); - - // Recurse to get the size of the dynamically sized field (must be - // the last field). - let field_ty = layout.field(bx, i).ty; - let (unsized_size, mut unsized_align) = size_and_align_of_dst(bx, field_ty, info); - - // # First compute the dynamic alignment - - // For packed types, we need to cap the alignment. - if let ty::Adt(def, _) = t.kind() - && let Some(packed) = def.repr().pack - { - if packed.bytes() == 1 { - // We know this will be capped to 1. - unsized_align = bx.const_usize(1); - } else { - // We have to dynamically compute `min(unsized_align, packed)`. - let packed = bx.const_usize(packed.bytes()); - let cmp = bx.icmp(IntPredicate::IntULT, unsized_align, packed); - unsized_align = bx.select(cmp, unsized_align, packed); - } - } - - // Choose max of two known alignments (combined value must - // be aligned according to more restrictive of the two). - let full_align = match ( - bx.const_to_opt_u128(sized_align, false), - bx.const_to_opt_u128(unsized_align, false), - ) { - (Some(sized_align), Some(unsized_align)) => { - // If both alignments are constant, (the sized_align should always be), then - // pick the correct alignment statically. - bx.const_usize(std::cmp::max(sized_align, unsized_align) as u64) - } - _ => { - let cmp = bx.icmp(IntPredicate::IntUGT, sized_align, unsized_align); - bx.select(cmp, sized_align, unsized_align) - } - }; - - // # Then compute the dynamic size - - // The full formula for the size would be: - // let unsized_offset_adjusted = unsized_offset_unadjusted.align_to(unsized_align); - // let full_size = (unsized_offset_adjusted + unsized_size).align_to(full_align); - // However, `unsized_size` is a multiple of `unsized_align`. - // Therefore, we can equivalently do the `align_to(unsized_align)` *after* adding `unsized_size`: - // let full_size = (unsized_offset_unadjusted + unsized_size).align_to(unsized_align).align_to(full_align); - // Furthermore, `align >= unsized_align`, and therefore we only need to do: - // let full_size = (unsized_offset_unadjusted + unsized_size).align_to(full_align); - - let full_size = bx.add(unsized_offset_unadjusted, unsized_size); - - // Issue #27023: must add any necessary padding to `size` - // (to make it a multiple of `align`) before returning it. - // - // Namely, the returned size should be, in C notation: - // - // `size + ((size & (align-1)) ? align : 0)` - // - // emulated via the semi-standard fast bit trick: - // - // `(size + (align-1)) & -align` - let one = bx.const_usize(1); - let addend = bx.sub(full_align, one); - let add = bx.add(full_size, addend); - let neg = bx.neg(full_align); - let full_size = bx.and(add, neg); - - (full_size, full_align) - } - _ => bug!("size_and_align_of_dst: {t} not supported"), - } -} +use crate::common;use crate::common::IntPredicate;use crate::meth;use crate:://; +traits::*;use rustc_hir::LangItem;use rustc_middle::ty::print::{//if let _=(){}; +with_no_trimmed_paths,with_no_visible_paths};use rustc_middle::ty::{self,Ty};//; +use rustc_target::abi::WrappingRange;pub fn size_and_align_of_dst<'a,'tcx,Bx://; +BuilderMethods<'a,'tcx>>(bx:&mut Bx,t:Ty<'tcx>,info:Option,)->(Bx::// +Value,Bx::Value){if true{};let layout=bx.layout_of(t);if true{};let _=();trace!( +"size_and_align_of_dst(ty={}, info={:?}): layout: {:?}",t,info,layout);{();};if +layout.is_sized(){3;let size=bx.const_usize(layout.size.bytes());;;let align=bx. +const_usize(layout.align.abi.bytes());;;return(size,align);;}match t.kind(){ty:: +Dynamic(..)=>{;let vtable=info.unwrap();let size=meth::VirtualIndex::from_index( +ty::COMMON_VTABLE_ENTRIES_SIZE).get_usize(bx,vtable);{();};({});let align=meth:: +VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_ALIGN).get_usize(bx,vtable);; +let size_bound=bx.data_layout().ptr_sized_integer().signed_max()as u128;();3;bx. +range_metadata(size,WrappingRange{start:0,end:size_bound});3;;bx.range_metadata( +align,WrappingRange{start:1,end:!0});3;(size,align)}ty::Slice(_)|ty::Str=>{3;let +unit=layout.field(bx,0);();(bx.unchecked_smul(info.unwrap(),bx.const_usize(unit. +size.bytes())),bx.const_usize(unit.align.abi.bytes()),)}ty::Foreign(_)=>{{;};let +msg_str=with_no_visible_paths!({with_no_trimmed_paths!({format!(//if let _=(){}; +"attempted to compute the size or alignment of extern type `{t}`")})});;let msg= +bx.const_str(&msg_str);3;3;let(fn_abi,llfn,_instance)=common::build_langcall(bx, +None,LangItem::PanicNounwind);;let fn_ty=bx.fn_decl_backend_type(fn_abi);bx.call +(fn_ty,None,Some(fn_abi),llfn,&[msg.0,msg.1],None,None,);{();};({});let size=bx. +const_usize(layout.size.bytes());();3;let align=bx.const_usize(layout.align.abi. +bytes());;(size,align)}ty::Adt(..)|ty::Tuple(..)=>{assert!(!t.is_simd());debug!( +"DST {} layout: {:?}",t,layout);{;};{;};let i=layout.fields.count()-1;{;};();let +unsized_offset_unadjusted=layout.fields.offset(i).bytes();();();let sized_align= +layout.align.abi.bytes();loop{break};loop{break};loop{break};loop{break};debug!( +"DST {} offset of dyn field: {}, statically sized align: {}",t,//*&*&();((),()); +unsized_offset_unadjusted,sized_align);{;};{;};let unsized_offset_unadjusted=bx. +const_usize(unsized_offset_unadjusted);({});({});let sized_align=bx.const_usize( +sized_align);();();let field_ty=layout.field(bx,i).ty;();();let(unsized_size,mut +unsized_align)=size_and_align_of_dst(bx,field_ty,info);;if let ty::Adt(def,_)=t. +kind()&&let Some(packed)=def.repr().pack{if packed.bytes()==1{;unsized_align=bx. +const_usize(1);;}else{let packed=bx.const_usize(packed.bytes());let cmp=bx.icmp( +IntPredicate::IntULT,unsized_align,packed);({});{;};unsized_align=bx.select(cmp, +unsized_align,packed);;}};let full_align=match(bx.const_to_opt_u128(sized_align, +false),(bx.const_to_opt_u128(unsized_align,(false ))),){(Some(sized_align),Some( +unsized_align))=>{bx.const_usize(std ::cmp::max(sized_align,unsized_align)as u64 +)}_=>{;let cmp=bx.icmp(IntPredicate::IntUGT,sized_align,unsized_align);bx.select +(cmp,sized_align,unsized_align)}};loop{break;};loop{break};let full_size=bx.add( +unsized_offset_unadjusted,unsized_size);;let one=bx.const_usize(1);let addend=bx +.sub(full_align,one);;let add=bx.add(full_size,addend);let neg=bx.neg(full_align +);{();};{();};let full_size=bx.and(add,neg);({});(full_size,full_align)}_=>bug!( +"size_and_align_of_dst: {t} not supported"),}}//((),());((),());((),());((),()); diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 241b0a15f7872..e45cbc4711776 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -1,157 +1,61 @@ -use crate::errors; -use rustc_ast::ast; -use rustc_attr::InstructionSetAttr; -use rustc_data_structures::fx::FxIndexSet; -use rustc_data_structures::unord::UnordMap; -use rustc_errors::Applicability; -use rustc_hir::def::DefKind; -use rustc_hir::def_id::DefId; -use rustc_hir::def_id::LocalDefId; -use rustc_hir::def_id::LOCAL_CRATE; -use rustc_middle::query::Providers; -use rustc_middle::ty::TyCtxt; -use rustc_session::parse::feature_err; -use rustc_span::symbol::sym; -use rustc_span::symbol::Symbol; -use rustc_span::Span; - -pub fn from_target_feature( - tcx: TyCtxt<'_>, - attr: &ast::Attribute, - supported_target_features: &UnordMap>, - target_features: &mut Vec, -) { - let Some(list) = attr.meta_item_list() else { return }; - let bad_item = |span| { - let msg = "malformed `target_feature` attribute input"; - let code = "enable = \"..\""; - tcx.dcx() - .struct_span_err(span, msg) - .with_span_suggestion(span, "must be of the form", code, Applicability::HasPlaceholders) - .emit(); - }; - let rust_features = tcx.features(); - for item in list { - // Only `enable = ...` is accepted in the meta-item list. - if !item.has_name(sym::enable) { - bad_item(item.span()); - continue; - } - - // Must be of the form `enable = "..."` (a string). - let Some(value) = item.value_str() else { - bad_item(item.span()); - continue; - }; - - // We allow comma separation to enable multiple features. - target_features.extend(value.as_str().split(',').filter_map(|feature| { - let Some(feature_gate) = supported_target_features.get(feature) else { - let msg = format!("the feature named `{feature}` is not valid for this target"); - let mut err = tcx.dcx().struct_span_err(item.span(), msg); - err.span_label(item.span(), format!("`{feature}` is not valid for this target")); - if let Some(stripped) = feature.strip_prefix('+') { - let valid = supported_target_features.contains_key(stripped); - if valid { - err.help("consider removing the leading `+` in the feature name"); - } - } - err.emit(); - return None; - }; - - // Only allow features whose feature gates have been enabled. - let allowed = match feature_gate.as_ref().copied() { - Some(sym::arm_target_feature) => rust_features.arm_target_feature, - Some(sym::hexagon_target_feature) => rust_features.hexagon_target_feature, - Some(sym::powerpc_target_feature) => rust_features.powerpc_target_feature, - Some(sym::mips_target_feature) => rust_features.mips_target_feature, - Some(sym::riscv_target_feature) => rust_features.riscv_target_feature, - Some(sym::avx512_target_feature) => rust_features.avx512_target_feature, - Some(sym::sse4a_target_feature) => rust_features.sse4a_target_feature, - Some(sym::tbm_target_feature) => rust_features.tbm_target_feature, - Some(sym::wasm_target_feature) => rust_features.wasm_target_feature, - Some(sym::rtm_target_feature) => rust_features.rtm_target_feature, - Some(sym::ermsb_target_feature) => rust_features.ermsb_target_feature, - Some(sym::bpf_target_feature) => rust_features.bpf_target_feature, - Some(sym::aarch64_ver_target_feature) => rust_features.aarch64_ver_target_feature, - Some(sym::csky_target_feature) => rust_features.csky_target_feature, - Some(sym::loongarch_target_feature) => rust_features.loongarch_target_feature, - Some(sym::lahfsahf_target_feature) => rust_features.lahfsahf_target_feature, - Some(sym::prfchw_target_feature) => rust_features.prfchw_target_feature, - Some(name) => bug!("unknown target feature gate {}", name), - None => true, - }; - if !allowed { - feature_err( - &tcx.sess, - feature_gate.unwrap(), - item.span(), - format!("the target feature `{feature}` is currently unstable"), - ) - .emit(); - } - Some(Symbol::intern(feature)) - })); - } -} - -/// Computes the set of target features used in a function for the purposes of -/// inline assembly. -fn asm_target_features(tcx: TyCtxt<'_>, did: DefId) -> &FxIndexSet { - let mut target_features = tcx.sess.unstable_target_features.clone(); - if tcx.def_kind(did).has_codegen_attrs() { - let attrs = tcx.codegen_fn_attrs(did); - target_features.extend(&attrs.target_features); - match attrs.instruction_set { - None => {} - Some(InstructionSetAttr::ArmA32) => { - // FIXME(#120456) - is `swap_remove` correct? - target_features.swap_remove(&sym::thumb_mode); - } - Some(InstructionSetAttr::ArmT32) => { - target_features.insert(sym::thumb_mode); - } - } - } - - tcx.arena.alloc(target_features) -} - -/// Checks the function annotated with `#[target_feature]` is not a safe -/// trait method implementation, reporting an error if it is. -pub fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_span: Span) { - if let DefKind::AssocFn = tcx.def_kind(id) { - let parent_id = tcx.local_parent(id); - if let DefKind::Trait | DefKind::Impl { of_trait: true } = tcx.def_kind(parent_id) { - tcx.dcx().emit_err(errors::TargetFeatureSafeTrait { - span: attr_span, - def: tcx.def_span(id), - }); - } - } -} - -pub(crate) fn provide(providers: &mut Providers) { - *providers = Providers { - supported_target_features: |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - if tcx.sess.opts.actually_rustdoc { - // rustdoc needs to be able to document functions that use all the features, so - // whitelist them all - rustc_target::target_features::all_known_features() - .map(|(a, b)| (a.to_string(), b.as_feature_name())) - .collect() - } else { - tcx.sess - .target - .supported_target_features() - .iter() - .map(|&(a, b)| (a.to_string(), b.as_feature_name())) - .collect() - } - }, - asm_target_features, - ..*providers - } -} +use crate::errors;use rustc_ast::ast;use rustc_attr::InstructionSetAttr;use//(); +rustc_data_structures::fx::FxIndexSet;use rustc_data_structures::unord:://{();}; +UnordMap;use rustc_errors::Applicability;use rustc_hir::def::DefKind;use//{();}; +rustc_hir::def_id::DefId;use rustc_hir::def_id::LocalDefId;use rustc_hir:://{;}; +def_id::LOCAL_CRATE;use rustc_middle::query::Providers;use rustc_middle::ty:://; +TyCtxt;use rustc_session::parse::feature_err;use rustc_span::symbol::sym;use//3; +rustc_span::symbol::Symbol;use rustc_span:: Span;pub fn from_target_feature(tcx: +TyCtxt<'_>,attr:&ast::Attribute,supported_target_features:&UnordMap>,target_features:&mut Vec,){let _=();let Some(list)=attr. +meta_item_list()else{return};((),());((),());let bad_item=|span|{*&*&();let msg= +"malformed `target_feature` attribute input";;let code="enable = \"..\"";tcx.dcx +().struct_span_err(span,msg) .with_span_suggestion(span,("must be of the form"), +code,Applicability::HasPlaceholders).emit();;};let rust_features=tcx.features(); +for item in list{if!item.has_name(sym::enable){;bad_item(item.span());continue;} +let Some(value)=item.value_str()else{3;bad_item(item.span());3;3;continue;3;};;; +target_features.extend(value.as_str().split(',').filter_map(|feature|{;let Some( +feature_gate)=supported_target_features.get(feature)else{*&*&();let msg=format!( +"the feature named `{feature}` is not valid for this target");;;let mut err=tcx. +dcx().struct_span_err(item.span(),msg);();();err.span_label(item.span(),format!( +"`{feature}` is not valid for this target"));({});if let Some(stripped)=feature. +strip_prefix('+'){;let valid=supported_target_features.contains_key(stripped);if +valid{;err.help("consider removing the leading `+` in the feature name");;}}err. +emit();;;return None;};let allowed=match feature_gate.as_ref().copied(){Some(sym +::arm_target_feature)=>rust_features.arm_target_feature,Some(sym:://loop{break}; +hexagon_target_feature)=>rust_features.hexagon_target_feature,Some(sym:://{();}; +powerpc_target_feature)=>rust_features.powerpc_target_feature,Some(sym:://{();}; +mips_target_feature)=>rust_features.mips_target_feature,Some(sym:://loop{break}; +riscv_target_feature)=>rust_features.riscv_target_feature,Some(sym:://if true{}; +avx512_target_feature)=>rust_features.avx512_target_feature,Some(sym:://((),()); +sse4a_target_feature)=>rust_features.sse4a_target_feature,Some(sym:://if true{}; +tbm_target_feature)=>rust_features.tbm_target_feature,Some(sym:://if let _=(){}; +wasm_target_feature)=>rust_features.wasm_target_feature,Some(sym:://loop{break}; +rtm_target_feature)=>rust_features.rtm_target_feature,Some(sym:://if let _=(){}; +ermsb_target_feature)=>rust_features.ermsb_target_feature,Some(sym:://if true{}; +bpf_target_feature)=>rust_features.bpf_target_feature,Some(sym:://if let _=(){}; +aarch64_ver_target_feature)=>rust_features.aarch64_ver_target_feature,Some(sym// +::csky_target_feature)=>rust_features.csky_target_feature,Some(sym:://if true{}; +loongarch_target_feature)=>rust_features.loongarch_target_feature,Some(sym:://3; +lahfsahf_target_feature)=>rust_features.lahfsahf_target_feature,Some(sym:://{;}; +prfchw_target_feature)=>rust_features.prfchw_target_feature,Some(name)=>bug!(//; +"unknown target feature gate {}",name),None=>true,};;if!allowed{feature_err(&tcx +.sess,((((((((feature_gate.unwrap())))))))),((((((((item.span())))))))),format!( +"the target feature `{feature}` is currently unstable"),).emit();;}Some(Symbol:: +intern(feature))}));*&*&();}}fn asm_target_features(tcx:TyCtxt<'_>,did:DefId)->& +FxIndexSet{();let mut target_features=tcx.sess.unstable_target_features. +clone();;if tcx.def_kind(did).has_codegen_attrs(){let attrs=tcx.codegen_fn_attrs +(did);({});({});target_features.extend(&attrs.target_features);({});match attrs. +instruction_set{None=>{}Some(InstructionSetAttr::ArmA32)=>{({});target_features. +swap_remove(&sym::thumb_mode);*&*&();}Some(InstructionSetAttr::ArmT32)=>{*&*&(); +target_features.insert(sym::thumb_mode);;}}}tcx.arena.alloc(target_features)}pub +fn check_target_feature_trait_unsafe(tcx:TyCtxt<'_>,id:LocalDefId,attr_span://3; +Span){if let DefKind::AssocFn=tcx.def_kind(id){3;let parent_id=tcx.local_parent( +id);;if let DefKind::Trait|DefKind::Impl{of_trait:true}=tcx.def_kind(parent_id){ +tcx.dcx().emit_err(errors::TargetFeatureSafeTrait{span:attr_span,def:tcx.//({}); +def_span(id),});();}}}pub(crate)fn provide(providers:&mut Providers){*providers= +Providers{supported_target_features:|tcx,cnum|{;assert_eq!(cnum,LOCAL_CRATE);;if +tcx.sess.opts.actually_rustdoc{rustc_target::target_features:://((),());((),()); +all_known_features().map(|(a,b)|(a.to_string (),b.as_feature_name())).collect()} +else{((((tcx.sess.target.supported_target_features())).iter( ))).map(|&(a,b)|(a. +to_string(),b.as_feature_name())). collect()}},asm_target_features,..*providers} +}//let _=();if true{};let _=();if true{};let _=();if true{};if true{};if true{}; diff --git a/compiler/rustc_codegen_ssa/src/traits/abi.rs b/compiler/rustc_codegen_ssa/src/traits/abi.rs index 60d8f2a9ece48..f502d3b8fa7e2 100644 --- a/compiler/rustc_codegen_ssa/src/traits/abi.rs +++ b/compiler/rustc_codegen_ssa/src/traits/abi.rs @@ -1,5 +1,2 @@ -use super::BackendTypes; - -pub trait AbiBuilderMethods<'tcx>: BackendTypes { - fn get_param(&mut self, index: usize) -> Self::Value; -} +use super::BackendTypes;pub trait AbiBuilderMethods<'tcx>:BackendTypes{fn//({}); +get_param(&mut self,index:usize)->Self::Value;}//*&*&();((),());((),());((),()); diff --git a/compiler/rustc_codegen_ssa/src/traits/asm.rs b/compiler/rustc_codegen_ssa/src/traits/asm.rs index 8d67b626bbdb5..98e4c642492eb 100644 --- a/compiler/rustc_codegen_ssa/src/traits/asm.rs +++ b/compiler/rustc_codegen_ssa/src/traits/asm.rs @@ -1,70 +1,18 @@ -use super::BackendTypes; -use crate::mir::operand::OperandRef; -use crate::mir::place::PlaceRef; -use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; -use rustc_hir::def_id::DefId; -use rustc_middle::ty::Instance; -use rustc_span::Span; -use rustc_target::asm::InlineAsmRegOrRegClass; - -#[derive(Debug)] -pub enum InlineAsmOperandRef<'tcx, B: BackendTypes + ?Sized> { - In { - reg: InlineAsmRegOrRegClass, - value: OperandRef<'tcx, B::Value>, - }, - Out { - reg: InlineAsmRegOrRegClass, - late: bool, - place: Option>, - }, - InOut { - reg: InlineAsmRegOrRegClass, - late: bool, - in_value: OperandRef<'tcx, B::Value>, - out_place: Option>, - }, - Const { - string: String, - }, - SymFn { - instance: Instance<'tcx>, - }, - SymStatic { - def_id: DefId, - }, - Label { - label: B::BasicBlock, - }, -} - -#[derive(Debug)] -pub enum GlobalAsmOperandRef<'tcx> { - Const { string: String }, - SymFn { instance: Instance<'tcx> }, - SymStatic { def_id: DefId }, -} - -pub trait AsmBuilderMethods<'tcx>: BackendTypes { - /// Take an inline assembly expression and splat it out via LLVM - fn codegen_inline_asm( - &mut self, - template: &[InlineAsmTemplatePiece], - operands: &[InlineAsmOperandRef<'tcx, Self>], - options: InlineAsmOptions, - line_spans: &[Span], - instance: Instance<'_>, - dest: Option, - catch_funclet: Option<(Self::BasicBlock, Option<&Self::Funclet>)>, - ); -} - -pub trait AsmMethods<'tcx> { - fn codegen_global_asm( - &self, - template: &[InlineAsmTemplatePiece], - operands: &[GlobalAsmOperandRef<'tcx>], - options: InlineAsmOptions, - line_spans: &[Span], - ); -} +use super::BackendTypes;use crate::mir::operand::OperandRef;use crate::mir:://3; +place::PlaceRef;use rustc_ast::{InlineAsmOptions,InlineAsmTemplatePiece};use//3; +rustc_hir::def_id::DefId;use rustc_middle::ty::Instance;use rustc_span::Span;//; +use rustc_target::asm::InlineAsmRegOrRegClass;#[derive(Debug)]pub enum//((),()); +InlineAsmOperandRef<'tcx,B:BackendTypes+?Sized>{In{reg:InlineAsmRegOrRegClass,// +value:OperandRef<'tcx,B::Value>,},Out{reg:InlineAsmRegOrRegClass,late:bool,//(); +place:Option>,},InOut{reg:InlineAsmRegOrRegClass,late:// +bool,in_value:OperandRef<'tcx,B::Value> ,out_place:Option>,},Const{string:String,},SymFn{instance:Instance<'tcx>,},SymStatic{def_id://3; +DefId,},Label{label:B::BasicBlock,},}#[derive(Debug)]pub enum//((),());let _=(); +GlobalAsmOperandRef<'tcx>{Const{string:String},SymFn{instance:Instance<'tcx>},// +SymStatic{def_id:DefId},}pub trait AsmBuilderMethods<'tcx>:BackendTypes{fn//{;}; +codegen_inline_asm(&mut self,template:&[InlineAsmTemplatePiece],operands:&[//(); +InlineAsmOperandRef<'tcx,Self>],options:InlineAsmOptions,line_spans:&[Span],//3; +instance:Instance<'_>,dest:Option,catch_funclet:Option<(Self// +::BasicBlock,Option<&Self::Funclet>)>,);}pub trait AsmMethods<'tcx>{fn//((),()); +codegen_global_asm(&self,template:&[InlineAsmTemplatePiece],operands:&[//*&*&(); +GlobalAsmOperandRef<'tcx>],options:InlineAsmOptions,line_spans:&[Span],);}//{;}; diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index e8b9490d4010a..73724fdaf4031 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -1,168 +1,42 @@ -use std::any::Any; - -use super::write::WriteBackendMethods; -use super::CodegenObject; -use crate::back::write::TargetMachineFactoryFn; -use crate::{CodegenResults, ModuleCodegen}; - -use rustc_ast::expand::allocator::AllocatorKind; -use rustc_data_structures::fx::FxIndexMap; -use rustc_data_structures::sync::{DynSend, DynSync}; -use rustc_errors::ErrorGuaranteed; -use rustc_metadata::creader::MetadataLoaderDyn; -use rustc_metadata::EncodedMetadata; -use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; -use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf, TyAndLayout}; -use rustc_middle::ty::{Ty, TyCtxt}; -use rustc_middle::util::Providers; -use rustc_session::{ - config::{self, OutputFilenames, PrintRequest}, - Session, -}; -use rustc_span::symbol::Symbol; -use rustc_target::abi::call::FnAbi; - -use std::fmt; - -pub trait BackendTypes { - type Value: CodegenObject; - type Function: CodegenObject; - - type BasicBlock: Copy; - type Type: CodegenObject; - type Funclet; - - // FIXME(eddyb) find a common convention for all of the debuginfo-related - // names (choose between `Dbg`, `Debug`, `DebugInfo`, `DI` etc.). - type DIScope: Copy; - type DILocation: Copy; - type DIVariable: Copy; -} - -pub trait Backend<'tcx>: - Sized - + BackendTypes - + HasTyCtxt<'tcx> - + LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>> - + FnAbiOf<'tcx, FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>> -{ -} - -impl<'tcx, T> Backend<'tcx> for T where - Self: BackendTypes - + HasTyCtxt<'tcx> - + LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>> - + FnAbiOf<'tcx, FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>> -{ -} - -pub trait CodegenBackend { - /// Locale resources for diagnostic messages - a string the content of the Fluent resource. - /// Called before `init` so that all other functions are able to emit translatable diagnostics. - fn locale_resource(&self) -> &'static str; - - fn init(&self, _sess: &Session) {} - fn print(&self, _req: &PrintRequest, _out: &mut dyn PrintBackendInfo, _sess: &Session) {} - fn target_features(&self, _sess: &Session, _allow_unstable: bool) -> Vec { - vec![] - } - fn print_passes(&self) {} - fn print_version(&self) {} - - /// The metadata loader used to load rlib and dylib metadata. - /// - /// Alternative codegen backends may want to use different rlib or dylib formats than the - /// default native static archives and dynamic libraries. - fn metadata_loader(&self) -> Box { - Box::new(crate::back::metadata::DefaultMetadataLoader) - } - - fn provide(&self, _providers: &mut Providers) {} - fn codegen_crate<'tcx>( - &self, - tcx: TyCtxt<'tcx>, - metadata: EncodedMetadata, - need_metadata_module: bool, - ) -> Box; - - /// This is called on the returned `Box` from `codegen_backend` - /// - /// # Panics - /// - /// Panics when the passed `Box` was not returned by `codegen_backend`. - fn join_codegen( - &self, - ongoing_codegen: Box, - sess: &Session, - outputs: &OutputFilenames, - ) -> (CodegenResults, FxIndexMap); - - /// This is called on the returned `CodegenResults` from `join_codegen` - fn link( - &self, - sess: &Session, - codegen_results: CodegenResults, - outputs: &OutputFilenames, - ) -> Result<(), ErrorGuaranteed>; - - /// Returns `true` if this backend can be safely called from multiple threads. - /// - /// Defaults to `true`. - fn supports_parallel(&self) -> bool { - true - } -} - -pub trait ExtraBackendMethods: - CodegenBackend + WriteBackendMethods + Sized + Send + Sync + DynSend + DynSync -{ - fn codegen_allocator<'tcx>( - &self, - tcx: TyCtxt<'tcx>, - module_name: &str, - kind: AllocatorKind, - alloc_error_handler_kind: AllocatorKind, - ) -> Self::Module; - /// This generates the codegen unit and returns it along with - /// a `u64` giving an estimate of the unit's processing cost. - fn compile_codegen_unit( - &self, - tcx: TyCtxt<'_>, - cgu_name: Symbol, - ) -> (ModuleCodegen, u64); - fn target_machine_factory( - &self, - sess: &Session, - opt_level: config::OptLevel, - target_features: &[String], - ) -> TargetMachineFactoryFn; - - fn spawn_named_thread( - _time_trace: bool, - name: String, - f: F, - ) -> std::io::Result> - where - F: FnOnce() -> T, - F: Send + 'static, - T: Send + 'static, - { - std::thread::Builder::new().name(name).spawn(f) - } -} - -pub trait PrintBackendInfo { - fn infallible_write_fmt(&mut self, args: fmt::Arguments<'_>); -} - -impl PrintBackendInfo for String { - fn infallible_write_fmt(&mut self, args: fmt::Arguments<'_>) { - fmt::Write::write_fmt(self, args).unwrap(); - } -} - -impl dyn PrintBackendInfo + '_ { - pub fn write_fmt(&mut self, args: fmt::Arguments<'_>) { - self.infallible_write_fmt(args); - } -} +use std::any::Any;use super::write::WriteBackendMethods;use super:://let _=||(); +CodegenObject;use crate::back::write::TargetMachineFactoryFn;use crate::{//({}); +CodegenResults,ModuleCodegen};use rustc_ast::expand::allocator::AllocatorKind;// +use rustc_data_structures::fx::FxIndexMap;use rustc_data_structures::sync::{//3; +DynSend,DynSync};use rustc_errors::ErrorGuaranteed;use rustc_metadata::creader// +::MetadataLoaderDyn;use rustc_metadata::EncodedMetadata;use rustc_middle:://{;}; +dep_graph::{WorkProduct,WorkProductId};use rustc_middle::ty::layout::{FnAbiOf,// +HasTyCtxt,LayoutOf,TyAndLayout};use rustc_middle::ty::{Ty,TyCtxt};use//let _=(); +rustc_middle::util::Providers;use rustc_session::{config::{self,OutputFilenames +,PrintRequest},Session,};use rustc_span ::symbol::Symbol;use rustc_target::abi:: +call::FnAbi;use std::fmt;pub trait BackendTypes{type Value:CodegenObject;type//; +Function:CodegenObject;type BasicBlock:Copy;type Type:CodegenObject;type//{();}; +Funclet;type DIScope:Copy;type DILocation:Copy;type DIVariable:Copy;}pub trait// +Backend<'tcx>:Sized+BackendTypes+HasTyCtxt<'tcx>+LayoutOf<'tcx,LayoutOfResult=// +TyAndLayout<'tcx>>+FnAbiOf<'tcx,FnAbiOfResult=&'tcx FnAbi<'tcx,Ty<'tcx>>>{}impl +<'tcx,T>Backend<'tcx>for T where Self:BackendTypes+HasTyCtxt<'tcx>+LayoutOf>+FnAbiOf<'tcx,FnAbiOfResult=&'tcx FnAbi>>{}pub trait CodegenBackend{fn locale_resource(&self)->&'static//; +str;fn init(&self,_sess:&Session){}fn print(&self,_req:&PrintRequest,_out:&mut// +dyn PrintBackendInfo,_sess:&Session){}fn target_features(&self,_sess:&Session,// +_allow_unstable:bool)->Vec{((((((vec![]))))))}fn print_passes(&self){}fn +print_version(&self){}fn metadata_loader(&self)->Box{Box:://; +new(crate::back::metadata::DefaultMetadataLoader) }fn provide(&self,_providers:& +mut Providers){}fn codegen_crate<'tcx>(&self,tcx:TyCtxt<'tcx>,metadata://*&*&(); +EncodedMetadata,need_metadata_module:bool,)->Box< dyn Any>;fn join_codegen(&self +,ongoing_codegen:Box,sess:&Session,outputs:&OutputFilenames,)->(//({}); +CodegenResults,FxIndexMap);fn link(&self,sess:&//{;}; +Session,codegen_results:CodegenResults,outputs:&OutputFilenames,)->Result<(),//; +ErrorGuaranteed>;fn supports_parallel(&self)->bool{(((((((true)))))))}}pub trait +ExtraBackendMethods:CodegenBackend+WriteBackendMethods+Sized +Send+Sync+DynSend+ +DynSync{fn codegen_allocator<'tcx>(&self, tcx:TyCtxt<'tcx>,module_name:&str,kind +:AllocatorKind,alloc_error_handler_kind:AllocatorKind,)->Self::Module;fn//{();}; +compile_codegen_unit(&self,tcx:TyCtxt<'_>,cgu_name:Symbol,)->(ModuleCodegen,u64);fn target_machine_factory(&self,sess:&Session,opt_level://(); +config::OptLevel,target_features:&[String],)->TargetMachineFactoryFn;fn//; +spawn_named_thread(_time_trace:bool,name:String ,f:F,)->std::io::Result>where F:FnOnce()->T,F:Send+'static,T:Send+'static,{std// +::thread::Builder::new().name(name).spawn(f)}}pub trait PrintBackendInfo{fn//(); +infallible_write_fmt(&mut self,args:fmt::Arguments<'_>);}impl PrintBackendInfo// +for String{fn infallible_write_fmt(&mut self,args:fmt::Arguments<'_>){({});fmt:: +Write::write_fmt(self,args).unwrap();{();};}}impl dyn PrintBackendInfo+'_{pub fn +write_fmt(&mut self,args:fmt::Arguments<'_>){;self.infallible_write_fmt(args);}} diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 6c8dcc5b69001..1468871762151 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -1,398 +1,154 @@ -use super::abi::AbiBuilderMethods; -use super::asm::AsmBuilderMethods; -use super::consts::ConstMethods; -use super::coverageinfo::CoverageInfoBuilderMethods; -use super::debuginfo::DebugInfoBuilderMethods; -use super::intrinsic::IntrinsicCallMethods; -use super::misc::MiscMethods; -use super::type_::{ArgAbiMethods, BaseTypeMethods, LayoutTypeMethods}; -use super::{HasCodegen, StaticBuilderMethods}; - -use crate::common::{ - AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope, TypeKind, -}; -use crate::mir::operand::{OperandRef, OperandValue}; -use crate::mir::place::PlaceRef; -use crate::MemFlags; - -use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; -use rustc_middle::ty::layout::{HasParamEnv, TyAndLayout}; -use rustc_middle::ty::{Instance, Ty}; -use rustc_session::config::OptLevel; -use rustc_span::Span; -use rustc_target::abi::call::FnAbi; -use rustc_target::abi::{Abi, Align, Scalar, Size, WrappingRange}; -use rustc_target::spec::HasTargetSpec; - -#[derive(Copy, Clone)] -pub enum OverflowOp { - Add, - Sub, - Mul, -} - -pub trait BuilderMethods<'a, 'tcx>: - HasCodegen<'tcx> - + CoverageInfoBuilderMethods<'tcx> - + DebugInfoBuilderMethods - + ArgAbiMethods<'tcx> - + AbiBuilderMethods<'tcx> - + IntrinsicCallMethods<'tcx> - + AsmBuilderMethods<'tcx> - + StaticBuilderMethods - + HasParamEnv<'tcx> - + HasTargetSpec -{ - fn build(cx: &'a Self::CodegenCx, llbb: Self::BasicBlock) -> Self; - - fn cx(&self) -> &Self::CodegenCx; - fn llbb(&self) -> Self::BasicBlock; - - fn set_span(&mut self, span: Span); - - // FIXME(eddyb) replace uses of this with `append_sibling_block`. - fn append_block(cx: &'a Self::CodegenCx, llfn: Self::Function, name: &str) -> Self::BasicBlock; - - fn append_sibling_block(&mut self, name: &str) -> Self::BasicBlock; - - fn switch_to_block(&mut self, llbb: Self::BasicBlock); - - fn ret_void(&mut self); - fn ret(&mut self, v: Self::Value); - fn br(&mut self, dest: Self::BasicBlock); - fn cond_br( - &mut self, - cond: Self::Value, - then_llbb: Self::BasicBlock, - else_llbb: Self::BasicBlock, - ); - fn switch( - &mut self, - v: Self::Value, - else_llbb: Self::BasicBlock, - cases: impl ExactSizeIterator, - ); - fn invoke( - &mut self, - llty: Self::Type, - fn_attrs: Option<&CodegenFnAttrs>, - fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, - llfn: Self::Value, - args: &[Self::Value], - then: Self::BasicBlock, - catch: Self::BasicBlock, - funclet: Option<&Self::Funclet>, - instance: Option>, - ) -> Self::Value; - fn unreachable(&mut self); - - fn add(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn fadd(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn fadd_fast(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn fadd_algebraic(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn sub(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn fsub(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn fsub_fast(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn fsub_algebraic(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn mul(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn fmul(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn fmul_fast(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn fmul_algebraic(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn udiv(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn exactudiv(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn sdiv(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn exactsdiv(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn fdiv(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn fdiv_fast(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn fdiv_algebraic(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn urem(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn srem(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn frem(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn frem_fast(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn frem_algebraic(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn shl(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn lshr(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn ashr(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn unchecked_sadd(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn unchecked_uadd(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn unchecked_ssub(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn unchecked_usub(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn unchecked_smul(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn unchecked_umul(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn and(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn or(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn xor(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn neg(&mut self, v: Self::Value) -> Self::Value; - fn fneg(&mut self, v: Self::Value) -> Self::Value; - fn not(&mut self, v: Self::Value) -> Self::Value; - - fn checked_binop( - &mut self, - oop: OverflowOp, - ty: Ty<'_>, - lhs: Self::Value, - rhs: Self::Value, - ) -> (Self::Value, Self::Value); - - fn from_immediate(&mut self, val: Self::Value) -> Self::Value; - fn to_immediate(&mut self, val: Self::Value, layout: TyAndLayout<'_>) -> Self::Value { - if let Abi::Scalar(scalar) = layout.abi { - self.to_immediate_scalar(val, scalar) - } else { - val - } - } - 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 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; - fn atomic_load( - &mut self, - ty: Self::Type, - ptr: Self::Value, - order: AtomicOrdering, - size: Size, - ) -> Self::Value; - fn load_operand(&mut self, place: PlaceRef<'tcx, Self::Value>) - -> OperandRef<'tcx, Self::Value>; - - /// Called for Rvalue::Repeat when the elem is neither a ZST nor optimizable using memset. - fn write_operand_repeatedly( - &mut self, - elem: OperandRef<'tcx, Self::Value>, - count: u64, - dest: PlaceRef<'tcx, Self::Value>, - ); - - fn range_metadata(&mut self, load: Self::Value, range: WrappingRange); - fn nonnull_metadata(&mut self, load: Self::Value); - - fn store(&mut self, val: Self::Value, ptr: Self::Value, align: Align) -> Self::Value; - fn store_with_flags( - &mut self, - val: Self::Value, - ptr: Self::Value, - align: Align, - flags: MemFlags, - ) -> Self::Value; - fn atomic_store( - &mut self, - val: Self::Value, - ptr: Self::Value, - order: AtomicOrdering, - size: Size, - ); - - fn gep(&mut self, ty: Self::Type, ptr: Self::Value, indices: &[Self::Value]) -> Self::Value; - fn inbounds_gep( - &mut self, - ty: Self::Type, - ptr: Self::Value, - indices: &[Self::Value], - ) -> Self::Value; - fn ptradd(&mut self, ptr: Self::Value, offset: Self::Value) -> Self::Value { - self.gep(self.cx().type_i8(), ptr, &[offset]) - } - fn inbounds_ptradd(&mut self, ptr: Self::Value, offset: Self::Value) -> Self::Value { - self.inbounds_gep(self.cx().type_i8(), ptr, &[offset]) - } - - fn trunc(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value; - fn sext(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value; - fn fptoui_sat(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value; - fn fptosi_sat(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value; - fn fptoui(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value; - fn fptosi(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value; - fn uitofp(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value; - fn sitofp(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value; - fn fptrunc(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value; - fn fpext(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value; - fn ptrtoint(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value; - fn inttoptr(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value; - fn bitcast(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value; - fn intcast(&mut self, val: Self::Value, dest_ty: Self::Type, is_signed: bool) -> Self::Value; - fn pointercast(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value; - - fn cast_float_to_int( - &mut self, - signed: bool, - x: Self::Value, - dest_ty: Self::Type, - ) -> Self::Value { - let in_ty = self.cx().val_ty(x); - let (float_ty, int_ty) = if self.cx().type_kind(dest_ty) == TypeKind::Vector - && self.cx().type_kind(in_ty) == TypeKind::Vector - { - (self.cx().element_type(in_ty), self.cx().element_type(dest_ty)) - } else { - (in_ty, dest_ty) - }; - assert!(matches!(self.cx().type_kind(float_ty), TypeKind::Float | TypeKind::Double)); - assert_eq!(self.cx().type_kind(int_ty), TypeKind::Integer); - - if let Some(false) = self.cx().sess().opts.unstable_opts.saturating_float_casts { - return if signed { self.fptosi(x, dest_ty) } else { self.fptoui(x, dest_ty) }; - } - - if signed { self.fptosi_sat(x, dest_ty) } else { self.fptoui_sat(x, dest_ty) } - } - - fn icmp(&mut self, op: IntPredicate, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - fn fcmp(&mut self, op: RealPredicate, lhs: Self::Value, rhs: Self::Value) -> Self::Value; - - fn memcpy( - &mut self, - dst: Self::Value, - dst_align: Align, - src: Self::Value, - src_align: Align, - size: Self::Value, - flags: MemFlags, - ); - fn memmove( - &mut self, - dst: Self::Value, - dst_align: Align, - src: Self::Value, - src_align: Align, - size: Self::Value, - flags: MemFlags, - ); - fn memset( - &mut self, - ptr: Self::Value, - fill_byte: Self::Value, - size: Self::Value, - align: Align, - flags: MemFlags, - ); - - /// *Typed* copy for non-overlapping places. - /// - /// Has a default implementation in terms of `memcpy`, but specific backends - /// can override to do something smarter if possible. - /// - /// (For example, typed load-stores with alias metadata.) - fn typed_place_copy( - &mut self, - dst: PlaceRef<'tcx, Self::Value>, - src: PlaceRef<'tcx, Self::Value>, - ) { - debug_assert!(src.llextra.is_none()); - debug_assert!(dst.llextra.is_none()); - debug_assert_eq!(dst.layout.size, src.layout.size); - if self.sess().opts.optimize == OptLevel::No && self.is_backend_immediate(dst.layout) { - // If we're not optimizing, the aliasing information from `memcpy` - // isn't useful, so just load-store the value for smaller code. - let temp = self.load_operand(src); - temp.val.store(self, dst); - } else if !dst.layout.is_zst() { - let bytes = self.const_usize(dst.layout.size.bytes()); - self.memcpy(dst.llval, dst.align, src.llval, src.align, bytes, MemFlags::empty()); - } - } - - /// *Typed* swap for non-overlapping places. - /// - /// Avoids `alloca`s for Immediates and ScalarPairs. - /// - /// FIXME: Maybe do something smarter for Ref types too? - /// For now, the `typed_swap` intrinsic just doesn't call this for those - /// cases (in non-debug), preferring the fallback body instead. - fn typed_place_swap( - &mut self, - left: PlaceRef<'tcx, Self::Value>, - right: PlaceRef<'tcx, Self::Value>, - ) { - let mut temp = self.load_operand(left); - if let OperandValue::Ref(..) = temp.val { - // The SSA value isn't stand-alone, so we need to copy it elsewhere - let alloca = PlaceRef::alloca(self, left.layout); - self.typed_place_copy(alloca, left); - temp = self.load_operand(alloca); - } - self.typed_place_copy(left, right); - temp.val.store(self, right); - } - - fn select( - &mut self, - cond: Self::Value, - then_val: Self::Value, - else_val: Self::Value, - ) -> Self::Value; - - fn va_arg(&mut self, list: Self::Value, ty: Self::Type) -> Self::Value; - fn extract_element(&mut self, vec: Self::Value, idx: Self::Value) -> Self::Value; - fn vector_splat(&mut self, num_elts: usize, elt: Self::Value) -> Self::Value; - fn extract_value(&mut self, agg_val: Self::Value, idx: u64) -> Self::Value; - fn insert_value(&mut self, agg_val: Self::Value, elt: Self::Value, idx: u64) -> Self::Value; - - fn set_personality_fn(&mut self, personality: Self::Value); - - // These are used by everyone except msvc - fn cleanup_landing_pad(&mut self, pers_fn: Self::Value) -> (Self::Value, Self::Value); - fn filter_landing_pad(&mut self, pers_fn: Self::Value) -> (Self::Value, Self::Value); - fn resume(&mut self, exn0: Self::Value, exn1: Self::Value); - - // These are used only by msvc - fn cleanup_pad(&mut self, parent: Option, args: &[Self::Value]) -> Self::Funclet; - fn cleanup_ret(&mut self, funclet: &Self::Funclet, unwind: Option); - fn catch_pad(&mut self, parent: Self::Value, args: &[Self::Value]) -> Self::Funclet; - fn catch_switch( - &mut self, - parent: Option, - unwind: Option, - handlers: &[Self::BasicBlock], - ) -> Self::Value; - - fn atomic_cmpxchg( - &mut self, - dst: Self::Value, - cmp: Self::Value, - src: Self::Value, - order: AtomicOrdering, - failure_order: AtomicOrdering, - weak: bool, - ) -> (Self::Value, Self::Value); - fn atomic_rmw( - &mut self, - op: AtomicRmwBinOp, - dst: Self::Value, - src: Self::Value, - order: AtomicOrdering, - ) -> Self::Value; - fn atomic_fence(&mut self, order: AtomicOrdering, scope: SynchronizationScope); - fn set_invariant_load(&mut self, load: Self::Value); - - /// Called for `StorageLive` - fn lifetime_start(&mut self, ptr: Self::Value, size: Size); - - /// Called for `StorageDead` - fn lifetime_end(&mut self, ptr: Self::Value, size: Size); - - fn instrprof_increment( - &mut self, - fn_name: Self::Value, - hash: Self::Value, - num_counters: Self::Value, - index: Self::Value, - ); - - fn call( - &mut self, - llty: Self::Type, - fn_attrs: Option<&CodegenFnAttrs>, - fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, - llfn: Self::Value, - args: &[Self::Value], - funclet: Option<&Self::Funclet>, - instance: Option>, - ) -> Self::Value; - fn zext(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value; - - fn apply_attrs_to_cleanup_callsite(&mut self, llret: Self::Value); -} +use super::abi::AbiBuilderMethods;use super::asm::AsmBuilderMethods;use super:: +consts::ConstMethods;use super::coverageinfo::CoverageInfoBuilderMethods;use//3; +super::debuginfo::DebugInfoBuilderMethods;use super::intrinsic:://if let _=(){}; +IntrinsicCallMethods;use super::misc::MiscMethods;use super::type_::{//let _=(); +ArgAbiMethods,BaseTypeMethods,LayoutTypeMethods};use super::{HasCodegen,//{();}; +StaticBuilderMethods};use crate::common::{AtomicOrdering,AtomicRmwBinOp,//{();}; +IntPredicate,RealPredicate,SynchronizationScope,TypeKind,};use crate::mir:://(); +operand::{OperandRef,OperandValue};use crate::mir::place::PlaceRef;use crate::// +MemFlags;use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;use//*&*&(); +rustc_middle::ty::layout::{HasParamEnv,TyAndLayout};use rustc_middle::ty::{//(); +Instance,Ty};use rustc_session::config::OptLevel;use rustc_span::Span;use//({}); +rustc_target::abi::call::FnAbi;use rustc_target::abi::{Abi,Align,Scalar,Size,//; +WrappingRange};use rustc_target::spec::HasTargetSpec;#[derive(Copy,Clone)]pub//; +enum OverflowOp{Add,Sub,Mul,}pub trait BuilderMethods<'a,'tcx>:HasCodegen<'tcx> ++CoverageInfoBuilderMethods<'tcx>+DebugInfoBuilderMethods+ArgAbiMethods<'tcx>+// +AbiBuilderMethods<'tcx>+IntrinsicCallMethods<'tcx>+AsmBuilderMethods<'tcx>+//(); +StaticBuilderMethods+HasParamEnv<'tcx>+HasTargetSpec{fn build(cx:&'a Self:://(); +CodegenCx,llbb:Self::BasicBlock)->Self;fn cx (&self)->&Self::CodegenCx;fn llbb(& +self)->Self::BasicBlock;fn set_span(&mut self,span:Span);fn append_block(cx:&'a +Self::CodegenCx,llfn:Self::Function,name:&str)->Self::BasicBlock;fn//let _=||(); +append_sibling_block(&mut self,name:& str)->Self::BasicBlock;fn switch_to_block( +&mut self,llbb:Self::BasicBlock);fn ret_void(& mut self);fn ret(&mut self,v:Self +::Value);fn br(&mut self,dest:Self::BasicBlock);fn cond_br(&mut self,cond:Self// +::Value,then_llbb:Self::BasicBlock,else_llbb:Self::BasicBlock,);fn switch(&mut// +self,v:Self::Value,else_llbb: Self::BasicBlock,cases:impl ExactSizeIterator,);fn invoke (&mut self,llty:Self::Type,fn_attrs:Option +<&CodegenFnAttrs>,fn_abi:Option<&FnAbi<'tcx,Ty <'tcx>>>,llfn:Self::Value,args:&[ +Self::Value],then:Self::BasicBlock,catch:Self::BasicBlock,funclet:Option<&Self// +::Funclet>,instance:Option>,)->Self::Value;fn unreachable(&mut//; +self);fn add(&mut self,lhs:Self::Value,rhs:Self::Value)->Self::Value;fn fadd(&// +mut self,lhs:Self::Value,rhs:Self::Value)->Self::Value;fn fadd_fast(&mut self,// +lhs:Self::Value,rhs:Self::Value)->Self::Value;fn fadd_algebraic(&mut self,lhs:// +Self::Value,rhs:Self::Value)->Self::Value;fn sub(&mut self,lhs:Self::Value,rhs: +Self::Value)->Self::Value;fn fsub(&mut self,lhs:Self::Value,rhs:Self::Value)->// +Self::Value;fn fsub_fast(&mut self,lhs:Self::Value,rhs:Self::Value)->Self:://(); +Value;fn fsub_algebraic(&mut self,lhs: Self::Value,rhs:Self::Value)->Self::Value +;fn mul(&mut self,lhs:Self::Value,rhs:Self::Value)->Self::Value;fn fmul(&mut//3; +self,lhs:Self::Value,rhs:Self::Value)->Self::Value;fn fmul_fast(&mut self,lhs:// +Self::Value,rhs:Self::Value)->Self::Value;fn fmul_algebraic(&mut self,lhs:Self// +::Value,rhs:Self::Value)->Self::Value;fn udiv(&mut self,lhs:Self::Value,rhs://3; +Self::Value)->Self::Value;fn exactudiv(&mut self,lhs:Self::Value,rhs:Self:://(); +Value)->Self::Value;fn sdiv(&mut self,lhs:Self::Value,rhs:Self::Value)->Self::// +Value;fn exactsdiv(&mut self,lhs:Self::Value,rhs:Self::Value)->Self::Value;fn//; +fdiv(&mut self,lhs:Self::Value,rhs:Self::Value)->Self::Value;fn fdiv_fast(&mut// +self,lhs:Self::Value,rhs:Self::Value) ->Self::Value;fn fdiv_algebraic(&mut self, +lhs:Self::Value,rhs:Self::Value)->Self:: Value;fn urem(&mut self,lhs:Self::Value +,rhs:Self::Value)->Self::Value;fn srem(&mut self,lhs:Self::Value,rhs:Self:://(); +Value)->Self::Value;fn frem(&mut self,lhs:Self::Value,rhs:Self::Value)->Self::// +Value;fn frem_fast(&mut self,lhs:Self::Value,rhs:Self::Value)->Self::Value;fn//; +frem_algebraic(&mut self,lhs:Self::Value,rhs :Self::Value)->Self::Value;fn shl(& +mut self,lhs:Self::Value,rhs:Self::Value)->Self::Value;fn lshr(&mut self,lhs://; +Self::Value,rhs:Self::Value)->Self::Value; fn ashr(&mut self,lhs:Self::Value,rhs +:Self::Value)->Self::Value;fn unchecked_sadd( &mut self,lhs:Self::Value,rhs:Self +::Value)->Self::Value;fn unchecked_uadd(&mut self,lhs:Self::Value,rhs:Self:://3; +Value)->Self::Value;fn unchecked_ssub(&mut self,lhs:Self::Value,rhs:Self::Value +)->Self::Value;fn unchecked_usub(&mut self,lhs:Self::Value,rhs:Self::Value)->//; +Self::Value;fn unchecked_smul(&mut self,lhs:Self::Value,rhs:Self::Value)->Self// +::Value;fn unchecked_umul(&mut self,lhs:Self::Value,rhs:Self::Value)->Self:://3; +Value;fn and(&mut self,lhs:Self::Value, rhs:Self::Value)->Self::Value;fn or(&mut +self,lhs:Self::Value,rhs:Self::Value)->Self::Value;fn xor(&mut self,lhs:Self::// +Value,rhs:Self::Value)->Self::Value;fn neg(&mut self,v:Self::Value)->Self:://(); +Value;fn fneg(&mut self,v:Self::Value)->Self::Value;fn not(&mut self,v:Self:://; +Value)->Self::Value;fn checked_binop(&mut self,oop:OverflowOp,ty:Ty<'_>,lhs://3; +Self::Value,rhs:Self::Value,)->(Self ::Value,Self::Value);fn from_immediate(&mut +self,val:Self::Value)->Self::Value;fn to_immediate(&mut self,val:Self::Value,//; +layout:TyAndLayout<'_>)->Self::Value{if let Abi::Scalar(scalar)=layout.abi{self +.to_immediate_scalar(val,scalar)}else{val }}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 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;fn atomic_load(&mut self,ty:Self::Type,ptr:Self::Value,order://let _=(); +AtomicOrdering,size:Size,)->Self::Value;fn load_operand(&mut self,place://{();}; +PlaceRef<'tcx,Self::Value>)->OperandRef<'tcx,Self::Value>;fn//let _=();let _=(); +write_operand_repeatedly(&mut self,elem:OperandRef< 'tcx,Self::Value>,count:u64, +dest:PlaceRef<'tcx,Self::Value>,);fn range_metadata(&mut self,load:Self::Value, +range:WrappingRange);fn nonnull_metadata(&mut self ,load:Self::Value);fn store(& +mut self,val:Self::Value,ptr:Self::Value,align:Align)->Self::Value;fn//let _=(); +store_with_flags(&mut self,val:Self::Value,ptr:Self::Value,align:Align,flags://; +MemFlags,)->Self::Value;fn atomic_store(&mut self,val:Self::Value,ptr:Self:://3; +Value,order:AtomicOrdering,size:Size,);fn gep(&mut self,ty:Self::Type,ptr:Self// +::Value,indices:&[Self::Value])->Self::Value;fn inbounds_gep(&mut self,ty:Self// +::Type,ptr:Self::Value,indices:&[Self::Value],)->Self::Value;fn ptradd(&mut//(); +self,ptr:Self::Value,offset:Self::Value)->Self ::Value{self.gep((((self.cx()))). +type_i8(),ptr,(&[offset])) }fn inbounds_ptradd(&mut self,ptr:Self::Value,offset: +Self::Value)->Self::Value{self.inbounds_gep(self.cx( ).type_i8(),ptr,&[offset])} +fn trunc(&mut self,val:Self::Value,dest_ty:Self::Type)->Self::Value;fn sext(&//; +mut self,val:Self::Value,dest_ty:Self::Type)->Self::Value;fn fptoui_sat(&mut//3; +self,val:Self::Value,dest_ty:Self::Type)->Self::Value;fn fptosi_sat(&mut self,// +val:Self::Value,dest_ty:Self::Type)->Self:: Value;fn fptoui(&mut self,val:Self:: +Value,dest_ty:Self::Type)->Self::Value;fn fptosi(&mut self,val:Self::Value,//(); +dest_ty:Self::Type)->Self::Value;fn uitofp(&mut self,val:Self::Value,dest_ty://; +Self::Type)->Self::Value;fn sitofp(& mut self,val:Self::Value,dest_ty:Self::Type +)->Self::Value;fn fptrunc(&mut self, val:Self::Value,dest_ty:Self::Type)->Self:: +Value;fn fpext(&mut self,val:Self::Value,dest_ty:Self::Type)->Self::Value;fn//3; +ptrtoint(&mut self,val:Self::Value, dest_ty:Self::Type)->Self::Value;fn inttoptr +(&mut self,val:Self::Value,dest_ty:Self::Type)->Self::Value;fn bitcast(&mut//(); +self,val:Self::Value,dest_ty:Self::Type)-> Self::Value;fn intcast(&mut self,val: +Self::Value,dest_ty:Self::Type,is_signed: bool)->Self::Value;fn pointercast(&mut +self,val:Self::Value,dest_ty:Self::Type)->Self::Value;fn cast_float_to_int(&//3; +mut self,signed:bool,x:Self::Value,dest_ty:Self::Type,)->Self::Value{;let in_ty= +self.cx().val_ty(x);();();let(float_ty,int_ty)=if self.cx().type_kind(dest_ty)== +TypeKind::Vector&&(((self.cx()).type_kind(in_ty))==TypeKind::Vector){(self.cx(). +element_type(in_ty),self.cx().element_type(dest_ty))}else{(in_ty,dest_ty)};();3; +assert!(matches!(self.cx(). type_kind(float_ty),TypeKind::Float|TypeKind::Double +));;assert_eq!(self.cx().type_kind(int_ty),TypeKind::Integer);if let Some(false) +=self.cx().sess().opts.unstable_opts.saturating_float_casts{();return if signed{ +self.fptosi(x,dest_ty)}else{self.fptoui(x,dest_ty)};;}if signed{self.fptosi_sat( +x,dest_ty)}else{(self.fptoui_sat(x,dest_ty))}}fn icmp(&mut self,op:IntPredicate, +lhs:Self::Value,rhs:Self::Value)->Self::Value;fn fcmp(&mut self,op://let _=||(); +RealPredicate,lhs:Self::Value,rhs:Self::Value )->Self::Value;fn memcpy(&mut self +,dst:Self::Value,dst_align:Align,src:Self::Value,src_align:Align,size:Self:://3; +Value,flags:MemFlags,);fn memmove(&mut self,dst:Self::Value,dst_align:Align,src +:Self::Value,src_align:Align,size:Self::Value,flags:MemFlags,);fn memset(&mut//; +self,ptr:Self::Value,fill_byte:Self::Value,size:Self::Value,align:Align,flags:// +MemFlags,);fn typed_place_copy(&mut self,dst:PlaceRef<'tcx,Self::Value>,src://3; +PlaceRef<'tcx,Self::Value>,){;debug_assert!(src.llextra.is_none());debug_assert! +(dst.llextra.is_none());;;debug_assert_eq!(dst.layout.size,src.layout.size);;if +self.sess().opts.optimize==OptLevel::No&&self.is_backend_immediate(dst.layout){; +let temp=self.load_operand(src);;;temp.val.store(self,dst);;}else if!dst.layout. +is_zst(){;let bytes=self.const_usize(dst.layout.size.bytes());;;self.memcpy(dst. +llval,dst.align,src.llval,src.align,bytes,MemFlags::empty());*&*&();((),());}}fn +typed_place_swap(&mut self,left:PlaceRef<'tcx ,Self::Value>,right:PlaceRef<'tcx, +Self::Value>,){;let mut temp=self.load_operand(left);if let OperandValue::Ref(.. +)=temp.val{;let alloca=PlaceRef::alloca(self,left.layout);self.typed_place_copy( +alloca,left);;temp=self.load_operand(alloca);}self.typed_place_copy(left,right); +temp.val.store(self,right);3;}fn select(&mut self,cond:Self::Value,then_val:Self +::Value,else_val:Self::Value,)->Self::Value;fn va_arg(&mut self,list:Self:://(); +Value,ty:Self::Type)->Self::Value;fn extract_element(&mut self,vec:Self::Value, +idx:Self::Value)->Self::Value;fn vector_splat(&mut self,num_elts:usize,elt:Self +::Value)->Self::Value;fn extract_value(&mut self,agg_val:Self::Value,idx:u64)-> +Self::Value;fn insert_value(&mut self,agg_val:Self::Value,elt:Self::Value,idx:// +u64)->Self::Value;fn set_personality_fn(&mut self,personality:Self::Value);fn//; +cleanup_landing_pad(&mut self,pers_fn:Self::Value)->(Self::Value,Self::Value);// +fn filter_landing_pad(&mut self,pers_fn:Self ::Value)->(Self::Value,Self::Value) +;fn resume(&mut self,exn0:Self::Value,exn1:Self::Value);fn cleanup_pad(&mut//(); +self,parent:Option,args:&[Self::Value])->Self::Funclet;fn//((),()); +cleanup_ret(&mut self,funclet:&Self::Funclet,unwind:Option);// +fn catch_pad(&mut self,parent:Self::Value,args:&[Self::Value])->Self::Funclet;// +fn catch_switch(&mut self,parent:Option,unwind:Option,handlers:&[Self::BasicBlock],)->Self::Value;fn atomic_cmpxchg(&mut// +self,dst:Self::Value,cmp:Self::Value,src:Self::Value,order:AtomicOrdering,//{;}; +failure_order:AtomicOrdering,weak:bool,)->(Self::Value,Self::Value);fn//((),()); +atomic_rmw(&mut self,op:AtomicRmwBinOp,dst:Self::Value,src:Self::Value,order://; +AtomicOrdering,)->Self::Value;fn atomic_fence(&mut self,order:AtomicOrdering,//; +scope:SynchronizationScope);fn set_invariant_load(&mut self,load:Self::Value);// +fn lifetime_start(&mut self,ptr:Self::Value,size:Size);fn lifetime_end(&mut//(); +self,ptr:Self::Value,size:Size); fn instrprof_increment(&mut self,fn_name:Self:: +Value,hash:Self::Value,num_counters:Self::Value,index:Self::Value,);fn call(&//; +mut self,llty:Self::Type,fn_attrs: Option<&CodegenFnAttrs>,fn_abi:Option<&FnAbi< +'tcx,Ty<'tcx>>>,llfn:Self::Value,args:&[Self::Value],funclet:Option<&Self:://(); +Funclet>,instance:Option>,)->Self::Value;fn zext(&mut self,val:// +Self::Value,dest_ty:Self::Type )->Self::Value;fn apply_attrs_to_cleanup_callsite +(&mut self,llret:Self::Value);}//let _=||();loop{break};loop{break};loop{break}; diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs index 4dff9c7684f18..1f82bfbf19a33 100644 --- a/compiler/rustc_codegen_ssa/src/traits/consts.rs +++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs @@ -1,41 +1,18 @@ -use super::BackendTypes; -use rustc_middle::mir::interpret::{ConstAllocation, Scalar}; -use rustc_target::abi; - -pub trait ConstMethods<'tcx>: BackendTypes { - // Constant constructors - fn const_null(&self, t: Self::Type) -> Self::Value; - /// Generate an uninitialized value (matching uninitialized memory in MIR). - /// Whether memory is initialized or not is tracked byte-for-byte. - fn const_undef(&self, t: Self::Type) -> Self::Value; - /// Generate a fake value. Poison always affects the entire value, even if just a single byte is - /// poison. This can only be used in codepaths that are already UB, i.e., UB-free Rust code - /// (including code that e.g. copies uninit memory with `MaybeUninit`) can never encounter a - /// poison value. - fn const_poison(&self, t: Self::Type) -> Self::Value; - fn const_int(&self, t: Self::Type, i: i64) -> Self::Value; - fn const_uint(&self, t: Self::Type, i: u64) -> Self::Value; - fn const_uint_big(&self, t: Self::Type, u: u128) -> Self::Value; - fn const_bool(&self, val: bool) -> Self::Value; - fn const_i16(&self, i: i16) -> Self::Value; - fn const_i32(&self, i: i32) -> Self::Value; - fn const_u32(&self, i: u32) -> Self::Value; - fn const_u64(&self, i: u64) -> Self::Value; - fn const_u128(&self, i: u128) -> Self::Value; - fn const_usize(&self, i: u64) -> Self::Value; - fn const_u8(&self, i: u8) -> Self::Value; - fn const_real(&self, t: Self::Type, val: f64) -> Self::Value; - - fn const_str(&self, s: &str) -> (Self::Value, Self::Value); - fn const_struct(&self, elts: &[Self::Value], packed: bool) -> Self::Value; - - fn const_to_opt_uint(&self, v: Self::Value) -> Option; - fn const_to_opt_u128(&self, v: Self::Value, sign_ext: bool) -> Option; - - fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value; - - fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: Self::Type) -> Self::Value; - - fn const_bitcast(&self, val: Self::Value, ty: Self::Type) -> Self::Value; - fn const_ptr_byte_offset(&self, val: Self::Value, offset: abi::Size) -> Self::Value; -} +use super::BackendTypes;use rustc_middle::mir::interpret::{ConstAllocation,//(); +Scalar};use rustc_target::abi;pub trait ConstMethods<'tcx>:BackendTypes{fn//{;}; +const_null(&self,t:Self::Type)->Self::Value;fn const_undef(&self,t:Self::Type)// +->Self::Value;fn const_poison(&self,t:Self::Type)->Self::Value;fn const_int(&//; +self,t:Self::Type,i:i64)->Self::Value; fn const_uint(&self,t:Self::Type,i:u64)-> +Self::Value;fn const_uint_big(&self,t:Self::Type,u:u128)->Self::Value;fn//{();}; +const_bool(&self,val:bool)->Self::Value;fn const_i16(&self,i:i16)->Self::Value; +fn const_i32(&self,i:i32)->Self::Value;fn const_u32(&self,i:u32)->Self::Value;// +fn const_u64(&self,i:u64)->Self::Value ;fn const_u128(&self,i:u128)->Self::Value +;fn const_usize(&self,i:u64)->Self::Value ;fn const_u8(&self,i:u8)->Self::Value; +fn const_real(&self,t:Self::Type,val:f64)->Self::Value;fn const_str(&self,s:&//; +str)->(Self::Value,Self::Value);fn const_struct(&self,elts:&[Self::Value],//{;}; +packed:bool)->Self::Value;fn const_to_opt_uint( &self,v:Self::Value)->Option;fn const_to_opt_u128(&self,v:Self::Value,sign_ext:bool)->Option;fn//{;}; +const_data_from_alloc(&self,alloc:ConstAllocation<'tcx>)->Self::Value;fn//{();}; +scalar_to_backend(&self,cv:Scalar,layout:abi::Scalar,llty:Self::Type)->Self:://; +Value;fn const_bitcast(&self,val:Self::Value,ty:Self::Type)->Self::Value;fn//(); +const_ptr_byte_offset(&self,val:Self::Value,offset:abi::Size)->Self::Value;}//3; diff --git a/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs b/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs index d1d813bd38922..a788162f41e70 100644 --- a/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs +++ b/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs @@ -1,11 +1,4 @@ -use super::BackendTypes; -use rustc_middle::mir::coverage::CoverageKind; -use rustc_middle::ty::Instance; - -pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes { - /// Handle the MIR coverage info in a backend-specific way. - /// - /// This can potentially be a no-op in backends that don't support - /// coverage instrumentation. - fn add_coverage(&mut self, instance: Instance<'tcx>, kind: &CoverageKind); -} +use super::BackendTypes;use rustc_middle::mir::coverage::CoverageKind;use//({}); +rustc_middle::ty::Instance;pub trait CoverageInfoBuilderMethods<'tcx>://((),()); +BackendTypes{fn add_coverage(&mut self,instance:Instance<'tcx>,kind:&//let _=(); +CoverageKind);}//*&*&();((),());((),());((),());((),());((),());((),());((),()); diff --git a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs index 4acc0ea076c13..011d8dbaf493d 100644 --- a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs @@ -1,84 +1,22 @@ -use super::BackendTypes; -use crate::mir::debuginfo::{FunctionDebugContext, VariableKind}; -use rustc_middle::mir; -use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty}; -use rustc_span::{SourceFile, Span, Symbol}; -use rustc_target::abi::call::FnAbi; -use rustc_target::abi::Size; - -use std::ops::Range; - -pub trait DebugInfoMethods<'tcx>: BackendTypes { - fn create_vtable_debuginfo( - &self, - ty: Ty<'tcx>, - trait_ref: Option>, - vtable: Self::Value, - ); - - /// Creates the function-specific debug context. - /// - /// Returns the FunctionDebugContext for the function which holds state needed - /// for debug info creation, if it is enabled. - fn create_function_debug_context( - &self, - instance: Instance<'tcx>, - fn_abi: &FnAbi<'tcx, Ty<'tcx>>, - llfn: Self::Function, - mir: &mir::Body<'tcx>, - ) -> Option>; - - // FIXME(eddyb) find a common convention for all of the debuginfo-related - // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.). - fn dbg_scope_fn( - &self, - instance: Instance<'tcx>, - fn_abi: &FnAbi<'tcx, Ty<'tcx>>, - maybe_definition_llfn: Option, - ) -> Self::DIScope; - - fn dbg_loc( - &self, - scope: Self::DIScope, - inlined_at: Option, - span: Span, - ) -> Self::DILocation; - - fn extend_scope_to_file( - &self, - scope_metadata: Self::DIScope, - file: &SourceFile, - ) -> Self::DIScope; - fn debuginfo_finalize(&self); - - // FIXME(eddyb) find a common convention for all of the debuginfo-related - // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.). - fn create_dbg_var( - &self, - variable_name: Symbol, - variable_type: Ty<'tcx>, - scope_metadata: Self::DIScope, - variable_kind: VariableKind, - span: Span, - ) -> Self::DIVariable; -} - -pub trait DebugInfoBuilderMethods: BackendTypes { - // FIXME(eddyb) find a common convention for all of the debuginfo-related - // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.). - fn dbg_var_addr( - &mut self, - dbg_var: Self::DIVariable, - dbg_loc: Self::DILocation, - variable_alloca: Self::Value, - direct_offset: Size, - // NB: each offset implies a deref (i.e. they're steps in a pointer chain). - indirect_offsets: &[Size], - // Byte range in the `dbg_var` covered by this fragment, - // if this is a fragment of a composite `DIVariable`. - fragment: Option>, - ); - fn set_dbg_loc(&mut self, dbg_loc: Self::DILocation); - fn insert_reference_to_gdb_debug_scripts_section_global(&mut self); - fn set_var_name(&mut self, value: Self::Value, name: &str); -} +use super::BackendTypes;use crate::mir::debuginfo::{FunctionDebugContext,//({}); +VariableKind};use rustc_middle::mir;use rustc_middle::ty::{Instance,//if true{}; +PolyExistentialTraitRef,Ty};use rustc_span::{SourceFile,Span,Symbol};use//{();}; +rustc_target::abi::call::FnAbi;use rustc_target:: abi::Size;use std::ops::Range; +pub trait DebugInfoMethods<'tcx>: BackendTypes{fn create_vtable_debuginfo(&self, +ty:Ty<'tcx>,trait_ref:Option< PolyExistentialTraitRef<'tcx>>,vtable:Self::Value, +);fn create_function_debug_context(&self,instance :Instance<'tcx>,fn_abi:&FnAbi< +'tcx,Ty<'tcx>>,llfn:Self::Function,mir:&mir::Body<'tcx>,)->Option>;fn dbg_scope_fn(&//3; +self,instance:Instance<'tcx>,fn_abi: &FnAbi<'tcx,Ty<'tcx>>,maybe_definition_llfn +:Option,)->Self::DIScope;fn dbg_loc(&self,scope:Self::DIScope,// +inlined_at:Option,span:Span,)->Self::DILocation;fn//if true{}; +extend_scope_to_file(&self,scope_metadata:Self::DIScope,file:&SourceFile,)->//3; +Self::DIScope;fn debuginfo_finalize(&self);fn create_dbg_var(&self,//let _=||(); +variable_name:Symbol,variable_type:Ty<'tcx>,scope_metadata:Self::DIScope,//({}); +variable_kind:VariableKind,span:Span,)->Self::DIVariable;}pub trait//let _=||(); +DebugInfoBuilderMethods:BackendTypes{fn dbg_var_addr(&mut self,dbg_var:Self:://; +DIVariable,dbg_loc:Self::DILocation,variable_alloca:Self::Value,direct_offset:// +Size,indirect_offsets:&[Size],fragment:Option>,);fn set_dbg_loc(&//; +mut self,dbg_loc:Self::DILocation);fn//if true{};if true{};if true{};let _=||(); +insert_reference_to_gdb_debug_scripts_section_global(&mut self);fn set_var_name +(&mut self,value:Self::Value,name:&str);}//let _=();let _=();let _=();if true{}; diff --git a/compiler/rustc_codegen_ssa/src/traits/declare.rs b/compiler/rustc_codegen_ssa/src/traits/declare.rs index 655afcd17f0da..e274c2aafec7e 100644 --- a/compiler/rustc_codegen_ssa/src/traits/declare.rs +++ b/compiler/rustc_codegen_ssa/src/traits/declare.rs @@ -1,21 +1,6 @@ -use super::BackendTypes; -use rustc_hir::def_id::DefId; -use rustc_middle::mir::mono::{Linkage, Visibility}; -use rustc_middle::ty::Instance; - -pub trait PreDefineMethods<'tcx>: BackendTypes { - fn predefine_static( - &self, - def_id: DefId, - linkage: Linkage, - visibility: Visibility, - symbol_name: &str, - ); - fn predefine_fn( - &self, - instance: Instance<'tcx>, - linkage: Linkage, - visibility: Visibility, - symbol_name: &str, - ); -} +use super::BackendTypes;use rustc_hir::def_id::DefId;use rustc_middle::mir:://3; +mono::{Linkage,Visibility};use rustc_middle::ty::Instance;pub trait//let _=||(); +PreDefineMethods<'tcx>:BackendTypes{fn predefine_static(&self,def_id:DefId,//(); +linkage:Linkage,visibility:Visibility,symbol_name:& str,);fn predefine_fn(&self, +instance:Instance<'tcx>,linkage:Linkage ,visibility:Visibility,symbol_name:&str, +);}//let _=();let _=();let _=();if true{};let _=();if true{};let _=();if true{}; diff --git a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs index 502f0b3fcb510..bd39c76fdf330 100644 --- a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs @@ -1,41 +1,11 @@ -use super::BackendTypes; -use crate::mir::operand::OperandRef; -use rustc_middle::ty::{self, Ty}; -use rustc_span::Span; -use rustc_target::abi::call::FnAbi; - -pub trait IntrinsicCallMethods<'tcx>: BackendTypes { - /// 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`. - /// Returns `Err` if another instance should be called instead. This is used to invoke - /// intrinsic default bodies in case an intrinsic is not implemented by the backend. - fn codegen_intrinsic_call( - &mut self, - instance: ty::Instance<'tcx>, - fn_abi: &FnAbi<'tcx, Ty<'tcx>>, - args: &[OperandRef<'tcx, Self::Value>], - llresult: Self::Value, - span: Span, - ) -> Result<(), ty::Instance<'tcx>>; - - fn abort(&mut self); - fn assume(&mut self, val: Self::Value); - fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value; - /// Trait method used to test whether a given pointer is associated with a type identifier. - fn type_test(&mut self, pointer: Self::Value, typeid: Self::Value) -> Self::Value; - /// Trait method used to load a function while testing if it is associated with a type - /// identifier. - fn type_checked_load( - &mut self, - llvtable: Self::Value, - vtable_byte_offset: u64, - typeid: Self::Value, - ) -> Self::Value; - /// Trait method used to inject `va_start` on the "spoofed" `VaListImpl` in - /// Rust defined C-variadic functions. - fn va_start(&mut self, val: Self::Value) -> Self::Value; - /// Trait method used to inject `va_end` on the "spoofed" `VaListImpl` before - /// Rust defined C-variadic functions return. - fn va_end(&mut self, val: Self::Value) -> Self::Value; -} +use super::BackendTypes;use crate::mir::operand::OperandRef;use rustc_middle::// +ty::{self,Ty};use rustc_span::Span ;use rustc_target::abi::call::FnAbi;pub trait +IntrinsicCallMethods<'tcx>:BackendTypes{fn codegen_intrinsic_call(&mut self,//3; +instance:ty::Instance<'tcx>,fn_abi:&FnAbi< 'tcx,Ty<'tcx>>,args:&[OperandRef<'tcx +,Self::Value>],llresult:Self::Value,span: Span,)->Result<(),ty::Instance<'tcx>>; +fn abort(&mut self);fn assume(&mut self,val:Self::Value);fn expect(&mut self,//; +cond:Self::Value,expected:bool)->Self::Value;fn type_test(&mut self,pointer://3; +Self::Value,typeid:Self::Value)->Self::Value;fn type_checked_load(&mut self,//3; +llvtable:Self::Value,vtable_byte_offset:u64,typeid:Self::Value,)->Self::Value;// +fn va_start(&mut self,val:Self::Value)->Self::Value;fn va_end(&mut self,val://3; +Self::Value)->Self::Value;}//loop{break};loop{break;};loop{break;};loop{break;}; diff --git a/compiler/rustc_codegen_ssa/src/traits/misc.rs b/compiler/rustc_codegen_ssa/src/traits/misc.rs index 04e2b8796c46a..d64bcce216a92 100644 --- a/compiler/rustc_codegen_ssa/src/traits/misc.rs +++ b/compiler/rustc_codegen_ssa/src/traits/misc.rs @@ -1,22 +1,11 @@ -use super::BackendTypes; -use rustc_data_structures::fx::FxHashMap; -use rustc_middle::mir::mono::CodegenUnit; -use rustc_middle::ty::{self, Instance, Ty}; -use rustc_session::Session; -use std::cell::RefCell; - -pub trait MiscMethods<'tcx>: BackendTypes { - fn vtables( - &self, - ) -> &RefCell, Option>), Self::Value>>; - fn check_overflow(&self) -> bool; - fn get_fn(&self, instance: Instance<'tcx>) -> Self::Function; - fn get_fn_addr(&self, instance: Instance<'tcx>) -> Self::Value; - fn eh_personality(&self) -> Self::Value; - fn sess(&self) -> &Session; - fn codegen_unit(&self) -> &'tcx CodegenUnit<'tcx>; - fn set_frame_pointer_type(&self, llfn: Self::Function); - fn apply_target_cpu_attr(&self, llfn: Self::Function); - /// 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; -} +use super::BackendTypes;use rustc_data_structures::fx::FxHashMap;use//if true{}; +rustc_middle::mir::mono::CodegenUnit;use rustc_middle::ty::{self,Instance,Ty};// +use rustc_session::Session;use std::cell::RefCell;pub trait MiscMethods<'tcx>:// +BackendTypes{fn vtables(&self,)->&RefCell,Option>),Self::Value>>; fn check_overflow(&self)->bool;fn +get_fn(&self,instance:Instance<'tcx>)->Self::Function;fn get_fn_addr(&self,//(); +instance:Instance<'tcx>)->Self::Value;fn eh_personality(&self)->Self::Value;fn// +sess(&self)->&Session;fn codegen_unit(&self)->&'tcx CodegenUnit<'tcx>;fn//{();}; +set_frame_pointer_type(&self,llfn:Self::Function);fn apply_target_cpu_attr(&//3; +self,llfn:Self::Function);fn declare_c_main(&self,fn_type:Self::Type)->Option;}//*&*&();((),());*&*&();((),());*&*&();((),());((),());((),()); diff --git a/compiler/rustc_codegen_ssa/src/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs index 728c2bc8c49bc..3f1d3a0252596 100644 --- a/compiler/rustc_codegen_ssa/src/traits/mod.rs +++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs @@ -1,102 +1,27 @@ -//! Interface of a Rust codegen backend -//! -//! This crate defines all the traits that have to be implemented by a codegen backend in order to -//! use the backend-agnostic codegen code in `rustc_codegen_ssa`. -//! -//! The interface is designed around two backend-specific data structures, the codegen context and -//! the builder. The codegen context is supposed to be read-only after its creation and during the -//! actual codegen, while the builder stores the information about the function during codegen and -//! is used to produce the instructions of the backend IR. -//! -//! Finally, a third `Backend` structure has to implement methods related to how codegen information -//! is passed to the backend, especially for asynchronous compilation. -//! -//! The traits contain associated types that are backend-specific, such as the backend's value or -//! basic blocks. - -mod abi; -mod asm; -mod backend; -mod builder; -mod consts; -mod coverageinfo; -mod debuginfo; -mod declare; -mod intrinsic; -mod misc; -mod statics; -mod type_; -mod write; - -pub use self::abi::AbiBuilderMethods; -pub use self::asm::{AsmBuilderMethods, AsmMethods, GlobalAsmOperandRef, InlineAsmOperandRef}; -pub use self::backend::{ - Backend, BackendTypes, CodegenBackend, ExtraBackendMethods, PrintBackendInfo, -}; -pub use self::builder::{BuilderMethods, OverflowOp}; -pub use self::consts::ConstMethods; -pub use self::coverageinfo::CoverageInfoBuilderMethods; -pub use self::debuginfo::{DebugInfoBuilderMethods, DebugInfoMethods}; -pub use self::declare::PreDefineMethods; -pub use self::intrinsic::IntrinsicCallMethods; -pub use self::misc::MiscMethods; -pub use self::statics::{StaticBuilderMethods, StaticMethods}; -pub use self::type_::{ - ArgAbiMethods, BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods, TypeMembershipMethods, - TypeMethods, -}; -pub use self::write::{ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods}; - -use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt}; -use rustc_target::spec::HasTargetSpec; - -use std::fmt; - -pub trait CodegenObject: Copy + PartialEq + fmt::Debug {} -impl CodegenObject for T {} - -pub trait CodegenMethods<'tcx>: - Backend<'tcx> - + TypeMethods<'tcx> - + MiscMethods<'tcx> - + ConstMethods<'tcx> - + StaticMethods - + DebugInfoMethods<'tcx> - + AsmMethods<'tcx> - + PreDefineMethods<'tcx> - + HasParamEnv<'tcx> - + HasTyCtxt<'tcx> - + HasTargetSpec -{ -} - -impl<'tcx, T> CodegenMethods<'tcx> for T where - Self: Backend<'tcx> - + TypeMethods<'tcx> - + MiscMethods<'tcx> - + ConstMethods<'tcx> - + StaticMethods - + DebugInfoMethods<'tcx> - + AsmMethods<'tcx> - + PreDefineMethods<'tcx> - + HasParamEnv<'tcx> - + HasTyCtxt<'tcx> - + HasTargetSpec -{ -} - -pub trait HasCodegen<'tcx>: - Backend<'tcx> + std::ops::Deref>::CodegenCx> -{ - type CodegenCx: CodegenMethods<'tcx> - + BackendTypes< - Value = Self::Value, - Function = Self::Function, - BasicBlock = Self::BasicBlock, - Type = Self::Type, - Funclet = Self::Funclet, - DIScope = Self::DIScope, - DILocation = Self::DILocation, - DIVariable = Self::DIVariable, - >; -} +mod abi;mod asm;mod backend;mod builder;mod consts;mod coverageinfo;mod//*&*&(); +debuginfo;mod declare;mod intrinsic;mod misc;mod statics;mod type_;mod write;//; +pub use self::abi::AbiBuilderMethods;pub use self::asm::{AsmBuilderMethods,//(); +AsmMethods,GlobalAsmOperandRef,InlineAsmOperandRef};pub use self::backend::{//3; +Backend,BackendTypes,CodegenBackend,ExtraBackendMethods,PrintBackendInfo,};pub// +use self::builder::{BuilderMethods,OverflowOp};pub use self::consts:://let _=(); +ConstMethods;pub use self::coverageinfo::CoverageInfoBuilderMethods;pub use//(); +self::debuginfo::{DebugInfoBuilderMethods,DebugInfoMethods};pub use self:://{;}; +declare::PreDefineMethods;pub use self::intrinsic::IntrinsicCallMethods;pub use +self::misc::MiscMethods;pub use self::statics::{StaticBuilderMethods,//let _=(); +StaticMethods};pub use self::type_::{ArgAbiMethods,BaseTypeMethods,//let _=||(); +DerivedTypeMethods,LayoutTypeMethods,TypeMembershipMethods,TypeMethods,};pub//3; +use self::write::{ModuleBufferMethods,ThinBufferMethods,WriteBackendMethods};//; +use rustc_middle::ty::layout::{HasParamEnv,HasTyCtxt};use rustc_target::spec::// +HasTargetSpec;use std::fmt;pub trait CodegenObject:Copy+PartialEq+fmt::Debug{}// +impl CodegenObject for T{}pub trait CodegenMethods< +'tcx>:Backend<'tcx>+TypeMethods<'tcx>+MiscMethods<'tcx>+ConstMethods<'tcx>+//(); +StaticMethods+DebugInfoMethods<'tcx>+AsmMethods<'tcx>+PreDefineMethods<'tcx>+//; +HasParamEnv<'tcx>+HasTyCtxt<'tcx>+HasTargetSpec{}impl<'tcx,T>CodegenMethodsfor T where Self:Backend<'tcx>+TypeMethods<'tcx>+MiscMethods<'tcx>+//{();}; +ConstMethods<'tcx>+StaticMethods+DebugInfoMethods<'tcx>+AsmMethods<'tcx>+//({}); +PreDefineMethods<'tcx>+HasParamEnv<'tcx>+HasTyCtxt<'tcx>+HasTargetSpec{}pub//(); +trait HasCodegen<'tcx>:Backend<'tcx>+std ::ops::Deref>::CodegenCx>{type CodegenCx :CodegenMethods<'tcx>+BackendTypes;}//let _=||();loop{break};loop{break};loop{break}; diff --git a/compiler/rustc_codegen_ssa/src/traits/statics.rs b/compiler/rustc_codegen_ssa/src/traits/statics.rs index 737d93fd80ab0..607243eebce62 100644 --- a/compiler/rustc_codegen_ssa/src/traits/statics.rs +++ b/compiler/rustc_codegen_ssa/src/traits/statics.rs @@ -1,24 +1,7 @@ -use super::BackendTypes; -use rustc_hir::def_id::DefId; -use rustc_target::abi::Align; - -pub trait StaticMethods: BackendTypes { - fn static_addr_of(&self, cv: Self::Value, align: Align, kind: Option<&str>) -> Self::Value; - fn codegen_static(&self, def_id: DefId); - - /// Mark the given global value as "used", to prevent the compiler and linker from potentially - /// removing a static variable that may otherwise appear unused. - fn add_used_global(&self, global: Self::Value); - - /// Same as add_used_global(), but only prevent the compiler from potentially removing an - /// otherwise unused symbol. The linker is still permitted to drop it. - /// - /// This corresponds to the documented semantics of the `#[used]` attribute, although - /// on some targets (non-ELF), we may use `add_used_global` for `#[used]` statics - /// instead. - fn add_compiler_used_global(&self, global: Self::Value); -} - -pub trait StaticBuilderMethods: BackendTypes { - fn get_static(&mut self, def_id: DefId) -> Self::Value; -} +use super::BackendTypes;use rustc_hir::def_id::DefId;use rustc_target::abi:://3; +Align;pub trait StaticMethods:BackendTypes{fn static_addr_of(&self,cv:Self:://3; +Value,align:Align,kind:Option<&str>)->Self::Value;fn codegen_static(&self,//{;}; +def_id:DefId);fn add_used_global(&self,global:Self::Value);fn//((),());let _=(); +add_compiler_used_global(&self,global:Self::Value);}pub trait//((),());let _=(); +StaticBuilderMethods:BackendTypes{fn get_static(&mut self,def_id:DefId)->Self:: +Value;}//((),());let _=();let _=();let _=();let _=();let _=();let _=();let _=(); diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs index 555833759ebce..6bf7e80839296 100644 --- a/compiler/rustc_codegen_ssa/src/traits/type_.rs +++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs @@ -1,196 +1,57 @@ -use super::misc::MiscMethods; -use super::Backend; -use super::HasCodegen; -use crate::common::TypeKind; -use crate::mir::place::PlaceRef; -use rustc_middle::ty::layout::TyAndLayout; -use rustc_middle::ty::{self, Ty}; -use rustc_target::abi::call::{ArgAbi, CastTarget, FnAbi, Reg}; -use rustc_target::abi::{AddressSpace, Integer}; - -// This depends on `Backend` and not `BackendTypes`, because consumers will probably want to use -// `LayoutOf` or `HasTyCtxt`. This way, they don't have to add a constraint on it themselves. -pub trait BaseTypeMethods<'tcx>: Backend<'tcx> { - fn type_i1(&self) -> Self::Type; - fn type_i8(&self) -> Self::Type; - fn type_i16(&self) -> Self::Type; - fn type_i32(&self) -> Self::Type; - fn type_i64(&self) -> Self::Type; - fn type_i128(&self) -> Self::Type; - fn type_isize(&self) -> Self::Type; - - fn type_f16(&self) -> Self::Type; - fn type_f32(&self) -> Self::Type; - fn type_f64(&self) -> Self::Type; - fn type_f128(&self) -> Self::Type; - - fn type_array(&self, ty: Self::Type, len: u64) -> Self::Type; - fn type_func(&self, args: &[Self::Type], ret: Self::Type) -> Self::Type; - fn type_struct(&self, els: &[Self::Type], packed: bool) -> Self::Type; - fn type_kind(&self, ty: Self::Type) -> TypeKind; - fn type_ptr(&self) -> Self::Type; - fn type_ptr_ext(&self, address_space: AddressSpace) -> Self::Type; - fn element_type(&self, ty: Self::Type) -> Self::Type; - - /// Returns the number of elements in `self` if it is an LLVM vector type. - fn vector_length(&self, ty: Self::Type) -> usize; - - fn float_width(&self, ty: Self::Type) -> usize; - - /// Retrieves the bit width of the integer type `self`. - fn int_width(&self, ty: Self::Type) -> u64; - - fn val_ty(&self, v: Self::Value) -> Self::Type; -} - -pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> { - fn type_int(&self) -> Self::Type { - match &self.sess().target.c_int_width[..] { - "16" => self.type_i16(), - "32" => self.type_i32(), - "64" => self.type_i64(), - width => bug!("Unsupported c_int_width: {}", width), - } - } - - fn type_from_integer(&self, i: Integer) -> Self::Type { - use Integer::*; - match i { - I8 => self.type_i8(), - I16 => self.type_i16(), - I32 => self.type_i32(), - I64 => self.type_i64(), - I128 => self.type_i128(), - } - } - - fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool { - ty.needs_drop(self.tcx(), ty::ParamEnv::reveal_all()) - } - - fn type_is_sized(&self, ty: Ty<'tcx>) -> bool { - ty.is_sized(self.tcx(), ty::ParamEnv::reveal_all()) - } - - fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool { - 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(), param_env) { - return false; - } - - let tail = self.tcx().struct_tail_erasing_lifetimes(ty, param_env); - match tail.kind() { - ty::Foreign(..) => false, - ty::Str | ty::Slice(..) | ty::Dynamic(..) => true, - _ => bug!("unexpected unsized tail: {:?}", tail), - } - } -} - -impl<'tcx, T> DerivedTypeMethods<'tcx> for T where Self: BaseTypeMethods<'tcx> + MiscMethods<'tcx> {} - -pub trait LayoutTypeMethods<'tcx>: Backend<'tcx> { - /// The backend type used for a rust type when it's in memory, - /// such as when it's stack-allocated or when it's being loaded or stored. - fn backend_type(&self, layout: TyAndLayout<'tcx>) -> Self::Type; - fn cast_backend_type(&self, ty: &CastTarget) -> Self::Type; - fn fn_decl_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Self::Type; - fn fn_ptr_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Self::Type; - fn reg_backend_type(&self, ty: &Reg) -> Self::Type; - /// The backend type used for a rust type when it's in an SSA register. - /// - /// For nearly all types this is the same as the [`Self::backend_type`], however - /// `bool` (and other `0`-or-`1` values) are kept as [`BaseTypeMethods::type_i1`] - /// in registers but as [`BaseTypeMethods::type_i8`] in memory. - /// - /// Converting values between the two different backend types is done using - /// [`from_immediate`](super::BuilderMethods::from_immediate) and - /// [`to_immediate_scalar`](super::BuilderMethods::to_immediate_scalar). - fn immediate_backend_type(&self, layout: TyAndLayout<'tcx>) -> Self::Type; - fn is_backend_immediate(&self, layout: TyAndLayout<'tcx>) -> bool; - fn is_backend_scalar_pair(&self, layout: TyAndLayout<'tcx>) -> bool; - fn scalar_pair_element_backend_type( - &self, - layout: TyAndLayout<'tcx>, - index: usize, - immediate: bool, - ) -> Self::Type; - - /// A type that produces an [`OperandValue::Ref`] when loaded. - /// - /// AKA one that's not a ZST, not `is_backend_immediate`, and - /// not `is_backend_scalar_pair`. For such a type, a - /// [`load_operand`] doesn't actually `load` anything. - /// - /// [`OperandValue::Ref`]: crate::mir::operand::OperandValue::Ref - /// [`load_operand`]: super::BuilderMethods::load_operand - fn is_backend_ref(&self, layout: TyAndLayout<'tcx>) -> bool { - !(layout.is_zst() - || self.is_backend_immediate(layout) - || self.is_backend_scalar_pair(layout)) - } - - /// A type that can be used in a [`super::BuilderMethods::load`] + - /// [`super::BuilderMethods::store`] pair to implement a *typed* copy, - /// such as a MIR `*_0 = *_1`. - /// - /// It's always legal to return `None` here, as the provided impl does, - /// in which case callers should use [`super::BuilderMethods::memcpy`] - /// instead of the `load`+`store` pair. - /// - /// This can be helpful for things like arrays, where the LLVM backend type - /// `[3 x i16]` optimizes to three separate loads and stores, but it can - /// instead be copied via an `i48` that stays as the single `load`+`store`. - /// (As of 2023-05 LLVM cannot necessarily optimize away a `memcpy` in these - /// cases, due to `poison` handling, but in codegen we have more information - /// about the type invariants, so can emit something better instead.) - /// - /// This *should* return `None` for particularly-large types, where leaving - /// the `memcpy` may well be important to avoid code size explosion. - fn scalar_copy_backend_type(&self, layout: TyAndLayout<'tcx>) -> Option { - let _ = layout; - None - } -} - -// For backends that support CFI using type membership (i.e., testing whether a given pointer is -// associated with a type identifier). -pub trait TypeMembershipMethods<'tcx>: Backend<'tcx> { - fn add_type_metadata(&self, _function: Self::Function, _typeid: String) {} - fn set_type_metadata(&self, _function: Self::Function, _typeid: String) {} - fn typeid_metadata(&self, _typeid: String) -> Option { - None - } - fn add_kcfi_type_metadata(&self, _function: Self::Function, _typeid: u32) {} - fn set_kcfi_type_metadata(&self, _function: Self::Function, _typeid: u32) {} -} - -pub trait ArgAbiMethods<'tcx>: HasCodegen<'tcx> { - fn store_fn_arg( - &mut self, - arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, - idx: &mut usize, - dst: PlaceRef<'tcx, Self::Value>, - ); - fn store_arg( - &mut self, - arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, - val: Self::Value, - dst: PlaceRef<'tcx, Self::Value>, - ); - fn arg_memory_ty(&self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>) -> Self::Type; -} - -pub trait TypeMethods<'tcx>: - DerivedTypeMethods<'tcx> + LayoutTypeMethods<'tcx> + TypeMembershipMethods<'tcx> -{ -} - -impl<'tcx, T> TypeMethods<'tcx> for T where - Self: DerivedTypeMethods<'tcx> + LayoutTypeMethods<'tcx> + TypeMembershipMethods<'tcx> -{ -} +use super::misc::MiscMethods;use super ::Backend;use super::HasCodegen;use crate +::common::TypeKind;use crate::mir:: place::PlaceRef;use rustc_middle::ty::layout +::TyAndLayout;use rustc_middle::ty::{self,Ty};use rustc_target::abi::call::{//3; +ArgAbi,CastTarget,FnAbi,Reg};use rustc_target::abi::{AddressSpace,Integer};pub// +trait BaseTypeMethods<'tcx>:Backend<'tcx>{fn type_i1(&self)->Self::Type;fn//{;}; +type_i8(&self)->Self::Type;fn type_i16(&self)->Self::Type;fn type_i32(&self)->// +Self::Type;fn type_i64(&self)->Self::Type;fn type_i128(&self)->Self::Type;fn//3; +type_isize(&self)->Self::Type;fn type_f16( &self)->Self::Type;fn type_f32(&self) +->Self::Type;fn type_f64(&self)->Self::Type;fn type_f128(&self)->Self::Type;fn// +type_array(&self,ty:Self::Type,len:u64)->Self::Type;fn type_func(&self,args:&[// +Self::Type],ret:Self::Type)->Self::Type; fn type_struct(&self,els:&[Self::Type], +packed:bool)->Self::Type;fn type_kind(&self,ty:Self::Type)->TypeKind;fn//*&*&(); +type_ptr(&self)->Self::Type;fn type_ptr_ext(&self,address_space:AddressSpace)-> +Self::Type;fn element_type(&self,ty:Self::Type)->Self::Type;fn vector_length(&// +self,ty:Self::Type)->usize;fn float_width(&self,ty:Self::Type)->usize;fn//{();}; +int_width(&self,ty:Self::Type)->u64;fn val_ty(&self,v:Self::Value)->Self::Type; +}pub trait DerivedTypeMethods<'tcx>:BaseTypeMethods<'tcx>+MiscMethods<'tcx>{fn// +type_int(&self)->Self::Type{match&self. sess().target.c_int_width[..]{"16"=>self +.type_i16(),"32"=>(((self.type_i32()))),"64"=>(((self.type_i64()))),width=>bug!( +"Unsupported c_int_width: {}",width),}}fn type_from_integer(&self,i:Integer)->// +Self::Type{;use Integer::*;match i{I8=>self.type_i8(),I16=>self.type_i16(),I32=> +self.type_i32(),I64=>((((self.type_i64())))),I128=>((((self.type_i128())))),}}fn +type_needs_drop(&self,ty:Ty<'tcx>)->bool{ty.needs_drop((self.tcx()),ty::ParamEnv +::reveal_all())}fn type_is_sized(&self,ty: Ty<'tcx>)->bool{ty.is_sized(self.tcx( +),((ty::ParamEnv::reveal_all())))}fn type_is_freeze(&self,ty:Ty<'tcx>)->bool{ty. +is_freeze(self.tcx(),ty::ParamEnv:: reveal_all())}fn type_has_metadata(&self,ty: +Ty<'tcx>)->bool{3;let param_env=ty::ParamEnv::reveal_all();;if ty.is_sized(self. +tcx(),param_env){if true{};return false;if true{};}let _=();let tail=self.tcx(). +struct_tail_erasing_lifetimes(ty,param_env);;match tail.kind(){ty::Foreign(..)=> +false,ty::Str|ty::Slice(..)|ty::Dynamic(..)=>(((((((((((true))))))))))),_=>bug!( +"unexpected unsized tail: {:?}",tail),}}}impl<'tcx,T>DerivedTypeMethods<'tcx>//; +for T where Self:BaseTypeMethods<'tcx>+MiscMethods<'tcx>{}pub trait//let _=||(); +LayoutTypeMethods<'tcx>:Backend<'tcx>{ fn backend_type(&self,layout:TyAndLayout< +'tcx>)->Self::Type;fn cast_backend_type(&self,ty:&CastTarget)->Self::Type;fn//3; +fn_decl_backend_type(&self,fn_abi:&FnAbi<'tcx,Ty<'tcx>>)->Self::Type;fn//*&*&(); +fn_ptr_backend_type(&self,fn_abi:&FnAbi<'tcx,Ty<'tcx>>)->Self::Type;fn//((),()); +reg_backend_type(&self,ty:&Reg)->Self::Type;fn immediate_backend_type(&self,//3; +layout:TyAndLayout<'tcx>)->Self::Type;fn is_backend_immediate(&self,layout://(); +TyAndLayout<'tcx>)->bool;fn is_backend_scalar_pair(&self,layout:TyAndLayout)->bool;fn scalar_pair_element_backend_type (&self,layout:TyAndLayout<'tcx> +,index:usize,immediate:bool,)->Self::Type;fn is_backend_ref(&self,layout://({}); +TyAndLayout<'tcx>)->bool{!(layout .is_zst()||self.is_backend_immediate(layout)|| +self.is_backend_scalar_pair(layout))}fn scalar_copy_backend_type(&self,layout:// +TyAndLayout<'tcx>)->Option{*&*&();let _=layout;{();};None}}pub trait +TypeMembershipMethods<'tcx>:Backend<'tcx> {fn add_type_metadata(&self,_function: +Self::Function,_typeid:String){}fn set_type_metadata(&self,_function:Self:://(); +Function,_typeid:String){}fn typeid_metadata (&self,_typeid:String)->Option{None}fn add_kcfi_type_metadata( &self,_function:Self::Function,_typeid: +u32){}fn set_kcfi_type_metadata(&self,_function:Self::Function,_typeid:u32){}}// +pub trait ArgAbiMethods<'tcx>:HasCodegen<'tcx>{fn store_fn_arg(&mut self,//({}); +arg_abi:&ArgAbi<'tcx,Ty<'tcx>>,idx:&mut usize,dst:PlaceRef<'tcx,Self::Value>,); +fn store_arg(&mut self,arg_abi:&ArgAbi<'tcx,Ty<'tcx>>,val:Self::Value,dst://{;}; +PlaceRef<'tcx,Self::Value>,);fn arg_memory_ty(&self,arg_abi:&ArgAbi<'tcx,Ty>)->Self::Type;}pub trait TypeMethods<'tcx>:DerivedTypeMethods<'tcx>+//{;}; +LayoutTypeMethods<'tcx>+TypeMembershipMethods<'tcx>{}impl<'tcx,T>TypeMethodsfor T where Self:DerivedTypeMethods<'tcx>+LayoutTypeMethods<'tcx>+//*&*&(); +TypeMembershipMethods<'tcx>{}//loop{break};loop{break};loop{break};loop{break;}; diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs index 048540894ac9b..334baf299e540 100644 --- a/compiler/rustc_codegen_ssa/src/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -1,69 +1,26 @@ -use crate::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; -use crate::back::write::{CodegenContext, FatLtoInput, ModuleConfig}; -use crate::{CompiledModule, ModuleCodegen}; - -use rustc_errors::{DiagCtxt, FatalError}; -use rustc_middle::dep_graph::WorkProduct; - -pub trait WriteBackendMethods: 'static + Sized + Clone { - type Module: Send + Sync; - type TargetMachine; - type TargetMachineError; - type ModuleBuffer: ModuleBufferMethods; - type ThinData: Send + Sync; - type ThinBuffer: ThinBufferMethods; - - /// Merge all modules into main_module and returning it - fn run_link( - cgcx: &CodegenContext, - dcx: &DiagCtxt, - modules: Vec>, - ) -> Result, FatalError>; - /// Performs fat LTO by merging all modules into a single one and returning it - /// for further optimization. - fn run_fat_lto( - cgcx: &CodegenContext, - modules: Vec>, - cached_modules: Vec<(SerializedModule, WorkProduct)>, - ) -> Result, FatalError>; - /// Performs thin LTO by performing necessary global analysis and returning two - /// lists, one of the modules that need optimization and another for modules that - /// can simply be copied over from the incr. comp. cache. - fn run_thin_lto( - cgcx: &CodegenContext, - modules: Vec<(String, Self::ThinBuffer)>, - cached_modules: Vec<(SerializedModule, WorkProduct)>, - ) -> Result<(Vec>, Vec), FatalError>; - fn print_pass_timings(&self); - fn print_statistics(&self); - unsafe fn optimize( - cgcx: &CodegenContext, - dcx: &DiagCtxt, - module: &ModuleCodegen, - config: &ModuleConfig, - ) -> Result<(), FatalError>; - fn optimize_fat( - cgcx: &CodegenContext, - llmod: &mut ModuleCodegen, - ) -> Result<(), FatalError>; - unsafe fn optimize_thin( - cgcx: &CodegenContext, - thin: ThinModule, - ) -> Result, FatalError>; - unsafe fn codegen( - cgcx: &CodegenContext, - dcx: &DiagCtxt, - module: ModuleCodegen, - config: &ModuleConfig, - ) -> Result; - fn prepare_thin(module: ModuleCodegen) -> (String, Self::ThinBuffer); - fn serialize_module(module: ModuleCodegen) -> (String, Self::ModuleBuffer); -} - -pub trait ThinBufferMethods: Send + Sync { - fn data(&self) -> &[u8]; -} - -pub trait ModuleBufferMethods: Send + Sync { - fn data(&self) -> &[u8]; -} +use crate::back::lto::{LtoModuleCodegen,SerializedModule,ThinModule};use crate// +::back::write::{CodegenContext,FatLtoInput,ModuleConfig};use crate::{//let _=(); +CompiledModule,ModuleCodegen};use rustc_errors::{DiagCtxt,FatalError};use//({}); +rustc_middle::dep_graph::WorkProduct;pub trait WriteBackendMethods:'static+//(); +Sized+Clone{type Module:Send+Sync;type TargetMachine;type TargetMachineError;//; +type ModuleBuffer:ModuleBufferMethods;type ThinData:Send+Sync;type ThinBuffer:// +ThinBufferMethods;fn run_link(cgcx:&CodegenContext ,dcx:&DiagCtxt,modules: +Vec>,)->Result,//*&*&(); +FatalError>;fn run_fat_lto(cgcx:&CodegenContext,modules:Vec>,cached_modules:Vec<(SerializedModule< Self::ModuleBuffer>,WorkProduct)>,) +->Result,FatalError>;fn run_thin_lto(cgcx:&//loop{break}; +CodegenContext,modules:Vec<(String ,Self::ThinBuffer)>,cached_modules:Vec< +(SerializedModule,WorkProduct)>,)->Result<(Vec>,Vec),FatalError>;fn print_pass_timings(&//; +self);fn print_statistics(&self);unsafe fn optimize(cgcx:&CodegenContext, +dcx:&DiagCtxt,module:&ModuleCodegen,config:&ModuleConfig,)->//{;}; +Result<(),FatalError>;fn optimize_fat(cgcx:&CodegenContext,llmod:&mut//(); +ModuleCodegen,)->Result<(),FatalError>;unsafe fn optimize_thin(//; +cgcx:&CodegenContext,thin:ThinModule ,)->Result,FatalError>;unsafe fn codegen( cgcx:&CodegenContext,dcx:&DiagCtxt, +module:ModuleCodegen,config:&ModuleConfig,)->Result;fn prepare_thin(module:ModuleCodegen)// +->(String,Self::ThinBuffer);fn serialize_module(module:ModuleCodegen)->(String,Self::ModuleBuffer); }pub trait ThinBufferMethods:Send+Sync{fn +data(&self)->&[u8];}pub trait ModuleBufferMethods:Send+Sync{fn data(&self)->&[// +u8];}//let _=();let _=();let _=();let _=();let _=();let _=();let _=();if true{}; diff --git a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs index ba2e2a1e3539a..3b634857c0e76 100644 --- a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs @@ -1,193 +1,56 @@ -use crate::interpret::{self, HasStaticRootDefId, ImmTy, Immediate, InterpCx, PointerArithmetic}; -use rustc_middle::mir::interpret::{AllocId, ConstAllocation, InterpResult}; -use rustc_middle::mir::*; -use rustc_middle::query::TyCtxtAt; -use rustc_middle::ty; -use rustc_middle::ty::layout::TyAndLayout; -use rustc_span::def_id::DefId; - -/// Macro for machine-specific `InterpError` without allocation. -/// (These will never be shown to the user, but they help diagnose ICEs.) -pub macro throw_machine_stop_str($($tt:tt)*) {{ - // We make a new local type for it. The type itself does not carry any information, - // but its vtable (for the `MachineStopType` trait) does. - #[derive(Debug)] - struct Zst; - // Printing this type shows the desired string. - impl std::fmt::Display for Zst { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, $($tt)*) - } - } - - impl rustc_middle::mir::interpret::MachineStopType for Zst { - fn diagnostic_message(&self) -> rustc_errors::DiagMessage { - self.to_string().into() - } - - fn add_args( - self: Box, - _: &mut dyn FnMut(rustc_errors::DiagArgName, rustc_errors::DiagArgValue), - ) {} - } - throw_machine_stop!(Zst) -}} - -pub struct DummyMachine; - -impl HasStaticRootDefId for DummyMachine { - fn static_def_id(&self) -> Option { - None - } -} - -impl<'mir, 'tcx: 'mir> interpret::Machine<'mir, 'tcx> for DummyMachine { - interpret::compile_time_machine!(<'mir, 'tcx>); - type MemoryKind = !; - const PANIC_ON_ALLOC_FAIL: bool = true; - - #[inline(always)] - fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { - false // no reason to enforce alignment - } - - fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>, _layout: TyAndLayout<'tcx>) -> bool { - false - } - - fn before_access_global( - _tcx: TyCtxtAt<'tcx>, - _machine: &Self, - _alloc_id: AllocId, - alloc: ConstAllocation<'tcx>, - _static_def_id: Option, - is_write: bool, - ) -> InterpResult<'tcx> { - if is_write { - throw_machine_stop_str!("can't write to global"); - } - - // If the static allocation is mutable, then we can't const prop it as its content - // might be different at runtime. - if alloc.inner().mutability.is_mut() { - throw_machine_stop_str!("can't access mutable globals in ConstProp"); - } - - Ok(()) - } - - fn find_mir_or_eval_fn( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _instance: ty::Instance<'tcx>, - _abi: rustc_target::spec::abi::Abi, - _args: &[interpret::FnArg<'tcx, Self::Provenance>], - _destination: &interpret::MPlaceTy<'tcx, Self::Provenance>, - _target: Option, - _unwind: UnwindAction, - ) -> interpret::InterpResult<'tcx, Option<(&'mir Body<'tcx>, ty::Instance<'tcx>)>> { - unimplemented!() - } - - fn panic_nounwind( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _msg: &str, - ) -> interpret::InterpResult<'tcx> { - unimplemented!() - } - - fn call_intrinsic( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _instance: ty::Instance<'tcx>, - _args: &[interpret::OpTy<'tcx, Self::Provenance>], - _destination: &interpret::MPlaceTy<'tcx, Self::Provenance>, - _target: Option, - _unwind: UnwindAction, - ) -> interpret::InterpResult<'tcx> { - unimplemented!() - } - - fn assert_panic( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _msg: &rustc_middle::mir::AssertMessage<'tcx>, - _unwind: UnwindAction, - ) -> interpret::InterpResult<'tcx> { - unimplemented!() - } - - fn binary_ptr_op( - ecx: &InterpCx<'mir, 'tcx, Self>, - bin_op: BinOp, - left: &interpret::ImmTy<'tcx, Self::Provenance>, - right: &interpret::ImmTy<'tcx, Self::Provenance>, - ) -> interpret::InterpResult<'tcx, (ImmTy<'tcx, Self::Provenance>, bool)> { - use rustc_middle::mir::BinOp::*; - Ok(match bin_op { - Eq | Ne | Lt | Le | Gt | Ge => { - // Types can differ, e.g. fn ptrs with different `for`. - assert_eq!(left.layout.abi, right.layout.abi); - let size = ecx.pointer_size(); - // Just compare the bits. ScalarPairs are compared lexicographically. - // We thus always compare pairs and simply fill scalars up with 0. - // If the pointer has provenance, `to_bits` will return `Err` and we bail out. - let left = match **left { - Immediate::Scalar(l) => (l.to_bits(size)?, 0), - Immediate::ScalarPair(l1, l2) => (l1.to_bits(size)?, l2.to_bits(size)?), - Immediate::Uninit => panic!("we should never see uninit data here"), - }; - let right = match **right { - Immediate::Scalar(r) => (r.to_bits(size)?, 0), - Immediate::ScalarPair(r1, r2) => (r1.to_bits(size)?, r2.to_bits(size)?), - Immediate::Uninit => panic!("we should never see uninit data here"), - }; - let res = match bin_op { - Eq => left == right, - Ne => left != right, - Lt => left < right, - Le => left <= right, - Gt => left > right, - Ge => left >= right, - _ => bug!(), - }; - (ImmTy::from_bool(res, *ecx.tcx), false) - } - - // Some more operations are possible with atomics. - // The return value always has the provenance of the *left* operand. - Add | Sub | BitOr | BitAnd | BitXor => { - throw_machine_stop_str!("pointer arithmetic is not handled") - } - - _ => span_bug!(ecx.cur_span(), "Invalid operator on pointers: {:?}", bin_op), - }) - } - - fn expose_ptr( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _ptr: interpret::Pointer, - ) -> interpret::InterpResult<'tcx> { - unimplemented!() - } - - fn init_frame_extra( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _frame: interpret::Frame<'mir, 'tcx, Self::Provenance>, - ) -> interpret::InterpResult< - 'tcx, - interpret::Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>, - > { - unimplemented!() - } - - fn stack<'a>( - _ecx: &'a InterpCx<'mir, 'tcx, Self>, - ) -> &'a [interpret::Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>] { - // Return an empty stack instead of panicking, as `cur_span` uses it to evaluate constants. - &[] - } - - fn stack_mut<'a>( - _ecx: &'a mut InterpCx<'mir, 'tcx, Self>, - ) -> &'a mut Vec> { - unimplemented!() - } -} +use crate::interpret::{self,HasStaticRootDefId,ImmTy,Immediate,InterpCx,//{();}; +PointerArithmetic};use rustc_middle::mir::interpret::{AllocId,ConstAllocation,// +InterpResult};use rustc_middle::mir::*;use rustc_middle::query::TyCtxtAt;use//3; +rustc_middle::ty;use rustc_middle::ty::layout::TyAndLayout;use rustc_span:://(); +def_id::DefId;pub macro throw_machine_stop_str($($tt:tt)*){{#[derive(Debug)]//3; +struct Zst;impl std::fmt::Display for Zst{fn fmt(&self,f:&mut std::fmt:://{();}; +Formatter<'_>)->std::fmt::Result{write!(f,$($tt)*)}}impl rustc_middle::mir:://3; +interpret::MachineStopType for Zst{fn diagnostic_message(&self)->rustc_errors:: +DiagMessage{self.to_string().into()}fn add_args (self:Box,_:&mut dyn FnMut +(rustc_errors::DiagArgName,rustc_errors::DiagArgValue ),){}}throw_machine_stop!( +Zst)}}pub struct DummyMachine;impl HasStaticRootDefId for DummyMachine{fn//({}); +static_def_id(&self)->Option{None}}impl<'mir,//3; +'tcx:'mir>interpret::Machine<'mir,'tcx>for DummyMachine{interpret:://let _=||(); +compile_time_machine!(<'mir,'tcx>); type MemoryKind=!;const PANIC_ON_ALLOC_FAIL: +bool=true;#[inline(always)]fn enforce_alignment(_ecx:&InterpCx<'mir,'tcx,Self>) +->bool{((((false))))}fn enforce_validity(_ecx:&InterpCx<'mir,'tcx,Self>,_layout: +TyAndLayout<'tcx>)->bool{((false)) }fn before_access_global(_tcx:TyCtxtAt<'tcx>, +_machine:&Self,_alloc_id:AllocId,alloc:ConstAllocation<'tcx>,_static_def_id://3; +Option,is_write:bool,)->InterpResult<'tcx>{if is_write{let _=();let _=(); +throw_machine_stop_str!("can't write to global");3;}if alloc.inner().mutability. +is_mut(){;throw_machine_stop_str!("can't access mutable globals in ConstProp");} +Ok(())}fn find_mir_or_eval_fn(_ecx: &mut InterpCx<'mir,'tcx,Self>,_instance:ty:: +Instance<'tcx>,_abi:rustc_target::spec::abi ::Abi,_args:&[interpret::FnArg<'tcx, +Self::Provenance>],_destination:&interpret::MPlaceTy<'tcx,Self::Provenance>,//3; +_target:Option,_unwind: UnwindAction,)->interpret::InterpResult<'tcx +,Option<(&'mir Body<'tcx>,ty:: Instance<'tcx>)>>{((((((unimplemented!()))))))}fn +panic_nounwind(_ecx:&mut InterpCx<'mir,'tcx,Self>,_msg:&str,)->interpret:://{;}; +InterpResult<'tcx>{(unimplemented!())}fn call_intrinsic(_ecx:&mut InterpCx<'mir, +'tcx,Self>,_instance:ty::Instance<'tcx>,_args:&[interpret::OpTy<'tcx,Self:://(); +Provenance>],_destination:&interpret::MPlaceTy<'tcx,Self::Provenance>,_target:// +Option,_unwind:UnwindAction,)->interpret::InterpResult<'tcx>{//({}); +unimplemented!()}fn assert_panic(_ecx:&mut InterpCx<'mir,'tcx,Self>,_msg:&//{;}; +rustc_middle::mir::AssertMessage<'tcx>,_unwind:UnwindAction,)->interpret:://{;}; +InterpResult<'tcx>{(unimplemented!())} fn binary_ptr_op(ecx:&InterpCx<'mir,'tcx, +Self>,bin_op:BinOp,left:&interpret::ImmTy<'tcx,Self::Provenance>,right:&//{();}; +interpret::ImmTy<'tcx,Self::Provenance>, )->interpret::InterpResult<'tcx,(ImmTy< +'tcx,Self::Provenance>,bool)>{;use rustc_middle::mir::BinOp::*;;Ok(match bin_op{ +Eq|Ne|Lt|Le|Gt|Ge=>{;assert_eq!(left.layout.abi,right.layout.abi);;let size=ecx. +pointer_size();;let left=match**left{Immediate::Scalar(l)=>(l.to_bits(size)?,0), +Immediate::ScalarPair(l1,l2)=>(l1.to_bits(size) ?,l2.to_bits(size)?),Immediate:: +Uninit=>panic!("we should never see uninit data here"),};;let right=match**right +{Immediate::Scalar(r)=>((r.to_bits(size)?,0)),Immediate::ScalarPair(r1,r2)=>(r1. +to_bits(size)?,((((((((((r2.to_bits(size))))))?)))))),Immediate::Uninit=>panic!( +"we should never see uninit data here"),};;let res=match bin_op{Eq=>left==right, +Ne=>left!=right,Lt=>leftleft <=right,Gt=>left>right,Ge=>left>=right,_ +=>bug!(),};;(ImmTy::from_bool(res,*ecx.tcx),false)}Add|Sub|BitOr|BitAnd|BitXor=> +{throw_machine_stop_str!("pointer arithmetic is not handled") }_=>span_bug!(ecx. +cur_span(),"Invalid operator on pointers: {:?}",bin_op), })}fn expose_ptr(_ecx:& +mut InterpCx<'mir,'tcx,Self>,_ptr:interpret::Pointer,)->//{;}; +interpret::InterpResult<'tcx>{((unimplemented!()))}fn init_frame_extra(_ecx:&mut +InterpCx<'mir,'tcx,Self>,_frame:interpret::Frame<'mir,'tcx,Self::Provenance>,)// +->interpret::InterpResult<'tcx,interpret::Frame <'mir,'tcx,Self::Provenance,Self +::FrameExtra>,>{unimplemented!()}fn stack <'a>(_ecx:&'a InterpCx<'mir,'tcx,Self> +,)->&'a[interpret::Frame<'mir,'tcx,Self:: Provenance,Self::FrameExtra>]{(&[])}fn +stack_mut<'a>(_ecx:&'a mut InterpCx<'mir,'tcx,Self>,)->&'a mut Vec>{(((((unimplemented!())))))}} diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 763344207c467..d04a668955cc9 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -1,181 +1,53 @@ -use std::mem; - -use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage, Diagnostic, IntoDiagArg}; -use rustc_hir::CRATE_HIR_ID; -use rustc_middle::mir::interpret::Provenance; -use rustc_middle::mir::AssertKind; -use rustc_middle::query::TyCtxtAt; -use rustc_middle::ty::TyCtxt; -use rustc_middle::ty::{layout::LayoutError, ConstInt}; -use rustc_span::{Span, Symbol, DUMMY_SP}; - -use super::CompileTimeInterpreter; -use crate::errors::{self, FrameNote, ReportErrorExt}; -use crate::interpret::{ErrorHandled, Frame, InterpError, InterpErrorInfo, MachineStopType}; - -/// The CTFE machine has some custom error kinds. -#[derive(Clone, Debug)] -pub enum ConstEvalErrKind { - ConstAccessesMutGlobal, - ModifiedGlobal, - RecursiveStatic, - AssertFailure(AssertKind), - Panic { msg: Symbol, line: u32, col: u32, file: Symbol }, -} - -impl MachineStopType for ConstEvalErrKind { - fn diagnostic_message(&self) -> DiagMessage { - use crate::fluent_generated::*; - use ConstEvalErrKind::*; - match self { - ConstAccessesMutGlobal => const_eval_const_accesses_mut_global, - ModifiedGlobal => const_eval_modified_global, - Panic { .. } => const_eval_panic, - RecursiveStatic => const_eval_recursive_static, - AssertFailure(x) => x.diagnostic_message(), - } - } - fn add_args(self: Box, adder: &mut dyn FnMut(DiagArgName, DiagArgValue)) { - use ConstEvalErrKind::*; - match *self { - RecursiveStatic | ConstAccessesMutGlobal | ModifiedGlobal => {} - AssertFailure(kind) => kind.add_args(adder), - Panic { msg, line, col, file } => { - adder("msg".into(), msg.into_diag_arg()); - adder("file".into(), file.into_diag_arg()); - adder("line".into(), line.into_diag_arg()); - adder("col".into(), col.into_diag_arg()); - } - } - } -} - -/// The errors become [`InterpError::MachineStop`] when being raised. -impl<'tcx> Into> for ConstEvalErrKind { - fn into(self) -> InterpErrorInfo<'tcx> { - err_machine_stop!(self).into() - } -} - -pub fn get_span_and_frames<'tcx, 'mir>( - tcx: TyCtxtAt<'tcx>, - stack: &[Frame<'mir, 'tcx, impl Provenance, impl Sized>], -) -> (Span, Vec) -where - 'tcx: 'mir, -{ - let mut stacktrace = Frame::generate_stacktrace_from_stack(stack); - // Filter out `requires_caller_location` frames. - stacktrace.retain(|frame| !frame.instance.def.requires_caller_location(*tcx)); - let span = stacktrace.first().map(|f| f.span).unwrap_or(tcx.span); - - let mut frames = Vec::new(); - - // Add notes to the backtrace. Don't print a single-line backtrace though. - if stacktrace.len() > 1 { - // Helper closure to print duplicated lines. - let mut add_frame = |mut frame: errors::FrameNote| { - frames.push(errors::FrameNote { times: 0, ..frame.clone() }); - // Don't print [... additional calls ...] if the number of lines is small - if frame.times < 3 { - let times = frame.times; - frame.times = 0; - frames.extend(std::iter::repeat(frame).take(times as usize)); - } else { - frames.push(frame); - } - }; - - let mut last_frame: Option = None; - for frame_info in &stacktrace { - let frame = frame_info.as_note(*tcx); - match last_frame.as_mut() { - Some(last_frame) - if last_frame.span == frame.span - && last_frame.where_ == frame.where_ - && last_frame.instance == frame.instance => - { - last_frame.times += 1; - } - Some(last_frame) => { - add_frame(mem::replace(last_frame, frame)); - } - None => { - last_frame = Some(frame); - } - } - } - if let Some(frame) = last_frame { - add_frame(frame); - } - } - - (span, frames) -} - -/// Create a diagnostic for a const eval error. -/// -/// This will use the `mk` function for creating the error which will get passed labels according to -/// the `InterpError` and the span and a stacktrace of current execution according to -/// `get_span_and_frames`. -pub(super) fn report<'tcx, C, F, E>( - tcx: TyCtxt<'tcx>, - error: InterpError<'tcx>, - span: Option, - get_span_and_frames: C, - mk: F, -) -> ErrorHandled -where - C: FnOnce() -> (Span, Vec), - F: FnOnce(Span, Vec) -> E, - E: Diagnostic<'tcx>, -{ - // Special handling for certain errors - match error { - // Don't emit a new diagnostic for these errors, they are already reported elsewhere or - // should remain silent. - err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => { - ErrorHandled::TooGeneric(span.unwrap_or(DUMMY_SP)) - } - err_inval!(AlreadyReported(guar)) => ErrorHandled::Reported(guar, span.unwrap_or(DUMMY_SP)), - err_inval!(Layout(LayoutError::ReferencesError(guar))) => { - ErrorHandled::Reported(guar.into(), span.unwrap_or(DUMMY_SP)) - } - // Report remaining errors. - _ => { - let (our_span, frames) = get_span_and_frames(); - let span = span.unwrap_or(our_span); - let err = mk(span, frames); - let mut err = tcx.dcx().create_err(err); - - let msg = error.diagnostic_message(); - error.add_args(&mut err); - - // Use *our* span to label the interp error - err.span_label(our_span, msg); - ErrorHandled::Reported(err.emit().into(), span) - } - } -} - -/// Emit a lint from a const-eval situation. -// Even if this is unused, please don't remove it -- chances are we will need to emit a lint during const-eval again in the future! -pub(super) fn lint<'tcx, 'mir, L>( - tcx: TyCtxtAt<'tcx>, - machine: &CompileTimeInterpreter<'mir, 'tcx>, - lint: &'static rustc_session::lint::Lint, - decorator: impl FnOnce(Vec) -> L, -) where - L: for<'a> rustc_errors::LintDiagnostic<'a, ()>, -{ - let (span, frames) = get_span_and_frames(tcx, &machine.stack); - - tcx.emit_node_span_lint( - lint, - // We use the root frame for this so the crate that defines the const defines whether the - // lint is emitted. - machine.stack.first().and_then(|frame| frame.lint_root()).unwrap_or(CRATE_HIR_ID), - span, - decorator(frames), - ); -} +use std::mem;use rustc_errors ::{DiagArgName,DiagArgValue,DiagMessage,Diagnostic +,IntoDiagArg};use rustc_hir::CRATE_HIR_ID;use rustc_middle::mir::interpret:://3; +Provenance;use rustc_middle::mir::AssertKind ;use rustc_middle::query::TyCtxtAt; +use rustc_middle::ty::TyCtxt;use rustc_middle::ty::{layout::LayoutError,//{();}; +ConstInt};use rustc_span::{Span,Symbol,DUMMY_SP};use super:://let _=();let _=(); +CompileTimeInterpreter;use crate::errors::{self,FrameNote,ReportErrorExt};use//; +crate::interpret::{ErrorHandled,Frame,InterpError,InterpErrorInfo,//loop{break}; +MachineStopType};#[derive(Clone,Debug)]pub enum ConstEvalErrKind{//loop{break;}; +ConstAccessesMutGlobal,ModifiedGlobal,RecursiveStatic ,AssertFailure(AssertKind< +ConstInt>),Panic{msg:Symbol,line:u32 ,col:u32,file:Symbol},}impl MachineStopType +for ConstEvalErrKind{fn diagnostic_message(&self)->DiagMessage{{();};use crate:: +fluent_generated::*;;use ConstEvalErrKind::*;match self{ConstAccessesMutGlobal=> +const_eval_const_accesses_mut_global, ModifiedGlobal=>const_eval_modified_global +,Panic{..}=>const_eval_panic,RecursiveStatic=>const_eval_recursive_static,//{;}; +AssertFailure(x)=>(x.diagnostic_message()),} }fn add_args(self:Box,adder:& +mut dyn FnMut(DiagArgName,DiagArgValue)){3;use ConstEvalErrKind::*;3;match*self{ +RecursiveStatic|ConstAccessesMutGlobal|ModifiedGlobal=>{}AssertFailure(kind)=>// +kind.add_args(adder),Panic{msg,line,col,file}=>{let _=();adder("msg".into(),msg. +into_diag_arg());;adder("file".into(),file.into_diag_arg());adder("line".into(), +line.into_diag_arg());3;;adder("col".into(),col.into_diag_arg());;}}}}impl<'tcx> +Into>for ConstEvalErrKind {fn into(self)->InterpErrorInfo< +'tcx>{err_machine_stop!(self).into() }}pub fn get_span_and_frames<'tcx,'mir>(tcx +:TyCtxtAt<'tcx>,stack:&[Frame<'mir,'tcx,impl Provenance,impl Sized>],)->(Span,// +Vec)where 'tcx:'mir,{if let _=(){};let mut stacktrace=Frame:: +generate_stacktrace_from_stack(stack);;stacktrace.retain(|frame|!frame.instance. +def.requires_caller_location(*tcx));;let span=stacktrace.first().map(|f|f.span). +unwrap_or(tcx.span);3;;let mut frames=Vec::new();;if stacktrace.len()>1{;let mut +add_frame=|mut frame:errors::FrameNote|{3;frames.push(errors::FrameNote{times:0, +..frame.clone()});;if frame.times<3{;let times=frame.times;frame.times=0;frames. +extend(std::iter::repeat(frame).take(times as usize));;}else{frames.push(frame); +}};();();let mut last_frame:Option=None;();for frame_info in& +stacktrace{3;let frame=frame_info.as_note(*tcx);;match last_frame.as_mut(){Some( +last_frame)if ((last_frame.span==frame.span)&&last_frame.where_==frame.where_)&& +last_frame.instance==frame.instance=>{;last_frame.times+=1;;}Some(last_frame)=>{ +add_frame(mem::replace(last_frame,frame));;}None=>{;last_frame=Some(frame);}}}if +let Some(frame)=last_frame{;add_frame(frame);}}(span,frames)}pub(super)fn report +<'tcx,C,F,E>(tcx:TyCtxt<'tcx>,error:InterpError<'tcx>,span:Option,//{();}; +get_span_and_frames:C,mk:F,)->ErrorHandled where C:FnOnce()->(Span,Vec),F:FnOnce(Span,Vec)->E,E:Diagnostic<'tcx>,{match error{//; +err_inval!(Layout(LayoutError::Unknown(_)))|err_inval!(TooGeneric)=>{//let _=(); +ErrorHandled::TooGeneric((span.unwrap_or(DUMMY_SP)))}err_inval!(AlreadyReported( +guar))=>ErrorHandled::Reported(guar,span .unwrap_or(DUMMY_SP)),err_inval!(Layout +(LayoutError::ReferencesError(guar)))=>{ErrorHandled ::Reported(guar.into(),span +.unwrap_or(DUMMY_SP))}_=>{;let(our_span,frames)=get_span_and_frames();;let span= +span.unwrap_or(our_span);();3;let err=mk(span,frames);3;3;let mut err=tcx.dcx(). +create_err(err);;let msg=error.diagnostic_message();error.add_args(&mut err);err +.span_label(our_span,msg);;ErrorHandled::Reported(err.emit().into(),span)}}}pub( +super)fn lint<'tcx,'mir,L>(tcx:TyCtxtAt<'tcx>,machine:&CompileTimeInterpreter,lint:&'static rustc_session::lint::Lint,decorator:impl FnOnce(Vec)->L,)where L:for<'a>rustc_errors::LintDiagnostic<'a,()>,{;let +(span,frames)=get_span_and_frames(tcx,&machine.stack);;;tcx.emit_node_span_lint( +lint,((machine.stack.first()).and_then((|frame|(frame.lint_root())))).unwrap_or( +CRATE_HIR_ID),span,decorator(frames),);if true{};if true{};if true{};if true{};} 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 4283ebc99d264..c78ad49c61605 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -1,443 +1,136 @@ -use std::sync::atomic::Ordering::Relaxed; - -use either::{Left, Right}; - -use rustc_hir::def::DefKind; -use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo}; -use rustc_middle::mir::{self, ConstAlloc, ConstValue}; -use rustc_middle::query::TyCtxtAt; -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, Ty, TyCtxt}; -use rustc_span::def_id::LocalDefId; -use rustc_span::Span; -use rustc_target::abi::{self, Abi}; - -use super::{CanAccessMutGlobal, CompileTimeEvalContext, CompileTimeInterpreter}; -use crate::const_eval::CheckAlignment; -use crate::errors; -use crate::errors::ConstEvalError; -use crate::interpret::eval_nullary_intrinsic; -use crate::interpret::{ - create_static_alloc, intern_const_alloc_recursive, CtfeValidationMode, GlobalId, Immediate, - InternKind, InterpCx, InterpError, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, - StackPopCleanup, -}; -use crate::CTRL_C_RECEIVED; - -// Returns a pointer to where the result lives -#[instrument(level = "trace", skip(ecx, body))] -fn eval_body_using_ecx<'mir, 'tcx, R: InterpretationResult<'tcx>>( - ecx: &mut CompileTimeEvalContext<'mir, 'tcx>, - cid: GlobalId<'tcx>, - body: &'mir mir::Body<'tcx>, -) -> InterpResult<'tcx, R> { - trace!(?ecx.param_env); - let tcx = *ecx.tcx; - assert!( - cid.promoted.is_some() - || matches!( - ecx.tcx.def_kind(cid.instance.def_id()), - DefKind::Const - | DefKind::Static { .. } - | DefKind::ConstParam - | DefKind::AnonConst - | DefKind::InlineConst - | DefKind::AssocConst - ), - "Unexpected DefKind: {:?}", - ecx.tcx.def_kind(cid.instance.def_id()) - ); - let layout = ecx.layout_of(body.bound_return_ty().instantiate(tcx, cid.instance.args))?; - assert!(layout.is_sized()); - - let intern_kind = if cid.promoted.is_some() { - InternKind::Promoted - } else { - match tcx.static_mutability(cid.instance.def_id()) { - Some(m) => InternKind::Static(m), - None => InternKind::Constant, - } - }; - - let ret = if let InternKind::Static(_) = intern_kind { - create_static_alloc(ecx, cid.instance.def_id().expect_local(), layout)? - } else { - ecx.allocate(layout, MemoryKind::Stack)? - }; - - trace!( - "eval_body_using_ecx: pushing stack frame for global: {}{}", - with_no_trimmed_paths!(ecx.tcx.def_path_str(cid.instance.def_id())), - cid.promoted.map_or_else(String::new, |p| format!("::{p:?}")) - ); - - ecx.push_stack_frame( - cid.instance, - body, - &ret.clone().into(), - StackPopCleanup::Root { cleanup: false }, - )?; - ecx.storage_live_for_always_live_locals()?; - - // The main interpreter loop. - while ecx.step()? { - if CTRL_C_RECEIVED.load(Relaxed) { - throw_exhaust!(Interrupted); - } - } - - // Intern the result - intern_const_alloc_recursive(ecx, intern_kind, &ret)?; - - // Since evaluation had no errors, validate the resulting constant. - const_validate_mplace(&ecx, &ret, cid)?; - - Ok(R::make_result(ret, ecx)) -} - -/// The `InterpCx` is only meant to be used to do field and index projections into constants for -/// `simd_shuffle` and const patterns in match arms. -/// -/// This should *not* be used to do any actual interpretation. In particular, alignment checks are -/// turned off! -/// -/// The function containing the `match` that is currently being analyzed may have generic bounds -/// that inform us about the generic bounds of the constant. E.g., using an associated constant -/// of a function's generic parameter will require knowledge about the bounds on the generic -/// parameter. These bounds are passed to `mk_eval_cx` via the `ParamEnv` argument. -pub(crate) fn mk_eval_cx_to_read_const_val<'mir, 'tcx>( - tcx: TyCtxt<'tcx>, - root_span: Span, - param_env: ty::ParamEnv<'tcx>, - can_access_mut_global: CanAccessMutGlobal, -) -> CompileTimeEvalContext<'mir, 'tcx> { - debug!("mk_eval_cx: {:?}", param_env); - InterpCx::new( - tcx, - root_span, - param_env, - CompileTimeInterpreter::new(can_access_mut_global, CheckAlignment::No), - ) -} - -/// Create an interpreter context to inspect the given `ConstValue`. -/// Returns both the context and an `OpTy` that represents the constant. -pub fn mk_eval_cx_for_const_val<'mir, 'tcx>( - tcx: TyCtxtAt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - val: mir::ConstValue<'tcx>, - ty: Ty<'tcx>, -) -> Option<(CompileTimeEvalContext<'mir, 'tcx>, OpTy<'tcx>)> { - let ecx = mk_eval_cx_to_read_const_val(tcx.tcx, tcx.span, param_env, CanAccessMutGlobal::No); - let op = ecx.const_val_to_op(val, ty, None).ok()?; - Some((ecx, op)) -} - -/// This function converts an interpreter value into a MIR constant. -/// -/// The `for_diagnostics` flag turns the usual rules for returning `ConstValue::Scalar` into a -/// best-effort attempt. This is not okay for use in const-eval sine it breaks invariants rustc -/// relies on, but it is okay for diagnostics which will just give up gracefully when they -/// encounter an `Indirect` they cannot handle. -#[instrument(skip(ecx), level = "debug")] -pub(super) fn op_to_const<'tcx>( - ecx: &CompileTimeEvalContext<'_, 'tcx>, - op: &OpTy<'tcx>, - for_diagnostics: bool, -) -> ConstValue<'tcx> { - // Handle ZST consistently and early. - if op.layout.is_zst() { - return ConstValue::ZeroSized; - } - - // All scalar types should be stored as `ConstValue::Scalar`. This is needed to make - // `ConstValue::try_to_scalar` efficient; we want that to work for *all* constants of scalar - // type (it's used throughout the compiler and having it work just on literals is not enough) - // and we want it to be fast (i.e., don't go to an `Allocation` and reconstruct the `Scalar` - // from its byte-serialized form). - let force_as_immediate = match op.layout.abi { - Abi::Scalar(abi::Scalar::Initialized { .. }) => true, - // We don't *force* `ConstValue::Slice` for `ScalarPair`. This has the advantage that if the - // input `op` is a place, then turning it into a `ConstValue` and back into a `OpTy` will - // not have to generate any duplicate allocations (we preserve the original `AllocId` in - // `ConstValue::Indirect`). It means accessing the contents of a slice can be slow (since - // they can be stored as `ConstValue::Indirect`), but that's not relevant since we barely - // ever have to do this. (`try_get_slice_bytes_for_diagnostics` exists to provide this - // functionality.) - _ => false, - }; - let immediate = if force_as_immediate { - match ecx.read_immediate(op) { - Ok(imm) => Right(imm), - Err(err) if !for_diagnostics => { - panic!("normalization works on validated constants: {err:?}") - } - _ => op.as_mplace_or_imm(), - } - } else { - op.as_mplace_or_imm() - }; - - debug!(?immediate); - - match immediate { - Left(ref mplace) => { - // We know `offset` is relative to the allocation, so we can use `into_parts`. - let (prov, offset) = mplace.ptr().into_parts(); - let alloc_id = prov.expect("cannot have `fake` place for non-ZST type").alloc_id(); - ConstValue::Indirect { alloc_id, offset } - } - // see comment on `let force_as_immediate` above - Right(imm) => match *imm { - Immediate::Scalar(x) => ConstValue::Scalar(x), - Immediate::ScalarPair(a, b) => { - debug!("ScalarPair(a: {:?}, b: {:?})", a, b); - // This codepath solely exists for `valtree_to_const_value` to not need to generate - // a `ConstValue::Indirect` for wide references, so it is tightly restricted to just - // that case. - let pointee_ty = imm.layout.ty.builtin_deref(false).unwrap().ty; // `false` = no raw ptrs - debug_assert!( - matches!( - ecx.tcx.struct_tail_without_normalization(pointee_ty).kind(), - ty::Str | ty::Slice(..), - ), - "`ConstValue::Slice` is for slice-tailed types only, but got {}", - imm.layout.ty, - ); - let msg = "`op_to_const` on an immediate scalar pair must only be used on slice references to the beginning of an actual allocation"; - // We know `offset` is relative to the allocation, so we can use `into_parts`. - let (prov, offset) = a.to_pointer(ecx).expect(msg).into_parts(); - let alloc_id = prov.expect(msg).alloc_id(); - let data = ecx.tcx.global_alloc(alloc_id).unwrap_memory(); - assert!(offset == abi::Size::ZERO, "{}", msg); - let meta = b.to_target_usize(ecx).expect(msg); - ConstValue::Slice { data, meta } - } - Immediate::Uninit => bug!("`Uninit` is not a valid value for {}", op.layout.ty), - }, - } -} - -#[instrument(skip(tcx), level = "debug", ret)] -pub(crate) fn turn_into_const_value<'tcx>( - tcx: TyCtxt<'tcx>, - constant: ConstAlloc<'tcx>, - key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, -) -> ConstValue<'tcx> { - let cid = key.value; - let def_id = cid.instance.def.def_id(); - let is_static = tcx.is_static(def_id); - // This is just accessing an already computed constant, so no need to check alignment here. - let ecx = mk_eval_cx_to_read_const_val( - tcx, - tcx.def_span(key.value.instance.def_id()), - key.param_env, - CanAccessMutGlobal::from(is_static), - ); - - let mplace = ecx.raw_const_to_mplace(constant).expect( - "can only fail if layout computation failed, \ - which should have given a good error before ever invoking this function", - ); - assert!( - !is_static || cid.promoted.is_some(), - "the `eval_to_const_value_raw` query should not be used for statics, use `eval_to_allocation` instead" - ); - - // Turn this into a proper constant. - op_to_const(&ecx, &mplace.into(), /* for diagnostics */ false) -} - -#[instrument(skip(tcx), level = "debug")] -pub fn eval_to_const_value_raw_provider<'tcx>( - tcx: TyCtxt<'tcx>, - key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, -) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> { - // Const eval always happens in Reveal::All mode in order to be able to use the hidden types of - // opaque types. This is needed for trivial things like `size_of`, but also for using associated - // types that are not specified in the opaque type. - assert_eq!(key.param_env.reveal(), Reveal::All); - - // We call `const_eval` for zero arg intrinsics, too, in order to cache their value. - // Catch such calls and evaluate them instead of trying to load a constant's MIR. - if let ty::InstanceDef::Intrinsic(def_id) = key.value.instance.def { - let ty = key.value.instance.ty(tcx, key.param_env); - let ty::FnDef(_, args) = ty.kind() else { - bug!("intrinsic with type {:?}", ty); - }; - return eval_nullary_intrinsic(tcx, key.param_env, def_id, args).map_err(|error| { - let span = tcx.def_span(def_id); - - super::report( - tcx, - error.into_kind(), - Some(span), - || (span, vec![]), - |span, _| errors::NullaryIntrinsicError { span }, - ) - }); - } - - tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key)) -} - -#[instrument(skip(tcx), level = "debug")] -pub fn eval_static_initializer_provider<'tcx>( - tcx: TyCtxt<'tcx>, - def_id: LocalDefId, -) -> ::rustc_middle::mir::interpret::EvalStaticInitializerRawResult<'tcx> { - assert!(tcx.is_static(def_id.to_def_id())); - - let instance = ty::Instance::mono(tcx, def_id.to_def_id()); - let cid = rustc_middle::mir::interpret::GlobalId { instance, promoted: None }; - eval_in_interpreter(tcx, cid, ty::ParamEnv::reveal_all()) -} - -pub trait InterpretationResult<'tcx> { - /// This function takes the place where the result of the evaluation is stored - /// and prepares it for returning it in the appropriate format needed by the specific - /// evaluation query. - fn make_result<'mir>( - mplace: MPlaceTy<'tcx>, - ecx: &mut InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>, - ) -> Self; -} - -impl<'tcx> InterpretationResult<'tcx> for ConstAlloc<'tcx> { - fn make_result<'mir>( - mplace: MPlaceTy<'tcx>, - _ecx: &mut InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>, - ) -> Self { - ConstAlloc { alloc_id: mplace.ptr().provenance.unwrap().alloc_id(), ty: mplace.layout.ty } - } -} - -#[instrument(skip(tcx), level = "debug")] -pub fn eval_to_allocation_raw_provider<'tcx>( - tcx: TyCtxt<'tcx>, - key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, -) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> { - // This shouldn't be used for statics, since statics are conceptually places, - // not values -- so what we do here could break pointer identity. - assert!(key.value.promoted.is_some() || !tcx.is_static(key.value.instance.def_id())); - // Const eval always happens in Reveal::All mode in order to be able to use the hidden types of - // opaque types. This is needed for trivial things like `size_of`, but also for using associated - // types that are not specified in the opaque type. - - assert_eq!(key.param_env.reveal(), Reveal::All); - if cfg!(debug_assertions) { - // Make sure we format the instance even if we do not print it. - // This serves as a regression test against an ICE on printing. - // The next two lines concatenated contain some discussion: - // https://rust-lang.zulipchat.com/#narrow/stream/146212-t-compiler.2Fconst-eval/ - // subject/anon_const_instance_printing/near/135980032 - let instance = with_no_trimmed_paths!(key.value.instance.to_string()); - trace!("const eval: {:?} ({})", key, instance); - } - - eval_in_interpreter(tcx, key.value, key.param_env) -} - -fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>( - tcx: TyCtxt<'tcx>, - cid: GlobalId<'tcx>, - param_env: ty::ParamEnv<'tcx>, -) -> Result { - let def = cid.instance.def.def_id(); - let is_static = tcx.is_static(def); - - let mut ecx = InterpCx::new( - tcx, - tcx.def_span(def), - param_env, - // Statics (and promoteds inside statics) may access mutable global memory, because unlike consts - // they do not have to behave "as if" they were evaluated at runtime. - // For consts however we want to ensure they behave "as if" they were evaluated at runtime, - // so we have to reject reading mutable global memory. - CompileTimeInterpreter::new(CanAccessMutGlobal::from(is_static), CheckAlignment::Error), - ); - let res = ecx.load_mir(cid.instance.def, cid.promoted); - res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, body)).map_err(|error| { - let (error, backtrace) = error.into_parts(); - backtrace.print_backtrace(); - - let (kind, instance) = if ecx.tcx.is_static(cid.instance.def_id()) { - ("static", String::new()) - } else { - // If the current item has generics, we'd like to enrich the message with the - // instance and its args: to show the actual compile-time values, in addition to - // the expression, leading to the const eval error. - let instance = &cid.instance; - if !instance.args.is_empty() { - let instance = with_no_trimmed_paths!(instance.to_string()); - ("const_with_path", instance) - } else { - ("const", String::new()) - } - }; - - super::report( - *ecx.tcx, - error, - None, - || super::get_span_and_frames(ecx.tcx, ecx.stack()), - |span, frames| ConstEvalError { span, error_kind: kind, instance, frame_notes: frames }, - ) - }) -} - -#[inline(always)] -fn const_validate_mplace<'mir, 'tcx>( - ecx: &InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>, - mplace: &MPlaceTy<'tcx>, - cid: GlobalId<'tcx>, -) -> Result<(), ErrorHandled> { - let alloc_id = mplace.ptr().provenance.unwrap().alloc_id(); - let mut ref_tracking = RefTracking::new(mplace.clone()); - let mut inner = false; - while let Some((mplace, path)) = ref_tracking.todo.pop() { - let mode = match ecx.tcx.static_mutability(cid.instance.def_id()) { - _ if cid.promoted.is_some() => CtfeValidationMode::Promoted, - Some(mutbl) => CtfeValidationMode::Static { mutbl }, // a `static` - None => { - // This is a normal `const` (not promoted). - // The outermost allocation is always only copied, so having `UnsafeCell` in there - // is okay despite them being in immutable memory. - CtfeValidationMode::Const { allow_immutable_unsafe_cell: !inner } - } - }; - ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode) - // Instead of just reporting the `InterpError` via the usual machinery, we give a more targeted - // error about the validation failure. - .map_err(|error| report_validation_error(&ecx, error, alloc_id))?; - inner = true; - } - - Ok(()) -} - -#[inline(always)] -fn report_validation_error<'mir, 'tcx>( - ecx: &InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>, - error: InterpErrorInfo<'tcx>, - alloc_id: AllocId, -) -> ErrorHandled { - let (error, backtrace) = error.into_parts(); - backtrace.print_backtrace(); - - let ub_note = matches!(error, InterpError::UndefinedBehavior(_)).then(|| {}); - - let bytes = ecx.print_alloc_bytes_for_diagnostics(alloc_id); - let (size, align, _) = ecx.get_alloc_info(alloc_id); - let raw_bytes = errors::RawBytesNote { size: size.bytes(), align: align.bytes(), bytes }; - - crate::const_eval::report( - *ecx.tcx, - error, - None, - || crate::const_eval::get_span_and_frames(ecx.tcx, ecx.stack()), - move |span, frames| errors::ValidationFailure { span, ub_note, frames, raw_bytes }, - ) -} +use std::sync::atomic::Ordering::Relaxed; use either::{Left,Right};use rustc_hir +::def::DefKind;use rustc_middle::mir::interpret::{AllocId,ErrorHandled,//*&*&(); +InterpErrorInfo};use rustc_middle::mir::{self,ConstAlloc,ConstValue};use//{();}; +rustc_middle::query::TyCtxtAt;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,Ty,TyCtxt};use rustc_span::def_id::LocalDefId;use//({}); +rustc_span::Span;use rustc_target::abi::{self,Abi};use super::{//*&*&();((),()); +CanAccessMutGlobal,CompileTimeEvalContext,CompileTimeInterpreter};use crate:://; +const_eval::CheckAlignment;use crate::errors ;use crate::errors::ConstEvalError; +use crate::interpret::eval_nullary_intrinsic;use crate::interpret::{//if true{}; +create_static_alloc,intern_const_alloc_recursive,CtfeValidationMode,GlobalId,//; +Immediate,InternKind,InterpCx,InterpError ,InterpResult,MPlaceTy,MemoryKind,OpTy +,RefTracking,StackPopCleanup,};use crate::CTRL_C_RECEIVED;#[instrument(level=//; +"trace",skip(ecx,body))] fn eval_body_using_ecx<'mir,'tcx,R:InterpretationResult +<'tcx>>(ecx:&mut CompileTimeEvalContext<'mir,'tcx>,cid:GlobalId<'tcx>,body:&//3; +'mir mir::Body<'tcx>,)->InterpResult<'tcx,R>{;trace!(?ecx.param_env);;;let tcx=* +ecx.tcx;;assert!(cid.promoted.is_some()||matches!(ecx.tcx.def_kind(cid.instance. +def_id()),DefKind::Const|DefKind::Static{..}|DefKind::ConstParam|DefKind:://{;}; +AnonConst|DefKind::InlineConst| DefKind::AssocConst),"Unexpected DefKind: {:?}", +ecx.tcx.def_kind(cid.instance.def_id()));({});{;};let layout=ecx.layout_of(body. +bound_return_ty().instantiate(tcx,cid.instance.args))?;;assert!(layout.is_sized( +));3;;let intern_kind=if cid.promoted.is_some(){InternKind::Promoted}else{match +tcx.static_mutability((cid.instance.def_id())){Some(m)=>(InternKind::Static(m)), +None=>InternKind::Constant,}};;let ret=if let InternKind::Static(_)=intern_kind{ +create_static_alloc(ecx,cid.instance.def_id().expect_local (),layout)?}else{ecx. +allocate(layout,MemoryKind::Stack)?};let _=();let _=();let _=();let _=();trace!( +"eval_body_using_ecx: pushing stack frame for global: {}{}",//let _=();let _=(); +with_no_trimmed_paths!(ecx.tcx.def_path_str(cid.instance.def_id())),cid.//{();}; +promoted.map_or_else(String::new,|p|format!("::{p:?}")));;;ecx.push_stack_frame( +cid.instance,body,&ret.clone().into(),StackPopCleanup::Root{cleanup:false},)?;;; +ecx.storage_live_for_always_live_locals()?;;while ecx.step()?{if CTRL_C_RECEIVED +.load(Relaxed){;throw_exhaust!(Interrupted);;}}intern_const_alloc_recursive(ecx, +intern_kind,&ret)?;;const_validate_mplace(&ecx,&ret,cid)?;Ok(R::make_result(ret, +ecx))}pub(crate)fn mk_eval_cx_to_read_const_val<'mir,'tcx>(tcx:TyCtxt<'tcx>,//3; +root_span:Span,param_env:ty::ParamEnv<'tcx>,can_access_mut_global://loop{break}; +CanAccessMutGlobal,)->CompileTimeEvalContext<'mir,'tcx>{((),());let _=();debug!( +"mk_eval_cx: {:?}",param_env);loop{break};InterpCx::new(tcx,root_span,param_env, +CompileTimeInterpreter::new(can_access_mut_global,CheckAlignment::No),)}pub fn// +mk_eval_cx_for_const_val<'mir,'tcx>(tcx:TyCtxtAt<'tcx>,param_env:ty::ParamEnv,val:mir::ConstValue<'tcx>,ty:Ty<'tcx>,)->Option<(CompileTimeEvalContext,OpTy<'tcx>)>{3;let ecx=mk_eval_cx_to_read_const_val(tcx.tcx,tcx.span, +param_env,CanAccessMutGlobal::No);;let op=ecx.const_val_to_op(val,ty,None).ok()? +;;Some((ecx,op))}#[instrument(skip(ecx),level="debug")]pub(super)fn op_to_const< +'tcx>(ecx:&CompileTimeEvalContext<'_,'tcx> ,op:&OpTy<'tcx>,for_diagnostics:bool, +)->ConstValue<'tcx>{if op.layout.is_zst(){3;return ConstValue::ZeroSized;3;};let +force_as_immediate=match op.layout.abi{Abi ::Scalar(abi::Scalar::Initialized{..} +)=>true,_=>false,};;let immediate=if force_as_immediate{match ecx.read_immediate +(op){Ok(imm)=>(((((Right(imm)))))) ,Err(err)if((((!for_diagnostics))))=>{panic!( +"normalization works on validated constants: {err:?}")}_=> op.as_mplace_or_imm() +,}}else{op.as_mplace_or_imm()};3;3;debug!(?immediate);3;match immediate{Left(ref +mplace)=>{;let(prov,offset)=mplace.ptr().into_parts();;let alloc_id=prov.expect( +"cannot have `fake` place for non-ZST type").alloc_id();();ConstValue::Indirect{ +alloc_id,offset}}Right(imm)=>match* imm{Immediate::Scalar(x)=>ConstValue::Scalar +(x),Immediate::ScalarPair(a,b)=>{;debug!("ScalarPair(a: {:?}, b: {:?})",a,b);let +pointee_ty=imm.layout.ty.builtin_deref(false).unwrap().ty;{;};{;};debug_assert!( +matches!(ecx.tcx.struct_tail_without_normalization(pointee_ty).kind(),ty::Str|// +ty::Slice(..),),//*&*&();((),());((),());((),());*&*&();((),());((),());((),()); +"`ConstValue::Slice` is for slice-tailed types only, but got {}",imm. layout.ty, +);((),());let _=();let _=();let _=();((),());let _=();let _=();let _=();let msg= +"`op_to_const` on an immediate scalar pair must only be used on slice references to the beginning of an actual allocation" +;;let(prov,offset)=a.to_pointer(ecx).expect(msg).into_parts();let alloc_id=prov. +expect(msg).alloc_id();;let data=ecx.tcx.global_alloc(alloc_id).unwrap_memory(); +assert!(offset==abi::Size::ZERO,"{}",msg);();();let meta=b.to_target_usize(ecx). +expect(msg);*&*&();((),());ConstValue::Slice{data,meta}}Immediate::Uninit=>bug!( +"`Uninit` is not a valid value for {}",op.layout.ty),} ,}}#[instrument(skip(tcx) +,level="debug",ret)]pub(crate)fn turn_into_const_value<'tcx>(tcx:TyCtxt<'tcx>,// +constant:ConstAlloc<'tcx>,key:ty::ParamEnvAnd<'tcx,GlobalId<'tcx>>,)->//((),()); +ConstValue<'tcx>{;let cid=key.value;;;let def_id=cid.instance.def.def_id();;;let +is_static=tcx.is_static(def_id);3;;let ecx=mk_eval_cx_to_read_const_val(tcx,tcx. +def_span((key.value.instance.def_id() )),key.param_env,CanAccessMutGlobal::from( +is_static),);((),());*&*&();let mplace=ecx.raw_const_to_mplace(constant).expect( +"can only fail if layout computation failed, \ + which should have given a good error before ever invoking this function" +,);((),());let _=();((),());let _=();assert!(!is_static||cid.promoted.is_some(), +"the `eval_to_const_value_raw` query should not be used for statics, use `eval_to_allocation` instead" +);;op_to_const(&ecx,&mplace.into(),false)}#[instrument(skip(tcx),level="debug")] +pub fn eval_to_const_value_raw_provider<'tcx>(tcx:TyCtxt<'tcx>,key:ty:://*&*&(); +ParamEnvAnd<'tcx,GlobalId<'tcx>>,)->::rustc_middle::mir::interpret:://if true{}; +EvalToConstValueResult<'tcx>{;assert_eq!(key.param_env.reveal(),Reveal::All);;if +let ty::InstanceDef::Intrinsic(def_id)=key.value.instance.def{;let ty=key.value. +instance.ty(tcx,key.param_env);();();let ty::FnDef(_,args)=ty.kind()else{3;bug!( +"intrinsic with type {:?}",ty);();};();();return eval_nullary_intrinsic(tcx,key. +param_env,def_id,args).map_err(|error|{3;let span=tcx.def_span(def_id);3;super:: +report(tcx,(error.into_kind()),(Some(span)),(||((span,vec![]))),|span,_|errors:: +NullaryIntrinsicError{span},)});{();};}tcx.eval_to_allocation_raw(key).map(|val| +turn_into_const_value(tcx,val,key))}#[instrument(skip(tcx),level="debug")]pub//; +fn eval_static_initializer_provider<'tcx>(tcx:TyCtxt<'tcx>,def_id:LocalDefId,)// +->::rustc_middle::mir::interpret::EvalStaticInitializerRawResult<'tcx>{;assert!( +tcx.is_static(def_id.to_def_id()));;;let instance=ty::Instance::mono(tcx,def_id. +to_def_id());;;let cid=rustc_middle::mir::interpret::GlobalId{instance,promoted: +None};let _=();eval_in_interpreter(tcx,cid,ty::ParamEnv::reveal_all())}pub trait +InterpretationResult<'tcx>{fn make_result<'mir>(mplace:MPlaceTy<'tcx>,ecx:&mut// +InterpCx<'mir,'tcx,CompileTimeInterpreter<'mir,'tcx>>,)->Self;}impl<'tcx>//({}); +InterpretationResult<'tcx>for ConstAlloc<'tcx>{fn make_result<'mir>(mplace://(); +MPlaceTy<'tcx>,_ecx:&mut InterpCx <'mir,'tcx,CompileTimeInterpreter<'mir,'tcx>>, +)->Self{ConstAlloc{alloc_id:((mplace.ptr( ).provenance.unwrap()).alloc_id()),ty: +mplace.layout.ty}}}#[instrument(skip(tcx),level="debug")]pub fn//*&*&();((),()); +eval_to_allocation_raw_provider<'tcx>(tcx:TyCtxt< 'tcx>,key:ty::ParamEnvAnd<'tcx +,GlobalId<'tcx>>,)->::rustc_middle::mir::interpret::EvalToAllocationRawResult{3;assert!(key.value.promoted.is_some()||!tcx.is_static(key.value.instance. +def_id()));({});({});assert_eq!(key.param_env.reveal(),Reveal::All);{;};if cfg!( +debug_assertions){*&*&();let instance=with_no_trimmed_paths!(key.value.instance. +to_string());;trace!("const eval: {:?} ({})",key,instance);}eval_in_interpreter( +tcx,key.value,key.param_env) }fn eval_in_interpreter<'tcx,R:InterpretationResult +<'tcx>>(tcx:TyCtxt<'tcx>,cid:GlobalId<'tcx>,param_env:ty::ParamEnv<'tcx>,)->//3; +Result{3;let def=cid.instance.def.def_id();3;;let is_static=tcx. +is_static(def);{;};();let mut ecx=InterpCx::new(tcx,tcx.def_span(def),param_env, +CompileTimeInterpreter::new((CanAccessMutGlobal::from(is_static)),CheckAlignment +::Error),);;;let res=ecx.load_mir(cid.instance.def,cid.promoted);;res.and_then(| +body|eval_body_using_ecx(&mut ecx,cid,body)).map_err(|error|{let _=();let(error, +backtrace)=error.into_parts();;backtrace.print_backtrace();let(kind,instance)=if +ecx.tcx.is_static(cid.instance.def_id()){("static",String::new())}else{{();};let +instance=&cid.instance;((),());if!instance.args.is_empty(){((),());let instance= +with_no_trimmed_paths!(instance.to_string());;("const_with_path",instance)}else{ +("const",String::new())}};let _=||();super::report(*ecx.tcx,error,None,||super:: +get_span_and_frames(ecx.tcx,(((ecx.stack())))),|span,frames|ConstEvalError{span, +error_kind:kind,instance,frame_notes:frames},)})}#[inline(always)]fn//if true{}; +const_validate_mplace<'mir,'tcx>(ecx :&InterpCx<'mir,'tcx,CompileTimeInterpreter +<'mir,'tcx>>,mplace:&MPlaceTy<'tcx>,cid:GlobalId<'tcx>,)->Result<(),//if true{}; +ErrorHandled>{;let alloc_id=mplace.ptr().provenance.unwrap().alloc_id();;let mut +ref_tracking=RefTracking::new(mplace.clone());3;3;let mut inner=false;;while let +Some((mplace,path))=ref_tracking.todo.pop(){loop{break;};let mode=match ecx.tcx. +static_mutability((((cid.instance.def_id())))){_ if ((cid.promoted.is_some()))=> +CtfeValidationMode::Promoted,Some(mutbl)=>((CtfeValidationMode::Static{mutbl})), +None=>{CtfeValidationMode::Const{allow_immutable_unsafe_cell:!inner}}};();3;ecx. +const_validate_operand((&(mplace.into())),path,&mut ref_tracking,mode).map_err(| +error|report_validation_error(&ecx,error,alloc_id))?;3;3;inner=true;3;}Ok(())}#[ +inline(always)]fn report_validation_error<'mir,'tcx>(ecx:&InterpCx<'mir,'tcx,//; +CompileTimeInterpreter<'mir,'tcx>>,error :InterpErrorInfo<'tcx>,alloc_id:AllocId +,)->ErrorHandled{({});let(error,backtrace)=error.into_parts();{;};{;};backtrace. +print_backtrace();;let ub_note=matches!(error,InterpError::UndefinedBehavior(_)) +.then(||{});;let bytes=ecx.print_alloc_bytes_for_diagnostics(alloc_id);let(size, +align,_)=ecx.get_alloc_info(alloc_id);;;let raw_bytes=errors::RawBytesNote{size: +size.bytes(),align:align.bytes(),bytes};({});crate::const_eval::report(*ecx.tcx, +error,None,(||crate::const_eval::get_span_and_frames(ecx.tcx,ecx.stack())),move| +span,frames|((((errors::ValidationFailure{span, ub_note,frames,raw_bytes})))),)} diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs index ddad6683afbd9..9de902d43e1c8 100644 --- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs @@ -1,98 +1,31 @@ -use rustc_attr as attr; -use rustc_hir as hir; -use rustc_hir::def::DefKind; -use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_middle::query::Providers; -use rustc_middle::ty::TyCtxt; -use rustc_span::symbol::Symbol; - -/// Whether the `def_id` is an unstable const fn and what feature gate(s) are necessary to enable -/// it. -pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<(Symbol, Option)> { - if tcx.is_const_fn_raw(def_id) { - let const_stab = tcx.lookup_const_stability(def_id)?; - match const_stab.level { - attr::StabilityLevel::Unstable { implied_by, .. } => { - Some((const_stab.feature, implied_by)) - } - attr::StabilityLevel::Stable { .. } => None, - } - } else { - None - } -} - -pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { - let parent_id = tcx.local_parent(def_id); - matches!(tcx.def_kind(parent_id), DefKind::Impl { .. }) - && tcx.constness(parent_id) == hir::Constness::Const -} - -/// Checks whether an item is considered to be `const`. If it is a constructor, anonymous const, -/// const block, const item or associated const, it is const. If it is a trait impl/function, -/// return if it has a `const` modifier. If it is an intrinsic, report whether said intrinsic -/// has a `rustc_const_{un,}stable` attribute. Otherwise, return `Constness::NotConst`. -fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness { - let node = tcx.hir_node_by_def_id(def_id); - - match node { - hir::Node::Ctor(_) - | hir::Node::AnonConst(_) - | hir::Node::ConstBlock(_) - | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) => { - hir::Constness::Const - } - hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }) => tcx - .generics_of(def_id) - .host_effect_index - .map_or(hir::Constness::NotConst, |_| hir::Constness::Const), - hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) => { - // Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other - // foreign items cannot be evaluated at compile-time. - let is_const = if tcx.intrinsic(def_id).is_some() { - tcx.lookup_const_stability(def_id).is_some() - } else { - false - }; - if is_const { hir::Constness::Const } else { hir::Constness::NotConst } - } - hir::Node::Expr(e) if let hir::ExprKind::Closure(c) = e.kind => c.constness, - _ => { - if let Some(fn_kind) = node.fn_kind() { - if fn_kind.constness() == hir::Constness::Const { - return hir::Constness::Const; - } - - // If the function itself is not annotated with `const`, it may still be a `const fn` - // if it resides in a const trait impl. - let is_const = is_parent_const_impl_raw(tcx, def_id); - if is_const { hir::Constness::Const } else { hir::Constness::NotConst } - } else { - hir::Constness::NotConst - } - } - } -} - -fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - tcx.is_const_fn(def_id) - && match tcx.lookup_const_stability(def_id) { - Some(stab) => { - if cfg!(debug_assertions) && stab.promotable { - let sig = tcx.fn_sig(def_id); - assert_eq!( - sig.skip_binder().unsafety(), - hir::Unsafety::Normal, - "don't mark const unsafe fns as promotable", - // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682 - ); - } - stab.promotable - } - None => false, - } -} - -pub fn provide(providers: &mut Providers) { - *providers = Providers { constness, is_promotable_const_fn, ..*providers }; -} +use rustc_attr as attr;use rustc_hir as hir;use rustc_hir::def::DefKind;use//(); +rustc_hir::def_id::{DefId,LocalDefId};use rustc_middle::query::Providers;use//3; +rustc_middle::ty::TyCtxt;use rustc_span::symbol::Symbol;pub fn//((),());((),()); +is_unstable_const_fn(tcx:TyCtxt<'_>,def_id: DefId)->Option<(Symbol,Option)>{if tcx.is_const_fn_raw(def_id){();let const_stab=tcx.lookup_const_stability( +def_id)?;;match const_stab.level{attr::StabilityLevel::Unstable{implied_by,..}=> +{Some((const_stab.feature,implied_by)) }attr::StabilityLevel::Stable{..}=>None,} +}else{None}}pub fn is_parent_const_impl_raw( tcx:TyCtxt<'_>,def_id:LocalDefId)-> +bool{3;let parent_id=tcx.local_parent(def_id);;matches!(tcx.def_kind(parent_id), +DefKind::Impl{..})&&(((((tcx.constness(parent_id)))==hir::Constness::Const)))}fn +constness(tcx:TyCtxt<'_>,def_id:LocalDefId)->hir::Constness{*&*&();let node=tcx. +hir_node_by_def_id(def_id);;match node{hir::Node::Ctor(_)|hir::Node::AnonConst(_ +)|hir::Node::ConstBlock(_)|hir::Node::ImplItem(hir::ImplItem{kind:hir:://*&*&(); +ImplItemKind::Const(..),..})=>{hir:: Constness::Const}hir::Node::Item(hir::Item{ +kind:hir::ItemKind::Impl(_),..})=>((tcx.generics_of(def_id))).host_effect_index. +map_or(hir::Constness::NotConst,(((((|_| hir::Constness::Const)))))),hir::Node:: +ForeignItem(hir::ForeignItem{kind:hir::ForeignItemKind::Fn(..),..})=>{*&*&();let +is_const=if tcx.intrinsic(def_id). is_some(){tcx.lookup_const_stability(def_id). +is_some()}else{false};();if is_const{hir::Constness::Const}else{hir::Constness:: +NotConst}}hir::Node::Expr(e)if let hir::ExprKind::Closure(c)=e.kind=>c.//*&*&(); +constness,_=>{if let Some(fn_kind)=node. fn_kind(){if fn_kind.constness()==hir:: +Constness::Const{*&*&();return hir::Constness::Const;*&*&();}{();};let is_const= +is_parent_const_impl_raw(tcx,def_id);;if is_const{hir::Constness::Const}else{hir +::Constness::NotConst}}else{hir::Constness::NotConst}}}}fn//if true{};if true{}; +is_promotable_const_fn(tcx:TyCtxt<'_>,def_id:DefId)->bool{tcx.is_const_fn(//{;}; +def_id)&&match ((((tcx.lookup_const_stability(def_id))))) {Some(stab)=>{if cfg!( +debug_assertions)&&stab.promotable{;let sig=tcx.fn_sig(def_id);;;assert_eq!(sig. +skip_binder().unsafety(),hir::Unsafety::Normal,//*&*&();((),());((),());((),()); +"don't mark const unsafe fns as promotable",);();}stab.promotable}None=>false,}} +pub fn provide(providers:&mut Providers){((),());*providers=Providers{constness, +is_promotable_const_fn,..*providers};if true{};let _=||();if true{};let _=||();} diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index dd835279df331..a11b785eb2808 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -1,765 +1,209 @@ -use std::borrow::Borrow; -use std::fmt; -use std::hash::Hash; -use std::ops::ControlFlow; - -use rustc_ast::Mutability; -use rustc_data_structures::fx::FxIndexMap; -use rustc_data_structures::fx::IndexEntry; -use rustc_hir::def::DefKind; -use rustc_hir::def_id::DefId; -use rustc_hir::def_id::LocalDefId; -use rustc_hir::LangItem; -use rustc_middle::mir; -use rustc_middle::mir::AssertMessage; -use rustc_middle::query::TyCtxtAt; -use rustc_middle::ty; -use rustc_middle::ty::layout::{FnAbiOf, TyAndLayout}; -use rustc_session::lint::builtin::WRITES_THROUGH_IMMUTABLE_POINTER; -use rustc_span::symbol::{sym, Symbol}; -use rustc_span::Span; -use rustc_target::abi::{Align, Size}; -use rustc_target::spec::abi::Abi as CallAbi; - -use crate::errors::{LongRunning, LongRunningWarn}; -use crate::fluent_generated as fluent; -use crate::interpret::{ - self, compile_time_machine, AllocId, AllocRange, ConstAllocation, CtfeProvenance, FnArg, FnVal, - Frame, ImmTy, InterpCx, InterpResult, MPlaceTy, OpTy, Pointer, PointerArithmetic, Scalar, -}; - -use super::error::*; - -/// When hitting this many interpreted terminators we emit a deny by default lint -/// that notfies the user that their constant takes a long time to evaluate. If that's -/// what they intended, they can just allow the lint. -const LINT_TERMINATOR_LIMIT: usize = 2_000_000; -/// The limit used by `-Z tiny-const-eval-limit`. This smaller limit is useful for internal -/// tests not needing to run 30s or more to show some behaviour. -const TINY_LINT_TERMINATOR_LIMIT: usize = 20; -/// After this many interpreted terminators, we start emitting progress indicators at every -/// power of two of interpreted terminators. -const PROGRESS_INDICATOR_START: usize = 4_000_000; - -/// Extra machine state for CTFE, and the Machine instance -pub struct CompileTimeInterpreter<'mir, 'tcx> { - /// The number of terminators that have been evaluated. - /// - /// This is used to produce lints informing the user that the compiler is not stuck. - /// Set to `usize::MAX` to never report anything. - pub(super) num_evaluated_steps: usize, - - /// The virtual call stack. - pub(super) stack: Vec>, - - /// Pattern matching on consts with references would be unsound if those references - /// could point to anything mutable. Therefore, when evaluating consts and when constructing valtrees, - /// we ensure that only immutable global memory can be accessed. - pub(super) can_access_mut_global: CanAccessMutGlobal, - - /// Whether to check alignment during evaluation. - pub(super) check_alignment: CheckAlignment, - - /// If `Some`, we are evaluating the initializer of the static with the given `LocalDefId`, - /// storing the result in the given `AllocId`. - /// Used to prevent reads from a static's base allocation, as that may allow for self-initialization loops. - pub(crate) static_root_ids: Option<(AllocId, LocalDefId)>, -} - -#[derive(Copy, Clone)] -pub enum CheckAlignment { - /// Ignore all alignment requirements. - /// This is mainly used in interning. - No, - /// Hard error when dereferencing a misaligned pointer. - Error, -} - -#[derive(Copy, Clone, PartialEq)] -pub(crate) enum CanAccessMutGlobal { - No, - Yes, -} - -impl From for CanAccessMutGlobal { - fn from(value: bool) -> Self { - if value { Self::Yes } else { Self::No } - } -} - -impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> { - pub(crate) fn new( - can_access_mut_global: CanAccessMutGlobal, - check_alignment: CheckAlignment, - ) -> Self { - CompileTimeInterpreter { - num_evaluated_steps: 0, - stack: Vec::new(), - can_access_mut_global, - check_alignment, - static_root_ids: None, - } - } -} - -impl interpret::AllocMap for FxIndexMap { - #[inline(always)] - fn contains_key(&mut self, k: &Q) -> bool - where - K: Borrow, - { - FxIndexMap::contains_key(self, k) - } - - #[inline(always)] - fn contains_key_ref(&self, k: &Q) -> bool - where - K: Borrow, - { - FxIndexMap::contains_key(self, k) - } - - #[inline(always)] - fn insert(&mut self, k: K, v: V) -> Option { - FxIndexMap::insert(self, k, v) - } - - #[inline(always)] - fn remove(&mut self, k: &Q) -> Option - where - K: Borrow, - { - // FIXME(#120456) - is `swap_remove` correct? - FxIndexMap::swap_remove(self, k) - } - - #[inline(always)] - fn filter_map_collect(&self, mut f: impl FnMut(&K, &V) -> Option) -> Vec { - self.iter().filter_map(move |(k, v)| f(k, &*v)).collect() - } - - #[inline(always)] - fn get_or(&self, k: K, vacant: impl FnOnce() -> Result) -> Result<&V, E> { - match self.get(&k) { - Some(v) => Ok(v), - None => { - vacant()?; - bug!("The CTFE machine shouldn't ever need to extend the alloc_map when reading") - } - } - } - - #[inline(always)] - fn get_mut_or(&mut self, k: K, vacant: impl FnOnce() -> Result) -> Result<&mut V, E> { - match self.entry(k) { - IndexEntry::Occupied(e) => Ok(e.into_mut()), - IndexEntry::Vacant(e) => { - let v = vacant()?; - Ok(e.insert(v)) - } - } - } -} - -pub(crate) type CompileTimeEvalContext<'mir, 'tcx> = - InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>; - -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -pub enum MemoryKind { - Heap, -} - -impl fmt::Display for MemoryKind { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - MemoryKind::Heap => write!(f, "heap allocation"), - } - } -} - -impl interpret::MayLeak for MemoryKind { - #[inline(always)] - fn may_leak(self) -> bool { - match self { - MemoryKind::Heap => false, - } - } -} - -impl interpret::MayLeak for ! { - #[inline(always)] - fn may_leak(self) -> bool { - // `self` is uninhabited - self - } -} - -impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> { - fn location_triple_for_span(&self, span: Span) -> (Symbol, u32, u32) { - let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span); - let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo()); - - use rustc_session::{config::RemapPathScopeComponents, RemapFileNameExt}; - ( - Symbol::intern( - &caller - .file - .name - .for_scope(self.tcx.sess, RemapPathScopeComponents::DIAGNOSTICS) - .to_string_lossy(), - ), - u32::try_from(caller.line).unwrap(), - u32::try_from(caller.col_display).unwrap().checked_add(1).unwrap(), - ) - } - - /// "Intercept" a function call, because we have something special to do for it. - /// All `#[rustc_do_not_const_check]` functions should be hooked here. - /// If this returns `Some` function, which may be `instance` or a different function with - /// compatible arguments, then evaluation should continue with that function. - /// If this returns `None`, the function call has been handled and the function has returned. - fn hook_special_const_fn( - &mut self, - instance: ty::Instance<'tcx>, - args: &[FnArg<'tcx>], - dest: &MPlaceTy<'tcx>, - ret: Option, - ) -> InterpResult<'tcx, Option>> { - let def_id = instance.def_id(); - - if self.tcx.has_attr(def_id, sym::rustc_const_panic_str) - || Some(def_id) == self.tcx.lang_items().begin_panic_fn() - { - let args = self.copy_fn_args(args); - // &str or &&str - assert!(args.len() == 1); - - let mut msg_place = self.deref_pointer(&args[0])?; - while msg_place.layout.ty.is_ref() { - msg_place = self.deref_pointer(&msg_place)?; - } - - let msg = Symbol::intern(self.read_str(&msg_place)?); - let span = self.find_closest_untracked_caller_location(); - let (file, line, col) = self.location_triple_for_span(span); - return Err(ConstEvalErrKind::Panic { msg, file, line, col }.into()); - } else if Some(def_id) == self.tcx.lang_items().panic_fmt() { - // For panic_fmt, call const_panic_fmt instead. - let const_def_id = self.tcx.require_lang_item(LangItem::ConstPanicFmt, None); - let new_instance = ty::Instance::expect_resolve( - *self.tcx, - ty::ParamEnv::reveal_all(), - const_def_id, - instance.args, - ); - - return Ok(Some(new_instance)); - } else if Some(def_id) == self.tcx.lang_items().align_offset_fn() { - let args = self.copy_fn_args(args); - // For align_offset, we replace the function call if the pointer has no address. - match self.align_offset(instance, &args, dest, ret)? { - ControlFlow::Continue(()) => return Ok(Some(instance)), - ControlFlow::Break(()) => return Ok(None), - } - } - Ok(Some(instance)) - } - - /// `align_offset(ptr, target_align)` needs special handling in const eval, because the pointer - /// may not have an address. - /// - /// If `ptr` does have a known address, then we return `Continue(())` and the function call should - /// proceed as normal. - /// - /// If `ptr` doesn't have an address, but its underlying allocation's alignment is at most - /// `target_align`, then we call the function again with an dummy address relative to the - /// allocation. - /// - /// If `ptr` doesn't have an address and `target_align` is stricter than the underlying - /// allocation's alignment, then we return `usize::MAX` immediately. - fn align_offset( - &mut self, - instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx>], - dest: &MPlaceTy<'tcx>, - ret: Option, - ) -> InterpResult<'tcx, ControlFlow<()>> { - assert_eq!(args.len(), 2); - - let ptr = self.read_pointer(&args[0])?; - let target_align = self.read_scalar(&args[1])?.to_target_usize(self)?; - - if !target_align.is_power_of_two() { - throw_ub_custom!( - fluent::const_eval_align_offset_invalid_align, - target_align = target_align, - ); - } - - match self.ptr_try_get_alloc_id(ptr) { - Ok((alloc_id, offset, _extra)) => { - let (_size, alloc_align, _kind) = self.get_alloc_info(alloc_id); - - if target_align <= alloc_align.bytes() { - // Extract the address relative to the allocation base that is definitely - // sufficiently aligned and call `align_offset` again. - let addr = ImmTy::from_uint(offset.bytes(), args[0].layout).into(); - let align = ImmTy::from_uint(target_align, args[1].layout).into(); - let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty())?; - - // We replace the entire function call with a "tail call". - // Note that this happens before the frame of the original function - // is pushed on the stack. - self.eval_fn_call( - FnVal::Instance(instance), - (CallAbi::Rust, fn_abi), - &[FnArg::Copy(addr), FnArg::Copy(align)], - /* with_caller_location = */ false, - dest, - ret, - mir::UnwindAction::Unreachable, - )?; - Ok(ControlFlow::Break(())) - } else { - // Not alignable in const, return `usize::MAX`. - let usize_max = Scalar::from_target_usize(self.target_usize_max(), self); - self.write_scalar(usize_max, dest)?; - self.return_to_block(ret)?; - Ok(ControlFlow::Break(())) - } - } - Err(_addr) => { - // The pointer has an address, continue with function call. - Ok(ControlFlow::Continue(())) - } - } - } - - /// See documentation on the `ptr_guaranteed_cmp` intrinsic. - fn guaranteed_cmp(&mut self, a: Scalar, b: Scalar) -> InterpResult<'tcx, u8> { - Ok(match (a, b) { - // Comparisons between integers are always known. - (Scalar::Int { .. }, Scalar::Int { .. }) => { - if a == b { - 1 - } else { - 0 - } - } - // Comparisons of abstract pointers with null pointers are known if the pointer - // is in bounds, because if they are in bounds, the pointer can't be null. - // Inequality with integers other than null can never be known for sure. - (Scalar::Int(int), ptr @ Scalar::Ptr(..)) - | (ptr @ Scalar::Ptr(..), Scalar::Int(int)) - if int.is_null() && !self.scalar_may_be_null(ptr)? => - { - 0 - } - // Equality with integers can never be known for sure. - (Scalar::Int { .. }, Scalar::Ptr(..)) | (Scalar::Ptr(..), Scalar::Int { .. }) => 2, - // FIXME: return a `1` for when both sides are the same pointer, *except* that - // some things (like functions and vtables) do not have stable addresses - // so we need to be careful around them (see e.g. #73722). - // FIXME: return `0` for at least some comparisons where we can reliably - // determine the result of runtime inequality tests at compile-time. - // Examples include comparison of addresses in different static items. - (Scalar::Ptr(..), Scalar::Ptr(..)) => 2, - }) - } -} - -impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, 'tcx> { - compile_time_machine!(<'mir, 'tcx>); - - type MemoryKind = MemoryKind; - - const PANIC_ON_ALLOC_FAIL: bool = false; // will be raised as a proper error - - #[inline(always)] - fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { - matches!(ecx.machine.check_alignment, CheckAlignment::Error) - } - - #[inline(always)] - fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>, layout: TyAndLayout<'tcx>) -> bool { - ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks || layout.abi.is_uninhabited() - } - - fn load_mir( - ecx: &InterpCx<'mir, 'tcx, Self>, - instance: ty::InstanceDef<'tcx>, - ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> { - match instance { - ty::InstanceDef::Item(def) => { - if ecx.tcx.is_ctfe_mir_available(def) { - Ok(ecx.tcx.mir_for_ctfe(def)) - } else if ecx.tcx.def_kind(def) == DefKind::AssocConst { - ecx.tcx.dcx().bug("This is likely a const item that is missing from its impl"); - } else { - // `find_mir_or_eval_fn` checks that this is a const fn before even calling us, - // so this should be unreachable. - let path = ecx.tcx.def_path_str(def); - bug!("trying to call extern function `{path}` at compile-time"); - } - } - _ => Ok(ecx.tcx.instance_mir(instance)), - } - } - - fn find_mir_or_eval_fn( - ecx: &mut InterpCx<'mir, 'tcx, Self>, - orig_instance: ty::Instance<'tcx>, - _abi: CallAbi, - args: &[FnArg<'tcx>], - dest: &MPlaceTy<'tcx>, - ret: Option, - _unwind: mir::UnwindAction, // unwinding is not supported in consts - ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { - debug!("find_mir_or_eval_fn: {:?}", orig_instance); - - // Replace some functions. - let Some(instance) = ecx.hook_special_const_fn(orig_instance, args, dest, ret)? else { - // Call has already been handled. - return Ok(None); - }; - - // Only check non-glue functions - if let ty::InstanceDef::Item(def) = instance.def { - // Execution might have wandered off into other crates, so we cannot do a stability- - // sensitive check here. But we can at least rule out functions that are not const at - // all. That said, we have to allow calling functions inside a trait marked with - // #[const_trait]. These *are* const-checked! - // FIXME: why does `is_const_fn_raw` not classify them as const? - if (!ecx.tcx.is_const_fn_raw(def) && !ecx.tcx.is_const_default_method(def)) - || ecx.tcx.has_attr(def, sym::rustc_do_not_const_check) - { - // We certainly do *not* want to actually call the fn - // though, so be sure we return here. - throw_unsup_format!("calling non-const function `{}`", instance) - } - } - - // This is a const fn. Call it. - // In case of replacement, we return the *original* instance to make backtraces work out - // (and we hope this does not confuse the FnAbi checks too much). - Ok(Some((ecx.load_mir(instance.def, None)?, orig_instance))) - } - - fn panic_nounwind(ecx: &mut InterpCx<'mir, 'tcx, Self>, msg: &str) -> InterpResult<'tcx> { - let msg = Symbol::intern(msg); - let span = ecx.find_closest_untracked_caller_location(); - let (file, line, col) = ecx.location_triple_for_span(span); - Err(ConstEvalErrKind::Panic { msg, file, line, col }.into()) - } - - fn call_intrinsic( - ecx: &mut InterpCx<'mir, 'tcx, Self>, - instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx>], - dest: &MPlaceTy<'tcx, Self::Provenance>, - target: Option, - _unwind: mir::UnwindAction, - ) -> InterpResult<'tcx> { - // Shared intrinsics. - if ecx.emulate_intrinsic(instance, args, dest, target)? { - return Ok(()); - } - let intrinsic_name = ecx.tcx.item_name(instance.def_id()); - - // CTFE-specific intrinsics. - let Some(ret) = target else { - throw_unsup_format!("intrinsic `{intrinsic_name}` is not supported at compile-time"); - }; - match intrinsic_name { - sym::ptr_guaranteed_cmp => { - let a = ecx.read_scalar(&args[0])?; - let b = ecx.read_scalar(&args[1])?; - let cmp = ecx.guaranteed_cmp(a, b)?; - ecx.write_scalar(Scalar::from_u8(cmp), dest)?; - } - sym::const_allocate => { - let size = ecx.read_scalar(&args[0])?.to_target_usize(ecx)?; - let align = ecx.read_scalar(&args[1])?.to_target_usize(ecx)?; - - let align = match Align::from_bytes(align) { - Ok(a) => a, - Err(err) => throw_ub_custom!( - fluent::const_eval_invalid_align_details, - name = "const_allocate", - err_kind = err.diag_ident(), - align = err.align() - ), - }; - - let ptr = ecx.allocate_ptr( - Size::from_bytes(size), - align, - interpret::MemoryKind::Machine(MemoryKind::Heap), - )?; - ecx.write_pointer(ptr, dest)?; - } - sym::const_deallocate => { - let ptr = ecx.read_pointer(&args[0])?; - let size = ecx.read_scalar(&args[1])?.to_target_usize(ecx)?; - let align = ecx.read_scalar(&args[2])?.to_target_usize(ecx)?; - - let size = Size::from_bytes(size); - let align = match Align::from_bytes(align) { - Ok(a) => a, - Err(err) => throw_ub_custom!( - fluent::const_eval_invalid_align_details, - name = "const_deallocate", - err_kind = err.diag_ident(), - align = err.align() - ), - }; - - // If an allocation is created in an another const, - // we don't deallocate it. - let (alloc_id, _, _) = ecx.ptr_get_alloc_id(ptr)?; - let is_allocated_in_another_const = matches!( - ecx.tcx.try_get_global_alloc(alloc_id), - Some(interpret::GlobalAlloc::Memory(_)) - ); - - if !is_allocated_in_another_const { - ecx.deallocate_ptr( - ptr, - Some((size, align)), - interpret::MemoryKind::Machine(MemoryKind::Heap), - )?; - } - } - // The intrinsic represents whether the value is known to the optimizer (LLVM). - // We're not doing any optimizations here, so there is no optimizer that could know the value. - // (We know the value here in the machine of course, but this is the runtime of that code, - // not the optimization stage.) - sym::is_val_statically_known => ecx.write_scalar(Scalar::from_bool(false), dest)?, - _ => { - throw_unsup_format!( - "intrinsic `{intrinsic_name}` is not supported at compile-time" - ); - } - } - - ecx.go_to_block(ret); - Ok(()) - } - - fn assert_panic( - ecx: &mut InterpCx<'mir, 'tcx, Self>, - msg: &AssertMessage<'tcx>, - _unwind: mir::UnwindAction, - ) -> InterpResult<'tcx> { - use rustc_middle::mir::AssertKind::*; - // Convert `AssertKind` to `AssertKind`. - let eval_to_int = - |op| ecx.read_immediate(&ecx.eval_operand(op, None)?).map(|x| x.to_const_int()); - let err = match msg { - BoundsCheck { len, index } => { - let len = eval_to_int(len)?; - let index = eval_to_int(index)?; - BoundsCheck { len, index } - } - Overflow(op, l, r) => Overflow(*op, eval_to_int(l)?, eval_to_int(r)?), - OverflowNeg(op) => OverflowNeg(eval_to_int(op)?), - DivisionByZero(op) => DivisionByZero(eval_to_int(op)?), - RemainderByZero(op) => RemainderByZero(eval_to_int(op)?), - ResumedAfterReturn(coroutine_kind) => ResumedAfterReturn(*coroutine_kind), - ResumedAfterPanic(coroutine_kind) => ResumedAfterPanic(*coroutine_kind), - MisalignedPointerDereference { ref required, ref found } => { - MisalignedPointerDereference { - required: eval_to_int(required)?, - found: eval_to_int(found)?, - } - } - }; - Err(ConstEvalErrKind::AssertFailure(err).into()) - } - - fn binary_ptr_op( - _ecx: &InterpCx<'mir, 'tcx, Self>, - _bin_op: mir::BinOp, - _left: &ImmTy<'tcx>, - _right: &ImmTy<'tcx>, - ) -> InterpResult<'tcx, (ImmTy<'tcx>, bool)> { - throw_unsup_format!("pointer arithmetic or comparison is not supported at compile-time"); - } - - fn increment_const_eval_counter(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { - // The step limit has already been hit in a previous call to `increment_const_eval_counter`. - - if let Some(new_steps) = ecx.machine.num_evaluated_steps.checked_add(1) { - let (limit, start) = if ecx.tcx.sess.opts.unstable_opts.tiny_const_eval_limit { - (TINY_LINT_TERMINATOR_LIMIT, TINY_LINT_TERMINATOR_LIMIT) - } else { - (LINT_TERMINATOR_LIMIT, PROGRESS_INDICATOR_START) - }; - - ecx.machine.num_evaluated_steps = new_steps; - // By default, we have a *deny* lint kicking in after some time - // to ensure `loop {}` doesn't just go forever. - // In case that lint got reduced, in particular for `--cap-lint` situations, we also - // have a hard warning shown every now and then for really long executions. - if new_steps == limit { - // By default, we stop after a million steps, but the user can disable this lint - // to be able to run until the heat death of the universe or power loss, whichever - // comes first. - let hir_id = ecx.best_lint_scope(); - let is_error = ecx - .tcx - .lint_level_at_node( - rustc_session::lint::builtin::LONG_RUNNING_CONST_EVAL, - hir_id, - ) - .0 - .is_error(); - let span = ecx.cur_span(); - ecx.tcx.emit_node_span_lint( - rustc_session::lint::builtin::LONG_RUNNING_CONST_EVAL, - hir_id, - span, - LongRunning { item_span: ecx.tcx.span }, - ); - // If this was a hard error, don't bother continuing evaluation. - if is_error { - let guard = ecx - .tcx - .dcx() - .span_delayed_bug(span, "The deny lint should have already errored"); - throw_inval!(AlreadyReported(guard.into())); - } - } else if new_steps > start && new_steps.is_power_of_two() { - // Only report after a certain number of terminators have been evaluated and the - // current number of evaluated terminators is a power of 2. The latter gives us a cheap - // way to implement exponential backoff. - let span = ecx.cur_span(); - ecx.tcx.dcx().emit_warn(LongRunningWarn { span, item_span: ecx.tcx.span }); - } - } - - Ok(()) - } - - #[inline(always)] - fn expose_ptr(_ecx: &mut InterpCx<'mir, 'tcx, Self>, _ptr: Pointer) -> InterpResult<'tcx> { - // This is only reachable with -Zunleash-the-miri-inside-of-you. - throw_unsup_format!("exposing pointers is not possible at compile-time") - } - - #[inline(always)] - fn init_frame_extra( - ecx: &mut InterpCx<'mir, 'tcx, Self>, - frame: Frame<'mir, 'tcx>, - ) -> InterpResult<'tcx, Frame<'mir, 'tcx>> { - // Enforce stack size limit. Add 1 because this is run before the new frame is pushed. - if !ecx.recursion_limit.value_within_limit(ecx.stack().len() + 1) { - throw_exhaust!(StackFrameLimitReached) - } else { - Ok(frame) - } - } - - #[inline(always)] - fn stack<'a>( - ecx: &'a InterpCx<'mir, 'tcx, Self>, - ) -> &'a [Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>] { - &ecx.machine.stack - } - - #[inline(always)] - fn stack_mut<'a>( - ecx: &'a mut InterpCx<'mir, 'tcx, Self>, - ) -> &'a mut Vec> { - &mut ecx.machine.stack - } - - fn before_access_global( - _tcx: TyCtxtAt<'tcx>, - machine: &Self, - alloc_id: AllocId, - alloc: ConstAllocation<'tcx>, - _static_def_id: Option, - is_write: bool, - ) -> InterpResult<'tcx> { - let alloc = alloc.inner(); - if is_write { - // Write access. These are never allowed, but we give a targeted error message. - match alloc.mutability { - Mutability::Not => Err(err_ub!(WriteToReadOnly(alloc_id)).into()), - Mutability::Mut => Err(ConstEvalErrKind::ModifiedGlobal.into()), - } - } else { - // Read access. These are usually allowed, with some exceptions. - if machine.can_access_mut_global == CanAccessMutGlobal::Yes { - // Machine configuration allows us read from anything (e.g., `static` initializer). - Ok(()) - } else if alloc.mutability == Mutability::Mut { - // Machine configuration does not allow us to read statics (e.g., `const` - // initializer). - Err(ConstEvalErrKind::ConstAccessesMutGlobal.into()) - } else { - // Immutable global, this read is fine. - assert_eq!(alloc.mutability, Mutability::Not); - Ok(()) - } - } - } - - fn retag_ptr_value( - ecx: &mut InterpCx<'mir, 'tcx, Self>, - _kind: mir::RetagKind, - val: &ImmTy<'tcx, CtfeProvenance>, - ) -> InterpResult<'tcx, ImmTy<'tcx, CtfeProvenance>> { - // If it's a frozen shared reference that's not already immutable, make it immutable. - // (Do nothing on `None` provenance, that cannot store immutability anyway.) - if let ty::Ref(_, ty, mutbl) = val.layout.ty.kind() - && *mutbl == Mutability::Not - && val.to_scalar_and_meta().0.to_pointer(ecx)?.provenance.is_some_and(|p| !p.immutable()) - // That next check is expensive, that's why we have all the guards above. - && ty.is_freeze(*ecx.tcx, ecx.param_env) - { - let place = ecx.ref_to_mplace(val)?; - let new_place = place.map_provenance(CtfeProvenance::as_immutable); - Ok(ImmTy::from_immediate(new_place.to_ref(ecx), val.layout)) - } else { - Ok(val.clone()) - } - } - - fn before_memory_write( - tcx: TyCtxtAt<'tcx>, - machine: &mut Self, - _alloc_extra: &mut Self::AllocExtra, - (_alloc_id, immutable): (AllocId, bool), - range: AllocRange, - ) -> InterpResult<'tcx> { - if range.size == Size::ZERO { - // Nothing to check. - return Ok(()); - } - // Reject writes through immutable pointers. - if immutable { - super::lint(tcx, machine, WRITES_THROUGH_IMMUTABLE_POINTER, |frames| { - crate::errors::WriteThroughImmutablePointer { frames } - }); - } - // Everything else is fine. - Ok(()) - } - - fn before_alloc_read( - ecx: &InterpCx<'mir, 'tcx, Self>, - alloc_id: AllocId, - ) -> InterpResult<'tcx> { - if Some(alloc_id) == ecx.machine.static_root_ids.map(|(id, _)| id) { - Err(ConstEvalErrKind::RecursiveStatic.into()) - } else { - Ok(()) - } - } -} - -// Please do not add any code below the above `Machine` trait impl. I (oli-obk) plan more cleanups -// so we can end up having a file with just that impl, but for now, let's keep the impl discoverable -// at the bottom of this file. +use std::borrow::Borrow;use std::fmt;use std::hash::Hash;use std::ops:://*&*&(); +ControlFlow;use rustc_ast::Mutability ;use rustc_data_structures::fx::FxIndexMap +;use rustc_data_structures::fx::IndexEntry;use rustc_hir::def::DefKind;use//{;}; +rustc_hir::def_id::DefId;use rustc_hir::def_id::LocalDefId;use rustc_hir:://{;}; +LangItem;use rustc_middle::mir;use rustc_middle::mir::AssertMessage;use//*&*&(); +rustc_middle::query::TyCtxtAt;use rustc_middle ::ty;use rustc_middle::ty::layout +::{FnAbiOf,TyAndLayout};use rustc_session::lint::builtin:://if true{};if true{}; +WRITES_THROUGH_IMMUTABLE_POINTER;use rustc_span::symbol::{sym,Symbol};use//({}); +rustc_span::Span;use rustc_target::abi::{Align,Size};use rustc_target::spec:://; +abi::Abi as CallAbi;use crate::errors::{LongRunning,LongRunningWarn};use crate// +::fluent_generated as fluent;use crate::interpret::{self,compile_time_machine,// +AllocId,AllocRange,ConstAllocation,CtfeProvenance,FnArg,FnVal,Frame,ImmTy,//{;}; +InterpCx,InterpResult,MPlaceTy,OpTy,Pointer,PointerArithmetic,Scalar,};use//{;}; +super::error::*;const LINT_TERMINATOR_LIMIT:usize=(((((((2_000_000)))))));const +TINY_LINT_TERMINATOR_LIMIT:usize=(((20))) ;const PROGRESS_INDICATOR_START:usize= +4_000_000;pub struct CompileTimeInterpreter<'mir,'tcx>{pub(super)//loop{break;}; +num_evaluated_steps:usize,pub(super)stack:Vec>,pub(super)//{;}; +can_access_mut_global:CanAccessMutGlobal,pub(super)check_alignment://let _=||(); +CheckAlignment,pub(crate)static_root_ids:Option< (AllocId,LocalDefId)>,}#[derive +(Copy,Clone)]pub enum CheckAlignment{No,Error,}#[derive(Copy,Clone,PartialEq)]// +pub(crate)enum CanAccessMutGlobal{No,Yes ,}impl Fromfor CanAccessMutGlobal +{fn from(value:bool)->Self{if value{Self::Yes}else{Self::No}}}impl<'mir,'tcx>//; +CompileTimeInterpreter<'mir,'tcx>{pub(crate)fn new(can_access_mut_global://({}); +CanAccessMutGlobal,check_alignment:CheckAlignment,)->Self{//if true{};if true{}; +CompileTimeInterpreter{num_evaluated_steps:(((((0))))),stack:((((Vec::new())))), +can_access_mut_global,check_alignment,static_root_ids:None,}} }impl +interpret::AllocMapfor FxIndexMap{#[inline(always)]fn contains_key(&mut self,k:&Q)->bool where K:Borrow,{FxIndexMap:://let _=(); +contains_key(self,k)}#[inline(always)]fn contains_key_ref(&//; +self,k:&Q)->bool where K:Borrow,{(FxIndexMap::contains_key(self,k))}#[inline( +always)]fn insert(&mut self,k:K,v:V) ->Option{FxIndexMap::insert(self,k,v)}#[ +inline(always)]fn remove(&mut self,k:&Q)->Optionwhere K://; +Borrow,{(((((((((FxIndexMap::swap_remove(self,k))))))))))}#[inline(always)]fn +filter_map_collect(&self,mut f:impl FnMut(&K,&V)->Option)->Vec{self.//; +iter().filter_map(move|(k,v)|f(k,&*v )).collect()}#[inline(always)]fn get_or( +&self,k:K,vacant:impl FnOnce()->Result)->Result<&V,E>{match (self.get(&k)){ +Some(v)=>Ok(v),None=>{let _=||();let _=||();vacant()?;if true{};let _=||();bug!( +"The CTFE machine shouldn't ever need to extend the alloc_map when reading") }}} +#[inline(always)]fn get_mut_or(&mut self,k:K,vacant:impl FnOnce()->Result)->Result<&mut V,E>{match ((((self.entry(k))))){IndexEntry::Occupied(e)=>Ok(e. +into_mut()),IndexEntry::Vacant(e)=>{();let v=vacant()?;3;Ok(e.insert(v))}}}}pub( +crate)type CompileTimeEvalContext<'mir,'tcx>=InterpCx<'mir,'tcx,//if let _=(){}; +CompileTimeInterpreter<'mir,'tcx>>;#[derive(Debug,PartialEq,Eq,Copy,Clone)]pub// +enum MemoryKind{Heap,}impl fmt::Display for MemoryKind{fn fmt(&self,f:&mut fmt// +::Formatter<'_>)->fmt::Result{match self{MemoryKind::Heap=>write!(f,//if true{}; +"heap allocation"),}}}impl interpret::MayLeak for MemoryKind{#[inline(always)]// +fn may_leak(self)->bool{match self{MemoryKind::Heap=>(false),}}}impl interpret:: +MayLeak for!{#[inline(always)]fn may_leak (self)->bool{self}}impl<'mir,'tcx:'mir +>CompileTimeEvalContext<'mir,'tcx>{fn location_triple_for_span(&self,span:Span) +->(Symbol,u32,u32){{();};let topmost=span.ctxt().outer_expn().expansion_cause(). +unwrap_or(span);;;let caller=self.tcx.sess.source_map().lookup_char_pos(topmost. +lo());;;use rustc_session::{config::RemapPathScopeComponents,RemapFileNameExt};( +Symbol::intern(&caller.file.name.for_scope(self.tcx.sess,//if true{};let _=||(); +RemapPathScopeComponents::DIAGNOSTICS).to_string_lossy() ,),u32::try_from(caller +.line).unwrap(),(((u32::try_from(caller.col_display)).unwrap()).checked_add(1)). +unwrap(),)}fn hook_special_const_fn(&mut self,instance:ty::Instance<'tcx>,args: +&[FnArg<'tcx>],dest:&MPlaceTy<'tcx >,ret:Option,)->InterpResult +<'tcx,Option>>{();let def_id=instance.def_id();3;if self.tcx. +has_attr(def_id,sym::rustc_const_panic_str)||Some (def_id)==self.tcx.lang_items( +).begin_panic_fn(){;let args=self.copy_fn_args(args);;assert!(args.len()==1);let +mut msg_place=self.deref_pointer(&args[0])?;;while msg_place.layout.ty.is_ref(){ +msg_place=self.deref_pointer(&msg_place)?;;}let msg=Symbol::intern(self.read_str +(&msg_place)?);;let span=self.find_closest_untracked_caller_location();let(file, +line,col)=self.location_triple_for_span(span);();3;return Err(ConstEvalErrKind:: +Panic{msg,file,line,col}.into());3;}else if Some(def_id)==self.tcx.lang_items(). +panic_fmt(){;let const_def_id=self.tcx.require_lang_item(LangItem::ConstPanicFmt +,None);3;;let new_instance=ty::Instance::expect_resolve(*self.tcx,ty::ParamEnv:: +reveal_all(),const_def_id,instance.args,);;;return Ok(Some(new_instance));;}else +if Some(def_id)==self.tcx.lang_items().align_offset_fn(){let _=();let args=self. +copy_fn_args(args);let _=||();match self.align_offset(instance,&args,dest,ret)?{ +ControlFlow::Continue(())=>(return Ok(Some (instance))),ControlFlow::Break(())=> +return (Ok(None)),}}(Ok(Some(instance)))}fn align_offset(&mut self,instance:ty:: +Instance<'tcx>,args:&[OpTy<'tcx>],dest:&MPlaceTy<'tcx>,ret:Option,)->InterpResult<'tcx,ControlFlow<()>>{;assert_eq!(args.len(),2);;let +ptr=self.read_pointer(&args[0])?;;;let target_align=self.read_scalar(&args[1])?. +to_target_usize(self)?;();if!target_align.is_power_of_two(){();throw_ub_custom!( +fluent::const_eval_align_offset_invalid_align,target_align=target_align,);({});} +match self.ptr_try_get_alloc_id(ptr){Ok((alloc_id,offset,_extra))=>{3;let(_size, +alloc_align,_kind)=self.get_alloc_info(alloc_id);3;if target_align<=alloc_align. +bytes(){3;let addr=ImmTy::from_uint(offset.bytes(),args[0].layout).into();3;;let +align=ImmTy::from_uint(target_align,args[1].layout).into();();3;let fn_abi=self. +fn_abi_of_instance(instance,ty::List::empty())?;{;};();self.eval_fn_call(FnVal:: +Instance(instance),(CallAbi::Rust,fn_abi), &[FnArg::Copy(addr),FnArg::Copy(align +)],false,dest,ret,mir::UnwindAction::Unreachable,)?;;Ok(ControlFlow::Break(()))} +else{;let usize_max=Scalar::from_target_usize(self.target_usize_max(),self);self +.write_scalar(usize_max,dest)?;;self.return_to_block(ret)?;Ok(ControlFlow::Break +(()))}}Err(_addr)=>{Ok(ControlFlow ::Continue(()))}}}fn guaranteed_cmp(&mut self +,a:Scalar,b:Scalar)->InterpResult<'tcx,u8>{Ok(match((((a,b)))){(Scalar::Int{..}, +Scalar::Int{..})=>{if (a==b){1}else{ 0}}(Scalar::Int(int),ptr@Scalar::Ptr(..))|( +ptr@Scalar::Ptr(..),Scalar::Int(int))if int.is_null()&&!self.scalar_may_be_null +(ptr)? =>{0}(Scalar::Int{..}, Scalar::Ptr(..))|(Scalar::Ptr(..),Scalar::Int{..}) +=>2,(Scalar::Ptr(..),Scalar::Ptr(..)) =>2,})}}impl<'mir,'tcx>interpret::Machine< +'mir,'tcx>for CompileTimeInterpreter<'mir,'tcx>{compile_time_machine!(<'mir,//3; +'tcx>);type MemoryKind=MemoryKind;const PANIC_ON_ALLOC_FAIL:bool=false;#[inline +(always)]fn enforce_alignment(ecx:&InterpCx<'mir ,'tcx,Self>)->bool{matches!(ecx +.machine.check_alignment,CheckAlignment::Error)}#[inline(always)]fn//let _=||(); +enforce_validity(ecx:&InterpCx<'mir,'tcx,Self >,layout:TyAndLayout<'tcx>)->bool{ +ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks||layout.abi.//loop{break}; +is_uninhabited()}fn load_mir(ecx:&InterpCx<'mir,'tcx,Self>,instance:ty:://{();}; +InstanceDef<'tcx>,)->InterpResult<'tcx,&'tcx mir::Body<'tcx>>{match instance{ty +::InstanceDef::Item(def)=>{if ((ecx.tcx.is_ctfe_mir_available(def))){Ok(ecx.tcx. +mir_for_ctfe(def))}else if ecx.tcx.def_kind(def)==DefKind::AssocConst{3;ecx.tcx. +dcx().bug("This is likely a const item that is missing from its impl");3;}else{; +let path=ecx.tcx.def_path_str(def);if true{};if true{};if true{};if true{};bug!( +"trying to call extern function `{path}` at compile-time");({});}}_=>Ok(ecx.tcx. +instance_mir(instance)),}}fn find_mir_or_eval_fn(ecx:&mut InterpCx<'mir,'tcx,//; +Self>,orig_instance:ty::Instance<'tcx>,_abi:CallAbi,args:&[FnArg<'tcx>],dest:&// +MPlaceTy<'tcx>,ret:Option,_unwind:mir::UnwindAction,)->//{();}; +InterpResult<'tcx,Option<(&'mir mir::Body<'tcx>,ty::Instance<'tcx>)>>{();debug!( +"find_mir_or_eval_fn: {:?}",orig_instance);*&*&();*&*&();let Some(instance)=ecx. +hook_special_const_fn(orig_instance,args,dest,ret)?else{3;return Ok(None);;};;if +let ty::InstanceDef::Item(def)=instance.def{if (!ecx.tcx.is_const_fn_raw(def)&&! +ecx.tcx.is_const_default_method(def))||ecx.tcx.has_attr(def,sym:://loop{break;}; +rustc_do_not_const_check){ throw_unsup_format!("calling non-const function `{}`" +,instance)}}(Ok((Some(((ecx.load_mir (instance.def,None)?,orig_instance))))))}fn +panic_nounwind(ecx:&mut InterpCx<'mir,'tcx,Self>,msg:&str)->InterpResult<'tcx>{; +let msg=Symbol::intern(msg);;let span=ecx.find_closest_untracked_caller_location +();;let(file,line,col)=ecx.location_triple_for_span(span);Err(ConstEvalErrKind:: +Panic{msg,file,line,col}.into()) }fn call_intrinsic(ecx:&mut InterpCx<'mir,'tcx, +Self>,instance:ty::Instance<'tcx>,args:& [OpTy<'tcx>],dest:&MPlaceTy<'tcx,Self:: +Provenance>,target:Option,_unwind:mir::UnwindAction,)->//{();}; +InterpResult<'tcx>{if ecx.emulate_intrinsic(instance,args,dest,target)?{;return +Ok(());;};let intrinsic_name=ecx.tcx.item_name(instance.def_id());let Some(ret)= +target else{loop{break};loop{break};loop{break};loop{break};throw_unsup_format!( +"intrinsic `{intrinsic_name}` is not supported at compile-time");{;};};{;};match +intrinsic_name{sym::ptr_guaranteed_cmp=>{;let a=ecx.read_scalar(&args[0])?;let b +=ecx.read_scalar(&args[1])?;;;let cmp=ecx.guaranteed_cmp(a,b)?;ecx.write_scalar( +Scalar::from_u8(cmp),dest)?;3;}sym::const_allocate=>{;let size=ecx.read_scalar(& +args[0])?.to_target_usize(ecx)?;{();};({});let align=ecx.read_scalar(&args[1])?. +to_target_usize(ecx)?;;let align=match Align::from_bytes(align){Ok(a)=>a,Err(err +)=>throw_ub_custom!(fluent::const_eval_invalid_align_details,name=//loop{break}; +"const_allocate",err_kind=err.diag_ident(),align=err.align()),};3;3;let ptr=ecx. +allocate_ptr((((Size::from_bytes(size)))) ,align,interpret::MemoryKind::Machine( +MemoryKind::Heap),)?;;;ecx.write_pointer(ptr,dest)?;}sym::const_deallocate=>{let +ptr=ecx.read_pointer(&args[0])?;{();};{();};let size=ecx.read_scalar(&args[1])?. +to_target_usize(ecx)?;;let align=ecx.read_scalar(&args[2])?.to_target_usize(ecx) +?;;let size=Size::from_bytes(size);let align=match Align::from_bytes(align){Ok(a +)=>a,Err(err)=>throw_ub_custom!(fluent::const_eval_invalid_align_details,name=// +"const_deallocate",err_kind=err.diag_ident(),align=err.align()),};;let(alloc_id, +_,_)=ecx.ptr_get_alloc_id(ptr)?;;let is_allocated_in_another_const=matches!(ecx. +tcx.try_get_global_alloc(alloc_id),Some(interpret::GlobalAlloc::Memory(_)));;if! +is_allocated_in_another_const{((),());ecx.deallocate_ptr(ptr,Some((size,align)), +interpret::MemoryKind::Machine(MemoryKind::Heap),)?;if true{};let _=||();}}sym:: +is_val_statically_known=>ecx.write_scalar(Scalar::from_bool(false),dest)?,_=>{3; +throw_unsup_format!(//if let _=(){};*&*&();((),());if let _=(){};*&*&();((),()); +"intrinsic `{intrinsic_name}` is not supported at compile-time");({});}}{;};ecx. +go_to_block(ret);;Ok(())}fn assert_panic(ecx:&mut InterpCx<'mir,'tcx,Self>,msg:& +AssertMessage<'tcx>,_unwind:mir::UnwindAction,)->InterpResult<'tcx>{let _=();use +rustc_middle::mir::AssertKind::*;3;;let eval_to_int=|op|ecx.read_immediate(&ecx. +eval_operand(op,None)?).map(|x|x.to_const_int());;let err=match msg{BoundsCheck{ +len,index}=>{();let len=eval_to_int(len)?;();();let index=eval_to_int(index)?;3; +BoundsCheck{len,index}}Overflow(op,l,r)=>Overflow(((*op)),(((eval_to_int(l))?)), +eval_to_int(r)?),OverflowNeg(op)=> OverflowNeg(eval_to_int(op)?),DivisionByZero( +op)=>(DivisionByZero((eval_to_int(op)? ))),RemainderByZero(op)=>RemainderByZero( +eval_to_int(op)?),ResumedAfterReturn(coroutine_kind)=>ResumedAfterReturn(*//{;}; +coroutine_kind),ResumedAfterPanic(coroutine_kind)=>ResumedAfterPanic(*//((),()); +coroutine_kind),MisalignedPointerDereference{ref required,ref found}=>{//*&*&(); +MisalignedPointerDereference{required:eval_to_int(required) ?,found:eval_to_int( +found)?,}}};3;Err(ConstEvalErrKind::AssertFailure(err).into())}fn binary_ptr_op( +_ecx:&InterpCx<'mir,'tcx,Self>,_bin_op:mir::BinOp,_left:&ImmTy<'tcx>,_right:&//; +ImmTy<'tcx>,)->InterpResult<'tcx,(ImmTy<'tcx>,bool)>{*&*&();throw_unsup_format!( +"pointer arithmetic or comparison is not supported at compile-time");((),());}fn +increment_const_eval_counter(ecx:&mut InterpCx<'mir,'tcx,Self>)->InterpResult{if let Some(new_steps)=ecx.machine.num_evaluated_steps.checked_add(1){;let +(limit,start)=if ecx.tcx.sess.opts.unstable_opts.tiny_const_eval_limit{(//{();}; +TINY_LINT_TERMINATOR_LIMIT,TINY_LINT_TERMINATOR_LIMIT)}else{(//((),());let _=(); +LINT_TERMINATOR_LIMIT,PROGRESS_INDICATOR_START)};if true{};let _=();ecx.machine. +num_evaluated_steps=new_steps;((),());if new_steps==limit{*&*&();let hir_id=ecx. +best_lint_scope();;let is_error=ecx.tcx.lint_level_at_node(rustc_session::lint:: +builtin::LONG_RUNNING_CONST_EVAL,hir_id,).0.is_error();;let span=ecx.cur_span(); +ecx.tcx.emit_node_span_lint(rustc_session::lint::builtin:://if true{};if true{}; +LONG_RUNNING_CONST_EVAL,hir_id,span,LongRunning{item_span:ecx.tcx.span},);{;};if +is_error{loop{break};loop{break;};let guard=ecx.tcx.dcx().span_delayed_bug(span, +"The deny lint should have already errored");;throw_inval!(AlreadyReported(guard +.into()));;}}else if new_steps>start&&new_steps.is_power_of_two(){;let span=ecx. +cur_span();;ecx.tcx.dcx().emit_warn(LongRunningWarn{span,item_span:ecx.tcx.span} +);();}}Ok(())}#[inline(always)]fn expose_ptr(_ecx:&mut InterpCx<'mir,'tcx,Self>, +_ptr:Pointer)->InterpResult<'tcx>{throw_unsup_format!(//loop{break};loop{break}; +"exposing pointers is not possible at compile-time")}#[inline(always)]fn//{();}; +init_frame_extra(ecx:&mut InterpCx<'mir,'tcx,Self>,frame:Frame<'mir,'tcx>,)->//; +InterpResult<'tcx,Frame<'mir,'tcx>>{if!ecx.recursion_limit.value_within_limit(// +ecx.stack().len()+(1)){throw_exhaust!(StackFrameLimitReached)}else{Ok(frame)}}#[ +inline(always)]fn stack<'a>(ecx:&'a InterpCx<'mir,'tcx,Self>,)->&'a[Frame<'mir, +'tcx,Self::Provenance,Self::FrameExtra>]{& ecx.machine.stack}#[inline(always)]fn +stack_mut<'a>(ecx:&'a mut InterpCx<'mir,'tcx,Self>,)->&'a mut Vec>{(((((((&mut ecx.machine.stack)))))))}fn +before_access_global(_tcx:TyCtxtAt<'tcx>,machine:&Self,alloc_id:AllocId,alloc:// +ConstAllocation<'tcx>,_static_def_id:Option,is_write:bool,)->//if true{}; +InterpResult<'tcx>{;let alloc=alloc.inner();;if is_write{match alloc.mutability{ +Mutability::Not=>Err(err_ub!(WriteToReadOnly( alloc_id)).into()),Mutability::Mut +=>((((Err((((ConstEvalErrKind::ModifiedGlobal.into() )))))))),}}else{if machine. +can_access_mut_global==CanAccessMutGlobal::Yes{(Ok(()))}else if alloc.mutability +==Mutability::Mut{Err(ConstEvalErrKind::ConstAccessesMutGlobal.into())}else{{;}; +assert_eq!(alloc.mutability,Mutability::Not);3;Ok(())}}}fn retag_ptr_value(ecx:& +mut InterpCx<'mir,'tcx,Self>,_kind:mir::RetagKind,val:&ImmTy<'tcx,//loop{break}; +CtfeProvenance>,)->InterpResult<'tcx,ImmTy<'tcx, CtfeProvenance>>{if let ty::Ref +(_,ty,mutbl)=(((val.layout.ty.kind())))&&(((((*mutbl))==Mutability::Not)))&&val. +to_scalar_and_meta().0.to_pointer(ecx)?. provenance.is_some_and(|p|!p.immutable( +))&&ty.is_freeze(*ecx.tcx,ecx.param_env){;let place=ecx.ref_to_mplace(val)?;;let +new_place=place.map_provenance(CtfeProvenance::as_immutable);let _=();Ok(ImmTy:: +from_immediate((new_place.to_ref(ecx)),val.layout))}else{(Ok((val.clone())))}}fn +before_memory_write(tcx:TyCtxtAt<'tcx>,machine: &mut Self,_alloc_extra:&mut Self +::AllocExtra,(_alloc_id,immutable):(AllocId,bool),range:AllocRange,)->//((),()); +InterpResult<'tcx>{if range.size==Size::ZERO{;return Ok(());;}if immutable{super +::lint(tcx,machine,WRITES_THROUGH_IMMUTABLE_POINTER,|frames|{crate::errors:://3; +WriteThroughImmutablePointer{frames}});*&*&();}Ok(())}fn before_alloc_read(ecx:& +InterpCx<'mir,'tcx,Self>,alloc_id:AllocId,)->InterpResult<'tcx>{if Some(//{();}; +alloc_id)==(ecx.machine.static_root_ids.map(|( id,_)|id)){Err(ConstEvalErrKind:: +RecursiveStatic.into())}else{(((((((((((Ok(((((((((((()))))))))))))))))))))))}}} diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index 8efc67bcb0c4d..c60cadf9cf6c4 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -1,98 +1,32 @@ -// Not in interpret to make sure we do not use private implementation details - -use rustc_middle::mir; -use rustc_middle::mir::interpret::InterpErrorInfo; -use rustc_middle::query::{Key, TyCtxtAt}; -use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_target::abi::VariantIdx; - -use crate::interpret::{format_interp_error, InterpCx}; - -mod dummy_machine; -mod error; -mod eval_queries; -mod fn_queries; -mod machine; -mod valtrees; - -pub use dummy_machine::*; -pub use error::*; -pub use eval_queries::*; -pub use fn_queries::*; -pub use machine::*; -pub(crate) use valtrees::{eval_to_valtree, valtree_to_const_value}; - -// We forbid type-level constants that contain more than `VALTREE_MAX_NODES` nodes. -const VALTREE_MAX_NODES: usize = 100000; - -pub(crate) enum ValTreeCreationError { - NodesOverflow, - /// Values of this type, or this particular value, are not supported as valtrees. - NonSupportedType, -} -pub(crate) type ValTreeCreationResult<'tcx> = Result, ValTreeCreationError>; - -impl From> for ValTreeCreationError { - fn from(err: InterpErrorInfo<'_>) -> Self { - ty::tls::with(|tcx| { - bug!( - "Unexpected Undefined Behavior error during valtree construction: {}", - format_interp_error(tcx.dcx(), err), - ) - }) - } -} - -#[instrument(skip(tcx), level = "debug")] -pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>( - tcx: TyCtxtAt<'tcx>, - val: mir::ConstValue<'tcx>, - ty: Ty<'tcx>, -) -> Option> { - let param_env = ty::ParamEnv::reveal_all(); - let (ecx, op) = mk_eval_cx_for_const_val(tcx, param_env, val, ty)?; - - // We go to `usize` as we cannot allocate anything bigger anyway. - let (field_count, variant, down) = match ty.kind() { - ty::Array(_, len) => (len.eval_target_usize(tcx.tcx, param_env) as usize, None, op), - ty::Adt(def, _) if def.variants().is_empty() => { - return None; - } - ty::Adt(def, _) => { - let variant = ecx.read_discriminant(&op).ok()?; - let down = ecx.project_downcast(&op, variant).ok()?; - (def.variants()[variant].fields.len(), Some(variant), down) - } - ty::Tuple(args) => (args.len(), None, op), - _ => bug!("cannot destructure mir constant {:?}", val), - }; - - let fields_iter = (0..field_count) - .map(|i| { - let field_op = ecx.project_field(&down, i).ok()?; - let val = op_to_const(&ecx, &field_op, /* for diagnostics */ true); - Some((val, field_op.layout.ty)) - }) - .collect::>>()?; - let fields = tcx.arena.alloc_from_iter(fields_iter); - - Some(mir::DestructuredConstant { variant, fields }) -} - -/// Computes the tag (if any) for a given type and variant. -#[instrument(skip(tcx), level = "debug")] -pub fn tag_for_variant_provider<'tcx>( - tcx: TyCtxt<'tcx>, - (ty, variant_index): (Ty<'tcx>, VariantIdx), -) -> Option { - assert!(ty.is_enum()); - - let ecx = InterpCx::new( - tcx, - ty.default_span(tcx), - ty::ParamEnv::reveal_all(), - crate::const_eval::DummyMachine, - ); - - ecx.tag_for_variant(ty, variant_index).unwrap().map(|(tag, _tag_field)| tag) -} +use rustc_middle::mir;use rustc_middle::mir::interpret::InterpErrorInfo;use//(); +rustc_middle::query::{Key,TyCtxtAt};use rustc_middle::ty::{self,Ty,TyCtxt};use// +rustc_target::abi::VariantIdx;use crate::interpret::{format_interp_error,//({}); +InterpCx};mod dummy_machine;mod error;mod eval_queries;mod fn_queries;mod//({}); +machine;mod valtrees;pub use dummy_machine::*;pub use error::*;pub use//((),()); +eval_queries::*;pub use fn_queries::*;pub use machine::*;pub(crate)use valtrees +::{eval_to_valtree,valtree_to_const_value};const VALTREE_MAX_NODES:usize=100000 +;pub(crate)enum ValTreeCreationError{ NodesOverflow,NonSupportedType,}pub(crate) +type ValTreeCreationResult<'tcx>=Result< ty::ValTree<'tcx>,ValTreeCreationError> +;impl From>for ValTreeCreationError{fn from(err://if true{}; +InterpErrorInfo<'_>)->Self{ty::tls::with(|tcx|{bug!(//loop{break;};loop{break;}; +"Unexpected Undefined Behavior error during valtree construction: {}",//((),()); +format_interp_error(tcx.dcx(),err),)})}}#[instrument(skip(tcx),level="debug")]// +pub(crate)fn try_destructure_mir_constant_for_user_output<'tcx>(tcx:TyCtxtAt,val:mir::ConstValue<'tcx>,ty :Ty<'tcx>,)->Option>{*&*&();let param_env=ty::ParamEnv::reveal_all();{();};{();};let(ecx,op)= +mk_eval_cx_for_const_val(tcx,param_env,val,ty)?;;;let(field_count,variant,down)= +match (ty.kind()){ty::Array(_,len )=>(len.eval_target_usize(tcx.tcx,param_env)as +usize,None,op),ty::Adt(def,_)if def.variants().is_empty()=>{3;return None;;}ty:: +Adt(def,_)=>{();let variant=ecx.read_discriminant(&op).ok()?;();();let down=ecx. +project_downcast(&op,variant).ok()?;;(def.variants()[variant].fields.len(),Some( +variant),down)}ty::Tuple(args)=>(((((((((( args.len())))),None,op)))))),_=>bug!( +"cannot destructure mir constant {:?}",val),};;let fields_iter=(0..field_count). +map(|i|{;let field_op=ecx.project_field(&down,i).ok()?;let val=op_to_const(&ecx, +&field_op,true);;Some((val,field_op.layout.ty))}).collect::>>()?;; +let fields=tcx.arena.alloc_from_iter(fields_iter);if true{};if true{};Some(mir:: +DestructuredConstant{variant,fields})}#[ instrument(skip(tcx),level="debug")]pub +fn tag_for_variant_provider<'tcx>(tcx:TyCtxt<'tcx>,(ty,variant_index):(Ty<'tcx// +>,VariantIdx),)->Option{;assert!(ty.is_enum());let ecx=InterpCx:: +new(tcx,(ty.default_span(tcx)), (ty::ParamEnv::reveal_all()),crate::const_eval:: +DummyMachine,);((),());ecx.tag_for_variant(ty,variant_index).unwrap().map(|(tag, +_tag_field)|tag)}//*&*&();((),());*&*&();((),());*&*&();((),());((),());((),()); diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index d91ad3fcab1fd..55dde197f7925 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -1,448 +1,135 @@ -use rustc_middle::mir; -use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId}; -use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout}; -use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt}; -use rustc_span::DUMMY_SP; -use rustc_target::abi::{Abi, VariantIdx}; - -use super::eval_queries::{mk_eval_cx_to_read_const_val, op_to_const}; -use super::machine::CompileTimeEvalContext; -use super::{ValTreeCreationError, ValTreeCreationResult, VALTREE_MAX_NODES}; -use crate::const_eval::CanAccessMutGlobal; -use crate::errors::MaxNumNodesInConstErr; -use crate::interpret::MPlaceTy; -use crate::interpret::{ - intern_const_alloc_recursive, ImmTy, Immediate, InternKind, MemPlaceMeta, MemoryKind, PlaceTy, - Projectable, Scalar, -}; - -#[instrument(skip(ecx), level = "debug")] -fn branches<'tcx>( - ecx: &CompileTimeEvalContext<'tcx, 'tcx>, - place: &MPlaceTy<'tcx>, - n: usize, - variant: Option, - num_nodes: &mut usize, -) -> ValTreeCreationResult<'tcx> { - let place = match variant { - Some(variant) => ecx.project_downcast(place, variant).unwrap(), - None => place.clone(), - }; - let variant = variant.map(|variant| Some(ty::ValTree::Leaf(ScalarInt::from(variant.as_u32())))); - debug!(?place, ?variant); - - let mut fields = Vec::with_capacity(n); - for i in 0..n { - let field = ecx.project_field(&place, i).unwrap(); - let valtree = const_to_valtree_inner(ecx, &field, num_nodes)?; - fields.push(Some(valtree)); - } - - // For enums, we prepend their variant index before the variant's fields so we can figure out - // the variant again when just seeing a valtree. - let branches = variant - .into_iter() - .chain(fields.into_iter()) - .collect::>>() - .expect("should have already checked for errors in ValTree creation"); - - // Have to account for ZSTs here - if branches.len() == 0 { - *num_nodes += 1; - } - - Ok(ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter(branches))) -} - -#[instrument(skip(ecx), level = "debug")] -fn slice_branches<'tcx>( - ecx: &CompileTimeEvalContext<'tcx, 'tcx>, - place: &MPlaceTy<'tcx>, - num_nodes: &mut usize, -) -> ValTreeCreationResult<'tcx> { - let n = place.len(ecx).unwrap_or_else(|_| panic!("expected to use len of place {place:?}")); - - let mut elems = Vec::with_capacity(n as usize); - for i in 0..n { - let place_elem = ecx.project_index(place, i).unwrap(); - let valtree = const_to_valtree_inner(ecx, &place_elem, num_nodes)?; - elems.push(valtree); - } - - Ok(ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter(elems))) -} - -#[instrument(skip(ecx), level = "debug")] -fn const_to_valtree_inner<'tcx>( - ecx: &CompileTimeEvalContext<'tcx, 'tcx>, - place: &MPlaceTy<'tcx>, - num_nodes: &mut usize, -) -> ValTreeCreationResult<'tcx> { - let ty = place.layout.ty; - debug!("ty kind: {:?}", ty.kind()); - - if *num_nodes >= VALTREE_MAX_NODES { - return Err(ValTreeCreationError::NodesOverflow); - } - - match ty.kind() { - ty::FnDef(..) => { - *num_nodes += 1; - Ok(ty::ValTree::zst()) - } - ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => { - let val = ecx.read_immediate(place)?; - let val = val.to_scalar(); - *num_nodes += 1; - - Ok(ty::ValTree::Leaf(val.assert_int())) - } - - ty::RawPtr(_, _) => { - // Not all raw pointers are allowed, as we cannot properly test them for - // equality at compile-time (see `ptr_guaranteed_cmp`). - // However we allow those that are just integers in disguise. - // First, get the pointer. Remember it might be wide! - let val = ecx.read_immediate(place)?; - // We could allow wide raw pointers where both sides are integers in the future, - // but for now we reject them. - if matches!(val.layout.abi, Abi::ScalarPair(..)) { - return Err(ValTreeCreationError::NonSupportedType); - } - let val = val.to_scalar(); - // We are in the CTFE machine, so ptr-to-int casts will fail. - // This can only be `Ok` if `val` already is an integer. - let Ok(val) = val.try_to_int() else { - return Err(ValTreeCreationError::NonSupportedType); - }; - // It's just a ScalarInt! - Ok(ty::ValTree::Leaf(val)) - } - - // Technically we could allow function pointers (represented as `ty::Instance`), but this is not guaranteed to - // agree with runtime equality tests. - ty::FnPtr(_) => Err(ValTreeCreationError::NonSupportedType), - - ty::Ref(_, _, _) => { - let derefd_place = ecx.deref_pointer(place)?; - const_to_valtree_inner(ecx, &derefd_place, num_nodes) - } - - ty::Str | ty::Slice(_) | ty::Array(_, _) => { - slice_branches(ecx, place, num_nodes) - } - // Trait objects are not allowed in type level constants, as we have no concept for - // resolving their backing type, even if we can do that at const eval time. We may - // hypothetically be able to allow `dyn StructuralPartialEq` trait objects in the future, - // but it is unclear if this is useful. - ty::Dynamic(..) => Err(ValTreeCreationError::NonSupportedType), - - ty::Tuple(elem_tys) => { - branches(ecx, place, elem_tys.len(), None, num_nodes) - } - - ty::Adt(def, _) => { - if def.is_union() { - return Err(ValTreeCreationError::NonSupportedType); - } else if def.variants().is_empty() { - bug!("uninhabited types should have errored and never gotten converted to valtree") - } - - let variant = ecx.read_discriminant(place)?; - branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant), num_nodes) - } - - ty::Never - | ty::Error(_) - | ty::Foreign(..) - | ty::Infer(ty::FreshIntTy(_)) - | ty::Infer(ty::FreshFloatTy(_)) - // FIXME(oli-obk): we could look behind opaque types - | ty::Alias(..) - | ty::Param(_) - | ty::Bound(..) - | ty::Placeholder(..) - | ty::Infer(_) - // FIXME(oli-obk): we can probably encode closures just like structs - | ty::Closure(..) - | ty::CoroutineClosure(..) - | ty::Coroutine(..) - | ty::CoroutineWitness(..) => Err(ValTreeCreationError::NonSupportedType), - } -} - -/// Valtrees don't store the `MemPlaceMeta` that all dynamically sized values have in the interpreter. -/// This function reconstructs it. -fn reconstruct_place_meta<'tcx>( - layout: TyAndLayout<'tcx>, - valtree: ty::ValTree<'tcx>, - tcx: TyCtxt<'tcx>, -) -> MemPlaceMeta { - if layout.is_sized() { - return MemPlaceMeta::None; - } - - let mut last_valtree = valtree; - // Traverse the type, and update `last_valtree` as we go. - let tail = tcx.struct_tail_with_normalize( - layout.ty, - |ty| ty, - || { - let branches = last_valtree.unwrap_branch(); - last_valtree = *branches.last().unwrap(); - debug!(?branches, ?last_valtree); - }, - ); - // Sanity-check that we got a tail we support. - match tail.kind() { - ty::Slice(..) | ty::Str => {} - _ => bug!("unsized tail of a valtree must be Slice or Str"), - }; - - // Get the number of elements in the unsized field. - let num_elems = last_valtree.unwrap_branch().len(); - MemPlaceMeta::Meta(Scalar::from_target_usize(num_elems as u64, &tcx)) -} - -#[instrument(skip(ecx), level = "debug", ret)] -fn create_valtree_place<'tcx>( - ecx: &mut CompileTimeEvalContext<'tcx, 'tcx>, - layout: TyAndLayout<'tcx>, - valtree: ty::ValTree<'tcx>, -) -> MPlaceTy<'tcx> { - let meta = reconstruct_place_meta(layout, valtree, ecx.tcx.tcx); - ecx.allocate_dyn(layout, MemoryKind::Stack, meta).unwrap() -} - -/// Evaluates a constant and turns it into a type-level constant value. -pub(crate) fn eval_to_valtree<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - cid: GlobalId<'tcx>, -) -> EvalToValTreeResult<'tcx> { - let const_alloc = tcx.eval_to_allocation_raw(param_env.and(cid))?; - - // FIXME Need to provide a span to `eval_to_valtree` - let ecx = mk_eval_cx_to_read_const_val( - tcx, - DUMMY_SP, - param_env, - // It is absolutely crucial for soundness that - // we do not read from mutable memory. - CanAccessMutGlobal::No, - ); - let place = ecx.raw_const_to_mplace(const_alloc).unwrap(); - debug!(?place); - - let mut num_nodes = 0; - let valtree_result = const_to_valtree_inner(&ecx, &place, &mut num_nodes); - - match valtree_result { - Ok(valtree) => Ok(Some(valtree)), - Err(err) => { - let did = cid.instance.def_id(); - let global_const_id = cid.display(tcx); - let span = tcx.hir().span_if_local(did); - match err { - ValTreeCreationError::NodesOverflow => { - let handled = - tcx.dcx().emit_err(MaxNumNodesInConstErr { span, global_const_id }); - Err(handled.into()) - } - ValTreeCreationError::NonSupportedType => Ok(None), - } - } - } -} - -/// Converts a `ValTree` to a `ConstValue`, which is needed after mir -/// construction has finished. -// FIXME Merge `valtree_to_const_value` and `valtree_into_mplace` into one function -#[instrument(skip(tcx), level = "debug", ret)] -pub fn valtree_to_const_value<'tcx>( - tcx: TyCtxt<'tcx>, - param_env_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, - valtree: ty::ValTree<'tcx>, -) -> mir::ConstValue<'tcx> { - // Basic idea: We directly construct `Scalar` values from trivial `ValTree`s - // (those for constants with type bool, int, uint, float or char). - // For all other types we create an `MPlace` and fill that by walking - // the `ValTree` and using `place_projection` and `place_field` to - // create inner `MPlace`s which are filled recursively. - // FIXME Does this need an example? - - let (param_env, ty) = param_env_ty.into_parts(); - - match ty.kind() { - ty::FnDef(..) => { - assert!(valtree.unwrap_branch().is_empty()); - mir::ConstValue::ZeroSized - } - ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char | ty::RawPtr(_, _) => { - match valtree { - ty::ValTree::Leaf(scalar_int) => mir::ConstValue::Scalar(Scalar::Int(scalar_int)), - ty::ValTree::Branch(_) => bug!( - "ValTrees for Bool, Int, Uint, Float, Char or RawPtr should have the form ValTree::Leaf" - ), - } - } - ty::Ref(_, inner_ty, _) => { - let mut ecx = - mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, param_env, CanAccessMutGlobal::No); - let imm = valtree_to_ref(&mut ecx, valtree, *inner_ty); - let imm = ImmTy::from_immediate(imm, tcx.layout_of(param_env_ty).unwrap()); - op_to_const(&ecx, &imm.into(), /* for diagnostics */ false) - } - ty::Tuple(_) | ty::Array(_, _) | ty::Adt(..) => { - let layout = tcx.layout_of(param_env_ty).unwrap(); - if layout.is_zst() { - // Fast path to avoid some allocations. - return mir::ConstValue::ZeroSized; - } - if layout.abi.is_scalar() - && (matches!(ty.kind(), ty::Tuple(_)) - || matches!(ty.kind(), ty::Adt(def, _) if def.is_struct())) - { - // A Scalar tuple/struct; we can avoid creating an allocation. - let branches = valtree.unwrap_branch(); - // Find the non-ZST field. (There can be aligned ZST!) - for (i, &inner_valtree) in branches.iter().enumerate() { - let field = layout.field(&LayoutCx { tcx, param_env }, i); - if !field.is_zst() { - return valtree_to_const_value(tcx, param_env.and(field.ty), inner_valtree); - } - } - bug!("could not find non-ZST field during in {layout:#?}"); - } - - let mut ecx = - mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, param_env, CanAccessMutGlobal::No); - - // Need to create a place for this valtree. - let place = create_valtree_place(&mut ecx, layout, valtree); - - valtree_into_mplace(&mut ecx, &place, valtree); - dump_place(&ecx, &place); - intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &place).unwrap(); - - op_to_const(&ecx, &place.into(), /* for diagnostics */ false) - } - ty::Never - | ty::Error(_) - | ty::Foreign(..) - | ty::Infer(ty::FreshIntTy(_)) - | ty::Infer(ty::FreshFloatTy(_)) - | ty::Alias(..) - | ty::Param(_) - | ty::Bound(..) - | ty::Placeholder(..) - | ty::Infer(_) - | ty::Closure(..) - | ty::CoroutineClosure(..) - | ty::Coroutine(..) - | ty::CoroutineWitness(..) - | ty::FnPtr(_) - | ty::Str - | ty::Slice(_) - | ty::Dynamic(..) => bug!("no ValTree should have been created for type {:?}", ty.kind()), - } -} - -/// Put a valtree into memory and return a reference to that. -fn valtree_to_ref<'tcx>( - ecx: &mut CompileTimeEvalContext<'tcx, 'tcx>, - valtree: ty::ValTree<'tcx>, - pointee_ty: Ty<'tcx>, -) -> Immediate { - let pointee_place = create_valtree_place(ecx, ecx.layout_of(pointee_ty).unwrap(), valtree); - debug!(?pointee_place); - - valtree_into_mplace(ecx, &pointee_place, valtree); - dump_place(ecx, &pointee_place); - intern_const_alloc_recursive(ecx, InternKind::Constant, &pointee_place).unwrap(); - - pointee_place.to_ref(&ecx.tcx) -} - -#[instrument(skip(ecx), level = "debug")] -fn valtree_into_mplace<'tcx>( - ecx: &mut CompileTimeEvalContext<'tcx, 'tcx>, - place: &MPlaceTy<'tcx>, - valtree: ty::ValTree<'tcx>, -) { - // This will match on valtree and write the value(s) corresponding to the ValTree - // inside the place recursively. - - let ty = place.layout.ty; - - match ty.kind() { - ty::FnDef(_, _) => { - // Zero-sized type, nothing to do. - } - ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char | ty::RawPtr(..) => { - let scalar_int = valtree.unwrap_leaf(); - debug!("writing trivial valtree {:?} to place {:?}", scalar_int, place); - ecx.write_immediate(Immediate::Scalar(scalar_int.into()), place).unwrap(); - } - ty::Ref(_, inner_ty, _) => { - let imm = valtree_to_ref(ecx, valtree, *inner_ty); - debug!(?imm); - ecx.write_immediate(imm, place).unwrap(); - } - ty::Adt(_, _) | ty::Tuple(_) | ty::Array(_, _) | ty::Str | ty::Slice(_) => { - let branches = valtree.unwrap_branch(); - - // Need to downcast place for enums - let (place_adjusted, branches, variant_idx) = match ty.kind() { - ty::Adt(def, _) if def.is_enum() => { - // First element of valtree corresponds to variant - let scalar_int = branches[0].unwrap_leaf(); - let variant_idx = VariantIdx::from_u32(scalar_int.try_to_u32().unwrap()); - let variant = def.variant(variant_idx); - debug!(?variant); - - ( - ecx.project_downcast(place, variant_idx).unwrap(), - &branches[1..], - Some(variant_idx), - ) - } - _ => (place.clone(), branches, None), - }; - debug!(?place_adjusted, ?branches); - - // Create the places (by indexing into `place`) for the fields and fill - // them recursively - for (i, inner_valtree) in branches.iter().enumerate() { - debug!(?i, ?inner_valtree); - - let place_inner = match ty.kind() { - ty::Str | ty::Slice(_) | ty::Array(..) => { - ecx.project_index(place, i as u64).unwrap() - } - _ => ecx.project_field(&place_adjusted, i).unwrap(), - }; - - debug!(?place_inner); - valtree_into_mplace(ecx, &place_inner, *inner_valtree); - dump_place(ecx, &place_inner); - } - - debug!("dump of place_adjusted:"); - dump_place(ecx, &place_adjusted); - - if let Some(variant_idx) = variant_idx { - // don't forget filling the place with the discriminant of the enum - ecx.write_discriminant(variant_idx, place).unwrap(); - } - - debug!("dump of place after writing discriminant:"); - dump_place(ecx, place); - } - _ => bug!("shouldn't have created a ValTree for {:?}", ty), - } -} - -fn dump_place<'tcx>(ecx: &CompileTimeEvalContext<'tcx, 'tcx>, place: &MPlaceTy<'tcx>) { - trace!("{:?}", ecx.dump_place(&PlaceTy::from(place.clone()))); -} +use rustc_middle::mir;use rustc_middle::mir::interpret::{EvalToValTreeResult,//; +GlobalId};use rustc_middle::ty::layout::{LayoutCx,LayoutOf,TyAndLayout};use//(); +rustc_middle::ty::{self,ScalarInt,Ty,TyCtxt};use rustc_span::DUMMY_SP;use//({}); +rustc_target::abi::{Abi,VariantIdx};use super::eval_queries::{//((),());((),()); +mk_eval_cx_to_read_const_val,op_to_const};use super::machine:://((),());((),()); +CompileTimeEvalContext;use super::{ValTreeCreationError,ValTreeCreationResult,// +VALTREE_MAX_NODES};use crate::const_eval::CanAccessMutGlobal;use crate::errors// +::MaxNumNodesInConstErr;use crate::interpret::MPlaceTy;use crate::interpret::{// +intern_const_alloc_recursive,ImmTy,Immediate ,InternKind,MemPlaceMeta,MemoryKind +,PlaceTy,Projectable,Scalar,};#[instrument( skip(ecx),level="debug")]fn branches +<'tcx>(ecx:&CompileTimeEvalContext<'tcx,'tcx>,place:&MPlaceTy<'tcx>,n:usize,//3; +variant:Option,num_nodes:&mut usize,)->ValTreeCreationResult<'tcx>{; +let place=match variant{Some(variant) =>((ecx.project_downcast(place,variant))). +unwrap(),None=>place.clone(),};{;};();let variant=variant.map(|variant|Some(ty:: +ValTree::Leaf(ScalarInt::from(variant.as_u32()))));;;debug!(?place,?variant);let +mut fields=Vec::with_capacity(n);3;for i in 0..n{3;let field=ecx.project_field(& +place,i).unwrap();;;let valtree=const_to_valtree_inner(ecx,&field,num_nodes)?;;; +fields.push(Some(valtree));();}();let branches=variant.into_iter().chain(fields. +into_iter()).collect::>>().expect(//*&*&();((),());*&*&();((),()); +"should have already checked for errors in ValTree creation");;if branches.len() +==0{{;};*num_nodes+=1;{;};}Ok(ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter( +branches)))}#[instrument(skip(ecx) ,level="debug")]fn slice_branches<'tcx>(ecx:& +CompileTimeEvalContext<'tcx,'tcx>,place:&MPlaceTy<'tcx>,num_nodes:&mut usize,)// +->ValTreeCreationResult<'tcx>{{;};let n=place.len(ecx).unwrap_or_else(|_|panic!( +"expected to use len of place {place:?}"));3;;let mut elems=Vec::with_capacity(n +as usize);;for i in 0..n{;let place_elem=ecx.project_index(place,i).unwrap();let +valtree=const_to_valtree_inner(ecx,&place_elem,num_nodes)?;;elems.push(valtree); +}(Ok((ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter(elems)))))}#[instrument( +skip(ecx),level="debug")]fn const_to_valtree_inner<'tcx>(ecx:&//((),());((),()); +CompileTimeEvalContext<'tcx,'tcx>,place:&MPlaceTy<'tcx>,num_nodes:&mut usize,)// +->ValTreeCreationResult<'tcx>{;let ty=place.layout.ty;debug!("ty kind: {:?}",ty. +kind());{;};if*num_nodes>=VALTREE_MAX_NODES{();return Err(ValTreeCreationError:: +NodesOverflow);;}match ty.kind(){ty::FnDef(..)=>{;*num_nodes+=1;Ok(ty::ValTree:: +zst())}ty::Bool|ty::Int(_)|ty::Uint(_)|ty::Float(_)|ty::Char=>{({});let val=ecx. +read_immediate(place)?;;;let val=val.to_scalar();;*num_nodes+=1;Ok(ty::ValTree:: +Leaf(val.assert_int()))}ty::RawPtr(_,_)=>{;let val=ecx.read_immediate(place)?;if +matches!(val.layout.abi,Abi::ScalarPair(..)){3;return Err(ValTreeCreationError:: +NonSupportedType);;};let val=val.to_scalar();;;let Ok(val)=val.try_to_int()else{ +return Err(ValTreeCreationError::NonSupportedType);;};Ok(ty::ValTree::Leaf(val)) +}ty::FnPtr(_)=>Err(ValTreeCreationError::NonSupportedType),ty::Ref(_,_,_)=>{;let +derefd_place=ecx.deref_pointer(place)?;loop{break;};const_to_valtree_inner(ecx,& +derefd_place,num_nodes)}ty::Str|ty::Slice(_)|ty::Array(_,_)=>{slice_branches(//; +ecx,place,num_nodes)}ty::Dynamic(..)=>Err(ValTreeCreationError:://if let _=(){}; +NonSupportedType),ty::Tuple(elem_tys)=>{branches (ecx,place,elem_tys.len(),None, +num_nodes)}ty::Adt(def,_)=>{if def.is_union(){;return Err(ValTreeCreationError:: +NonSupportedType);let _=||();let _=||();}else if def.variants().is_empty(){bug!( +"uninhabited types should have errored and never gotten converted to valtree")}; +let variant=ecx.read_discriminant(place)?;*&*&();branches(ecx,place,def.variant( +variant).fields.len(),(def.is_enum().then_some(variant)),num_nodes)}ty::Never|ty +::Error(_)|ty::Foreign(..)|ty::Infer(ty::FreshIntTy(_))|ty::Infer(ty:://((),()); +FreshFloatTy(_))|ty::Alias(..)|ty::Param(_)|ty::Bound(..)|ty::Placeholder(..)|// +ty::Infer(_)|ty::Closure(..)|ty::CoroutineClosure(..)|ty::Coroutine(..)|ty:://3; +CoroutineWitness(..)=>(((((Err(ValTreeCreationError::NonSupportedType)))))),}}fn +reconstruct_place_meta<'tcx>(layout:TyAndLayout<'tcx >,valtree:ty::ValTree<'tcx> +,tcx:TyCtxt<'tcx>,)->MemPlaceMeta{if layout.is_sized(){{;};return MemPlaceMeta:: +None;3;};let mut last_valtree=valtree;;;let tail=tcx.struct_tail_with_normalize( +layout.ty,|ty|ty,||{3;let branches=last_valtree.unwrap_branch();;;last_valtree=* +branches.last().unwrap();;debug!(?branches,?last_valtree);},);match tail.kind(){ +ty::Slice(..)|ty::Str=>{}_=>bug!(//let _=||();let _=||();let _=||();loop{break}; +"unsized tail of a valtree must be Slice or Str"),};;let num_elems=last_valtree. +unwrap_branch().len();;MemPlaceMeta::Meta(Scalar::from_target_usize(num_elems as +u64,(&tcx)))}#[instrument( skip(ecx),level="debug",ret)]fn create_valtree_place< +'tcx>(ecx:&mut CompileTimeEvalContext<'tcx,'tcx>,layout:TyAndLayout<'tcx>,//{;}; +valtree:ty::ValTree<'tcx>,)->MPlaceTy<'tcx>{{;};let meta=reconstruct_place_meta( +layout,valtree,ecx.tcx.tcx);{;};ecx.allocate_dyn(layout,MemoryKind::Stack,meta). +unwrap()}pub(crate)fn eval_to_valtree<'tcx>(tcx:TyCtxt<'tcx>,param_env:ty:://(); +ParamEnv<'tcx>,cid:GlobalId<'tcx>,)->EvalToValTreeResult<'tcx>{;let const_alloc= +tcx.eval_to_allocation_raw(param_env.and(cid))?;loop{break};loop{break};let ecx= +mk_eval_cx_to_read_const_val(tcx,DUMMY_SP,param_env,CanAccessMutGlobal::No,);3;; +let place=ecx.raw_const_to_mplace(const_alloc).unwrap();;;debug!(?place);let mut +num_nodes=0;({});({});let valtree_result=const_to_valtree_inner(&ecx,&place,&mut +num_nodes);3;match valtree_result{Ok(valtree)=>Ok(Some(valtree)),Err(err)=>{;let +did=cid.instance.def_id();;let global_const_id=cid.display(tcx);let span=tcx.hir +().span_if_local(did);{;};match err{ValTreeCreationError::NodesOverflow=>{();let +handled=tcx.dcx().emit_err(MaxNumNodesInConstErr{span,global_const_id});{;};Err( +handled.into())}ValTreeCreationError::NonSupportedType=> ((((Ok(None))))),}}}}#[ +instrument(skip(tcx),level="debug",ret )]pub fn valtree_to_const_value<'tcx>(tcx +:TyCtxt<'tcx>,param_env_ty:ty::ParamEnvAnd<'tcx,Ty<'tcx>>,valtree:ty::ValTree,)->mir::ConstValue<'tcx>{();let(param_env,ty)=param_env_ty.into_parts();3; +match ty.kind(){ty::FnDef(..)=>{;assert!(valtree.unwrap_branch().is_empty());mir +::ConstValue::ZeroSized}ty::Bool|ty::Int(_)|ty::Uint(_)|ty::Float(_)|ty::Char|// +ty::RawPtr(_,_)=>{match valtree{ty::ValTree::Leaf(scalar_int)=>mir::ConstValue// +::Scalar(((((((((Scalar::Int(scalar_int)))))))))) ,ty::ValTree::Branch(_)=>bug!( +"ValTrees for Bool, Int, Uint, Float, Char or RawPtr should have the form ValTree::Leaf" +),}}ty::Ref(_,inner_ty,_)=>{*&*&();let mut ecx=mk_eval_cx_to_read_const_val(tcx, +DUMMY_SP,param_env,CanAccessMutGlobal::No);();3;let imm=valtree_to_ref(&mut ecx, +valtree,*inner_ty);;let imm=ImmTy::from_immediate(imm,tcx.layout_of(param_env_ty +).unwrap());3;op_to_const(&ecx,&imm.into(),false)}ty::Tuple(_)|ty::Array(_,_)|ty +::Adt(..)=>{;let layout=tcx.layout_of(param_env_ty).unwrap();if layout.is_zst(){ +return mir::ConstValue::ZeroSized;;}if layout.abi.is_scalar()&&(matches!(ty.kind +(),ty::Tuple(_))||matches!(ty.kind(),ty::Adt(def,_)if def.is_struct())){({});let +branches=valtree.unwrap_branch();*&*&();for(i,&inner_valtree)in branches.iter(). +enumerate(){;let field=layout.field(&LayoutCx{tcx,param_env},i);if!field.is_zst( +){;return valtree_to_const_value(tcx,param_env.and(field.ty),inner_valtree);;}}; +bug!("could not find non-ZST field during in {layout:#?}");{;};}{;};let mut ecx= +mk_eval_cx_to_read_const_val(tcx,DUMMY_SP,param_env,CanAccessMutGlobal::No);;let +place=create_valtree_place(&mut ecx,layout,valtree);3;3;valtree_into_mplace(&mut +ecx,&place,valtree);;;dump_place(&ecx,&place);;intern_const_alloc_recursive(&mut +ecx,InternKind::Constant,&place).unwrap();;op_to_const(&ecx,&place.into(),false) +}ty::Never|ty::Error(_)|ty::Foreign(.. )|ty::Infer(ty::FreshIntTy(_))|ty::Infer( +ty::FreshFloatTy(_))|ty::Alias(..)|ty::Param(_)|ty::Bound(..)|ty::Placeholder(// +..)|ty::Infer(_)|ty::Closure(..)|ty::CoroutineClosure(..)|ty::Coroutine(..)|ty// +::CoroutineWitness(..)|ty::FnPtr(_)|ty::Str| ty::Slice(_)|ty::Dynamic(..)=>bug!( +"no ValTree should have been created for type {:?}",ty.kind()),}}fn//let _=||(); +valtree_to_ref<'tcx>(ecx:&mut CompileTimeEvalContext<'tcx,'tcx>,valtree:ty:://3; +ValTree<'tcx>,pointee_ty:Ty<'tcx>,)->Immediate{*&*&();((),());let pointee_place= +create_valtree_place(ecx,ecx.layout_of(pointee_ty).unwrap(),valtree);3;;debug!(? +pointee_place);;valtree_into_mplace(ecx,&pointee_place,valtree);dump_place(ecx,& +pointee_place);({});({});intern_const_alloc_recursive(ecx,InternKind::Constant,& +pointee_place).unwrap();3;pointee_place.to_ref(&ecx.tcx)}#[instrument(skip(ecx), +level="debug")]fn valtree_into_mplace<'tcx>(ecx:&mut CompileTimeEvalContext,place:&MPlaceTy<'tcx>,valtree:ty::ValTree<'tcx>,){{();};let ty=place. +layout.ty;3;match ty.kind(){ty::FnDef(_,_)=>{}ty::Bool|ty::Int(_)|ty::Uint(_)|ty +::Float(_)|ty::Char|ty::RawPtr(..)=>{;let scalar_int=valtree.unwrap_leaf();debug +!("writing trivial valtree {:?} to place {:?}",scalar_int,place);{();};({});ecx. +write_immediate(Immediate::Scalar(scalar_int.into()),place).unwrap();;}ty::Ref(_ +,inner_ty,_)=>{;let imm=valtree_to_ref(ecx,valtree,*inner_ty);;debug!(?imm);ecx. +write_immediate(imm,place).unwrap();3;}ty::Adt(_,_)|ty::Tuple(_)|ty::Array(_,_)| +ty::Str|ty::Slice(_)=>{;let branches=valtree.unwrap_branch();let(place_adjusted, +branches,variant_idx)=match ty.kind(){ty::Adt(def,_)if def.is_enum()=>{{();};let +scalar_int=branches[0].unwrap_leaf();();();let variant_idx=VariantIdx::from_u32( +scalar_int.try_to_u32().unwrap());;let variant=def.variant(variant_idx);debug!(? +variant);;(ecx.project_downcast(place,variant_idx).unwrap(),&branches[1..],Some( +variant_idx),)}_=>(place.clone(),branches,None),};();();debug!(?place_adjusted,? +branches);{;};for(i,inner_valtree)in branches.iter().enumerate(){{;};debug!(?i,? +inner_valtree);;;let place_inner=match ty.kind(){ty::Str|ty::Slice(_)|ty::Array( +..)=>{(((ecx.project_index(place,(i as u64 ))).unwrap()))}_=>ecx.project_field(& +place_adjusted,i).unwrap(),};3;;debug!(?place_inner);;;valtree_into_mplace(ecx,& +place_inner,*inner_valtree);{;};{;};dump_place(ecx,&place_inner);{;};}();debug!( +"dump of place_adjusted:");();();dump_place(ecx,&place_adjusted);();if let Some( +variant_idx)=variant_idx{;ecx.write_discriminant(variant_idx,place).unwrap();;}; +debug!("dump of place after writing discriminant:");;;dump_place(ecx,place);}_=> +bug!("shouldn't have created a ValTree for {:?}",ty),} }fn dump_place<'tcx>(ecx: +&CompileTimeEvalContext<'tcx,'tcx>,place:&MPlaceTy<'tcx>){{;};trace!("{:?}",ecx. +dump_place(&PlaceTy::from(place.clone())));let _=();let _=();let _=();let _=();} diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 5c46ec799f1ec..030f63d9cc165 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -1,902 +1,326 @@ -use std::borrow::Cow; - -use rustc_errors::{ - codes::*, Diag, DiagArgValue, DiagCtxt, DiagMessage, Diagnostic, EmissionGuarantee, Level, -}; -use rustc_hir::ConstContext; -use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; -use rustc_middle::mir::interpret::{ - CheckInAllocMsg, ExpectedKind, InterpError, InvalidMetaKind, InvalidProgramInfo, Misalignment, - PointerKind, ResourceExhaustionInfo, UndefinedBehaviorInfo, UnsupportedOpInfo, - ValidationErrorInfo, -}; -use rustc_middle::ty::{self, Mutability, Ty}; -use rustc_span::Span; -use rustc_target::abi::call::AdjustForForeignAbiError; -use rustc_target::abi::{Size, WrappingRange}; - -use crate::interpret::InternKind; - -#[derive(Diagnostic)] -#[diag(const_eval_dangling_ptr_in_final)] -pub(crate) struct DanglingPtrInFinal { - #[primary_span] - pub span: Span, - pub kind: InternKind, -} - -#[derive(LintDiagnostic)] -#[diag(const_eval_mutable_ptr_in_final)] -pub(crate) struct MutablePtrInFinal { - // rust-lang/rust#122153: This was marked as `#[primary_span]` under - // `derive(Diagnostic)`. Since we expect we may hard-error in future, we are - // keeping the field (and skipping it under `derive(LintDiagnostic)`). - #[skip_arg] - pub span: Span, - pub kind: InternKind, -} - -#[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, - code = "#[rustc_const_unstable(feature = \"...\", issue = \"...\")]\n", - applicability = "has-placeholders" - )] - #[suggestion( - const_eval_bypass_sugg, - code = "#[rustc_allow_const_fn_unstable({gate})]\n", - applicability = "has-placeholders" - )] - pub attr_span: Span, -} - -#[derive(Diagnostic)] -#[diag(const_eval_thread_local_access, code = E0625)] -pub(crate) struct ThreadLocalAccessErr { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(const_eval_raw_ptr_to_int)] -#[note] -#[note(const_eval_note2)] -pub(crate) struct RawPtrToIntErr { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(const_eval_raw_ptr_comparison)] -#[note] -pub(crate) struct RawPtrComparisonErr { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(const_eval_panic_non_str)] -pub(crate) struct PanicNonStrErr { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(const_eval_mut_deref, code = E0658)] -pub(crate) struct MutDerefErr { - #[primary_span] - pub span: Span, - pub kind: ConstContext, -} - -#[derive(Diagnostic)] -#[diag(const_eval_transient_mut_borrow, code = E0658)] -pub(crate) struct TransientMutBorrowErr { - #[primary_span] - pub span: Span, - pub kind: ConstContext, -} - -#[derive(Diagnostic)] -#[diag(const_eval_transient_mut_raw, code = E0658)] -pub(crate) struct TransientMutRawErr { - #[primary_span] - pub span: Span, - pub kind: ConstContext, -} - -#[derive(Diagnostic)] -#[diag(const_eval_max_num_nodes_in_const)] -pub(crate) struct MaxNumNodesInConstErr { - #[primary_span] - pub span: Option, - pub global_const_id: String, -} - -#[derive(Diagnostic)] -#[diag(const_eval_unallowed_fn_pointer_call)] -pub(crate) struct UnallowedFnPointerCall { - #[primary_span] - pub span: Span, - pub kind: ConstContext, -} - -#[derive(Diagnostic)] -#[diag(const_eval_unstable_const_fn)] -pub(crate) struct UnstableConstFn { - #[primary_span] - pub span: Span, - pub def_path: String, -} - -#[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)] - pub teach: Option<()>, -} - -#[derive(Diagnostic)] -#[diag(const_eval_unallowed_mutable_raw, code = E0764)] -pub(crate) struct UnallowedMutableRaw { - #[primary_span] - pub span: Span, - pub kind: ConstContext, - #[note(const_eval_teach_note)] - pub teach: Option<()>, -} -#[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(Diagnostic)] -#[diag(const_eval_non_const_fn_call, code = E0015)] -pub(crate) struct NonConstFnCall { - #[primary_span] - pub span: Span, - pub def_path_str: String, - pub kind: ConstContext, -} - -#[derive(Diagnostic)] -#[diag(const_eval_unallowed_op_in_const_context)] -pub(crate) struct UnallowedOpInConstContext { - #[primary_span] - pub span: Span, - pub msg: String, -} - -#[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)] - pub teach: Option<()>, -} - -#[derive(Diagnostic)] -#[diag(const_eval_unallowed_inline_asm, code = E0015)] -pub(crate) struct UnallowedInlineAsm { - #[primary_span] - pub span: Span, - pub kind: ConstContext, -} - -#[derive(Diagnostic)] -#[diag(const_eval_interior_mutable_data_refer, code = E0492)] -pub(crate) struct InteriorMutableDataRefer { - #[primary_span] - #[label] - pub span: Span, - #[help] - pub opt_help: Option<()>, - pub kind: ConstContext, - #[note(const_eval_teach_note)] - pub teach: Option<()>, -} - -#[derive(Diagnostic)] -#[diag(const_eval_interior_mutability_borrow)] -pub(crate) struct InteriorMutabilityBorrow { - #[primary_span] - pub span: Span, -} - -#[derive(LintDiagnostic)] -#[diag(const_eval_long_running)] -#[note] -pub struct LongRunning { - #[help] - pub item_span: Span, -} - -#[derive(Diagnostic)] -#[diag(const_eval_long_running)] -pub struct LongRunningWarn { - #[primary_span] - #[label] - pub span: Span, - #[help] - pub item_span: Span, -} - -#[derive(Subdiagnostic)] -#[note(const_eval_non_const_impl)] -pub(crate) struct NonConstImplNote { - #[primary_span] - pub span: Span, -} - -#[derive(Subdiagnostic, Clone)] -#[note(const_eval_frame_note)] -pub struct FrameNote { - #[primary_span] - pub span: Span, - pub times: i32, - pub where_: &'static str, - pub instance: String, -} - -#[derive(Subdiagnostic)] -#[note(const_eval_raw_bytes)] -pub struct RawBytesNote { - pub size: u64, - pub align: u64, - pub bytes: String, -} - -// FIXME(fee1-dead) do not use stringly typed `ConstContext` - -#[derive(Diagnostic)] -#[diag(const_eval_match_eq_non_const, code = E0015)] -#[note] -pub struct NonConstMatchEq<'tcx> { - #[primary_span] - pub span: Span, - pub ty: Ty<'tcx>, - pub kind: ConstContext, -} - -#[derive(Diagnostic)] -#[diag(const_eval_for_loop_into_iter_non_const, code = E0015)] -pub struct NonConstForLoopIntoIter<'tcx> { - #[primary_span] - pub span: Span, - pub ty: Ty<'tcx>, - pub kind: ConstContext, -} - -#[derive(Diagnostic)] -#[diag(const_eval_question_branch_non_const, code = E0015)] -pub struct NonConstQuestionBranch<'tcx> { - #[primary_span] - pub span: Span, - pub ty: Ty<'tcx>, - pub kind: ConstContext, -} - -#[derive(Diagnostic)] -#[diag(const_eval_question_from_residual_non_const, code = E0015)] -pub struct NonConstQuestionFromResidual<'tcx> { - #[primary_span] - pub span: Span, - pub ty: Ty<'tcx>, - pub kind: ConstContext, -} - -#[derive(Diagnostic)] -#[diag(const_eval_try_block_from_output_non_const, code = E0015)] -pub struct NonConstTryBlockFromOutput<'tcx> { - #[primary_span] - pub span: Span, - pub ty: Ty<'tcx>, - pub kind: ConstContext, -} - -#[derive(Diagnostic)] -#[diag(const_eval_await_non_const, code = E0015)] -pub struct NonConstAwait<'tcx> { - #[primary_span] - pub span: Span, - pub ty: Ty<'tcx>, - pub kind: ConstContext, -} - -#[derive(Diagnostic)] -#[diag(const_eval_closure_non_const, code = E0015)] -pub struct NonConstClosure { - #[primary_span] - pub span: Span, - pub kind: ConstContext, - #[subdiagnostic] - pub note: Option, -} - -#[derive(Subdiagnostic)] -pub enum NonConstClosureNote { - #[note(const_eval_closure_fndef_not_const)] - FnDef { - #[primary_span] - span: Span, - }, - #[note(const_eval_fn_ptr_call)] - FnPtr, - #[note(const_eval_closure_call)] - Closure, -} - -#[derive(Subdiagnostic)] -#[multipart_suggestion(const_eval_consider_dereferencing, applicability = "machine-applicable")] -pub struct ConsiderDereferencing { - pub deref: String, - #[suggestion_part(code = "{deref}")] - pub span: Span, - #[suggestion_part(code = "{deref}")] - pub rhs_span: Span, -} - -#[derive(Diagnostic)] -#[diag(const_eval_operator_non_const, code = E0015)] -pub struct NonConstOperator { - #[primary_span] - pub span: Span, - pub kind: ConstContext, - #[subdiagnostic] - pub sugg: Option, -} - -#[derive(Diagnostic)] -#[diag(const_eval_deref_coercion_non_const, code = E0015)] -#[note] -pub struct NonConstDerefCoercion<'tcx> { - #[primary_span] - pub span: Span, - pub ty: Ty<'tcx>, - pub kind: ConstContext, - pub target_ty: Ty<'tcx>, - #[note(const_eval_target_note)] - pub deref_target: Option, -} - -#[derive(Diagnostic)] -#[diag(const_eval_live_drop, code = E0493)] -pub struct LiveDrop<'tcx> { - #[primary_span] - #[label] - pub span: Span, - pub kind: ConstContext, - pub dropped_ty: Ty<'tcx>, - #[label(const_eval_dropped_at_label)] - pub dropped_at: Option, -} - -#[derive(Diagnostic)] -#[diag(const_eval_error, code = E0080)] -pub struct ConstEvalError { - #[primary_span] - pub span: Span, - /// One of "const", "const_with_path", and "static" - pub error_kind: &'static str, - pub instance: String, - #[subdiagnostic] - pub frame_notes: Vec, -} - -#[derive(LintDiagnostic)] -#[diag(const_eval_write_through_immutable_pointer)] -pub struct WriteThroughImmutablePointer { - #[subdiagnostic] - pub frames: Vec, -} - -#[derive(Diagnostic)] -#[diag(const_eval_nullary_intrinsic_fail)] -pub struct NullaryIntrinsicError { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(const_eval_validation_failure, code = E0080)] -pub struct ValidationFailure { - #[primary_span] - pub span: Span, - #[note(const_eval_validation_failure_note)] - pub ub_note: Option<()>, - #[subdiagnostic] - pub frames: Vec, - #[subdiagnostic] - pub raw_bytes: RawBytesNote, -} - -pub trait ReportErrorExt { - /// Returns the diagnostic message for this error. - fn diagnostic_message(&self) -> DiagMessage; - fn add_args(self, diag: &mut Diag<'_, G>); - - fn debug(self) -> String - where - Self: Sized, - { - ty::tls::with(move |tcx| { - let dcx = tcx.dcx(); - let mut diag = dcx.struct_allow(DiagMessage::Str(String::new().into())); - let message = self.diagnostic_message(); - self.add_args(&mut diag); - let s = dcx.eagerly_translate_to_string(message, diag.args.iter()); - diag.cancel(); - s - }) - } -} - -fn bad_pointer_message(msg: CheckInAllocMsg, dcx: &DiagCtxt) -> String { - use crate::fluent_generated::*; - - let msg = match msg { - CheckInAllocMsg::MemoryAccessTest => const_eval_memory_access_test, - CheckInAllocMsg::PointerArithmeticTest => const_eval_pointer_arithmetic_test, - CheckInAllocMsg::OffsetFromTest => const_eval_offset_from_test, - CheckInAllocMsg::InboundsTest => const_eval_in_bounds_test, - }; - - dcx.eagerly_translate_to_string(msg, [].into_iter()) -} - -impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { - fn diagnostic_message(&self) -> DiagMessage { - use crate::fluent_generated::*; - use UndefinedBehaviorInfo::*; - match self { - Ub(msg) => msg.clone().into(), - Custom(x) => (x.msg)(), - ValidationError(e) => e.diagnostic_message(), - - Unreachable => const_eval_unreachable, - BoundsCheckFailed { .. } => const_eval_bounds_check_failed, - DivisionByZero => const_eval_division_by_zero, - RemainderByZero => const_eval_remainder_by_zero, - DivisionOverflow => const_eval_division_overflow, - RemainderOverflow => const_eval_remainder_overflow, - PointerArithOverflow => const_eval_pointer_arithmetic_overflow, - InvalidMeta(InvalidMetaKind::SliceTooBig) => const_eval_invalid_meta_slice, - InvalidMeta(InvalidMetaKind::TooBig) => const_eval_invalid_meta, - UnterminatedCString(_) => const_eval_unterminated_c_string, - PointerUseAfterFree(_, _) => const_eval_pointer_use_after_free, - PointerOutOfBounds { ptr_size: Size::ZERO, .. } => const_eval_zst_pointer_out_of_bounds, - PointerOutOfBounds { .. } => const_eval_pointer_out_of_bounds, - DanglingIntPointer(0, _) => const_eval_dangling_null_pointer, - DanglingIntPointer(_, _) => const_eval_dangling_int_pointer, - AlignmentCheckFailed { .. } => const_eval_alignment_check_failed, - WriteToReadOnly(_) => const_eval_write_to_read_only, - DerefFunctionPointer(_) => const_eval_deref_function_pointer, - DerefVTablePointer(_) => const_eval_deref_vtable_pointer, - InvalidBool(_) => const_eval_invalid_bool, - InvalidChar(_) => const_eval_invalid_char, - InvalidTag(_) => const_eval_invalid_tag, - InvalidFunctionPointer(_) => const_eval_invalid_function_pointer, - InvalidVTablePointer(_) => const_eval_invalid_vtable_pointer, - InvalidStr(_) => const_eval_invalid_str, - InvalidUninitBytes(None) => const_eval_invalid_uninit_bytes_unknown, - InvalidUninitBytes(Some(_)) => const_eval_invalid_uninit_bytes, - DeadLocal => const_eval_dead_local, - ScalarSizeMismatch(_) => const_eval_scalar_size_mismatch, - UninhabitedEnumVariantWritten(_) => const_eval_uninhabited_enum_variant_written, - UninhabitedEnumVariantRead(_) => const_eval_uninhabited_enum_variant_read, - InvalidNichedEnumVariantWritten { .. } => { - const_eval_invalid_niched_enum_variant_written - } - AbiMismatchArgument { .. } => const_eval_incompatible_types, - AbiMismatchReturn { .. } => const_eval_incompatible_return_types, - } - } - - fn add_args(self, diag: &mut Diag<'_, G>) { - use UndefinedBehaviorInfo::*; - let dcx = diag.dcx; - match self { - Ub(_) => {} - Custom(custom) => { - (custom.add_args)(&mut |name, value| { - diag.arg(name, value); - }); - } - ValidationError(e) => e.add_args(diag), - - Unreachable - | DivisionByZero - | RemainderByZero - | DivisionOverflow - | RemainderOverflow - | PointerArithOverflow - | InvalidMeta(InvalidMetaKind::SliceTooBig) - | InvalidMeta(InvalidMetaKind::TooBig) - | InvalidUninitBytes(None) - | DeadLocal - | UninhabitedEnumVariantWritten(_) - | UninhabitedEnumVariantRead(_) => {} - BoundsCheckFailed { len, index } => { - diag.arg("len", len); - diag.arg("index", index); - } - UnterminatedCString(ptr) | InvalidFunctionPointer(ptr) | InvalidVTablePointer(ptr) => { - diag.arg("pointer", ptr); - } - PointerUseAfterFree(alloc_id, msg) => { - diag.arg("alloc_id", alloc_id) - .arg("bad_pointer_message", bad_pointer_message(msg, dcx)); - } - PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size, msg } => { - diag.arg("alloc_id", alloc_id) - .arg("alloc_size", alloc_size.bytes()) - .arg("ptr_offset", ptr_offset) - .arg("ptr_size", ptr_size.bytes()) - .arg("bad_pointer_message", bad_pointer_message(msg, dcx)); - } - DanglingIntPointer(ptr, msg) => { - if ptr != 0 { - diag.arg("pointer", format!("{ptr:#x}[noalloc]")); - } - - diag.arg("bad_pointer_message", bad_pointer_message(msg, dcx)); - } - AlignmentCheckFailed(Misalignment { required, has }, msg) => { - diag.arg("required", required.bytes()); - diag.arg("has", has.bytes()); - diag.arg("msg", format!("{msg:?}")); - } - WriteToReadOnly(alloc) | DerefFunctionPointer(alloc) | DerefVTablePointer(alloc) => { - diag.arg("allocation", alloc); - } - InvalidBool(b) => { - diag.arg("value", format!("{b:02x}")); - } - InvalidChar(c) => { - diag.arg("value", format!("{c:08x}")); - } - InvalidTag(tag) => { - diag.arg("tag", format!("{tag:x}")); - } - InvalidStr(err) => { - diag.arg("err", format!("{err}")); - } - InvalidUninitBytes(Some((alloc, info))) => { - diag.arg("alloc", alloc); - diag.arg("access", info.access); - diag.arg("uninit", info.bad); - } - ScalarSizeMismatch(info) => { - diag.arg("target_size", info.target_size); - diag.arg("data_size", info.data_size); - } - InvalidNichedEnumVariantWritten { enum_ty } => { - diag.arg("ty", enum_ty.to_string()); - } - AbiMismatchArgument { caller_ty, callee_ty } - | AbiMismatchReturn { caller_ty, callee_ty } => { - diag.arg("caller_ty", caller_ty.to_string()); - diag.arg("callee_ty", callee_ty.to_string()); - } - } - } -} - -impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { - fn diagnostic_message(&self) -> DiagMessage { - use crate::fluent_generated::*; - use rustc_middle::mir::interpret::ValidationErrorKind::*; - match self.kind { - PtrToUninhabited { ptr_kind: PointerKind::Box, .. } => { - const_eval_validation_box_to_uninhabited - } - PtrToUninhabited { ptr_kind: PointerKind::Ref(_), .. } => { - const_eval_validation_ref_to_uninhabited - } - - PtrToStatic { ptr_kind: PointerKind::Box } => const_eval_validation_box_to_static, - PtrToStatic { ptr_kind: PointerKind::Ref(_) } => const_eval_validation_ref_to_static, - - PointerAsInt { .. } => const_eval_validation_pointer_as_int, - PartialPointer => const_eval_validation_partial_pointer, - ConstRefToMutable => const_eval_validation_const_ref_to_mutable, - ConstRefToExtern => const_eval_validation_const_ref_to_extern, - MutableRefToImmutable => const_eval_validation_mutable_ref_to_immutable, - NullFnPtr => const_eval_validation_null_fn_ptr, - NeverVal => const_eval_validation_never_val, - NullablePtrOutOfRange { .. } => const_eval_validation_nullable_ptr_out_of_range, - PtrOutOfRange { .. } => const_eval_validation_ptr_out_of_range, - OutOfRange { .. } => const_eval_validation_out_of_range, - UnsafeCellInImmutable => const_eval_validation_unsafe_cell, - UninhabitedVal { .. } => const_eval_validation_uninhabited_val, - InvalidEnumTag { .. } => const_eval_validation_invalid_enum_tag, - UninhabitedEnumVariant => const_eval_validation_uninhabited_enum_variant, - Uninit { .. } => const_eval_validation_uninit, - InvalidVTablePtr { .. } => const_eval_validation_invalid_vtable_ptr, - InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Box } => { - const_eval_validation_invalid_box_slice_meta - } - InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Ref(_) } => { - const_eval_validation_invalid_ref_slice_meta - } - - InvalidMetaTooLarge { ptr_kind: PointerKind::Box } => { - const_eval_validation_invalid_box_meta - } - InvalidMetaTooLarge { ptr_kind: PointerKind::Ref(_) } => { - const_eval_validation_invalid_ref_meta - } - UnalignedPtr { ptr_kind: PointerKind::Ref(_), .. } => { - const_eval_validation_unaligned_ref - } - UnalignedPtr { ptr_kind: PointerKind::Box, .. } => const_eval_validation_unaligned_box, - - NullPtr { ptr_kind: PointerKind::Box } => const_eval_validation_null_box, - NullPtr { ptr_kind: PointerKind::Ref(_) } => const_eval_validation_null_ref, - DanglingPtrNoProvenance { ptr_kind: PointerKind::Box, .. } => { - const_eval_validation_dangling_box_no_provenance - } - DanglingPtrNoProvenance { ptr_kind: PointerKind::Ref(_), .. } => { - const_eval_validation_dangling_ref_no_provenance - } - DanglingPtrOutOfBounds { ptr_kind: PointerKind::Box } => { - const_eval_validation_dangling_box_out_of_bounds - } - DanglingPtrOutOfBounds { ptr_kind: PointerKind::Ref(_) } => { - const_eval_validation_dangling_ref_out_of_bounds - } - DanglingPtrUseAfterFree { ptr_kind: PointerKind::Box } => { - const_eval_validation_dangling_box_use_after_free - } - DanglingPtrUseAfterFree { ptr_kind: PointerKind::Ref(_) } => { - const_eval_validation_dangling_ref_use_after_free - } - InvalidBool { .. } => const_eval_validation_invalid_bool, - InvalidChar { .. } => const_eval_validation_invalid_char, - InvalidFnPtr { .. } => const_eval_validation_invalid_fn_ptr, - } - } - - fn add_args(self, err: &mut Diag<'_, G>) { - use crate::fluent_generated as fluent; - use rustc_middle::mir::interpret::ValidationErrorKind::*; - - if let PointerAsInt { .. } | PartialPointer = self.kind { - err.help(fluent::const_eval_ptr_as_bytes_1); - err.help(fluent::const_eval_ptr_as_bytes_2); - } - - let message = if let Some(path) = self.path { - err.dcx.eagerly_translate_to_string( - fluent::const_eval_validation_front_matter_invalid_value_with_path, - [("path".into(), DiagArgValue::Str(path.into()))].iter().map(|(a, b)| (a, b)), - ) - } else { - err.dcx.eagerly_translate_to_string( - fluent::const_eval_validation_front_matter_invalid_value, - [].into_iter(), - ) - }; - - err.arg("front_matter", message); - - fn add_range_arg( - r: WrappingRange, - max_hi: u128, - err: &mut Diag<'_, G>, - ) { - let WrappingRange { start: lo, end: hi } = r; - assert!(hi <= max_hi); - let msg = if lo > hi { - fluent::const_eval_range_wrapping - } else if lo == hi { - fluent::const_eval_range_singular - } else if lo == 0 { - assert!(hi < max_hi, "should not be printing if the range covers everything"); - fluent::const_eval_range_upper - } else if hi == max_hi { - assert!(lo > 0, "should not be printing if the range covers everything"); - fluent::const_eval_range_lower - } else { - fluent::const_eval_range - }; - - let args = [ - ("lo".into(), DiagArgValue::Str(lo.to_string().into())), - ("hi".into(), DiagArgValue::Str(hi.to_string().into())), - ]; - let args = args.iter().map(|(a, b)| (a, b)); - let message = err.dcx.eagerly_translate_to_string(msg, args); - err.arg("in_range", message); - } - - match self.kind { - PtrToUninhabited { ty, .. } | UninhabitedVal { ty } => { - err.arg("ty", ty); - } - PointerAsInt { expected } | Uninit { expected } => { - let msg = match expected { - ExpectedKind::Reference => fluent::const_eval_validation_expected_ref, - ExpectedKind::Box => fluent::const_eval_validation_expected_box, - ExpectedKind::RawPtr => fluent::const_eval_validation_expected_raw_ptr, - ExpectedKind::InitScalar => fluent::const_eval_validation_expected_init_scalar, - ExpectedKind::Bool => fluent::const_eval_validation_expected_bool, - ExpectedKind::Char => fluent::const_eval_validation_expected_char, - ExpectedKind::Float => fluent::const_eval_validation_expected_float, - ExpectedKind::Int => fluent::const_eval_validation_expected_int, - ExpectedKind::FnPtr => fluent::const_eval_validation_expected_fn_ptr, - ExpectedKind::EnumTag => fluent::const_eval_validation_expected_enum_tag, - ExpectedKind::Str => fluent::const_eval_validation_expected_str, - }; - let msg = err.dcx.eagerly_translate_to_string(msg, [].into_iter()); - err.arg("expected", msg); - } - InvalidEnumTag { value } - | InvalidVTablePtr { value } - | InvalidBool { value } - | InvalidChar { value } - | InvalidFnPtr { value } => { - err.arg("value", value); - } - NullablePtrOutOfRange { range, max_value } | PtrOutOfRange { range, max_value } => { - add_range_arg(range, max_value, err) - } - OutOfRange { range, max_value, value } => { - err.arg("value", value); - add_range_arg(range, max_value, err); - } - UnalignedPtr { required_bytes, found_bytes, .. } => { - err.arg("required_bytes", required_bytes); - err.arg("found_bytes", found_bytes); - } - DanglingPtrNoProvenance { pointer, .. } => { - err.arg("pointer", pointer); - } - NullPtr { .. } - | PtrToStatic { .. } - | ConstRefToMutable - | ConstRefToExtern - | MutableRefToImmutable - | NullFnPtr - | NeverVal - | UnsafeCellInImmutable - | InvalidMetaSliceTooLarge { .. } - | InvalidMetaTooLarge { .. } - | DanglingPtrUseAfterFree { .. } - | DanglingPtrOutOfBounds { .. } - | UninhabitedEnumVariant - | PartialPointer => {} - } - } -} - -impl ReportErrorExt for UnsupportedOpInfo { - fn diagnostic_message(&self) -> DiagMessage { - use crate::fluent_generated::*; - match self { - UnsupportedOpInfo::Unsupported(s) => s.clone().into(), - UnsupportedOpInfo::UnsizedLocal => const_eval_unsized_local, - UnsupportedOpInfo::OverwritePartialPointer(_) => const_eval_partial_pointer_overwrite, - UnsupportedOpInfo::ReadPartialPointer(_) => const_eval_partial_pointer_copy, - UnsupportedOpInfo::ReadPointerAsInt(_) => const_eval_read_pointer_as_int, - UnsupportedOpInfo::ThreadLocalStatic(_) => const_eval_thread_local_static, - UnsupportedOpInfo::ExternStatic(_) => const_eval_extern_static, - } - } - fn add_args(self, diag: &mut Diag<'_, G>) { - use crate::fluent_generated::*; - - use UnsupportedOpInfo::*; - if let ReadPointerAsInt(_) | OverwritePartialPointer(_) | ReadPartialPointer(_) = self { - diag.help(const_eval_ptr_as_bytes_1); - diag.help(const_eval_ptr_as_bytes_2); - } - match self { - // `ReadPointerAsInt(Some(info))` is never printed anyway, it only serves as an error to - // be further processed by validity checking which then turns it into something nice to - // print. So it's not worth the effort of having diagnostics that can print the `info`. - UnsizedLocal | Unsupported(_) | ReadPointerAsInt(_) => {} - OverwritePartialPointer(ptr) | ReadPartialPointer(ptr) => { - diag.arg("ptr", ptr); - } - ThreadLocalStatic(did) | ExternStatic(did) => { - diag.arg("did", format!("{did:?}")); - } - } - } -} - -impl<'tcx> ReportErrorExt for InterpError<'tcx> { - fn diagnostic_message(&self) -> DiagMessage { - match self { - InterpError::UndefinedBehavior(ub) => ub.diagnostic_message(), - InterpError::Unsupported(e) => e.diagnostic_message(), - InterpError::InvalidProgram(e) => e.diagnostic_message(), - InterpError::ResourceExhaustion(e) => e.diagnostic_message(), - InterpError::MachineStop(e) => e.diagnostic_message(), - } - } - fn add_args(self, diag: &mut Diag<'_, G>) { - match self { - InterpError::UndefinedBehavior(ub) => ub.add_args(diag), - InterpError::Unsupported(e) => e.add_args(diag), - InterpError::InvalidProgram(e) => e.add_args(diag), - InterpError::ResourceExhaustion(e) => e.add_args(diag), - InterpError::MachineStop(e) => e.add_args(&mut |name, value| { - diag.arg(name, value); - }), - } - } -} - -impl<'tcx> ReportErrorExt for InvalidProgramInfo<'tcx> { - fn diagnostic_message(&self) -> DiagMessage { - use crate::fluent_generated::*; - match self { - InvalidProgramInfo::TooGeneric => const_eval_too_generic, - InvalidProgramInfo::AlreadyReported(_) => const_eval_already_reported, - InvalidProgramInfo::Layout(e) => e.diagnostic_message(), - InvalidProgramInfo::FnAbiAdjustForForeignAbi(_) => { - rustc_middle::error::middle_adjust_for_foreign_abi_error - } - } - } - fn add_args(self, diag: &mut Diag<'_, G>) { - match self { - InvalidProgramInfo::TooGeneric | InvalidProgramInfo::AlreadyReported(_) => {} - InvalidProgramInfo::Layout(e) => { - // The level doesn't matter, `dummy_diag` is consumed without it being used. - let dummy_level = Level::Bug; - let dummy_diag: Diag<'_, ()> = e.into_diagnostic().into_diag(diag.dcx, dummy_level); - for (name, val) in dummy_diag.args.iter() { - diag.arg(name.clone(), val.clone()); - } - dummy_diag.cancel(); - } - InvalidProgramInfo::FnAbiAdjustForForeignAbi( - AdjustForForeignAbiError::Unsupported { arch, abi }, - ) => { - diag.arg("arch", arch); - diag.arg("abi", abi.name()); - } - } - } -} - -impl ReportErrorExt for ResourceExhaustionInfo { - fn diagnostic_message(&self) -> DiagMessage { - use crate::fluent_generated::*; - match self { - ResourceExhaustionInfo::StackFrameLimitReached => const_eval_stack_frame_limit_reached, - ResourceExhaustionInfo::MemoryExhausted => const_eval_memory_exhausted, - ResourceExhaustionInfo::AddressSpaceFull => const_eval_address_space_full, - ResourceExhaustionInfo::Interrupted => const_eval_interrupted, - } - } - fn add_args(self, _: &mut Diag<'_, G>) {} -} - -impl rustc_errors::IntoDiagArg for InternKind { - fn into_diag_arg(self) -> DiagArgValue { - DiagArgValue::Str(Cow::Borrowed(match self { - InternKind::Static(Mutability::Not) => "static", - InternKind::Static(Mutability::Mut) => "static_mut", - InternKind::Constant => "const", - InternKind::Promoted => "promoted", - })) - } -} +use std::borrow::Cow;use rustc_errors::{codes::*,Diag,DiagArgValue,DiagCtxt,//3; +DiagMessage,Diagnostic,EmissionGuarantee,Level,};use rustc_hir::ConstContext;//; +use rustc_macros::{Diagnostic,LintDiagnostic,Subdiagnostic};use rustc_middle::// +mir::interpret::{CheckInAllocMsg,ExpectedKind,InterpError,InvalidMetaKind,//{;}; +InvalidProgramInfo,Misalignment,PointerKind,ResourceExhaustionInfo,//let _=||(); +UndefinedBehaviorInfo,UnsupportedOpInfo,ValidationErrorInfo,};use rustc_middle// +::ty::{self,Mutability,Ty};use rustc_span::Span;use rustc_target::abi::call:://; +AdjustForForeignAbiError;use rustc_target::abi::{Size,WrappingRange};use crate// +::interpret::InternKind;#[derive(Diagnostic)]#[diag(//loop{break;};loop{break;}; +const_eval_dangling_ptr_in_final)]pub(crate)struct DanglingPtrInFinal{#[//{();}; +primary_span]pub span:Span,pub kind: InternKind,}#[derive(LintDiagnostic)]#[diag +(const_eval_mutable_ptr_in_final)]pub(crate )struct MutablePtrInFinal{#[skip_arg +]pub span:Span,pub kind:InternKind,}#[derive(Diagnostic)]#[diag(//if let _=(){}; +const_eval_unstable_in_stable)]pub(crate)struct UnstableInStable{pub gate://{;}; +String,#[primary_span]pub span: Span,#[suggestion(const_eval_unstable_sugg,code= +"#[rustc_const_unstable(feature = \"...\", issue = \"...\")]\n",applicability=// +"has-placeholders")]#[suggestion(const_eval_bypass_sugg,code=//((),());let _=(); +"#[rustc_allow_const_fn_unstable({gate})]\n",applicability ="has-placeholders")] +pub attr_span:Span,}#[derive (Diagnostic)]#[diag(const_eval_thread_local_access, +code=E0625)]pub(crate)struct ThreadLocalAccessErr{#[primary_span]pub span:Span, +}#[derive(Diagnostic)]#[diag(const_eval_raw_ptr_to_int)]#[note]#[note(//((),()); +const_eval_note2)]pub(crate)struct RawPtrToIntErr {#[primary_span]pub span:Span, +}#[derive(Diagnostic)]#[diag(const_eval_raw_ptr_comparison)]#[note]pub(crate)//; +struct RawPtrComparisonErr{#[primary_span]pub span :Span,}#[derive(Diagnostic)]# +[diag(const_eval_panic_non_str)]pub(crate )struct PanicNonStrErr{#[primary_span] +pub span:Span,}#[derive(Diagnostic) ]#[diag(const_eval_mut_deref,code=E0658)]pub +(crate)struct MutDerefErr{#[primary_span]pub span:Span,pub kind:ConstContext,}# +[derive(Diagnostic)]#[diag(const_eval_transient_mut_borrow,code=E0658)]pub(//(); +crate)struct TransientMutBorrowErr{#[primary_span]pub span:Span,pub kind://({}); +ConstContext,}#[derive(Diagnostic)]#[diag(const_eval_transient_mut_raw,code=//3; +E0658)]pub(crate)struct TransientMutRawErr{#[primary_span]pub span:Span,pub//(); +kind:ConstContext,}#[derive(Diagnostic)]#[diag(//*&*&();((),());((),());((),()); +const_eval_max_num_nodes_in_const)]pub(crate)struct MaxNumNodesInConstErr{#[//3; +primary_span]pub span:Option,pub global_const_id:String,}#[derive(//{();}; +Diagnostic)]#[diag(const_eval_unallowed_fn_pointer_call)]pub(crate)struct//({}); +UnallowedFnPointerCall{#[primary_span]pub span:Span,pub kind:ConstContext,}#[//; +derive(Diagnostic)]#[diag(const_eval_unstable_const_fn)]pub(crate)struct//{();}; +UnstableConstFn{#[primary_span]pub span:Span,pub def_path:String,}#[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)]pub teach:Option<( )>,}#[derive(Diagnostic)]#[diag +(const_eval_unallowed_mutable_raw,code=E0764)]pub(crate)struct//((),());((),()); +UnallowedMutableRaw{#[primary_span]pub span:Span,pub kind:ConstContext,#[note(// +const_eval_teach_note)]pub teach:Option<()>,}#[derive(Diagnostic)]#[diag(//({}); +const_eval_non_const_fmt_macro_call,code=E0015)]pub(crate)struct//if let _=(){}; +NonConstFmtMacroCall{#[primary_span]pub span:Span,pub kind:ConstContext,}#[//(); +derive(Diagnostic)]#[diag(const_eval_non_const_fn_call,code=E0015)]pub(crate)//; +struct NonConstFnCall{#[primary_span]pub span:Span,pub def_path_str:String,pub// +kind:ConstContext,}#[derive(Diagnostic)]#[diag(//*&*&();((),());((),());((),()); +const_eval_unallowed_op_in_const_context)]pub(crate)struct//if true{};if true{}; +UnallowedOpInConstContext{#[primary_span]pub span:Span ,pub msg:String,}#[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)]pub teach:Option<()>,}#[derive(//{;}; +Diagnostic)]#[diag(const_eval_unallowed_inline_asm, code=E0015)]pub(crate)struct +UnallowedInlineAsm{#[primary_span]pub span:Span,pub kind:ConstContext,}#[//({}); +derive(Diagnostic)]#[diag(const_eval_interior_mutable_data_refer,code=E0492)]//; +pub(crate)struct InteriorMutableDataRefer{#[primary_span ]#[label]pub span:Span, +#[help]pub opt_help:Option<()>,pub kind:ConstContext,#[note(//let _=();let _=(); +const_eval_teach_note)]pub teach:Option<()>,}#[derive(Diagnostic)]#[diag(//({}); +const_eval_interior_mutability_borrow)]pub(crate)struct//let _=||();loop{break}; +InteriorMutabilityBorrow{#[primary_span]pub span :Span,}#[derive(LintDiagnostic) +]#[diag(const_eval_long_running)]#[note]pub struct LongRunning{#[help]pub//({}); +item_span:Span,}#[derive(Diagnostic) ]#[diag(const_eval_long_running)]pub struct +LongRunningWarn{#[primary_span]#[label]pub span:Span,#[help]pub item_span:Span// +,}#[derive(Subdiagnostic)]#[note(const_eval_non_const_impl)]pub(crate)struct//3; +NonConstImplNote{#[primary_span]pub span:Span, }#[derive(Subdiagnostic,Clone)]#[ +note(const_eval_frame_note)]pub struct FrameNote{#[primary_span]pub span:Span,// +pub times:i32,pub where_:&'static str,pub instance:String,}#[derive(//if true{}; +Subdiagnostic)]#[note(const_eval_raw_bytes)]pub struct RawBytesNote{pub size://; +u64,pub align:u64,pub bytes:String,}#[derive(Diagnostic)]#[diag(//if let _=(){}; +const_eval_match_eq_non_const,code=E0015)]#[note]pub struct NonConstMatchEq{#[primary_span]pub span:Span,pub ty:Ty<'tcx>,pub kind:ConstContext,}#[//3; +derive(Diagnostic)]#[diag(const_eval_for_loop_into_iter_non_const,code=E0015)]// +pub struct NonConstForLoopIntoIter<'tcx>{#[primary_span ]pub span:Span,pub ty:Ty +<'tcx>,pub kind:ConstContext,}#[derive(Diagnostic)]#[diag(//if true{};if true{}; +const_eval_question_branch_non_const,code=E0015)]pub struct//let _=();if true{}; +NonConstQuestionBranch<'tcx>{#[primary_span]pub span:Span,pub ty:Ty<'tcx>,pub//; +kind:ConstContext,}#[derive(Diagnostic)]#[diag(//*&*&();((),());((),());((),()); +const_eval_question_from_residual_non_const,code=E0015)]pub struct//loop{break}; +NonConstQuestionFromResidual<'tcx>{#[primary_span]pub span:Span,pub ty:Ty<'tcx> +,pub kind:ConstContext,}#[derive(Diagnostic)]#[diag(//loop{break;};loop{break;}; +const_eval_try_block_from_output_non_const,code=E0015)]pub struct//loop{break;}; +NonConstTryBlockFromOutput<'tcx>{#[primary_span]pub span:Span,pub ty:Ty<'tcx>,// +pub kind:ConstContext,}#[derive(Diagnostic)]#[diag(const_eval_await_non_const,// +code=E0015)]pub struct NonConstAwait<'tcx>{ #[primary_span]pub span:Span,pub ty: +Ty<'tcx>,pub kind:ConstContext,}#[derive(Diagnostic)]#[diag(//let _=();let _=(); +const_eval_closure_non_const,code=E0015)]pub struct NonConstClosure{#[//((),()); +primary_span]pub span:Span,pub kind:ConstContext,#[subdiagnostic]pub note://{;}; +Option,}#[derive(Subdiagnostic)]pub enum//((),());let _=(); +NonConstClosureNote{#[note(const_eval_closure_fndef_not_const)]FnDef{#[//*&*&(); +primary_span]span:Span,},#[note(const_eval_fn_ptr_call)]FnPtr,#[note(//let _=(); +const_eval_closure_call)]Closure,}#[derive(Subdiagnostic)]#[//let _=();let _=(); +multipart_suggestion(const_eval_consider_dereferencing,applicability=//let _=(); +"machine-applicable")]pub struct ConsiderDereferencing{pub deref:String,#[//{;}; +suggestion_part(code="{deref}")]pub span :Span,#[suggestion_part(code="{deref}") +]pub rhs_span:Span,}#[derive(Diagnostic)]#[diag(const_eval_operator_non_const,// +code=E0015)]pub struct NonConstOperator{#[primary_span]pub span:Span,pub kind:// +ConstContext,#[subdiagnostic]pub sugg:Option,}#[derive(// +Diagnostic)]#[diag(const_eval_deref_coercion_non_const,code=E0015)]#[note]pub//; +struct NonConstDerefCoercion<'tcx>{#[primary_span]pub span:Span,pub ty:Ty<'tcx> +,pub kind:ConstContext,pub target_ty:Ty<'tcx>,#[note(const_eval_target_note)]//; +pub deref_target:Option,}# [derive(Diagnostic)]#[diag(const_eval_live_drop +,code=E0493)]pub struct LiveDrop<'tcx>{ #[primary_span]#[label]pub span:Span,pub +kind:ConstContext,pub dropped_ty:Ty<'tcx>,#[label(const_eval_dropped_at_label)// +]pub dropped_at:Option,}# [derive(Diagnostic)]#[diag(const_eval_error,code +=E0080)]pub struct ConstEvalError{#[ primary_span]pub span:Span,pub error_kind:& +'static str,pub instance:String,# [subdiagnostic]pub frame_notes:Vec, +}#[derive(LintDiagnostic)]#[diag(const_eval_write_through_immutable_pointer)]//; +pub struct WriteThroughImmutablePointer{#[subdiagnostic]pub frames:Vec,}#[derive(Diagnostic)]#[diag(const_eval_nullary_intrinsic_fail)]pub// +struct NullaryIntrinsicError{#[primary_span]pub span:Span,}#[derive(Diagnostic) +]#[diag(const_eval_validation_failure,code= E0080)]pub struct ValidationFailure{ +#[primary_span]pub span:Span,#[note(const_eval_validation_failure_note)]pub//(); +ub_note:Option<()>,#[subdiagnostic]pub frames:Vec,#[subdiagnostic]//; +pub raw_bytes:RawBytesNote,}pub trait ReportErrorExt{fn diagnostic_message(&//3; +self)->DiagMessage;fn add_args( self,diag:&mut Diag<'_,G>); +fn debug(self)->String where Self:Sized,{ty::tls::with(move|tcx|{();let dcx=tcx. +dcx();;let mut diag=dcx.struct_allow(DiagMessage::Str(String::new().into()));let +message=self.diagnostic_message();();();self.add_args(&mut diag);();3;let s=dcx. +eagerly_translate_to_string(message,diag.args.iter());3;3;diag.cancel();;s})}}fn +bad_pointer_message(msg:CheckInAllocMsg,dcx:&DiagCtxt)->String{{();};use crate:: +fluent_generated::*;{;};();let msg=match msg{CheckInAllocMsg::MemoryAccessTest=> +const_eval_memory_access_test,CheckInAllocMsg::PointerArithmeticTest=>//((),()); +const_eval_pointer_arithmetic_test,CheckInAllocMsg::OffsetFromTest=>//if true{}; +const_eval_offset_from_test,CheckInAllocMsg::InboundsTest=>//let _=();if true{}; +const_eval_in_bounds_test,};;dcx.eagerly_translate_to_string(msg,[].into_iter()) +}impl<'a>ReportErrorExt for UndefinedBehaviorInfo<'a>{fn diagnostic_message(&//; +self)->DiagMessage{;use crate::fluent_generated::*;use UndefinedBehaviorInfo::*; +match self{Ub(msg)=>(msg.clone().into()),Custom(x)=>(x.msg)(),ValidationError(e) +=>e.diagnostic_message() ,Unreachable=>const_eval_unreachable,BoundsCheckFailed{ +..}=>const_eval_bounds_check_failed ,DivisionByZero=>const_eval_division_by_zero +,RemainderByZero=>const_eval_remainder_by_zero,DivisionOverflow=>//loop{break;}; +const_eval_division_overflow,RemainderOverflow=>const_eval_remainder_overflow,// +PointerArithOverflow=>const_eval_pointer_arithmetic_overflow,InvalidMeta(//({}); +InvalidMetaKind::SliceTooBig)=>const_eval_invalid_meta_slice,InvalidMeta(//({}); +InvalidMetaKind::TooBig)=>const_eval_invalid_meta,UnterminatedCString(_)=>//{;}; +const_eval_unterminated_c_string,PointerUseAfterFree(_,_)=>//let _=();if true{}; +const_eval_pointer_use_after_free,PointerOutOfBounds{ptr_size:Size::ZERO,..}=>// +const_eval_zst_pointer_out_of_bounds,PointerOutOfBounds{..}=>//((),());let _=(); +const_eval_pointer_out_of_bounds,DanglingIntPointer(0,_)=>//if true{};if true{}; +const_eval_dangling_null_pointer,DanglingIntPointer(_,_)=>//if true{};if true{}; +const_eval_dangling_int_pointer,AlignmentCheckFailed{..}=>//if true{};if true{}; +const_eval_alignment_check_failed,WriteToReadOnly(_)=>//loop{break};loop{break}; +const_eval_write_to_read_only,DerefFunctionPointer(_)=>//let _=||();loop{break}; +const_eval_deref_function_pointer,DerefVTablePointer(_)=>//if true{};let _=||(); +const_eval_deref_vtable_pointer,InvalidBool(_)=>const_eval_invalid_bool,//{();}; +InvalidChar(_)=>const_eval_invalid_char,InvalidTag(_)=>const_eval_invalid_tag,// +InvalidFunctionPointer(_)=>const_eval_invalid_function_pointer,//*&*&();((),()); +InvalidVTablePointer(_)=>const_eval_invalid_vtable_pointer,InvalidStr(_)=>//{;}; +const_eval_invalid_str,InvalidUninitBytes(None)=>//if let _=(){};*&*&();((),()); +const_eval_invalid_uninit_bytes_unknown,InvalidUninitBytes(Some(_))=>//let _=(); +const_eval_invalid_uninit_bytes,DeadLocal=>const_eval_dead_local,//loop{break;}; +ScalarSizeMismatch(_)=>const_eval_scalar_size_mismatch,//let _=||();loop{break}; +UninhabitedEnumVariantWritten(_)=>const_eval_uninhabited_enum_variant_written,// +UninhabitedEnumVariantRead(_)=>const_eval_uninhabited_enum_variant_read,//{();}; +InvalidNichedEnumVariantWritten{..}=>{//if true{};if true{};if true{};if true{}; +const_eval_invalid_niched_enum_variant_written}AbiMismatchArgument{..}=>//{();}; +const_eval_incompatible_types,AbiMismatchReturn{..}=>//loop{break};loop{break;}; +const_eval_incompatible_return_types,}}fn add_args(self,//; +diag:&mut Diag<'_,G>){;use UndefinedBehaviorInfo::*;let dcx=diag.dcx;match self{ +Ub(_)=>{}Custom(custom)=>{();(custom.add_args)(&mut|name,value|{3;diag.arg(name, +value);();});3;}ValidationError(e)=>e.add_args(diag),Unreachable|DivisionByZero| +RemainderByZero|DivisionOverflow|RemainderOverflow|PointerArithOverflow|//{();}; +InvalidMeta(InvalidMetaKind::SliceTooBig)| InvalidMeta(InvalidMetaKind::TooBig)| +InvalidUninitBytes(None)|DeadLocal|UninhabitedEnumVariantWritten(_)|//if true{}; +UninhabitedEnumVariantRead(_)=>{}BoundsCheckFailed{len,index}=>{;diag.arg("len", +len);;;diag.arg("index",index);}UnterminatedCString(ptr)|InvalidFunctionPointer( +ptr)|InvalidVTablePointer(ptr)=>{;diag.arg("pointer",ptr);;}PointerUseAfterFree( +alloc_id,msg)=>{((),());diag.arg("alloc_id",alloc_id).arg("bad_pointer_message", +bad_pointer_message(msg,dcx));if true{};}PointerOutOfBounds{alloc_id,alloc_size, +ptr_offset,ptr_size,msg}=>{{();};diag.arg("alloc_id",alloc_id).arg("alloc_size", +alloc_size.bytes()).arg("ptr_offset", ptr_offset).arg("ptr_size",ptr_size.bytes( +)).arg("bad_pointer_message",bad_pointer_message(msg,dcx));;}DanglingIntPointer( +ptr,msg)=>{if ptr!=0{;diag.arg("pointer",format!("{ptr:#x}[noalloc]"));}diag.arg +("bad_pointer_message",bad_pointer_message(msg,dcx));({});}AlignmentCheckFailed( +Misalignment{required,has},msg)=>{;diag.arg("required",required.bytes());;;diag. +arg("has",has.bytes());3;3;diag.arg("msg",format!("{msg:?}"));;}WriteToReadOnly( +alloc)|DerefFunctionPointer(alloc)|DerefVTablePointer(alloc)=>{((),());diag.arg( +"allocation",alloc);3;}InvalidBool(b)=>{;diag.arg("value",format!("{b:02x}"));;} +InvalidChar(c)=>{;diag.arg("value",format!("{c:08x}"));;}InvalidTag(tag)=>{diag. +arg("tag",format!("{tag:x}"));;}InvalidStr(err)=>{diag.arg("err",format!("{err}" +));;}InvalidUninitBytes(Some((alloc,info)))=>{;diag.arg("alloc",alloc);diag.arg( +"access",info.access);;;diag.arg("uninit",info.bad);}ScalarSizeMismatch(info)=>{ +diag.arg("target_size",info.target_size);;diag.arg("data_size",info.data_size);} +InvalidNichedEnumVariantWritten{enum_ty}=>{;diag.arg("ty",enum_ty.to_string());} +AbiMismatchArgument{caller_ty,callee_ty} |AbiMismatchReturn{caller_ty,callee_ty} +=>{;diag.arg("caller_ty",caller_ty.to_string());;diag.arg("callee_ty",callee_ty. +to_string());{();};}}}}impl<'tcx>ReportErrorExt for ValidationErrorInfo<'tcx>{fn +diagnostic_message(&self)->DiagMessage{();use crate::fluent_generated::*;3;3;use +rustc_middle::mir::interpret::ValidationErrorKind::*;let _=||();match self.kind{ +PtrToUninhabited{ptr_kind:PointerKind::Box,..}=>{//if let _=(){};*&*&();((),()); +const_eval_validation_box_to_uninhabited}PtrToUninhabited{ptr_kind:PointerKind// +::Ref(_),..}=>{const_eval_validation_ref_to_uninhabited}PtrToStatic{ptr_kind://; +PointerKind::Box}=>const_eval_validation_box_to_static,PtrToStatic{ptr_kind://3; +PointerKind::Ref(_)}=>const_eval_validation_ref_to_static,PointerAsInt{..}=>//3; +const_eval_validation_pointer_as_int,PartialPointer=>//loop{break};loop{break;}; +const_eval_validation_partial_pointer,ConstRefToMutable=>//if true{};let _=||(); +const_eval_validation_const_ref_to_mutable,ConstRefToExtern=>//((),());let _=(); +const_eval_validation_const_ref_to_extern,MutableRefToImmutable=>//loop{break;}; +const_eval_validation_mutable_ref_to_immutable,NullFnPtr=>//if true{};if true{}; +const_eval_validation_null_fn_ptr,NeverVal=>const_eval_validation_never_val,//3; +NullablePtrOutOfRange{..}=>const_eval_validation_nullable_ptr_out_of_range,//(); +PtrOutOfRange{..}=>const_eval_validation_ptr_out_of_range,OutOfRange{..}=>//{;}; +const_eval_validation_out_of_range,UnsafeCellInImmutable=>//if true{};if true{}; +const_eval_validation_unsafe_cell,UninhabitedVal{..}=>//loop{break};loop{break}; +const_eval_validation_uninhabited_val,InvalidEnumTag{..}=>//if true{};if true{}; +const_eval_validation_invalid_enum_tag,UninhabitedEnumVariant=>//*&*&();((),()); +const_eval_validation_uninhabited_enum_variant,Uninit{..}=>//let _=();if true{}; +const_eval_validation_uninit,InvalidVTablePtr{..}=>//loop{break;};if let _=(){}; +const_eval_validation_invalid_vtable_ptr,InvalidMetaSliceTooLarge{ptr_kind://(); +PointerKind::Box}=>{const_eval_validation_invalid_box_slice_meta}//loop{break;}; +InvalidMetaSliceTooLarge{ptr_kind:PointerKind::Ref(_)}=>{//if true{};let _=||(); +const_eval_validation_invalid_ref_slice_meta}InvalidMetaTooLarge{ptr_kind://{;}; +PointerKind::Box}=> {const_eval_validation_invalid_box_meta}InvalidMetaTooLarge{ +ptr_kind:PointerKind::Ref(_)}=>{const_eval_validation_invalid_ref_meta}//*&*&(); +UnalignedPtr{ptr_kind:PointerKind::Ref(_),..}=>{//*&*&();((),());*&*&();((),()); +const_eval_validation_unaligned_ref}UnalignedPtr{ptr_kind:PointerKind::Box,..}// +=>const_eval_validation_unaligned_box,NullPtr{ptr_kind:PointerKind::Box}=>//{;}; +const_eval_validation_null_box,NullPtr{ptr_kind:PointerKind::Ref(_)}=>//((),()); +const_eval_validation_null_ref,DanglingPtrNoProvenance{ptr_kind:PointerKind:://; +Box,..}=>{const_eval_validation_dangling_box_no_provenance}//let _=();if true{}; +DanglingPtrNoProvenance{ptr_kind:PointerKind::Ref(_),..}=>{//let _=();if true{}; +const_eval_validation_dangling_ref_no_provenance}DanglingPtrOutOfBounds{//{();}; +ptr_kind:PointerKind::Box}=>{const_eval_validation_dangling_box_out_of_bounds}// +DanglingPtrOutOfBounds{ptr_kind:PointerKind::Ref(_)}=>{//let _=||();loop{break}; +const_eval_validation_dangling_ref_out_of_bounds}DanglingPtrUseAfterFree{//({}); +ptr_kind:PointerKind::Box }=>{const_eval_validation_dangling_box_use_after_free} +DanglingPtrUseAfterFree{ptr_kind:PointerKind::Ref(_)}=>{//let _=||();let _=||(); +const_eval_validation_dangling_ref_use_after_free}InvalidBool{..}=>//let _=||(); +const_eval_validation_invalid_bool,InvalidChar{..}=>//loop{break;};loop{break;}; +const_eval_validation_invalid_char,InvalidFnPtr{..}=>//loop{break};loop{break;}; +const_eval_validation_invalid_fn_ptr,}}fn add_args(self,//; +err:&mut Diag<'_,G>){;use crate::fluent_generated as fluent;;;use rustc_middle:: +mir::interpret::ValidationErrorKind::*;3;if let PointerAsInt{..}|PartialPointer= +self.kind{();err.help(fluent::const_eval_ptr_as_bytes_1);();();err.help(fluent:: +const_eval_ptr_as_bytes_2);3;}3;let message=if let Some(path)=self.path{err.dcx. +eagerly_translate_to_string(fluent:://if true{};let _=||();if true{};let _=||(); +const_eval_validation_front_matter_invalid_value_with_path,[(( ("path").into()), +DiagArgValue::Str((path.into())))].iter().map((| (a,b)|((a,b)))),)}else{err.dcx. +eagerly_translate_to_string(fluent:://if true{};let _=||();if true{};let _=||(); +const_eval_validation_front_matter_invalid_value,[].into_iter(),)};();3;err.arg( +"front_matter",message);;;fn add_range_arg(r:WrappingRange, +max_hi:u128,err:&mut Diag<'_,G>,){;let WrappingRange{start:lo,end:hi}=r;assert!( +hi<=max_hi);;;let msg=if lo>hi{fluent::const_eval_range_wrapping}else if lo==hi{ +fluent::const_eval_range_singular}else if lo==0{if let _=(){};assert!(hi0, +"should not be printing if the range covers everything");*&*&();((),());fluent:: +const_eval_range_lower}else{fluent::const_eval_range};3;;let args=[("lo".into(), +DiagArgValue::Str(((lo.to_string()).into()))),("hi".into(),DiagArgValue::Str(hi. +to_string().into())),];;;let args=args.iter().map(|(a,b)|(a,b));let message=err. +dcx.eagerly_translate_to_string(msg,args);;;err.arg("in_range",message);;};match +self.kind{PtrToUninhabited{ty,..}|UninhabitedVal{ty}=>{{;};err.arg("ty",ty);();} +PointerAsInt{expected}|Uninit{expected}=>{;let msg=match expected{ExpectedKind:: +Reference=>fluent::const_eval_validation_expected_ref ,ExpectedKind::Box=>fluent +::const_eval_validation_expected_box,ExpectedKind::RawPtr=>fluent:://let _=||(); +const_eval_validation_expected_raw_ptr,ExpectedKind::InitScalar=>fluent:://({}); +const_eval_validation_expected_init_scalar,ExpectedKind::Bool=>fluent:://*&*&(); +const_eval_validation_expected_bool,ExpectedKind::Char=>fluent:://if let _=(){}; +const_eval_validation_expected_char,ExpectedKind::Float=>fluent:://loop{break;}; +const_eval_validation_expected_float,ExpectedKind::Int=>fluent:://if let _=(){}; +const_eval_validation_expected_int,ExpectedKind::FnPtr=>fluent:://if let _=(){}; +const_eval_validation_expected_fn_ptr,ExpectedKind::EnumTag=>fluent:://let _=(); +const_eval_validation_expected_enum_tag,ExpectedKind::Str=>fluent:://let _=||(); +const_eval_validation_expected_str,};if let _=(){};loop{break;};let msg=err.dcx. +eagerly_translate_to_string(msg,[].into_iter());();3;err.arg("expected",msg);3;} +InvalidEnumTag{value}|InvalidVTablePtr{value}|InvalidBool{value}|InvalidChar{//; +value}|InvalidFnPtr{value}=>{();err.arg("value",value);3;}NullablePtrOutOfRange{ +range,max_value}|PtrOutOfRange{range, max_value}=>{add_range_arg(range,max_value +,err)}OutOfRange{range,max_value,value}=>{;err.arg("value",value);add_range_arg( +range,max_value,err);3;}UnalignedPtr{required_bytes,found_bytes,..}=>{3;err.arg( +"required_bytes",required_bytes);{;};{;};err.arg("found_bytes",found_bytes);();} +DanglingPtrNoProvenance{pointer,..}=>{;err.arg("pointer",pointer);;}NullPtr{..}| +PtrToStatic{..}|ConstRefToMutable|ConstRefToExtern|MutableRefToImmutable|//({}); +NullFnPtr|NeverVal|UnsafeCellInImmutable|InvalidMetaSliceTooLarge{..}|//((),()); +InvalidMetaTooLarge{..}|DanglingPtrUseAfterFree{ ..}|DanglingPtrOutOfBounds{..}| +UninhabitedEnumVariant|PartialPointer=>{}}}}impl ReportErrorExt for//let _=||(); +UnsupportedOpInfo{fn diagnostic_message(&self)->DiagMessage{let _=();use crate:: +fluent_generated::*;{;};match self{UnsupportedOpInfo::Unsupported(s)=>s.clone(). +into(),UnsupportedOpInfo::UnsizedLocal=>const_eval_unsized_local,//loop{break;}; +UnsupportedOpInfo::OverwritePartialPointer(_)=>//*&*&();((),());((),());((),()); +const_eval_partial_pointer_overwrite,UnsupportedOpInfo:: ReadPartialPointer(_)=> +const_eval_partial_pointer_copy,UnsupportedOpInfo::ReadPointerAsInt(_)=>//{();}; +const_eval_read_pointer_as_int,UnsupportedOpInfo::ThreadLocalStatic(_)=>//{();}; +const_eval_thread_local_static,UnsupportedOpInfo::ExternStatic(_)=>//let _=||(); +const_eval_extern_static,}}fn add_args(self,diag:&mut Diag +<'_,G>){();use crate::fluent_generated::*;();3;use UnsupportedOpInfo::*;3;if let +ReadPointerAsInt(_)|OverwritePartialPointer(_)|ReadPartialPointer(_)=self{;diag. +help(const_eval_ptr_as_bytes_1);3;3;diag.help(const_eval_ptr_as_bytes_2);;}match +self{UnsizedLocal|Unsupported(_) |ReadPointerAsInt(_)=>{}OverwritePartialPointer +(ptr)|ReadPartialPointer(ptr)=>{3;diag.arg("ptr",ptr);3;}ThreadLocalStatic(did)| +ExternStatic(did)=>{{();};diag.arg("did",format!("{did:?}"));({});}}}}impl<'tcx> +ReportErrorExt for InterpError<'tcx>{ fn diagnostic_message(&self)->DiagMessage{ +match self{InterpError::UndefinedBehavior(ub )=>((((ub.diagnostic_message())))), +InterpError::Unsupported(e)=>e .diagnostic_message(),InterpError::InvalidProgram +(e)=>(((((((e.diagnostic_message()))))))),InterpError::ResourceExhaustion(e)=>e. +diagnostic_message(),InterpError::MachineStop(e) =>(e.diagnostic_message()),}}fn +add_args(self,diag:&mut Diag<'_,G>){match self{InterpError +::UndefinedBehavior(ub)=>(((ub.add_args(diag)))),InterpError::Unsupported(e)=>e. +add_args(diag),InterpError::InvalidProgram(e) =>(e.add_args(diag)),InterpError:: +ResourceExhaustion(e)=>e.add_args(diag) ,InterpError::MachineStop(e)=>e.add_args +(&mut|name,value|{{;};diag.arg(name,value);();}),}}}impl<'tcx>ReportErrorExt for +InvalidProgramInfo<'tcx>{fn diagnostic_message(&self)->DiagMessage{3;use crate:: +fluent_generated::*;((),());let _=();match self{InvalidProgramInfo::TooGeneric=> +const_eval_too_generic,InvalidProgramInfo::AlreadyReported(_)=>//*&*&();((),()); +const_eval_already_reported,InvalidProgramInfo::Layout( e)=>e.diagnostic_message +(),InvalidProgramInfo::FnAbiAdjustForForeignAbi(_)=>{rustc_middle::error:://{;}; +middle_adjust_for_foreign_abi_error}}}fn add_args(self,//3; +diag:&mut Diag<'_,G>){match self{InvalidProgramInfo::TooGeneric|//if let _=(){}; +InvalidProgramInfo::AlreadyReported(_)=>{}InvalidProgramInfo::Layout(e)=>{();let +dummy_level=Level::Bug;;let dummy_diag:Diag<'_,()>=e.into_diagnostic().into_diag +(diag.dcx,dummy_level);3;for(name,val)in dummy_diag.args.iter(){3;diag.arg(name. +clone(),val.clone());{();};}{();};dummy_diag.cancel();({});}InvalidProgramInfo:: +FnAbiAdjustForForeignAbi(AdjustForForeignAbiError::Unsupported{arch,abi},)=>{(); +diag.arg("arch",arch);3;;diag.arg("abi",abi.name());;}}}}impl ReportErrorExt for +ResourceExhaustionInfo{fn diagnostic_message(&self)->DiagMessage{{;};use crate:: +fluent_generated::*;;match self{ResourceExhaustionInfo::StackFrameLimitReached=> +const_eval_stack_frame_limit_reached,ResourceExhaustionInfo::MemoryExhausted=>// +const_eval_memory_exhausted,ResourceExhaustionInfo::AddressSpaceFull=>//((),()); +const_eval_address_space_full,ResourceExhaustionInfo::Interrupted=>//let _=||(); +const_eval_interrupted,}}fn add_args (self,_:&mut Diag<'_,G +>){}}impl rustc_errors::IntoDiagArg for InternKind{fn into_diag_arg(self)->//(); +DiagArgValue{DiagArgValue::Str(Cow::Borrowed(match self{InternKind::Static(//(); +Mutability::Not)=>("static"),InternKind:: Static(Mutability::Mut)=>"static_mut", +InternKind::Constant=>((("const"))),InternKind::Promoted=>((("promoted"))),}))}} diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index bbf11f169f989..0804451b90c2a 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -1,479 +1,150 @@ -use std::assert_matches::assert_matches; - -use rustc_apfloat::ieee::{Double, Single}; -use rustc_apfloat::{Float, FloatConvert}; -use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar}; -use rustc_middle::mir::CastKind; -use rustc_middle::ty::adjustment::PointerCoercion; -use rustc_middle::ty::layout::{IntegerExt, LayoutOf, TyAndLayout}; -use rustc_middle::ty::{self, FloatTy, Ty}; -use rustc_target::abi::Integer; -use rustc_type_ir::TyKind::*; - -use super::{ - util::ensure_monomorphic_enough, FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy, -}; - -use crate::fluent_generated as fluent; - -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - pub fn cast( - &mut self, - src: &OpTy<'tcx, M::Provenance>, - cast_kind: CastKind, - cast_ty: Ty<'tcx>, - dest: &PlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx> { - // `cast_ty` will often be the same as `dest.ty`, but not always, since subtyping is still - // possible. - let cast_layout = - if cast_ty == dest.layout.ty { dest.layout } else { self.layout_of(cast_ty)? }; - // FIXME: In which cases should we trigger UB when the source is uninit? - match cast_kind { - CastKind::PointerCoercion(PointerCoercion::Unsize) => { - self.unsize_into(src, cast_layout, dest)?; - } - - CastKind::PointerExposeAddress => { - let src = self.read_immediate(src)?; - let res = self.pointer_expose_address_cast(&src, cast_layout)?; - self.write_immediate(*res, dest)?; - } - - CastKind::PointerFromExposedAddress => { - let src = self.read_immediate(src)?; - let res = self.pointer_from_exposed_address_cast(&src, cast_layout)?; - self.write_immediate(*res, dest)?; - } - - CastKind::IntToInt | CastKind::IntToFloat => { - let src = self.read_immediate(src)?; - let res = self.int_to_int_or_float(&src, cast_layout)?; - self.write_immediate(*res, dest)?; - } - - CastKind::FloatToFloat | CastKind::FloatToInt => { - let src = self.read_immediate(src)?; - let res = self.float_to_float_or_int(&src, cast_layout)?; - self.write_immediate(*res, dest)?; - } - - CastKind::FnPtrToPtr | CastKind::PtrToPtr => { - let src = self.read_immediate(src)?; - let res = self.ptr_to_ptr(&src, cast_layout)?; - self.write_immediate(*res, dest)?; - } - - CastKind::PointerCoercion( - PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer, - ) => { - // These are NOPs, but can be wide pointers. - let v = self.read_immediate(src)?; - self.write_immediate(*v, dest)?; - } - - CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer) => { - // All reifications must be monomorphic, bail out otherwise. - ensure_monomorphic_enough(*self.tcx, src.layout.ty)?; - - // The src operand does not matter, just its type - match *src.layout.ty.kind() { - ty::FnDef(def_id, args) => { - let instance = ty::Instance::resolve_for_fn_ptr( - *self.tcx, - self.param_env, - def_id, - args, - ) - .ok_or_else(|| err_inval!(TooGeneric))?; - - let fn_ptr = self.fn_ptr(FnVal::Instance(instance)); - self.write_pointer(fn_ptr, dest)?; - } - _ => span_bug!(self.cur_span(), "reify fn pointer on {}", src.layout.ty), - } - } - - CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer) => { - let src = self.read_immediate(src)?; - match cast_ty.kind() { - ty::FnPtr(_) => { - // No change to value - self.write_immediate(*src, dest)?; - } - _ => span_bug!(self.cur_span(), "fn to unsafe fn cast on {}", cast_ty), - } - } - - CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_)) => { - // All reifications must be monomorphic, bail out otherwise. - ensure_monomorphic_enough(*self.tcx, src.layout.ty)?; - - // The src operand does not matter, just its type - match *src.layout.ty.kind() { - ty::Closure(def_id, args) => { - let instance = ty::Instance::resolve_closure( - *self.tcx, - def_id, - args, - ty::ClosureKind::FnOnce, - ); - let fn_ptr = self.fn_ptr(FnVal::Instance(instance)); - self.write_pointer(fn_ptr, dest)?; - } - _ => span_bug!(self.cur_span(), "closure fn pointer on {}", src.layout.ty), - } - } - - CastKind::DynStar => { - if let ty::Dynamic(data, _, ty::DynStar) = cast_ty.kind() { - // Initial cast from sized to dyn trait - let vtable = self.get_vtable_ptr(src.layout.ty, data.principal())?; - let vtable = Scalar::from_maybe_pointer(vtable, self); - let data = self.read_immediate(src)?.to_scalar(); - let _assert_pointer_like = data.to_pointer(self)?; - let val = Immediate::ScalarPair(data, vtable); - self.write_immediate(val, dest)?; - } else { - bug!() - } - } - - CastKind::Transmute => { - assert!(src.layout.is_sized()); - assert!(dest.layout.is_sized()); - assert_eq!(cast_ty, dest.layout.ty); // we otherwise ignore `cast_ty` enirely... - if src.layout.size != dest.layout.size { - throw_ub_custom!( - fluent::const_eval_invalid_transmute, - src_bytes = src.layout.size.bytes(), - dest_bytes = dest.layout.size.bytes(), - src = src.layout.ty, - dest = dest.layout.ty, - ); - } - - self.copy_op_allow_transmute(src, dest)?; - } - } - Ok(()) - } - - /// Handles 'IntToInt' and 'IntToFloat' casts. - pub fn int_to_int_or_float( - &self, - src: &ImmTy<'tcx, M::Provenance>, - cast_to: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { - assert!(src.layout.ty.is_integral() || src.layout.ty.is_char() || src.layout.ty.is_bool()); - assert!(cast_to.ty.is_floating_point() || cast_to.ty.is_integral() || cast_to.ty.is_char()); - - Ok(ImmTy::from_scalar( - self.cast_from_int_like(src.to_scalar(), src.layout, cast_to.ty)?, - cast_to, - )) - } - - /// Handles 'FloatToFloat' and 'FloatToInt' casts. - pub fn float_to_float_or_int( - &self, - src: &ImmTy<'tcx, M::Provenance>, - cast_to: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { - use rustc_type_ir::TyKind::*; - - let Float(fty) = src.layout.ty.kind() else { - bug!("FloatToFloat/FloatToInt cast: source type {} is not a float type", src.layout.ty) - }; - let val = match fty { - FloatTy::F16 => unimplemented!("f16_f128"), - FloatTy::F32 => self.cast_from_float(src.to_scalar().to_f32()?, cast_to.ty), - FloatTy::F64 => self.cast_from_float(src.to_scalar().to_f64()?, cast_to.ty), - FloatTy::F128 => unimplemented!("f16_f128"), - }; - Ok(ImmTy::from_scalar(val, cast_to)) - } - - /// Handles 'FnPtrToPtr' and 'PtrToPtr' casts. - pub fn ptr_to_ptr( - &self, - src: &ImmTy<'tcx, M::Provenance>, - cast_to: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { - assert!(src.layout.ty.is_any_ptr()); - assert!(cast_to.ty.is_unsafe_ptr()); - // Handle casting any ptr to raw ptr (might be a fat ptr). - if cast_to.size == src.layout.size { - // Thin or fat pointer that just hast the ptr kind of target type changed. - return Ok(ImmTy::from_immediate(**src, cast_to)); - } else { - // Casting the metadata away from a fat ptr. - assert_eq!(src.layout.size, 2 * self.pointer_size()); - assert_eq!(cast_to.size, self.pointer_size()); - assert!(src.layout.ty.is_unsafe_ptr()); - return match **src { - Immediate::ScalarPair(data, _) => Ok(ImmTy::from_scalar(data, cast_to)), - Immediate::Scalar(..) => span_bug!( - self.cur_span(), - "{:?} input to a fat-to-thin cast ({} -> {})", - *src, - src.layout.ty, - cast_to.ty - ), - Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)), - }; - } - } - - pub fn pointer_expose_address_cast( - &mut self, - src: &ImmTy<'tcx, M::Provenance>, - cast_to: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { - assert_matches!(src.layout.ty.kind(), ty::RawPtr(_, _) | ty::FnPtr(_)); - assert!(cast_to.ty.is_integral()); - - let scalar = src.to_scalar(); - let ptr = scalar.to_pointer(self)?; - match ptr.into_pointer_or_addr() { - Ok(ptr) => M::expose_ptr(self, ptr)?, - Err(_) => {} // Do nothing, exposing an invalid pointer (`None` provenance) is a NOP. - }; - Ok(ImmTy::from_scalar(self.cast_from_int_like(scalar, src.layout, cast_to.ty)?, cast_to)) - } - - pub fn pointer_from_exposed_address_cast( - &self, - src: &ImmTy<'tcx, M::Provenance>, - cast_to: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { - assert!(src.layout.ty.is_integral()); - assert_matches!(cast_to.ty.kind(), ty::RawPtr(_, _)); - - // First cast to usize. - let scalar = src.to_scalar(); - let addr = self.cast_from_int_like(scalar, src.layout, self.tcx.types.usize)?; - let addr = addr.to_target_usize(self)?; - - // Then turn address into pointer. - let ptr = M::ptr_from_addr_cast(self, addr)?; - Ok(ImmTy::from_scalar(Scalar::from_maybe_pointer(ptr, self), cast_to)) - } - - /// 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. - fn cast_from_int_like( - &self, - scalar: Scalar, // input value (there is no ScalarTy so we separate data+layout) - src_layout: TyAndLayout<'tcx>, - cast_ty: Ty<'tcx>, - ) -> InterpResult<'tcx, Scalar> { - // Let's make sure v is sign-extended *if* it has a signed type. - let signed = src_layout.abi.is_signed(); // Also asserts that abi is `Scalar`. - - let v = scalar.to_bits(src_layout.size)?; - let v = if signed { self.sign_extend(v, src_layout) } else { v }; - trace!("cast_from_scalar: {}, {} -> {}", v, src_layout.ty, cast_ty); - - Ok(match *cast_ty.kind() { - // int -> int - Int(_) | Uint(_) => { - let size = match *cast_ty.kind() { - Int(t) => Integer::from_int_ty(self, t).size(), - Uint(t) => Integer::from_uint_ty(self, t).size(), - _ => bug!(), - }; - let v = size.truncate(v); - Scalar::from_uint(v, size) - } - - // signed int -> float - Float(fty) if signed => { - let v = v as i128; - match fty { - FloatTy::F16 => unimplemented!("f16_f128"), - FloatTy::F32 => Scalar::from_f32(Single::from_i128(v).value), - FloatTy::F64 => Scalar::from_f64(Double::from_i128(v).value), - FloatTy::F128 => unimplemented!("f16_f128"), - } - } - // unsigned int -> float - Float(fty) => match fty { - FloatTy::F16 => unimplemented!("f16_f128"), - FloatTy::F32 => Scalar::from_f32(Single::from_u128(v).value), - FloatTy::F64 => Scalar::from_f64(Double::from_u128(v).value), - FloatTy::F128 => unimplemented!("f16_f128"), - }, - - // u8 -> char - Char => Scalar::from_u32(u8::try_from(v).unwrap().into()), - - // Casts to bool are not permitted by rustc, no need to handle them here. - _ => span_bug!(self.cur_span(), "invalid int to {} cast", cast_ty), - }) - } - - /// Low-level cast helper function. Converts an apfloat `f` into int or float types. - fn cast_from_float(&self, f: F, dest_ty: Ty<'tcx>) -> Scalar - where - F: Float + Into> + FloatConvert + FloatConvert, - { - use rustc_type_ir::TyKind::*; - - fn adjust_nan< - 'mir, - 'tcx: 'mir, - M: Machine<'mir, 'tcx>, - F1: rustc_apfloat::Float + FloatConvert, - F2: rustc_apfloat::Float, - >( - ecx: &InterpCx<'mir, 'tcx, M>, - f1: F1, - f2: F2, - ) -> F2 { - if f2.is_nan() { M::generate_nan(ecx, &[f1]) } else { f2 } - } - - match *dest_ty.kind() { - // float -> uint - Uint(t) => { - let size = Integer::from_uint_ty(self, t).size(); - // `to_u128` is a saturating cast, which is what we need - // (https://doc.rust-lang.org/nightly/nightly-rustc/rustc_apfloat/trait.Float.html#method.to_i128_r). - let v = f.to_u128(size.bits_usize()).value; - // This should already fit the bit width - Scalar::from_uint(v, size) - } - // float -> int - Int(t) => { - let size = Integer::from_int_ty(self, t).size(); - // `to_i128` is a saturating cast, which is what we need - // (https://doc.rust-lang.org/nightly/nightly-rustc/rustc_apfloat/trait.Float.html#method.to_i128_r). - let v = f.to_i128(size.bits_usize()).value; - Scalar::from_int(v, size) - } - // float -> float - Float(fty) => match fty { - FloatTy::F16 => unimplemented!("f16_f128"), - FloatTy::F32 => Scalar::from_f32(adjust_nan(self, f, f.convert(&mut false).value)), - FloatTy::F64 => Scalar::from_f64(adjust_nan(self, f, f.convert(&mut false).value)), - FloatTy::F128 => unimplemented!("f16_f128"), - }, - // That's it. - _ => span_bug!(self.cur_span(), "invalid float to {} cast", dest_ty), - } - } - - /// `src` is a *pointer to* a `source_ty`, and in `dest` we should store a pointer to th same - /// data at type `cast_ty`. - fn unsize_into_ptr( - &mut self, - src: &OpTy<'tcx, M::Provenance>, - dest: &PlaceTy<'tcx, M::Provenance>, - // The pointee types - source_ty: Ty<'tcx>, - cast_ty: Ty<'tcx>, - ) -> InterpResult<'tcx> { - // A -> A conversion - let (src_pointee_ty, dest_pointee_ty) = - self.tcx.struct_lockstep_tails_erasing_lifetimes(source_ty, cast_ty, self.param_env); - - match (&src_pointee_ty.kind(), &dest_pointee_ty.kind()) { - (&ty::Array(_, length), &ty::Slice(_)) => { - let ptr = self.read_pointer(src)?; - // u64 cast is from usize to u64, which is always good - let val = Immediate::new_slice( - ptr, - length.eval_target_usize(*self.tcx, self.param_env), - self, - ); - self.write_immediate(val, dest) - } - (ty::Dynamic(data_a, _, ty::Dyn), ty::Dynamic(data_b, _, ty::Dyn)) => { - let val = self.read_immediate(src)?; - if data_a.principal() == data_b.principal() { - // A NOP cast that doesn't actually change anything, should be allowed even with mismatching vtables. - return self.write_immediate(*val, dest); - } - let (old_data, old_vptr) = val.to_scalar_pair(); - let old_data = old_data.to_pointer(self)?; - let old_vptr = old_vptr.to_pointer(self)?; - let (ty, old_trait) = self.get_ptr_vtable(old_vptr)?; - if old_trait != data_a.principal() { - throw_ub_custom!(fluent::const_eval_upcast_mismatch); - } - let new_vptr = self.get_vtable_ptr(ty, data_b.principal())?; - self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest) - } - (_, &ty::Dynamic(data, _, ty::Dyn)) => { - // Initial cast from sized to dyn trait - let vtable = self.get_vtable_ptr(src_pointee_ty, data.principal())?; - let ptr = self.read_pointer(src)?; - let val = Immediate::new_dyn_trait(ptr, vtable, &*self.tcx); - self.write_immediate(val, dest) - } - _ => { - // Do not ICE if we are not monomorphic enough. - ensure_monomorphic_enough(*self.tcx, src.layout.ty)?; - ensure_monomorphic_enough(*self.tcx, cast_ty)?; - - span_bug!( - self.cur_span(), - "invalid pointer unsizing {} -> {}", - src.layout.ty, - cast_ty - ) - } - } - } - - pub fn unsize_into( - &mut self, - src: &OpTy<'tcx, M::Provenance>, - cast_ty: TyAndLayout<'tcx>, - dest: &PlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx> { - trace!("Unsizing {:?} of type {} into {}", *src, src.layout.ty, cast_ty.ty); - match (&src.layout.ty.kind(), &cast_ty.ty.kind()) { - (&ty::Ref(_, s, _), &ty::Ref(_, c, _) | &ty::RawPtr(c, _)) - | (&ty::RawPtr(s, _), &ty::RawPtr(c, _)) => self.unsize_into_ptr(src, dest, *s, *c), - (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => { - assert_eq!(def_a, def_b); // implies same number of fields - - // Unsizing of generic struct with pointer fields, like `Arc` -> `Arc`. - // There can be extra fields as long as they don't change their type or are 1-ZST. - // There might also be no field that actually needs unsizing. - let mut found_cast_field = false; - for i in 0..src.layout.fields.count() { - let cast_ty_field = cast_ty.field(self, i); - let src_field = self.project_field(src, i)?; - let dst_field = self.project_field(dest, i)?; - if src_field.layout.is_1zst() && cast_ty_field.is_1zst() { - // Skip 1-ZST fields. - } else if src_field.layout.ty == cast_ty_field.ty { - self.copy_op(&src_field, &dst_field)?; - } else { - if found_cast_field { - span_bug!(self.cur_span(), "unsize_into: more than one field to cast"); - } - found_cast_field = true; - self.unsize_into(&src_field, cast_ty_field, &dst_field)?; - } - } - Ok(()) - } - _ => { - // Do not ICE if we are not monomorphic enough. - ensure_monomorphic_enough(*self.tcx, src.layout.ty)?; - ensure_monomorphic_enough(*self.tcx, cast_ty.ty)?; - - span_bug!( - self.cur_span(), - "unsize_into: invalid conversion: {:?} -> {:?}", - src.layout, - dest.layout - ) - } - } - } -} +use std::assert_matches::assert_matches;use rustc_apfloat::ieee::{Double,Single +};use rustc_apfloat::{Float,FloatConvert};use rustc_middle::mir::interpret::{//; +InterpResult,PointerArithmetic,Scalar};use rustc_middle::mir::CastKind;use//{;}; +rustc_middle::ty::adjustment::PointerCoercion;use rustc_middle::ty::layout::{//; +IntegerExt,LayoutOf,TyAndLayout};use rustc_middle::ty::{self,FloatTy,Ty};use//3; +rustc_target::abi::Integer;use rustc_type_ir::TyKind::*;use super::{util:://{;}; +ensure_monomorphic_enough,FnVal,ImmTy,Immediate, InterpCx,Machine,OpTy,PlaceTy,} +;use crate::fluent_generated as fluent;impl<'mir,'tcx:'mir,M:Machine<'mir,'tcx// +>>InterpCx<'mir,'tcx,M>{pub fn cast(&mut self,src:&OpTy<'tcx,M::Provenance>,//3; +cast_kind:CastKind,cast_ty:Ty<'tcx>,dest:&PlaceTy<'tcx,M::Provenance>,)->//({}); +InterpResult<'tcx>{;let cast_layout=if cast_ty==dest.layout.ty{dest.layout}else{ +self.layout_of(cast_ty)?};loop{break};match cast_kind{CastKind::PointerCoercion( +PointerCoercion::Unsize)=>{;self.unsize_into(src,cast_layout,dest)?;;}CastKind:: +PointerExposeAddress=>{{;};let src=self.read_immediate(src)?;();();let res=self. +pointer_expose_address_cast(&src,cast_layout)?;;self.write_immediate(*res,dest)? +;;}CastKind::PointerFromExposedAddress=>{;let src=self.read_immediate(src)?;;let +res=self.pointer_from_exposed_address_cast(&src,cast_layout)?;*&*&();{();};self. +write_immediate(*res,dest)?;;}CastKind::IntToInt|CastKind::IntToFloat=>{let src= +self.read_immediate(src)?;;;let res=self.int_to_int_or_float(&src,cast_layout)?; +self.write_immediate(*res,dest)?;;}CastKind::FloatToFloat|CastKind::FloatToInt=> +{3;let src=self.read_immediate(src)?;3;;let res=self.float_to_float_or_int(&src, +cast_layout)?;;self.write_immediate(*res,dest)?;}CastKind::FnPtrToPtr|CastKind:: +PtrToPtr=>{3;let src=self.read_immediate(src)?;3;3;let res=self.ptr_to_ptr(&src, +cast_layout)?;3;3;self.write_immediate(*res,dest)?;3;}CastKind::PointerCoercion( +PointerCoercion::MutToConstPointer|PointerCoercion::ArrayToPointer,)=>{();let v= +self.read_immediate(src)?;{;};{;};self.write_immediate(*v,dest)?;{;};}CastKind:: +PointerCoercion(PointerCoercion::ReifyFnPointer)=>{3;ensure_monomorphic_enough(* +self.tcx,src.layout.ty)?;3;match*src.layout.ty.kind(){ty::FnDef(def_id,args)=>{; +let instance=ty::Instance::resolve_for_fn_ptr((*self.tcx),self.param_env,def_id, +args,).ok_or_else(||err_inval!(TooGeneric))?;();3;let fn_ptr=self.fn_ptr(FnVal:: +Instance(instance));();();self.write_pointer(fn_ptr,dest)?;3;}_=>span_bug!(self. +cur_span(),"reify fn pointer on {}",src.layout. ty),}}CastKind::PointerCoercion( +PointerCoercion::UnsafeFnPointer)=>{3;let src=self.read_immediate(src)?;3;match +cast_ty.kind(){ty::FnPtr(_)=>{3;self.write_immediate(*src,dest)?;;}_=>span_bug!( +self.cur_span(),"fn to unsafe fn cast on {}",cast_ty),}}CastKind:://loop{break}; +PointerCoercion(PointerCoercion::ClosureFnPointer(_))=>{loop{break};loop{break}; +ensure_monomorphic_enough(*self.tcx,src.layout.ty)?;;match*src.layout.ty.kind(){ +ty::Closure(def_id,args)=>{;let instance=ty::Instance::resolve_closure(*self.tcx +,def_id,args,ty::ClosureKind::FnOnce,);;;let fn_ptr=self.fn_ptr(FnVal::Instance( +instance));3;3;self.write_pointer(fn_ptr,dest)?;3;}_=>span_bug!(self.cur_span(), +"closure fn pointer on {}",src.layout.ty),}}CastKind::DynStar=>{if let ty:://(); +Dynamic(data,_,ty::DynStar)=cast_ty.kind(){3;let vtable=self.get_vtable_ptr(src. +layout.ty,data.principal())?;;let vtable=Scalar::from_maybe_pointer(vtable,self) +;;;let data=self.read_immediate(src)?.to_scalar();let _assert_pointer_like=data. +to_pointer(self)?;{;};{;};let val=Immediate::ScalarPair(data,vtable);();();self. +write_immediate(val,dest)?;();}else{bug!()}}CastKind::Transmute=>{3;assert!(src. +layout.is_sized());3;;assert!(dest.layout.is_sized());;;assert_eq!(cast_ty,dest. +layout.ty);{;};if src.layout.size!=dest.layout.size{();throw_ub_custom!(fluent:: +const_eval_invalid_transmute,src_bytes=src.layout.size .bytes(),dest_bytes=dest. +layout.size.bytes(),src=src.layout.ty,dest=dest.layout.ty,);*&*&();}*&*&();self. +copy_op_allow_transmute(src,dest)?;();}}Ok(())}pub fn int_to_int_or_float(&self, +src:&ImmTy<'tcx,M::Provenance>,cast_to:TyAndLayout<'tcx>,)->InterpResult<'tcx,// +ImmTy<'tcx,M::Provenance>>{3;assert!(src.layout.ty.is_integral()||src.layout.ty. +is_char()||src.layout.ty.is_bool());3;3;assert!(cast_to.ty.is_floating_point()|| +cast_to.ty.is_integral()||cast_to.ty.is_char());({});Ok(ImmTy::from_scalar(self. +cast_from_int_like(((src.to_scalar())),src.layout,cast_to.ty)?,cast_to,))}pub fn +float_to_float_or_int(&self,src:&ImmTy< 'tcx,M::Provenance>,cast_to:TyAndLayout< +'tcx>,)->InterpResult<'tcx,ImmTy<'tcx,M::Provenance>>{;use rustc_type_ir::TyKind +::*;((),());((),());*&*&();((),());let Float(fty)=src.layout.ty.kind()else{bug!( +"FloatToFloat/FloatToInt cast: source type {} is not a float type",src.layout.// +ty)};;;let val=match fty{FloatTy::F16=>unimplemented!("f16_f128"),FloatTy::F32=> +self.cast_from_float((src.to_scalar().to_f32()?),cast_to.ty),FloatTy::F64=>self. +cast_from_float((((((src.to_scalar()).to_f64() ))?)),cast_to.ty),FloatTy::F128=> +unimplemented!("f16_f128"),};let _=();Ok(ImmTy::from_scalar(val,cast_to))}pub fn +ptr_to_ptr(&self,src:&ImmTy<'tcx,M::Provenance>,cast_to:TyAndLayout<'tcx>,)->//; +InterpResult<'tcx,ImmTy<'tcx,M::Provenance>>{;assert!(src.layout.ty.is_any_ptr() +);;;assert!(cast_to.ty.is_unsafe_ptr());if cast_to.size==src.layout.size{return +Ok(ImmTy::from_immediate(**src,cast_to));3;}else{3;assert_eq!(src.layout.size,2* +self.pointer_size());;;assert_eq!(cast_to.size,self.pointer_size());assert!(src. +layout.ty.is_unsafe_ptr());;return match**src{Immediate::ScalarPair(data,_)=>Ok( +ImmTy::from_scalar(data,cast_to)),Immediate::Scalar(..)=>span_bug!(self.//{();}; +cur_span(),"{:?} input to a fat-to-thin cast ({} -> {})",*src,src.layout.ty,//3; +cast_to.ty),Immediate::Uninit=>throw_ub!(InvalidUninitBytes(None)),};();}}pub fn +pointer_expose_address_cast(&mut self,src:&ImmTy<'tcx,M::Provenance>,cast_to://; +TyAndLayout<'tcx>,)->InterpResult<'tcx,ImmTy<'tcx,M::Provenance>>{if let _=(){}; +assert_matches!(src.layout.ty.kind(),ty::RawPtr(_,_)|ty::FnPtr(_));();3;assert!( +cast_to.ty.is_integral());;let scalar=src.to_scalar();let ptr=scalar.to_pointer( +self)?;;match ptr.into_pointer_or_addr(){Ok(ptr)=>M::expose_ptr(self,ptr)?,Err(_ +)=>{}};;Ok(ImmTy::from_scalar(self.cast_from_int_like(scalar,src.layout,cast_to. +ty)?,cast_to))}pub fn pointer_from_exposed_address_cast(&self,src:&ImmTy<'tcx,M +::Provenance>,cast_to:TyAndLayout<'tcx>,)->InterpResult<'tcx,ImmTy<'tcx,M:://(); +Provenance>>{;assert!(src.layout.ty.is_integral());;;assert_matches!(cast_to.ty. +kind(),ty::RawPtr(_,_));{;};{;};let scalar=src.to_scalar();{;};();let addr=self. +cast_from_int_like(scalar,src.layout,self.tcx.types.usize)?;();();let addr=addr. +to_target_usize(self)?;3;3;let ptr=M::ptr_from_addr_cast(self,addr)?;;Ok(ImmTy:: +from_scalar((((((((((Scalar::from_maybe_pointer(ptr,self )))))))))),cast_to))}fn +cast_from_int_like(&self,scalar:Scalar,src_layout:TyAndLayout,cast_ty:Ty<'tcx>,)->InterpResult<'tcx,Scalar>{3;let signed= +src_layout.abi.is_signed();3;3;let v=scalar.to_bits(src_layout.size)?;;;let v=if +signed{self.sign_extend(v,src_layout)}else{v};if let _=(){};loop{break;};trace!( +"cast_from_scalar: {}, {} -> {}",v,src_layout.ty,cast_ty);;Ok(match*cast_ty.kind +(){Int(_)|Uint(_)=>{;let size=match*cast_ty.kind(){Int(t)=>Integer::from_int_ty( +self,t).size(),Uint(t)=>Integer::from_uint_ty(self,t).size(),_=>bug!(),};;let v= +size.truncate(v);();Scalar::from_uint(v,size)}Float(fty)if signed=>{3;let v=v as +i128;3;match fty{FloatTy::F16=>unimplemented!("f16_f128"),FloatTy::F32=>Scalar:: +from_f32(((Single::from_i128(v))).value),FloatTy::F64=>Scalar::from_f64(Double:: +from_i128(v).value),FloatTy::F128=>((unimplemented!("f16_f128"))),}}Float(fty)=> +match fty{FloatTy::F16=>(((unimplemented! ("f16_f128")))),FloatTy::F32=>Scalar:: +from_f32(((Single::from_u128(v))).value),FloatTy::F64=>Scalar::from_f64(Double:: +from_u128(v).value),FloatTy::F128=>(unimplemented!("f16_f128")),},Char=>Scalar:: +from_u32(((((u8::try_from(v)).unwrap()). into()))),_=>span_bug!(self.cur_span(), +"invalid int to {} cast",cast_ty),})}fn cast_from_float (&self,f:F,dest_ty:Ty +<'tcx>)->Scalarwhere F:Float+Into>+//{();}; +FloatConvert+FloatConvert,{3;use rustc_type_ir::TyKind::*;3;3;fn +adjust_nan<'mir,'tcx:'mir,M:Machine<'mir,'tcx>,F1:rustc_apfloat::Float+//*&*&(); +FloatConvert,F2:rustc_apfloat::Float,>(ecx: &InterpCx<'mir,'tcx,M>,f1:F1,f2: +F2,)->F2{if f2.is_nan(){M::generate_nan(ecx,&[f1])}else{f2}};match*dest_ty.kind( +){Uint(t)=>{;let size=Integer::from_uint_ty(self,t).size();let v=f.to_u128(size. +bits_usize()).value;{;};Scalar::from_uint(v,size)}Int(t)=>{();let size=Integer:: +from_int_ty(self,t).size();3;;let v=f.to_i128(size.bits_usize()).value;;Scalar:: +from_int(v,size)}Float(fty)=>match fty{FloatTy::F16=>unimplemented!("f16_f128") +,FloatTy::F32=>Scalar::from_f32(adjust_nan(self,f,f .convert(&mut false).value)) +,FloatTy::F64=>Scalar::from_f64(adjust_nan(self,f,f .convert(&mut false).value)) +,FloatTy::F128=>(((unimplemented!("f16_f128")))),},_=>span_bug!(self.cur_span(), +"invalid float to {} cast",dest_ty),}}fn unsize_into_ptr(&mut self,src:&OpTy,dest:&PlaceTy<'tcx,M::Provenance>,source_ty:Ty<'tcx>,//({}); +cast_ty:Ty<'tcx>,)->InterpResult<'tcx>{;let(src_pointee_ty,dest_pointee_ty)=self +.tcx.struct_lockstep_tails_erasing_lifetimes(source_ty,cast_ty,self.param_env);; +match(&src_pointee_ty.kind(),&dest_pointee_ty.kind ()){(&ty::Array(_,length),&ty +::Slice(_))=>{;let ptr=self.read_pointer(src)?;let val=Immediate::new_slice(ptr, +length.eval_target_usize(*self.tcx,self.param_env),self,);;self.write_immediate( +val,dest)}(ty::Dynamic(data_a,_,ty::Dyn),ty::Dynamic(data_b,_,ty::Dyn))=>{();let +val=self.read_immediate(src)?;;if data_a.principal()==data_b.principal(){return +self.write_immediate(*val,dest);;};let(old_data,old_vptr)=val.to_scalar_pair();; +let old_data=old_data.to_pointer(self)?;;let old_vptr=old_vptr.to_pointer(self)? +;();();let(ty,old_trait)=self.get_ptr_vtable(old_vptr)?;();if old_trait!=data_a. +principal(){;throw_ub_custom!(fluent::const_eval_upcast_mismatch);}let new_vptr= +self.get_vtable_ptr(ty,data_b.principal())?;{;};self.write_immediate(Immediate:: +new_dyn_trait(old_data,new_vptr,self),dest)}(_,&ty::Dynamic(data,_,ty::Dyn))=>{; +let vtable=self.get_vtable_ptr(src_pointee_ty,data.principal())?;;;let ptr=self. +read_pointer(src)?;;let val=Immediate::new_dyn_trait(ptr,vtable,&*self.tcx);self +.write_immediate(val,dest)}_=>{3;ensure_monomorphic_enough(*self.tcx,src.layout. +ty)?;;;ensure_monomorphic_enough(*self.tcx,cast_ty)?;;span_bug!(self.cur_span(), +"invalid pointer unsizing {} -> {}",src.layout.ty,cast_ty )}}}pub fn unsize_into +(&mut self,src:&OpTy<'tcx,M::Provenance>,cast_ty:TyAndLayout<'tcx>,dest:&//({}); +PlaceTy<'tcx,M::Provenance>,)->InterpResult<'tcx>{let _=||();loop{break};trace!( +"Unsizing {:?} of type {} into {}",*src,src.layout.ty,cast_ty.ty);();match(&src. +layout.ty.kind(),(&(cast_ty.ty.kind()))){( &ty::Ref(_,s,_),&ty::Ref(_,c,_)|&ty:: +RawPtr(c,_))|(&ty::RawPtr(s,_), &ty::RawPtr(c,_))=>self.unsize_into_ptr(src,dest +,*s,*c),(&ty::Adt(def_a,_),&ty::Adt(def_b,_))=>{;assert_eq!(def_a,def_b);let mut +found_cast_field=false;;for i in 0..src.layout.fields.count(){;let cast_ty_field +=cast_ty.field(self,i);;;let src_field=self.project_field(src,i)?;let dst_field= +self.project_field(dest,i)?;*&*&();if src_field.layout.is_1zst()&&cast_ty_field. +is_1zst(){}else if src_field.layout.ty==cast_ty_field.ty{let _=();self.copy_op(& +src_field,&dst_field)?;();}else{if found_cast_field{3;span_bug!(self.cur_span(), +"unsize_into: more than one field to cast");3;}3;found_cast_field=true;3;3;self. +unsize_into(&src_field,cast_ty_field,&dst_field)?;let _=();}}Ok(())}_=>{((),()); +ensure_monomorphic_enough(*self.tcx,src.layout.ty)?;;ensure_monomorphic_enough(* +self.tcx,cast_ty.ty)?;((),());((),());((),());((),());span_bug!(self.cur_span(), +"unsize_into: invalid conversion: {:?} -> {:?}",src.layout,dest.layout)}}}}//(); diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs index 704f597cfdb6b..6916a69da3917 100644 --- a/compiler/rustc_const_eval/src/interpret/discriminant.rs +++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs @@ -1,304 +1,82 @@ -//! Functions for reading and writing discriminants of multi-variant layouts (enums and coroutines). - -use rustc_middle::mir; -use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt}; -use rustc_middle::ty::{self, ScalarInt, Ty}; -use rustc_target::abi::{self, TagEncoding}; -use rustc_target::abi::{VariantIdx, Variants}; - -use super::{ImmTy, InterpCx, InterpResult, Machine, Readable, Scalar, Writeable}; - -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - /// Writes the discriminant of the given variant. - /// - /// If the variant is uninhabited, this is UB. - #[instrument(skip(self), level = "trace")] - pub fn write_discriminant( - &mut self, - variant_index: VariantIdx, - dest: &impl Writeable<'tcx, M::Provenance>, - ) -> InterpResult<'tcx> { - // Layout computation excludes uninhabited variants from consideration - // therefore there's no way to represent those variants in the given layout. - // Essentially, uninhabited variants do not have a tag that corresponds to their - // discriminant, so we cannot do anything here. - // When evaluating we will always error before even getting here, but ConstProp 'executes' - // dead code, so we cannot ICE here. - if dest.layout().for_variant(self, variant_index).abi.is_uninhabited() { - throw_ub!(UninhabitedEnumVariantWritten(variant_index)) - } - - match self.tag_for_variant(dest.layout().ty, variant_index)? { - Some((tag, tag_field)) => { - // No need to validate that the discriminant here because the - // `TyAndLayout::for_variant()` call earlier already checks the - // variant is valid. - let tag_dest = self.project_field(dest, tag_field)?; - self.write_scalar(tag, &tag_dest) - } - None => { - // No need to write the tag here, because an untagged variant is - // implicitly encoded. For `Niche`-optimized enums, this works by - // simply by having a value that is outside the niche variants. - // But what if the data stored here does not actually encode - // this variant? That would be bad! So let's double-check... - let actual_variant = self.read_discriminant(&dest.to_op(self)?)?; - if actual_variant != variant_index { - throw_ub!(InvalidNichedEnumVariantWritten { enum_ty: dest.layout().ty }); - } - Ok(()) - } - } - } - - /// Read discriminant, return the runtime value as well as the variant index. - /// Can also legally be called on non-enums (e.g. through the discriminant_value intrinsic)! - /// - /// Will never return an uninhabited variant. - #[instrument(skip(self), level = "trace")] - pub fn read_discriminant( - &self, - op: &impl Readable<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, VariantIdx> { - let ty = op.layout().ty; - trace!("read_discriminant_value {:#?}", op.layout()); - // Get type and layout of the discriminant. - let discr_layout = self.layout_of(ty.discriminant_ty(*self.tcx))?; - trace!("discriminant type: {:?}", discr_layout.ty); - - // We use "discriminant" to refer to the value associated with a particular enum variant. - // This is not to be confused with its "variant index", which is just determining its position in the - // declared list of variants -- they can differ with explicitly assigned discriminants. - // We use "tag" to refer to how the discriminant is encoded in memory, which can be either - // straight-forward (`TagEncoding::Direct`) or with a niche (`TagEncoding::Niche`). - let (tag_scalar_layout, tag_encoding, tag_field) = match op.layout().variants { - Variants::Single { index } => { - // Do some extra checks on enums. - if ty.is_enum() { - // Hilariously, `Single` is used even for 0-variant enums. - // (See https://github.com/rust-lang/rust/issues/89765). - if matches!(ty.kind(), ty::Adt(def, ..) if def.variants().is_empty()) { - throw_ub!(UninhabitedEnumVariantRead(index)) - } - // For consistency with `write_discriminant`, and to make sure that - // `project_downcast` cannot fail due to strange layouts, we declare immediate UB - // for uninhabited variants. - if op.layout().for_variant(self, index).abi.is_uninhabited() { - throw_ub!(UninhabitedEnumVariantRead(index)) - } - } - return Ok(index); - } - Variants::Multiple { tag, ref tag_encoding, tag_field, .. } => { - (tag, tag_encoding, tag_field) - } - }; - - // There are *three* layouts that come into play here: - // - The discriminant has a type for typechecking. This is `discr_layout`, and is used for - // the `Scalar` we return. - // - The tag (encoded discriminant) has layout `tag_layout`. This is always an integer type, - // and used to interpret the value we read from the tag field. - // For the return value, a cast to `discr_layout` is performed. - // - The field storing the tag has a layout, which is very similar to `tag_layout` but - // may be a pointer. This is `tag_val.layout`; we just use it for sanity checks. - - // Get layout for tag. - let tag_layout = self.layout_of(tag_scalar_layout.primitive().to_int_ty(*self.tcx))?; - - // Read tag and sanity-check `tag_layout`. - let tag_val = self.read_immediate(&self.project_field(op, tag_field)?)?; - assert_eq!(tag_layout.size, tag_val.layout.size); - assert_eq!(tag_layout.abi.is_signed(), tag_val.layout.abi.is_signed()); - trace!("tag value: {}", tag_val); - - // Figure out which discriminant and variant this corresponds to. - let index = match *tag_encoding { - TagEncoding::Direct => { - // Generate a specific error if `tag_val` is not an integer. - // (`tag_bits` itself is only used for error messages below.) - let tag_bits = tag_val - .to_scalar() - .try_to_int() - .map_err(|dbg_val| err_ub!(InvalidTag(dbg_val)))? - .assert_bits(tag_layout.size); - // Cast bits from tag layout to discriminant layout. - // After the checks we did above, this cannot fail, as - // discriminants are int-like. - let discr_val = self.int_to_int_or_float(&tag_val, discr_layout).unwrap(); - let discr_bits = discr_val.to_scalar().assert_bits(discr_layout.size); - // Convert discriminant to variant index, and catch invalid discriminants. - let index = match *ty.kind() { - ty::Adt(adt, _) => { - adt.discriminants(*self.tcx).find(|(_, var)| var.val == discr_bits) - } - ty::Coroutine(def_id, args) => { - let args = args.as_coroutine(); - args.discriminants(def_id, *self.tcx).find(|(_, var)| var.val == discr_bits) - } - _ => span_bug!(self.cur_span(), "tagged layout for non-adt non-coroutine"), - } - .ok_or_else(|| err_ub!(InvalidTag(Scalar::from_uint(tag_bits, tag_layout.size))))?; - // Return the cast value, and the index. - index.0 - } - TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start } => { - let tag_val = tag_val.to_scalar(); - // Compute the variant this niche value/"tag" corresponds to. With niche layout, - // discriminant (encoded in niche/tag) and variant index are the same. - let variants_start = niche_variants.start().as_u32(); - let variants_end = niche_variants.end().as_u32(); - let variant = match tag_val.try_to_int() { - Err(dbg_val) => { - // So this is a pointer then, and casting to an int failed. - // Can only happen during CTFE. - // The niche must be just 0, and the ptr not null, then we know this is - // okay. Everything else, we conservatively reject. - let ptr_valid = niche_start == 0 - && variants_start == variants_end - && !self.scalar_may_be_null(tag_val)?; - if !ptr_valid { - throw_ub!(InvalidTag(dbg_val)) - } - untagged_variant - } - Ok(tag_bits) => { - let tag_bits = tag_bits.assert_bits(tag_layout.size); - // We need to use machine arithmetic to get the relative variant idx: - // variant_index_relative = tag_val - niche_start_val - let tag_val = ImmTy::from_uint(tag_bits, tag_layout); - let niche_start_val = ImmTy::from_uint(niche_start, tag_layout); - let variant_index_relative_val = - self.wrapping_binary_op(mir::BinOp::Sub, &tag_val, &niche_start_val)?; - let variant_index_relative = - variant_index_relative_val.to_scalar().assert_bits(tag_val.layout.size); - // Check if this is in the range that indicates an actual discriminant. - if variant_index_relative <= u128::from(variants_end - variants_start) { - let variant_index_relative = u32::try_from(variant_index_relative) - .expect("we checked that this fits into a u32"); - // Then computing the absolute variant idx should not overflow any more. - let variant_index = VariantIdx::from_u32( - variants_start - .checked_add(variant_index_relative) - .expect("overflow computing absolute variant idx"), - ); - let variants = - ty.ty_adt_def().expect("tagged layout for non adt").variants(); - assert!(variant_index < variants.next_index()); - variant_index - } else { - untagged_variant - } - } - }; - // Compute the size of the scalar we need to return. - // No need to cast, because the variant index directly serves as discriminant and is - // encoded in the tag. - variant - } - }; - // Reading the discriminant of an uninhabited variant is UB. This is the basis for the - // `uninhabited_enum_branching` MIR pass. It also ensures consistency with - // `write_discriminant`. - if op.layout().for_variant(self, index).abi.is_uninhabited() { - throw_ub!(UninhabitedEnumVariantRead(index)) - } - Ok(index) - } - - pub fn discriminant_for_variant( - &self, - ty: Ty<'tcx>, - variant: VariantIdx, - ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { - let discr_layout = self.layout_of(ty.discriminant_ty(*self.tcx))?; - let discr_value = match ty.discriminant_for_variant(*self.tcx, variant) { - Some(discr) => { - // This type actually has discriminants. - assert_eq!(discr.ty, discr_layout.ty); - Scalar::from_uint(discr.val, discr_layout.size) - } - None => { - // On a type without actual discriminants, variant is 0. - assert_eq!(variant.as_u32(), 0); - Scalar::from_uint(variant.as_u32(), discr_layout.size) - } - }; - Ok(ImmTy::from_scalar(discr_value, discr_layout)) - } - - /// Computes how to write the tag of a given variant of enum `ty`: - /// - `None` means that nothing needs to be done as the variant is encoded implicitly - /// - `Some((val, field_idx))` means that the given integer value needs to be stored at the - /// given field index. - pub(crate) fn tag_for_variant( - &self, - ty: Ty<'tcx>, - variant_index: VariantIdx, - ) -> InterpResult<'tcx, Option<(ScalarInt, usize)>> { - match self.layout_of(ty)?.variants { - abi::Variants::Single { index } => { - assert_eq!(index, variant_index); - Ok(None) - } - - abi::Variants::Multiple { - tag_encoding: TagEncoding::Direct, - tag: tag_layout, - tag_field, - .. - } => { - // raw discriminants for enums are isize or bigger during - // their computation, but the in-memory tag is the smallest possible - // representation - let discr = self.discriminant_for_variant(ty, variant_index)?; - let discr_size = discr.layout.size; - let discr_val = discr.to_scalar().to_bits(discr_size)?; - let tag_size = tag_layout.size(self); - let tag_val = tag_size.truncate(discr_val); - let tag = ScalarInt::try_from_uint(tag_val, tag_size).unwrap(); - Ok(Some((tag, tag_field))) - } - - abi::Variants::Multiple { - tag_encoding: TagEncoding::Niche { untagged_variant, .. }, - .. - } if untagged_variant == variant_index => { - // The untagged variant is implicitly encoded simply by having a - // value that is outside the niche variants. - Ok(None) - } - - abi::Variants::Multiple { - tag_encoding: - TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start }, - tag: tag_layout, - tag_field, - .. - } => { - assert!(variant_index != untagged_variant); - let variants_start = niche_variants.start().as_u32(); - let variant_index_relative = variant_index - .as_u32() - .checked_sub(variants_start) - .expect("overflow computing relative variant idx"); - // We need to use machine arithmetic when taking into account `niche_start`: - // tag_val = variant_index_relative + niche_start_val - let tag_layout = self.layout_of(tag_layout.primitive().to_int_ty(*self.tcx))?; - let niche_start_val = ImmTy::from_uint(niche_start, tag_layout); - let variant_index_relative_val = - ImmTy::from_uint(variant_index_relative, tag_layout); - let tag = self - .wrapping_binary_op( - mir::BinOp::Add, - &variant_index_relative_val, - &niche_start_val, - )? - .to_scalar() - .try_to_int() - .unwrap(); - Ok(Some((tag, tag_field))) - } - } - } -} +use rustc_middle::mir;use rustc_middle:: ty::layout::{LayoutOf,PrimitiveExt};use +rustc_middle::ty::{self,ScalarInt,Ty};use rustc_target::abi::{self,TagEncoding// +};use rustc_target::abi::{VariantIdx,Variants};use super::{ImmTy,InterpCx,//{;}; +InterpResult,Machine,Readable,Scalar,Writeable};impl<'mir,'tcx:'mir,M:Machine>InterpCx<'mir,'tcx,M>{#[instrument(skip(self),level="trace")]pub fn// +write_discriminant(&mut self,variant_index: VariantIdx,dest:&impl Writeable<'tcx +,M::Provenance>,)->InterpResult<'tcx>{if ((((dest.layout())))).for_variant(self, +variant_index).abi.is_uninhabited(){throw_ub!(UninhabitedEnumVariantWritten(//3; +variant_index))}match ((self.tag_for_variant(dest.layout().ty,variant_index))?){ +Some((tag,tag_field))=>{;let tag_dest=self.project_field(dest,tag_field)?;;self. +write_scalar(tag,&tag_dest)}None=>{3;let actual_variant=self.read_discriminant(& +dest.to_op(self)?)?;let _=();if actual_variant!=variant_index{((),());throw_ub!( +InvalidNichedEnumVariantWritten{enum_ty:dest.layout().ty});let _=();}Ok(())}}}#[ +instrument(skip(self),level="trace")]pub fn read_discriminant(&self,op:&impl//3; +Readable<'tcx,M::Provenance>,)->InterpResult<'tcx,VariantIdx>{;let ty=op.layout( +).ty;;trace!("read_discriminant_value {:#?}",op.layout());let discr_layout=self. +layout_of(ty.discriminant_ty(*self.tcx))?;();3;trace!("discriminant type: {:?}", +discr_layout.ty);;let(tag_scalar_layout,tag_encoding,tag_field)=match op.layout( +).variants{Variants::Single{index}=>{if ty. is_enum(){if matches!(ty.kind(),ty:: +Adt(def,..)if def.variants().is_empty()){throw_ub!(UninhabitedEnumVariantRead(// +index))}if (op.layout().for_variant(self,index).abi.is_uninhabited()){throw_ub!( +UninhabitedEnumVariantRead(index))}}3;return Ok(index);;}Variants::Multiple{tag, +ref tag_encoding,tag_field,..}=>{(tag,tag_encoding,tag_field)}};;let tag_layout= +self.layout_of(tag_scalar_layout.primitive().to_int_ty(*self.tcx))?;;let tag_val +=self.read_immediate(&self.project_field(op,tag_field)?)?;;assert_eq!(tag_layout +.size,tag_val.layout.size);;assert_eq!(tag_layout.abi.is_signed(),tag_val.layout +.abi.is_signed());;trace!("tag value: {}",tag_val);let index=match*tag_encoding{ +TagEncoding::Direct=>{();let tag_bits=tag_val.to_scalar().try_to_int().map_err(| +dbg_val|err_ub!(InvalidTag(dbg_val)))?.assert_bits(tag_layout.size);({});{;};let +discr_val=self.int_to_int_or_float(&tag_val,discr_layout).unwrap();({});({});let +discr_bits=discr_val.to_scalar().assert_bits(discr_layout.size);;let index=match +*(ty.kind()){ty::Adt(adt,_)=>{adt.discriminants(*self.tcx).find(|(_,var)|var.val +==discr_bits)}ty::Coroutine(def_id,args)=>{3;let args=args.as_coroutine();;args. +discriminants(def_id,*self.tcx).find(|(_ ,var)|var.val==discr_bits)}_=>span_bug! +(self.cur_span(),"tagged layout for non-adt non-coroutine"),}.ok_or_else(||//(); +err_ub!(InvalidTag(Scalar::from_uint(tag_bits,tag_layout.size))))?;({});index.0} +TagEncoding::Niche{untagged_variant,ref niche_variants,niche_start}=>{*&*&();let +tag_val=tag_val.to_scalar();;let variants_start=niche_variants.start().as_u32(); +let variants_end=niche_variants.end().as_u32();{;};();let variant=match tag_val. +try_to_int(){Err(dbg_val)=>{{();};let ptr_valid=niche_start==0&&variants_start== +variants_end&&!self.scalar_may_be_null(tag_val)?;((),());if!ptr_valid{throw_ub!( +InvalidTag(dbg_val))}untagged_variant}Ok(tag_bits)=>{({});let tag_bits=tag_bits. +assert_bits(tag_layout.size);;let tag_val=ImmTy::from_uint(tag_bits,tag_layout); +let niche_start_val=ImmTy::from_uint(niche_start,tag_layout);((),());((),());let +variant_index_relative_val=self.wrapping_binary_op(mir:: BinOp::Sub,(&tag_val),& +niche_start_val)?;{;};{;};let variant_index_relative=variant_index_relative_val. +to_scalar().assert_bits(tag_val.layout.size);3;if variant_index_relative<=u128:: +from(variants_end-variants_start){({});let variant_index_relative=u32::try_from( +variant_index_relative).expect("we checked that this fits into a u32");();();let +variant_index=VariantIdx::from_u32(variants_start.checked_add(//((),());((),()); +variant_index_relative).expect("overflow computing absolute variant idx"),);;let +variants=ty.ty_adt_def().expect("tagged layout for non adt").variants();;;assert +!(variant_index,variant:VariantIdx,)->InterpResult<'tcx,ImmTy<'tcx,M:://*&*&(); +Provenance>>{;let discr_layout=self.layout_of(ty.discriminant_ty(*self.tcx))?;;; +let discr_value=match ty.discriminant_for_variant( *self.tcx,variant){Some(discr +)=>{{();};assert_eq!(discr.ty,discr_layout.ty);({});Scalar::from_uint(discr.val, +discr_layout.size)}None=>{();assert_eq!(variant.as_u32(),0);3;Scalar::from_uint( +variant.as_u32(),discr_layout.size)}};((),());Ok(ImmTy::from_scalar(discr_value, +discr_layout))}pub(crate)fn tag_for_variant(&self,ty:Ty<'tcx>,variant_index://3; +VariantIdx,)->InterpResult<'tcx,Option<(ScalarInt ,usize)>>{match self.layout_of +(ty)?.variants{abi::Variants::Single{index}=>{;assert_eq!(index,variant_index);; +Ok(None)}abi::Variants::Multiple{tag_encoding:TagEncoding::Direct,tag://((),()); +tag_layout,tag_field,..}=>{if true{};let discr=self.discriminant_for_variant(ty, +variant_index)?;;let discr_size=discr.layout.size;let discr_val=discr.to_scalar( +).to_bits(discr_size)?;;let tag_size=tag_layout.size(self);let tag_val=tag_size. +truncate(discr_val);;let tag=ScalarInt::try_from_uint(tag_val,tag_size).unwrap() +;();Ok(Some((tag,tag_field)))}abi::Variants::Multiple{tag_encoding:TagEncoding:: +Niche{untagged_variant,..},..}if untagged_variant ==variant_index=>{Ok(None)}abi +::Variants::Multiple{tag_encoding:TagEncoding::Niche{untagged_variant,ref//({}); +niche_variants,niche_start},tag:tag_layout,tag_field,..}=>{loop{break;};assert!( +variant_index!=untagged_variant);();3;let variants_start=niche_variants.start(). +as_u32();({});{;};let variant_index_relative=variant_index.as_u32().checked_sub( +variants_start).expect("overflow computing relative variant idx");{();};({});let +tag_layout=self.layout_of(tag_layout.primitive().to_int_ty(*self.tcx))?;();3;let +niche_start_val=ImmTy::from_uint(niche_start,tag_layout);if true{};if true{};let +variant_index_relative_val=ImmTy::from_uint(variant_index_relative,tag_layout);; +let tag=self.wrapping_binary_op( mir::BinOp::Add,(&variant_index_relative_val),& +niche_start_val,)?.to_scalar().try_to_int().unwrap();;Ok(Some((tag,tag_field)))} +}}}//let _=();let _=();let _=();if true{};let _=();if true{};let _=();if true{}; diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 3283bcc4c453c..8a2eeefe6828b 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -1,1270 +1,321 @@ -use std::cell::Cell; -use std::{fmt, mem}; - -use either::{Either, Left, Right}; - -use hir::CRATE_HIR_ID; -use rustc_errors::DiagCtxt; -use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData}; -use rustc_index::IndexVec; -use rustc_middle::mir; -use rustc_middle::mir::interpret::{ - CtfeProvenance, ErrorHandled, InvalidMetaKind, ReportedErrorInfo, -}; -use rustc_middle::query::TyCtxtAt; -use rustc_middle::ty::layout::{ - self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers, - TyAndLayout, -}; -use rustc_middle::ty::{self, GenericArgsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, Variance}; -use rustc_mir_dataflow::storage::always_storage_live_locals; -use rustc_session::Limit; -use rustc_span::Span; -use rustc_target::abi::{call::FnAbi, Align, HasDataLayout, Size, TargetDataLayout}; - -use super::{ - GlobalId, Immediate, InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, - Memory, MemoryKind, OpTy, Operand, Place, PlaceTy, Pointer, PointerArithmetic, Projectable, - Provenance, Scalar, StackPopJump, -}; -use crate::errors; -use crate::util; -use crate::{fluent_generated as fluent, ReportErrorExt}; - -pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> { - /// Stores the `Machine` instance. - /// - /// Note: the stack is provided by the machine. - pub machine: M, - - /// The results of the type checker, from rustc. - /// The span in this is the "root" of the evaluation, i.e., the const - /// we are evaluating (if this is CTFE). - pub tcx: TyCtxtAt<'tcx>, - - /// Bounds in scope for polymorphic evaluations. - pub(crate) param_env: ty::ParamEnv<'tcx>, - - /// The virtual memory system. - pub memory: Memory<'mir, 'tcx, M>, - - /// The recursion limit (cached from `tcx.recursion_limit(())`) - pub recursion_limit: Limit, -} - -// The Phantomdata exists to prevent this type from being `Send`. If it were sent across a thread -// boundary and dropped in the other thread, it would exit the span in the other thread. -struct SpanGuard(tracing::Span, std::marker::PhantomData<*const u8>); - -impl SpanGuard { - /// By default a `SpanGuard` does nothing. - fn new() -> Self { - Self(tracing::Span::none(), std::marker::PhantomData) - } - - /// If a span is entered, we exit the previous span (if any, normally none) and enter the - /// new span. This is mainly so we don't have to use `Option` for the `tracing_span` field of - /// `Frame` by creating a dummy span to being with and then entering it once the frame has - /// been pushed. - fn enter(&mut self, span: tracing::Span) { - // This executes the destructor on the previous instance of `SpanGuard`, ensuring that - // we never enter or exit more spans than vice versa. Unless you `mem::leak`, then we - // can't protect the tracing stack, but that'll just lead to weird logging, no actual - // problems. - *self = Self(span, std::marker::PhantomData); - self.0.with_subscriber(|(id, dispatch)| { - dispatch.enter(id); - }); - } -} - -impl Drop for SpanGuard { - fn drop(&mut self) { - self.0.with_subscriber(|(id, dispatch)| { - dispatch.exit(id); - }); - } -} - -/// A stack frame. -pub struct Frame<'mir, 'tcx, Prov: Provenance = CtfeProvenance, Extra = ()> { - //////////////////////////////////////////////////////////////////////////////// - // Function and callsite information - //////////////////////////////////////////////////////////////////////////////// - /// The MIR for the function called on this frame. - pub body: &'mir mir::Body<'tcx>, - - /// The def_id and args of the current function. - pub instance: ty::Instance<'tcx>, - - /// Extra data for the machine. - pub extra: Extra, - - //////////////////////////////////////////////////////////////////////////////// - // Return place and locals - //////////////////////////////////////////////////////////////////////////////// - /// Work to perform when returning from this function. - pub return_to_block: StackPopCleanup, - - /// The location where the result of the current stack frame should be written to, - /// and its layout in the caller. - pub return_place: MPlaceTy<'tcx, Prov>, - - /// The list of locals for this stack frame, stored in order as - /// `[return_ptr, arguments..., variables..., temporaries...]`. - /// The locals are stored as `Option`s. - /// `None` represents a local that is currently dead, while a live local - /// can either directly contain `Scalar` or refer to some part of an `Allocation`. - /// - /// Do *not* access this directly; always go through the machine hook! - pub locals: IndexVec>, - - /// The span of the `tracing` crate is stored here. - /// When the guard is dropped, the span is exited. This gives us - /// a full stack trace on all tracing statements. - tracing_span: SpanGuard, - - //////////////////////////////////////////////////////////////////////////////// - // Current position within the function - //////////////////////////////////////////////////////////////////////////////// - /// If this is `Right`, we are not currently executing any particular statement in - /// this frame (can happen e.g. during frame initialization, and during unwinding on - /// frames without cleanup code). - /// - /// Needs to be public because ConstProp does unspeakable things to it. - pub loc: Either, -} - -/// What we store about a frame in an interpreter backtrace. -#[derive(Clone, Debug)] -pub struct FrameInfo<'tcx> { - pub instance: ty::Instance<'tcx>, - pub span: Span, -} - -#[derive(Clone, Copy, Eq, PartialEq, Debug)] // Miri debug-prints these -pub enum StackPopCleanup { - /// Jump to the next block in the caller, or cause UB if None (that's a function - /// that may never return). Also store layout of return place so - /// we can validate it at that layout. - /// `ret` stores the block we jump to on a normal return, while `unwind` - /// stores the block used for cleanup during unwinding. - Goto { ret: Option, unwind: mir::UnwindAction }, - /// The root frame of the stack: nowhere else to jump to. - /// `cleanup` says whether locals are deallocated. Static computation - /// wants them leaked to intern what they need (and just throw away - /// the entire `ecx` when it is done). - Root { cleanup: bool }, -} - -/// State of a local variable including a memoized layout -#[derive(Clone)] -pub struct LocalState<'tcx, Prov: Provenance = CtfeProvenance> { - value: LocalValue, - /// Don't modify if `Some`, this is only used to prevent computing the layout twice. - /// Avoids computing the layout of locals that are never actually initialized. - layout: Cell>>, -} - -impl std::fmt::Debug for LocalState<'_, Prov> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("LocalState") - .field("value", &self.value) - .field("ty", &self.layout.get().map(|l| l.ty)) - .finish() - } -} - -/// Current value of a local variable -/// -/// This does not store the type of the local; the type is given by `body.local_decls` and can never -/// change, so by not storing here we avoid having to maintain that as an invariant. -#[derive(Copy, Clone, Debug)] // Miri debug-prints these -pub(super) enum LocalValue { - /// This local is not currently alive, and cannot be used at all. - Dead, - /// A normal, live local. - /// Mostly for convenience, we re-use the `Operand` type here. - /// This is an optimization over just always having a pointer here; - /// we can thus avoid doing an allocation when the local just stores - /// immediate values *and* never has its address taken. - Live(Operand), -} - -impl<'tcx, Prov: Provenance> LocalState<'tcx, Prov> { - pub fn make_live_uninit(&mut self) { - self.value = LocalValue::Live(Operand::Immediate(Immediate::Uninit)); - } - - /// This is a hack because Miri needs a way to visit all the provenance in a `LocalState` - /// without having a layout or `TyCtxt` available, and we want to keep the `Operand` type - /// private. - pub fn as_mplace_or_imm( - &self, - ) -> Option>, MemPlaceMeta), Immediate>> { - match self.value { - LocalValue::Dead => None, - LocalValue::Live(Operand::Indirect(mplace)) => Some(Left((mplace.ptr, mplace.meta))), - LocalValue::Live(Operand::Immediate(imm)) => Some(Right(imm)), - } - } - - /// Read the local's value or error if the local is not yet live or not live anymore. - #[inline(always)] - pub(super) fn access(&self) -> InterpResult<'tcx, &Operand> { - match &self.value { - LocalValue::Dead => throw_ub!(DeadLocal), // could even be "invalid program"? - LocalValue::Live(val) => Ok(val), - } - } - - /// Overwrite the local. If the local can be overwritten in place, return a reference - /// to do so; otherwise return the `MemPlace` to consult instead. - #[inline(always)] - pub(super) fn access_mut(&mut self) -> InterpResult<'tcx, &mut Operand> { - match &mut self.value { - LocalValue::Dead => throw_ub!(DeadLocal), // could even be "invalid program"? - LocalValue::Live(val) => Ok(val), - } - } -} - -impl<'mir, 'tcx, Prov: Provenance> Frame<'mir, 'tcx, Prov> { - pub fn with_extra(self, extra: Extra) -> Frame<'mir, 'tcx, Prov, Extra> { - Frame { - body: self.body, - instance: self.instance, - return_to_block: self.return_to_block, - return_place: self.return_place, - locals: self.locals, - loc: self.loc, - extra, - tracing_span: self.tracing_span, - } - } -} - -impl<'mir, 'tcx, Prov: Provenance, Extra> Frame<'mir, 'tcx, Prov, Extra> { - /// Get the current location within the Frame. - /// - /// If this is `Left`, we are not currently executing any particular statement in - /// this frame (can happen e.g. during frame initialization, and during unwinding on - /// frames without cleanup code). - /// - /// Used by priroda. - pub fn current_loc(&self) -> Either { - self.loc - } - - /// Return the `SourceInfo` of the current instruction. - pub fn current_source_info(&self) -> Option<&mir::SourceInfo> { - self.loc.left().map(|loc| self.body.source_info(loc)) - } - - pub fn current_span(&self) -> Span { - match self.loc { - Left(loc) => self.body.source_info(loc).span, - Right(span) => span, - } - } - - pub fn lint_root(&self) -> Option { - self.current_source_info().and_then(|source_info| { - match &self.body.source_scopes[source_info.scope].local_data { - mir::ClearCrossCrate::Set(data) => Some(data.lint_root), - mir::ClearCrossCrate::Clear => None, - } - }) - } - - /// Returns the address of the buffer where the locals are stored. This is used by `Place` as a - /// sanity check to detect bugs where we mix up which stack frame a place refers to. - #[inline(always)] - pub(super) fn locals_addr(&self) -> usize { - self.locals.raw.as_ptr().addr() - } - - #[must_use] - pub fn generate_stacktrace_from_stack(stack: &[Self]) -> Vec> { - 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 stack.iter().rev() { - let span = match frame.loc { - Left(loc) => { - // If the stacktrace passes through MIR-inlined source scopes, add them. - let mir::SourceInfo { mut span, scope } = *frame.body.source_info(loc); - let mut scope_data = &frame.body.source_scopes[scope]; - while let Some((instance, call_span)) = scope_data.inlined { - frames.push(FrameInfo { span, instance }); - span = call_span; - scope_data = &frame.body.source_scopes[scope_data.parent_scope.unwrap()]; - } - span - } - Right(span) => span, - }; - frames.push(FrameInfo { span, instance: frame.instance }); - } - trace!("generate stacktrace: {:#?}", frames); - frames - } -} - -// FIXME: only used by miri, should be removed once translatable. -impl<'tcx> fmt::Display for FrameInfo<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - ty::tls::with(|tcx| { - if tcx.def_key(self.instance.def_id()).disambiguated_data.data == DefPathData::Closure { - write!(f, "inside closure") - } else { - // Note: this triggers a `must_produce_diag` 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) - } - }) - } -} - -impl<'tcx> FrameInfo<'tcx> { - pub fn as_note(&self, tcx: TyCtxt<'tcx>) -> errors::FrameNote { - let span = self.span; - if tcx.def_key(self.instance.def_id()).disambiguated_data.data == DefPathData::Closure { - errors::FrameNote { where_: "closure", span, instance: String::new(), times: 0 } - } else { - let instance = format!("{}", self.instance); - // Note: this triggers a `must_produce_diag` 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. - errors::FrameNote { where_: "instance", span, instance, times: 0 } - } - } -} - -impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for InterpCx<'mir, 'tcx, M> { - #[inline] - fn data_layout(&self) -> &TargetDataLayout { - &self.tcx.data_layout - } -} - -impl<'mir, 'tcx, M> layout::HasTyCtxt<'tcx> for InterpCx<'mir, 'tcx, M> -where - M: Machine<'mir, 'tcx>, -{ - #[inline] - fn tcx(&self) -> TyCtxt<'tcx> { - *self.tcx - } -} - -impl<'mir, 'tcx, M> layout::HasParamEnv<'tcx> for InterpCx<'mir, 'tcx, M> -where - M: Machine<'mir, 'tcx>, -{ - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.param_env - } -} - -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> LayoutOfHelpers<'tcx> for InterpCx<'mir, 'tcx, M> { - type LayoutOfResult = InterpResult<'tcx, TyAndLayout<'tcx>>; - - #[inline] - fn layout_tcx_at_span(&self) -> Span { - // Using the cheap root span for performance. - self.tcx.span - } - - #[inline] - fn handle_layout_err( - &self, - err: LayoutError<'tcx>, - _: Span, - _: Ty<'tcx>, - ) -> InterpErrorInfo<'tcx> { - err_inval!(Layout(err)).into() - } -} - -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> FnAbiOfHelpers<'tcx> for InterpCx<'mir, 'tcx, M> { - type FnAbiOfResult = InterpResult<'tcx, &'tcx FnAbi<'tcx, Ty<'tcx>>>; - - fn handle_fn_abi_err( - &self, - err: FnAbiError<'tcx>, - _span: Span, - _fn_abi_request: FnAbiRequest<'tcx>, - ) -> InterpErrorInfo<'tcx> { - match err { - FnAbiError::Layout(err) => err_inval!(Layout(err)).into(), - FnAbiError::AdjustForForeignAbi(err) => { - err_inval!(FnAbiAdjustForForeignAbi(err)).into() - } - } - } -} - -/// Test if it is valid for a MIR assignment to assign `src`-typed place to `dest`-typed value. -/// This test should be symmetric, as it is primarily about layout compatibility. -pub(super) fn mir_assign_valid_types<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - src: TyAndLayout<'tcx>, - dest: TyAndLayout<'tcx>, -) -> bool { - // Type-changing assignments can happen when subtyping is used. While - // all normal lifetimes are erased, higher-ranked types with their - // late-bound lifetimes are still around and can lead to type - // differences. - if util::relate_types(tcx, param_env, Variance::Covariant, src.ty, dest.ty) { - // Make sure the layout is equal, too -- just to be safe. Miri really - // needs layout equality. For performance reason we skip this check when - // the types are equal. Equal types *can* have different layouts when - // enum downcast is involved (as enum variants carry the type of the - // enum), but those should never occur in assignments. - if cfg!(debug_assertions) || src.ty != dest.ty { - assert_eq!(src.layout, dest.layout); - } - true - } else { - false - } -} - -/// Use the already known layout if given (but sanity check in debug mode), -/// or compute the layout. -#[cfg_attr(not(debug_assertions), inline(always))] -pub(super) fn from_known_layout<'tcx>( - tcx: TyCtxtAt<'tcx>, - param_env: ParamEnv<'tcx>, - known_layout: Option>, - compute: impl FnOnce() -> InterpResult<'tcx, TyAndLayout<'tcx>>, -) -> InterpResult<'tcx, TyAndLayout<'tcx>> { - match known_layout { - None => compute(), - Some(known_layout) => { - if cfg!(debug_assertions) { - let check_layout = compute()?; - if !mir_assign_valid_types(tcx.tcx, param_env, check_layout, known_layout) { - span_bug!( - tcx.span, - "expected type differs from actual type.\nexpected: {}\nactual: {}", - known_layout.ty, - check_layout.ty, - ); - } - } - Ok(known_layout) - } - } -} - -/// Turn the given error into a human-readable string. Expects the string to be printed, so if -/// `RUSTC_CTFE_BACKTRACE` is set this will show a backtrace of the rustc internals that -/// triggered the error. -/// -/// This is NOT the preferred way to render an error; use `report` from `const_eval` instead. -/// However, this is useful when error messages appear in ICEs. -pub fn format_interp_error<'tcx>(dcx: &DiagCtxt, e: InterpErrorInfo<'tcx>) -> String { - let (e, backtrace) = e.into_parts(); - backtrace.print_backtrace(); - // FIXME(fee1-dead), HACK: we want to use the error as title therefore we can just extract the - // label and arguments from the InterpError. - #[allow(rustc::untranslatable_diagnostic)] - let mut diag = dcx.struct_allow(""); - let msg = e.diagnostic_message(); - e.add_args(&mut diag); - let s = dcx.eagerly_translate_to_string(msg, diag.args.iter()); - diag.cancel(); - s -} - -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - pub fn new( - tcx: TyCtxt<'tcx>, - root_span: Span, - param_env: ty::ParamEnv<'tcx>, - machine: M, - ) -> Self { - InterpCx { - machine, - tcx: tcx.at(root_span), - param_env, - memory: Memory::new(), - recursion_limit: tcx.recursion_limit(), - } - } - - #[inline(always)] - pub fn cur_span(&self) -> Span { - // This deliberately does *not* honor `requires_caller_location` since it is used for much - // more than just panics. - self.stack().last().map_or(self.tcx.span, |f| f.current_span()) - } - - #[inline(always)] - /// Find the first stack frame that is within the current crate, if any, otherwise return the crate's HirId - pub fn best_lint_scope(&self) -> hir::HirId { - self.stack() - .iter() - .find_map(|frame| frame.body.source.def_id().as_local()) - .map_or(CRATE_HIR_ID, |def_id| self.tcx.local_def_id_to_hir_id(def_id)) - } - - #[inline(always)] - pub(crate) fn stack(&self) -> &[Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>] { - M::stack(self) - } - - #[inline(always)] - pub(crate) fn stack_mut( - &mut self, - ) -> &mut Vec> { - M::stack_mut(self) - } - - #[inline(always)] - pub fn frame_idx(&self) -> usize { - let stack = self.stack(); - assert!(!stack.is_empty()); - stack.len() - 1 - } - - #[inline(always)] - pub fn frame(&self) -> &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra> { - self.stack().last().expect("no call frames exist") - } - - #[inline(always)] - pub fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx, M::Provenance, M::FrameExtra> { - self.stack_mut().last_mut().expect("no call frames exist") - } - - #[inline(always)] - pub fn body(&self) -> &'mir mir::Body<'tcx> { - self.frame().body - } - - #[inline(always)] - pub fn sign_extend(&self, value: u128, ty: TyAndLayout<'_>) -> u128 { - assert!(ty.abi.is_signed()); - ty.size.sign_extend(value) - } - - #[inline(always)] - pub fn truncate(&self, value: u128, ty: TyAndLayout<'_>) -> u128 { - ty.size.truncate(value) - } - - #[inline] - pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool { - ty.is_freeze(*self.tcx, self.param_env) - } - - pub fn load_mir( - &self, - instance: ty::InstanceDef<'tcx>, - promoted: Option, - ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> { - trace!("load mir(instance={:?}, promoted={:?})", instance, promoted); - let body = if let Some(promoted) = promoted { - let def = instance.def_id(); - &self.tcx.promoted_mir(def)[promoted] - } else { - M::load_mir(self, instance)? - }; - // do not continue if typeck errors occurred (can only occur in local crate) - if let Some(err) = body.tainted_by_errors { - throw_inval!(AlreadyReported(ReportedErrorInfo::tainted_by_errors(err))); - } - Ok(body) - } - - /// Call this on things you got out of the MIR (so it is as generic as the current - /// stack frame), to bring it into the proper environment for this interpreter. - pub(super) fn instantiate_from_current_frame_and_normalize_erasing_regions< - T: TypeFoldable>, - >( - &self, - value: T, - ) -> Result { - self.instantiate_from_frame_and_normalize_erasing_regions(self.frame(), value) - } - - /// Call this on things you got out of the MIR (so it is as generic as the provided - /// stack frame), to bring it into the proper environment for this interpreter. - pub(super) fn instantiate_from_frame_and_normalize_erasing_regions< - T: TypeFoldable>, - >( - &self, - frame: &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>, - value: T, - ) -> Result { - frame - .instance - .try_instantiate_mir_and_normalize_erasing_regions( - *self.tcx, - self.param_env, - ty::EarlyBinder::bind(value), - ) - .map_err(|_| ErrorHandled::TooGeneric(self.cur_span())) - } - - /// The `args` are assumed to already be in our interpreter "universe" (param_env). - pub(super) fn resolve( - &self, - def: DefId, - args: GenericArgsRef<'tcx>, - ) -> InterpResult<'tcx, ty::Instance<'tcx>> { - trace!("resolve: {:?}, {:#?}", def, args); - trace!("param_env: {:#?}", self.param_env); - trace!("args: {:#?}", args); - match ty::Instance::resolve(*self.tcx, self.param_env, def, args) { - Ok(Some(instance)) => Ok(instance), - Ok(None) => throw_inval!(TooGeneric), - - // FIXME(eddyb) this could be a bit more specific than `AlreadyReported`. - Err(error_reported) => throw_inval!(AlreadyReported(error_reported.into())), - } - } - - /// Walks up the callstack from the intrinsic's callsite, searching for the first callsite in a - /// frame which is not `#[track_caller]`. This is the fancy version of `cur_span`. - pub(crate) fn find_closest_untracked_caller_location(&self) -> Span { - for frame in self.stack().iter().rev() { - debug!("find_closest_untracked_caller_location: checking frame {:?}", frame.instance); - - // Assert that the frame we look at is actually executing code currently - // (`loc` is `Right` when we are unwinding and the frame does not require cleanup). - let loc = frame.loc.left().unwrap(); - - // This could be a non-`Call` terminator (such as `Drop`), or not a terminator at all - // (such as `box`). Use the normal span by default. - let mut source_info = *frame.body.source_info(loc); - - // If this is a `Call` terminator, use the `fn_span` instead. - let block = &frame.body.basic_blocks[loc.block]; - if loc.statement_index == block.statements.len() { - debug!( - "find_closest_untracked_caller_location: got terminator {:?} ({:?})", - block.terminator(), - block.terminator().kind, - ); - if let mir::TerminatorKind::Call { fn_span, .. } = block.terminator().kind { - source_info.span = fn_span; - } - } - - let caller_location = if frame.instance.def.requires_caller_location(*self.tcx) { - // We use `Err(())` as indication that we should continue up the call stack since - // this is a `#[track_caller]` function. - Some(Err(())) - } else { - None - }; - if let Ok(span) = - frame.body.caller_location_span(source_info, caller_location, *self.tcx, Ok) - { - return span; - } - } - - span_bug!(self.cur_span(), "no non-`#[track_caller]` frame found") - } - - #[inline(always)] - pub(super) fn layout_of_local( - &self, - frame: &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>, - local: mir::Local, - layout: Option>, - ) -> InterpResult<'tcx, TyAndLayout<'tcx>> { - let state = &frame.locals[local]; - if let Some(layout) = state.layout.get() { - return Ok(layout); - } - - let layout = from_known_layout(self.tcx, self.param_env, layout, || { - let local_ty = frame.body.local_decls[local].ty; - let local_ty = - self.instantiate_from_frame_and_normalize_erasing_regions(frame, local_ty)?; - self.layout_of(local_ty) - })?; - - // Layouts of locals are requested a lot, so we cache them. - state.layout.set(Some(layout)); - Ok(layout) - } - - /// Returns the actual dynamic size and alignment of the place at the given type. - /// Only the "meta" (metadata) part of the place matters. - /// This can fail to provide an answer for extern types. - pub(super) fn size_and_align_of( - &self, - metadata: &MemPlaceMeta, - layout: &TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, Option<(Size, Align)>> { - if layout.is_sized() { - return Ok(Some((layout.size, layout.align.abi))); - } - match layout.ty.kind() { - ty::Adt(..) | ty::Tuple(..) => { - // First get the size of all statically known fields. - // Don't use type_of::sizing_type_of because that expects t to be sized, - // and it also rounds up to alignment, which we want to avoid, - // as the unsized field's alignment could be smaller. - assert!(!layout.ty.is_simd()); - assert!(layout.fields.count() > 0); - trace!("DST layout: {:?}", layout); - - let unsized_offset_unadjusted = layout.fields.offset(layout.fields.count() - 1); - let sized_align = layout.align.abi; - - // Recurse to get the size of the dynamically sized field (must be - // the last field). Can't have foreign types here, how would we - // adjust alignment and size for them? - let field = layout.field(self, layout.fields.count() - 1); - let Some((unsized_size, mut unsized_align)) = - self.size_and_align_of(metadata, &field)? - else { - // A field with an extern type. We don't know the actual dynamic size - // or the alignment. - return Ok(None); - }; - - // # First compute the dynamic alignment - - // Packed type alignment needs to be capped. - if let ty::Adt(def, _) = layout.ty.kind() { - if let Some(packed) = def.repr().pack { - unsized_align = unsized_align.min(packed); - } - } - - // Choose max of two known alignments (combined value must - // be aligned according to more restrictive of the two). - let full_align = sized_align.max(unsized_align); - - // # Then compute the dynamic size - - let unsized_offset_adjusted = unsized_offset_unadjusted.align_to(unsized_align); - let full_size = (unsized_offset_adjusted + unsized_size).align_to(full_align); - - // Just for our sanitiy's sake, assert that this is equal to what codegen would compute. - assert_eq!( - full_size, - (unsized_offset_unadjusted + unsized_size).align_to(full_align) - ); - - // Check if this brought us over the size limit. - if full_size > self.max_size_of_val() { - throw_ub!(InvalidMeta(InvalidMetaKind::TooBig)); - } - Ok(Some((full_size, full_align))) - } - ty::Dynamic(_, _, ty::Dyn) => { - let vtable = metadata.unwrap_meta().to_pointer(self)?; - // Read size and align from vtable (already checks size). - Ok(Some(self.get_vtable_size_and_align(vtable)?)) - } - - ty::Slice(_) | ty::Str => { - let len = metadata.unwrap_meta().to_target_usize(self)?; - let elem = layout.field(self, 0); - - // Make sure the slice is not too big. - let size = elem.size.bytes().saturating_mul(len); // we rely on `max_size_of_val` being smaller than `u64::MAX`. - let size = Size::from_bytes(size); - if size > self.max_size_of_val() { - throw_ub!(InvalidMeta(InvalidMetaKind::SliceTooBig)); - } - Ok(Some((size, elem.align.abi))) - } - - ty::Foreign(_) => Ok(None), - - _ => span_bug!(self.cur_span(), "size_and_align_of::<{}> not supported", layout.ty), - } - } - #[inline] - pub fn size_and_align_of_mplace( - &self, - mplace: &MPlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, Option<(Size, Align)>> { - self.size_and_align_of(&mplace.meta(), &mplace.layout) - } - - #[instrument(skip(self, body, return_place, return_to_block), level = "debug")] - pub fn push_stack_frame( - &mut self, - instance: ty::Instance<'tcx>, - body: &'mir mir::Body<'tcx>, - return_place: &MPlaceTy<'tcx, M::Provenance>, - return_to_block: StackPopCleanup, - ) -> InterpResult<'tcx> { - trace!("body: {:#?}", body); - let dead_local = LocalState { value: LocalValue::Dead, layout: Cell::new(None) }; - let locals = IndexVec::from_elem(dead_local, &body.local_decls); - // First push a stack frame so we have access to the local args - let pre_frame = Frame { - body, - loc: Right(body.span), // Span used for errors caused during preamble. - return_to_block, - return_place: return_place.clone(), - locals, - instance, - tracing_span: SpanGuard::new(), - extra: (), - }; - let frame = M::init_frame_extra(self, pre_frame)?; - self.stack_mut().push(frame); - - // Make sure all the constants required by this frame evaluate successfully (post-monomorphization check). - if M::POST_MONO_CHECKS { - for &const_ in &body.required_consts { - let c = self - .instantiate_from_current_frame_and_normalize_erasing_regions(const_.const_)?; - c.eval(*self.tcx, self.param_env, const_.span).map_err(|err| { - err.emit_note(*self.tcx); - err - })?; - } - } - - // done - M::after_stack_push(self)?; - self.frame_mut().loc = Left(mir::Location::START); - - let span = info_span!("frame", "{}", instance); - self.frame_mut().tracing_span.enter(span); - - Ok(()) - } - - /// Jump to the given block. - #[inline] - pub fn go_to_block(&mut self, target: mir::BasicBlock) { - self.frame_mut().loc = Left(mir::Location { block: target, statement_index: 0 }); - } - - /// *Return* to the given `target` basic block. - /// Do *not* use for unwinding! Use `unwind_to_block` instead. - /// - /// If `target` is `None`, that indicates the function cannot return, so we raise UB. - pub fn return_to_block(&mut self, target: Option) -> InterpResult<'tcx> { - if let Some(target) = target { - self.go_to_block(target); - Ok(()) - } else { - throw_ub!(Unreachable) - } - } - - /// *Unwind* to the given `target` basic block. - /// Do *not* use for returning! Use `return_to_block` instead. - /// - /// If `target` is `UnwindAction::Continue`, that indicates the function does not need cleanup - /// during unwinding, and we will just keep propagating that upwards. - /// - /// If `target` is `UnwindAction::Unreachable`, that indicates the function does not allow - /// unwinding, and doing so is UB. - #[cold] // usually we have normal returns, not unwinding - pub fn unwind_to_block(&mut self, target: mir::UnwindAction) -> InterpResult<'tcx> { - self.frame_mut().loc = match target { - mir::UnwindAction::Cleanup(block) => Left(mir::Location { block, statement_index: 0 }), - mir::UnwindAction::Continue => Right(self.frame_mut().body.span), - mir::UnwindAction::Unreachable => { - throw_ub_custom!(fluent::const_eval_unreachable_unwind); - } - mir::UnwindAction::Terminate(reason) => { - self.frame_mut().loc = Right(self.frame_mut().body.span); - M::unwind_terminate(self, reason)?; - // This might have pushed a new stack frame, or it terminated execution. - // Either way, `loc` will not be updated. - return Ok(()); - } - }; - Ok(()) - } - - /// Pops the current frame from the stack, deallocating the - /// memory for allocated locals. - /// - /// If `unwinding` is `false`, then we are performing a normal return - /// from a function. In this case, we jump back into the frame of the caller, - /// and continue execution as normal. - /// - /// If `unwinding` is `true`, then we are in the middle of a panic, - /// and need to unwind this frame. In this case, we jump to the - /// `cleanup` block for the function, which is responsible for running - /// `Drop` impls for any locals that have been initialized at this point. - /// The cleanup block ends with a special `Resume` terminator, which will - /// cause us to continue unwinding. - #[instrument(skip(self), level = "debug")] - pub(super) fn pop_stack_frame(&mut self, unwinding: bool) -> InterpResult<'tcx> { - info!( - "popping stack frame ({})", - if unwinding { "during unwinding" } else { "returning from function" } - ); - - // Check `unwinding`. - assert_eq!( - unwinding, - match self.frame().loc { - Left(loc) => self.body().basic_blocks[loc.block].is_cleanup, - Right(_) => true, - } - ); - if unwinding && self.frame_idx() == 0 { - throw_ub_custom!(fluent::const_eval_unwind_past_top); - } - - M::before_stack_pop(self, self.frame())?; - - // Copy return value. Must of course happen *before* we deallocate the locals. - let copy_ret_result = if !unwinding { - let op = self - .local_to_op(mir::RETURN_PLACE, None) - .expect("return place should always be live"); - let dest = self.frame().return_place.clone(); - let err = if self.stack().len() == 1 { - // The initializer of constants and statics will get validated separately - // after the constant has been fully evaluated. While we could fall back to the default - // code path, that will cause -Zenforce-validity to cycle on static initializers. - // Reading from a static's memory is not allowed during its evaluation, and will always - // trigger a cycle error. Validation must read from the memory of the current item. - // For Miri this means we do not validate the root frame return value, - // but Miri anyway calls `read_target_isize` on that so separate validation - // is not needed. - self.copy_op_no_dest_validation(&op, &dest) - } else { - self.copy_op_allow_transmute(&op, &dest) - }; - trace!("return value: {:?}", self.dump_place(&dest.into())); - // We delay actually short-circuiting on this error until *after* the stack frame is - // popped, since we want this error to be attributed to the caller, whose type defines - // this transmute. - err - } else { - Ok(()) - }; - - // Cleanup: deallocate locals. - // Usually we want to clean up (deallocate locals), but in a few rare cases we don't. - // We do this while the frame is still on the stack, so errors point to the callee. - let return_to_block = self.frame().return_to_block; - let cleanup = match return_to_block { - StackPopCleanup::Goto { .. } => true, - StackPopCleanup::Root { cleanup, .. } => cleanup, - }; - if cleanup { - // We need to take the locals out, since we need to mutate while iterating. - let locals = mem::take(&mut self.frame_mut().locals); - for local in &locals { - self.deallocate_local(local.value)?; - } - } - - // All right, now it is time to actually pop the frame. - // Note that its locals are gone already, but that's fine. - let frame = - self.stack_mut().pop().expect("tried to pop a stack frame, but there were none"); - // Report error from return value copy, if any. - copy_ret_result?; - - // If we are not doing cleanup, also skip everything else. - if !cleanup { - assert!(self.stack().is_empty(), "only the topmost frame should ever be leaked"); - assert!(!unwinding, "tried to skip cleanup during unwinding"); - // Skip machine hook. - return Ok(()); - } - if M::after_stack_pop(self, frame, unwinding)? == StackPopJump::NoJump { - // The hook already did everything. - return Ok(()); - } - - // Normal return, figure out where to jump. - if unwinding { - // Follow the unwind edge. - let unwind = match return_to_block { - StackPopCleanup::Goto { unwind, .. } => unwind, - StackPopCleanup::Root { .. } => { - panic!("encountered StackPopCleanup::Root when unwinding!") - } - }; - // This must be the very last thing that happens, since it can in fact push a new stack frame. - self.unwind_to_block(unwind) - } else { - // Follow the normal return edge. - match return_to_block { - StackPopCleanup::Goto { ret, .. } => self.return_to_block(ret), - StackPopCleanup::Root { .. } => { - assert!( - self.stack().is_empty(), - "only the topmost frame can have StackPopCleanup::Root" - ); - Ok(()) - } - } - } - } - - /// In the current stack frame, mark all locals as live that are not arguments and don't have - /// `Storage*` annotations (this includes the return place). - pub fn storage_live_for_always_live_locals(&mut self) -> InterpResult<'tcx> { - self.storage_live(mir::RETURN_PLACE)?; - - let body = self.body(); - let always_live = always_storage_live_locals(body); - for local in body.vars_and_temps_iter() { - if always_live.contains(local) { - self.storage_live(local)?; - } - } - Ok(()) - } - - pub fn storage_live_dyn( - &mut self, - local: mir::Local, - meta: MemPlaceMeta, - ) -> InterpResult<'tcx> { - trace!("{:?} is now live", local); - - // We avoid `ty.is_trivially_sized` since that does something expensive for ADTs. - fn is_very_trivially_sized(ty: Ty<'_>) -> bool { - match ty.kind() { - ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) - | ty::Uint(_) - | ty::Int(_) - | ty::Bool - | ty::Float(_) - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::RawPtr(..) - | ty::Char - | ty::Ref(..) - | ty::Coroutine(..) - | ty::CoroutineWitness(..) - | ty::Array(..) - | ty::Closure(..) - | ty::CoroutineClosure(..) - | ty::Never - | ty::Error(_) - | ty::Dynamic(_, _, ty::DynStar) => true, - - ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => false, - - ty::Tuple(tys) => tys.last().iter().all(|ty| is_very_trivially_sized(**ty)), - - // We don't want to do any queries, so there is not much we can do with ADTs. - ty::Adt(..) => false, - - ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => false, - - ty::Infer(ty::TyVar(_)) => false, - - ty::Bound(..) - | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { - bug!("`is_very_trivially_sized` applied to unexpected type: {}", ty) - } - } - } - - // This is a hot function, we avoid computing the layout when possible. - // `unsized_` will be `None` for sized types and `Some(layout)` for unsized types. - let unsized_ = if is_very_trivially_sized(self.body().local_decls[local].ty) { - None - } else { - // We need the layout. - let layout = self.layout_of_local(self.frame(), local, None)?; - if layout.is_sized() { None } else { Some(layout) } - }; - - let local_val = LocalValue::Live(if let Some(layout) = unsized_ { - if !meta.has_meta() { - throw_unsup!(UnsizedLocal); - } - // Need to allocate some memory, since `Immediate::Uninit` cannot be unsized. - let dest_place = self.allocate_dyn(layout, MemoryKind::Stack, meta)?; - Operand::Indirect(*dest_place.mplace()) - } else { - assert!(!meta.has_meta()); // we're dropping the metadata - // Just make this an efficient immediate. - // Note that not calling `layout_of` here does have one real consequence: - // if the type is too big, we'll only notice this when the local is actually initialized, - // which is a bit too late -- we should ideally notice this already here, when the memory - // is conceptually allocated. But given how rare that error is and that this is a hot function, - // we accept this downside for now. - Operand::Immediate(Immediate::Uninit) - }); - - // StorageLive expects the local to be dead, and marks it live. - let old = mem::replace(&mut self.frame_mut().locals[local].value, local_val); - if !matches!(old, LocalValue::Dead) { - throw_ub_custom!(fluent::const_eval_double_storage_live); - } - Ok(()) - } - - /// Mark a storage as live, killing the previous content. - #[inline(always)] - pub fn storage_live(&mut self, local: mir::Local) -> InterpResult<'tcx> { - self.storage_live_dyn(local, MemPlaceMeta::None) - } - - pub fn storage_dead(&mut self, local: mir::Local) -> InterpResult<'tcx> { - assert!(local != mir::RETURN_PLACE, "Cannot make return place dead"); - trace!("{:?} is now dead", local); - - // It is entirely okay for this local to be already dead (at least that's how we currently generate MIR) - let old = mem::replace(&mut self.frame_mut().locals[local].value, LocalValue::Dead); - self.deallocate_local(old)?; - Ok(()) - } - - #[instrument(skip(self), level = "debug")] - fn deallocate_local(&mut self, local: LocalValue) -> InterpResult<'tcx> { - if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local { - // All locals have a backing allocation, even if the allocation is empty - // due to the local having ZST type. Hence we can `unwrap`. - trace!( - "deallocating local {:?}: {:?}", - local, - // Locals always have a `alloc_id` (they are never the result of a int2ptr). - self.dump_alloc(ptr.provenance.unwrap().get_alloc_id().unwrap()) - ); - self.deallocate_ptr(ptr, None, MemoryKind::Stack)?; - }; - Ok(()) - } - - /// Call a query that can return `ErrorHandled`. Should be used for statics and other globals. - /// (`mir::Const`/`ty::Const` have `eval` methods that can be used directly instead.) - pub fn ctfe_query( - &self, - query: impl FnOnce(TyCtxtAt<'tcx>) -> Result, - ) -> Result { - // Use a precise span for better cycle errors. - query(self.tcx.at(self.cur_span())).map_err(|err| { - err.emit_note(*self.tcx); - err - }) - } - - pub fn eval_global( - &self, - instance: ty::Instance<'tcx>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { - let gid = GlobalId { instance, promoted: None }; - let val = if self.tcx.is_static(gid.instance.def_id()) { - let alloc_id = self.tcx.reserve_and_set_static_alloc(gid.instance.def_id()); - - let ty = instance.ty(self.tcx.tcx, self.param_env); - mir::ConstAlloc { alloc_id, ty } - } else { - self.ctfe_query(|tcx| tcx.eval_to_allocation_raw(self.param_env.and(gid)))? - }; - self.raw_const_to_mplace(val) - } - - pub fn eval_mir_constant( - &self, - val: &mir::Const<'tcx>, - span: Span, - layout: Option>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { - M::eval_mir_constant(self, *val, span, layout, |ecx, val, span, layout| { - let const_val = val.eval(*ecx.tcx, ecx.param_env, span).map_err(|err| { - // FIXME: somehow this is reachable even when POST_MONO_CHECKS is on. - // Are we not always populating `required_consts`? - err.emit_note(*ecx.tcx); - err - })?; - ecx.const_val_to_op(const_val, val.ty(), layout) - }) - } - - #[must_use] - pub fn dump_place( - &self, - place: &PlaceTy<'tcx, M::Provenance>, - ) -> PlacePrinter<'_, 'mir, 'tcx, M> { - PlacePrinter { ecx: self, place: *place.place() } - } - - #[must_use] - pub fn generate_stacktrace(&self) -> Vec> { - Frame::generate_stacktrace_from_stack(self.stack()) - } -} - -#[doc(hidden)] -/// Helper struct for the `dump_place` function. -pub struct PlacePrinter<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> { - ecx: &'a InterpCx<'mir, 'tcx, M>, - place: Place, -} - -impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> std::fmt::Debug - for PlacePrinter<'a, 'mir, 'tcx, M> -{ - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self.place { - Place::Local { local, offset, locals_addr } => { - debug_assert_eq!(locals_addr, self.ecx.frame().locals_addr()); - let mut allocs = Vec::new(); - write!(fmt, "{local:?}")?; - if let Some(offset) = offset { - write!(fmt, "+{:#x}", offset.bytes())?; - } - write!(fmt, ":")?; - - match self.ecx.frame().locals[local].value { - LocalValue::Dead => write!(fmt, " is dead")?, - LocalValue::Live(Operand::Immediate(Immediate::Uninit)) => { - write!(fmt, " is uninitialized")? - } - LocalValue::Live(Operand::Indirect(mplace)) => { - write!( - fmt, - " by {} ref {:?}:", - match mplace.meta { - MemPlaceMeta::Meta(meta) => format!(" meta({meta:?})"), - MemPlaceMeta::None => String::new(), - }, - mplace.ptr, - )?; - allocs.extend(mplace.ptr.provenance.map(Provenance::get_alloc_id)); - } - LocalValue::Live(Operand::Immediate(Immediate::Scalar(val))) => { - write!(fmt, " {val:?}")?; - if let Scalar::Ptr(ptr, _size) = val { - allocs.push(ptr.provenance.get_alloc_id()); - } - } - LocalValue::Live(Operand::Immediate(Immediate::ScalarPair(val1, val2))) => { - write!(fmt, " ({val1:?}, {val2:?})")?; - if let Scalar::Ptr(ptr, _size) = val1 { - allocs.push(ptr.provenance.get_alloc_id()); - } - if let Scalar::Ptr(ptr, _size) = val2 { - allocs.push(ptr.provenance.get_alloc_id()); - } - } - } - - write!(fmt, ": {:?}", self.ecx.dump_allocs(allocs.into_iter().flatten().collect())) - } - Place::Ptr(mplace) => match mplace.ptr.provenance.and_then(Provenance::get_alloc_id) { - Some(alloc_id) => { - write!(fmt, "by ref {:?}: {:?}", mplace.ptr, self.ecx.dump_alloc(alloc_id)) - } - ptr => write!(fmt, " integral by ref: {ptr:?}"), - }, - } - } -} +use std::cell::Cell;use std::{fmt,mem};use either::{Either,Left,Right};use hir// +::CRATE_HIR_ID;use rustc_errors::DiagCtxt;use rustc_hir::{self as hir,def_id::// +DefId,definitions::DefPathData};use rustc_index::IndexVec;use rustc_middle::mir +;use rustc_middle::mir:: interpret::{CtfeProvenance,ErrorHandled,InvalidMetaKind +,ReportedErrorInfo,};use rustc_middle::query::TyCtxtAt;use rustc_middle::ty:://; +layout::{self,FnAbiError,FnAbiOfHelpers,FnAbiRequest,LayoutError,LayoutOf,//{;}; +LayoutOfHelpers,TyAndLayout,};use rustc_middle::ty::{self,GenericArgsRef,//({}); +ParamEnv,Ty,TyCtxt,TypeFoldable,Variance};use rustc_mir_dataflow::storage:://(); +always_storage_live_locals;use rustc_session::Limit;use rustc_span::Span;use//3; +rustc_target::abi::{call::FnAbi,Align,HasDataLayout,Size,TargetDataLayout};use// +super::{GlobalId,Immediate,InterpErrorInfo,InterpResult,MPlaceTy,Machine,//({}); +MemPlace,MemPlaceMeta,Memory,MemoryKind,OpTy,Operand,Place,PlaceTy,Pointer,//(); +PointerArithmetic,Projectable,Provenance,Scalar,StackPopJump,};use crate:://{;}; +errors;use crate::util;use crate::{fluent_generated as fluent,ReportErrorExt};// +pub struct InterpCx<'mir,'tcx,M:Machine<'mir,'tcx>>{pub machine:M,pub tcx://{;}; +TyCtxtAt<'tcx>,pub(crate)param_env:ty::ParamEnv<'tcx>,pub memory:Memory<'mir,//; +'tcx,M>,pub recursion_limit:Limit,} struct SpanGuard(tracing::Span,std::marker:: +PhantomData<*const u8>);impl SpanGuard{fn new()->Self{Self(tracing::Span::none( +),std::marker::PhantomData)}fn enter(&mut self,span:tracing::Span){3;*self=Self( +span,std::marker::PhantomData);;self.0.with_subscriber(|(id,dispatch)|{dispatch. +enter(id);({});});({});}}impl Drop for SpanGuard{fn drop(&mut self){({});self.0. +with_subscriber(|(id,dispatch)|{;dispatch.exit(id);;});;}}pub struct Frame<'mir, +'tcx,Prov:Provenance=CtfeProvenance,Extra=()>{pub body:&'mir mir::Body<'tcx>,//; +pub instance:ty::Instance<'tcx>,pub extra:Extra,pub return_to_block://if true{}; +StackPopCleanup,pub return_place:MPlaceTy<'tcx,Prov>,pub locals:IndexVec>,tracing_span:SpanGuard,pub loc:Either,}#[derive(Clone,Debug)]pub struct FrameInfo<'tcx>{pub instance:// +ty::Instance<'tcx>,pub span:Span,}#[derive(Clone,Copy,Eq,PartialEq,Debug)]pub//; +enum StackPopCleanup{Goto{ret:Option< mir::BasicBlock>,unwind:mir::UnwindAction} +,Root{cleanup:bool},}#[derive( Clone)]pub struct LocalState<'tcx,Prov:Provenance +=CtfeProvenance>{value:LocalValue, layout:Cell>>, +}implstd::fmt::Debug for LocalState<'_,Prov>{fn fmt(&self,f:&// +mut std::fmt::Formatter<'_>)->std::fmt::Result{(f.debug_struct(("LocalState"))). +field("value",&self.value).field("ty",&self. layout.get().map(|l|l.ty)).finish() +}}#[derive(Copy,Clone,Debug)]pub(super)enum LocalValue{Dead,Live(Operand) ,}impl<'tcx,Prov:Provenance>LocalState< +'tcx,Prov>{pub fn make_live_uninit(&mut self){{();};self.value=LocalValue::Live( +Operand::Immediate(Immediate::Uninit));;}pub fn as_mplace_or_imm(&self,)->Option +>,MemPlaceMeta< Prov>),Immediate>>{match self +.value{LocalValue::Dead=>None,LocalValue:: Live(Operand::Indirect(mplace))=>Some +((Left(((mplace.ptr,mplace.meta))))),LocalValue::Live(Operand::Immediate(imm))=> +Some((Right(imm))),}}#[inline( always)]pub(super)fn access(&self)->InterpResult< +'tcx,&Operand>{match(&self.value ){LocalValue::Dead=>throw_ub!(DeadLocal), +LocalValue::Live(val)=>(Ok(val)),}}#[inline(always)]pub(super)fn access_mut(&mut +self)->InterpResult<'tcx,&mut Operand>{match(&mut self.value){LocalValue:: +Dead=>(throw_ub!(DeadLocal)),LocalValue::Live(val)=>(Ok(val)),}}}impl<'mir,'tcx, +Prov:Provenance>Frame<'mir,'tcx,Prov>{ pub fn with_extra(self,extra:Extra +)->Frame<'mir,'tcx,Prov,Extra>{Frame{body:self.body,instance:self.instance,//(); +return_to_block:self.return_to_block,return_place :self.return_place,locals:self +.locals,loc:self.loc,extra,tracing_span:self.tracing_span,}}}impl<'mir,'tcx,//3; +Prov:Provenance,Extra>Frame<'mir,'tcx,Prov,Extra>{pub fn current_loc(&self)->//; +Either{self.loc} pub fn current_source_info(&self)->Option<& +mir::SourceInfo>{((self.loc.left()).map(|loc|self.body.source_info(loc)))}pub fn +current_span(&self)->Span{match self.loc{Left (loc)=>self.body.source_info(loc). +span,Right(span)=>span,}}pub fn lint_root(&self)->Option{self.//{;}; +current_source_info().and_then(|source_info|{match&self.body.source_scopes[//(); +source_info.scope].local_data{mir::ClearCrossCrate::Set(data)=>Some(data.//({}); +lint_root),mir::ClearCrossCrate::Clear=>None,}})}#[inline(always)]pub(super)fn// +locals_addr(&self)->usize{((self.locals.raw. as_ptr()).addr())}#[must_use]pub fn +generate_stacktrace_from_stack(stack:&[Self])->Vec>{({});let mut +frames=Vec::new();;for frame in stack.iter().rev(){let span=match frame.loc{Left +(loc)=>{3;let mir::SourceInfo{mut span,scope}=*frame.body.source_info(loc);;;let +mut scope_data=&frame.body.source_scopes[scope];*&*&();while let Some((instance, +call_span))=scope_data.inlined{3;frames.push(FrameInfo{span,instance});3;3;span= +call_span;;scope_data=&frame.body.source_scopes[scope_data.parent_scope.unwrap() +];;}span}Right(span)=>span,};frames.push(FrameInfo{span,instance:frame.instance} +);;};trace!("generate stacktrace: {:#?}",frames);;frames}}impl<'tcx>fmt::Display +for FrameInfo<'tcx>{fn fmt(&self,f:&mut fmt::Formatter<'_>)->fmt::Result{ty:://; +tls::with(|tcx|{if (tcx.def_key(self.instance.def_id())).disambiguated_data.data +==DefPathData::Closure{(write!(f,"inside closure"))}else{write!(f,"inside `{}`", +self.instance)}})}}impl<'tcx>FrameInfo<'tcx>{pub fn as_note(&self,tcx:TyCtxt)->errors::FrameNote{();let span=self.span;();if tcx.def_key(self.instance. +def_id()).disambiguated_data.data==DefPathData::Closure{errors::FrameNote{//{;}; +where_:"closure",span,instance:String::new(),times:0}}else{;let instance=format! +("{}",self.instance);;errors::FrameNote{where_:"instance",span,instance,times:0} +}}}impl<'mir,'tcx,M:Machine<'mir, 'tcx>>HasDataLayout for InterpCx<'mir,'tcx,M>{ +#[inline]fn data_layout(&self)->&TargetDataLayout{(&self.tcx.data_layout)}}impl< +'mir,'tcx,M>layout::HasTyCtxt<'tcx>for InterpCx<'mir,'tcx,M>where M:Machine,{#[inline]fn tcx(&self)->TyCtxt <'tcx>{(*self.tcx)}}impl<'mir,'tcx,M> +layout::HasParamEnv<'tcx>for InterpCx<'mir,'tcx,M>where M:Machine<'mir,'tcx>,{// +fn param_env(&self)->ty::ParamEnv<'tcx>{self.param_env}}impl<'mir,'tcx:'mir,M:// +Machine<'mir,'tcx>>LayoutOfHelpers<'tcx>for InterpCx<'mir,'tcx,M>{type//((),()); +LayoutOfResult=InterpResult<'tcx,TyAndLayout<'tcx>>;#[inline]fn//*&*&();((),()); +layout_tcx_at_span(&self)->Span{self.tcx.span}#[inline]fn handle_layout_err(&//; +self,err:LayoutError<'tcx>,_:Span,_: Ty<'tcx>,)->InterpErrorInfo<'tcx>{err_inval +!(Layout(err)).into()}}impl <'mir,'tcx:'mir,M:Machine<'mir,'tcx>>FnAbiOfHelpers< +'tcx>for InterpCx<'mir,'tcx,M> {type FnAbiOfResult=InterpResult<'tcx,&'tcx FnAbi +<'tcx,Ty<'tcx>>>;fn handle_fn_abi_err(&self,err:FnAbiError<'tcx>,_span:Span,//3; +_fn_abi_request:FnAbiRequest<'tcx>,)->InterpErrorInfo<'tcx>{match err{//((),()); +FnAbiError::Layout(err)=>((((((err_inval!(Layout(err))))).into()))),FnAbiError:: +AdjustForForeignAbi(err)=>{err_inval!(FnAbiAdjustForForeignAbi( err)).into()}}}} +pub(super)fn mir_assign_valid_types<'tcx>(tcx:TyCtxt<'tcx>,param_env:ParamEnv,src:TyAndLayout<'tcx>,dest:TyAndLayout<'tcx>,)->bool{if util:://if true{}; +relate_types(tcx,param_env,Variance::Covariant,src.ty,dest.ty){if cfg!(//*&*&(); +debug_assertions)||src.ty!=dest.ty{3;assert_eq!(src.layout,dest.layout);3;}true} +else{(((false)))}}#[cfg_attr(not( debug_assertions),inline(always))]pub(super)fn +from_known_layout<'tcx>(tcx:TyCtxtAt<'tcx>,param_env:ParamEnv<'tcx>,//if true{}; +known_layout:Option>,compute :impl FnOnce()->InterpResult<'tcx +,TyAndLayout<'tcx>>,)->InterpResult< 'tcx,TyAndLayout<'tcx>>{match known_layout{ +None=>compute(),Some(known_layout)=>{if cfg!(debug_assertions){;let check_layout +=compute()?;let _=||();if!mir_assign_valid_types(tcx.tcx,param_env,check_layout, +known_layout){let _=||();loop{break};loop{break};loop{break};span_bug!(tcx.span, +"expected type differs from actual type.\nexpected: {}\nactual: {}",//if true{}; +known_layout.ty,check_layout.ty,);let _=();if true{};}}Ok(known_layout)}}}pub fn +format_interp_error<'tcx>(dcx:&DiagCtxt,e:InterpErrorInfo<'tcx>)->String{;let(e, +backtrace)=e.into_parts();();();backtrace.print_backtrace();();3;#[allow(rustc:: +untranslatable_diagnostic)]let mut diag=dcx.struct_allow("");({});{;};let msg=e. +diagnostic_message();*&*&();*&*&();e.add_args(&mut diag);*&*&();{();};let s=dcx. +eagerly_translate_to_string(msg,diag.args.iter());3;;diag.cancel();;s}impl<'mir, +'tcx:'mir,M:Machine<'mir,'tcx>>InterpCx<'mir, 'tcx,M>{pub fn new(tcx:TyCtxt<'tcx +>,root_span:Span,param_env:ty::ParamEnv<'tcx>,machine:M,)->Self{InterpCx{//({}); +machine,tcx:(tcx.at(root_span)),param_env ,memory:Memory::new(),recursion_limit: +tcx.recursion_limit(),}}#[inline(always)]pub fn cur_span(&self)->Span{self.//(); +stack().last().map_or(self.tcx.span,(| f|f.current_span()))}#[inline(always)]pub +fn best_lint_scope(&self)->hir::HirId{self. stack().iter().find_map(|frame|frame +.body.source.def_id().as_local()).map_or(CRATE_HIR_ID,|def_id|self.tcx.//*&*&(); +local_def_id_to_hir_id(def_id))}#[inline(always)]pub(crate)fn stack(&self)->&[// +Frame<'mir,'tcx,M::Provenance,M::FrameExtra>]{(M::stack(self))}#[inline(always)] +pub(crate)fn stack_mut(&mut self,)->&mut Vec>{M::stack_mut(self)}#[inline (always)]pub fn frame_idx(&self)->usize +{3;let stack=self.stack();3;;assert!(!stack.is_empty());;stack.len()-1}#[inline( +always)]pub fn frame(&self)->&Frame< 'mir,'tcx,M::Provenance,M::FrameExtra>{self +.stack().last().expect(((((("no call frames exist"))))))}#[inline(always)]pub fn +frame_mut(&mut self)->&mut Frame<'mir,'tcx,M::Provenance,M::FrameExtra>{self.//; +stack_mut().last_mut().expect(("no call frames exist" ))}#[inline(always)]pub fn +body(&self)->&'mir mir::Body<'tcx>{((self.frame())).body}#[inline(always)]pub fn +sign_extend(&self,value:u128,ty:TyAndLayout<'_>)->u128{;assert!(ty.abi.is_signed +());{;};ty.size.sign_extend(value)}#[inline(always)]pub fn truncate(&self,value: +u128,ty:TyAndLayout<'_>)->u128{(((((ty.size.truncate(value))))))}#[inline]pub fn +type_is_freeze(&self,ty:Ty<'tcx>)->bool{ ty.is_freeze(*self.tcx,self.param_env)} +pub fn load_mir(&self,instance:ty::InstanceDef<'tcx>,promoted:Option,)->InterpResult<'tcx,&'tcx mir::Body<'tcx>>{let _=();if true{};trace!( +"load mir(instance={:?}, promoted={:?})",instance,promoted);();3;let body=if let +Some(promoted)=promoted{;let def=instance.def_id();;&self.tcx.promoted_mir(def)[ +promoted]}else{M::load_mir(self,instance)?};if let _=(){};if let Some(err)=body. +tainted_by_errors{if let _=(){};throw_inval!(AlreadyReported(ReportedErrorInfo:: +tainted_by_errors(err)));((),());((),());((),());let _=();}Ok(body)}pub(super)fn +instantiate_from_current_frame_and_normalize_erasing_regions>,>(&self,value:T,)->Result{self.//((),());let _=(); +instantiate_from_frame_and_normalize_erasing_regions((self.frame() ),value)}pub( +super)fn instantiate_from_frame_and_normalize_erasing_regions>,>(&self,frame:&Frame <'mir,'tcx,M::Provenance,M::FrameExtra>,value +:T,)->Result{frame.instance.//((),());let _=();((),());let _=(); +try_instantiate_mir_and_normalize_erasing_regions(*self.tcx ,self.param_env,ty:: +EarlyBinder::bind(value),).map_err(|_ |ErrorHandled::TooGeneric(self.cur_span()) +)}pub(super)fn resolve(&self,def:DefId,args:GenericArgsRef<'tcx>,)->//if true{}; +InterpResult<'tcx,ty::Instance<'tcx>>{;trace!("resolve: {:?}, {:#?}",def,args);; +trace!("param_env: {:#?}",self.param_env);;trace!("args: {:#?}",args);match ty:: +Instance::resolve(((*self.tcx)),self.param_env,def,args){Ok(Some(instance))=>Ok( +instance),Ok(None)=>throw_inval!( TooGeneric),Err(error_reported)=>throw_inval!( +AlreadyReported(error_reported.into())),}}pub(crate)fn//loop{break};loop{break}; +find_closest_untracked_caller_location(&self)->Span{for frame in (self.stack()). +iter().rev(){*&*&();((),());*&*&();((),());*&*&();((),());*&*&();((),());debug!( +"find_closest_untracked_caller_location: checking frame {:?}",frame.instance);;; +let loc=frame.loc.left().unwrap();;;let mut source_info=*frame.body.source_info( +loc);3;3;let block=&frame.body.basic_blocks[loc.block];;if loc.statement_index== +block.statements.len(){loop{break};loop{break;};loop{break};loop{break;};debug!( +"find_closest_untracked_caller_location: got terminator {:?} ({:?})",block.//(); +terminator(),block.terminator().kind,);;if let mir::TerminatorKind::Call{fn_span +,..}=block.terminator().kind{;source_info.span=fn_span;}}let caller_location=if +frame.instance.def.requires_caller_location(*self.tcx){ Some(Err(()))}else{None} +;3;if let Ok(span)=frame.body.caller_location_span(source_info,caller_location,* +self.tcx,Ok){if let _=(){};return span;loop{break;};}}span_bug!(self.cur_span(), +"no non-`#[track_caller]` frame found")}#[inline(always)]pub(super)fn//let _=(); +layout_of_local(&self,frame:&Frame<'mir, 'tcx,M::Provenance,M::FrameExtra>,local +:mir::Local,layout:Option>,)->InterpResult<'tcx,TyAndLayout>{;let state=&frame.locals[local];;if let Some(layout)=state.layout.get(){; +return Ok(layout);;}let layout=from_known_layout(self.tcx,self.param_env,layout, +||{({});let local_ty=frame.body.local_decls[local].ty;{;};{;};let local_ty=self. +instantiate_from_frame_and_normalize_erasing_regions(frame,local_ty)?;({});self. +layout_of(local_ty)})?;;;state.layout.set(Some(layout));;Ok(layout)}pub(super)fn +size_and_align_of(&self,metadata:&MemPlaceMeta,layout:&//((),()); +TyAndLayout<'tcx>,)->InterpResult<'tcx,Option< (Size,Align)>>{if layout.is_sized +(){;return Ok(Some((layout.size,layout.align.abi)));}match layout.ty.kind(){ty:: +Adt(..)|ty::Tuple(..)=>{3;assert!(!layout.ty.is_simd());;;assert!(layout.fields. +count()>0);3;;trace!("DST layout: {:?}",layout);;;let unsized_offset_unadjusted= +layout.fields.offset(layout.fields.count()-1);;let sized_align=layout.align.abi; +let field=layout.field(self,layout.fields.count()-1);;let Some((unsized_size,mut +unsized_align))=self.size_and_align_of(metadata,&field)?else{;return Ok(None);;} +;3;if let ty::Adt(def,_)=layout.ty.kind(){if let Some(packed)=def.repr().pack{3; +unsized_align=unsized_align.min(packed);{;};}}();let full_align=sized_align.max( +unsized_align);;;let unsized_offset_adjusted=unsized_offset_unadjusted.align_to( +unsized_align);3;;let full_size=(unsized_offset_adjusted+unsized_size).align_to( +full_align);();();assert_eq!(full_size,(unsized_offset_unadjusted+unsized_size). +align_to(full_align));;if full_size>self.max_size_of_val(){throw_ub!(InvalidMeta +(InvalidMetaKind::TooBig));;}Ok(Some((full_size,full_align)))}ty::Dynamic(_,_,ty +::Dyn)=>{();let vtable=metadata.unwrap_meta().to_pointer(self)?;();Ok(Some(self. +get_vtable_size_and_align(vtable)?))}ty::Slice(_)|ty::Str=>{();let len=metadata. +unwrap_meta().to_target_usize(self)?;;;let elem=layout.field(self,0);;;let size= +elem.size.bytes().saturating_mul(len);;;let size=Size::from_bytes(size);if size> +self.max_size_of_val(){;throw_ub!(InvalidMeta(InvalidMetaKind::SliceTooBig));}Ok +((Some(((size,elem.align.abi)))))}ty ::Foreign(_)=>(Ok(None)),_=>span_bug!(self. +cur_span(),"size_and_align_of::<{}> not supported",layout.ty) ,}}#[inline]pub fn +size_and_align_of_mplace(&self,mplace:&MPlaceTy<'tcx,M::Provenance>,)->//*&*&(); +InterpResult<'tcx,Option<(Size,Align)>>{self .size_and_align_of(&mplace.meta(),& +mplace.layout)}#[instrument(skip (self,body,return_place,return_to_block),level= +"debug")]pub fn push_stack_frame(&mut self,instance:ty::Instance<'tcx>,body:&//; +'mir mir::Body<'tcx>,return_place: &MPlaceTy<'tcx,M::Provenance>,return_to_block +:StackPopCleanup,)->InterpResult<'tcx>{{;};trace!("body: {:#?}",body);{;};();let +dead_local=LocalState{value:LocalValue::Dead,layout:Cell::new(None)};;let locals +=IndexVec::from_elem(dead_local,&body.local_decls);;let pre_frame=Frame{body,loc +:(Right(body.span)),return_to_block, return_place:(return_place.clone()),locals, +instance,tracing_span:SpanGuard::new(),extra:(),};;let frame=M::init_frame_extra +(self,pre_frame)?;3;3;self.stack_mut().push(frame);3;if M::POST_MONO_CHECKS{for& +const_ in&body.required_consts{let _=();if true{};let _=();if true{};let c=self. +instantiate_from_current_frame_and_normalize_erasing_regions(const_.const_)?;;c. +eval(*self.tcx,self.param_env,const_.span).map_err(|err|{();err.emit_note(*self. +tcx);3;err})?;3;}}3;M::after_stack_push(self)?;;;self.frame_mut().loc=Left(mir:: +Location::START);;;let span=info_span!("frame","{}",instance);;self.frame_mut(). +tracing_span.enter(span);();Ok(())}#[inline]pub fn go_to_block(&mut self,target: +mir::BasicBlock){if true{};self.frame_mut().loc=Left(mir::Location{block:target, +statement_index:0});*&*&();}pub fn return_to_block(&mut self,target:Option)->InterpResult<'tcx>{if let Some(target)=target{();self.go_to_block( +target);3;Ok(())}else{throw_ub!(Unreachable)}}#[cold]pub fn unwind_to_block(&mut +self,target:mir::UnwindAction)->InterpResult<'tcx>{();self.frame_mut().loc=match +target{mir::UnwindAction::Cleanup(block)=>Left(mir::Location{block,//let _=||(); +statement_index:(0)}),mir::UnwindAction:: Continue=>Right(self.frame_mut().body. +span),mir::UnwindAction::Unreachable=>{((),());((),());throw_ub_custom!(fluent:: +const_eval_unreachable_unwind);3;}mir::UnwindAction::Terminate(reason)=>{3;self. +frame_mut().loc=Right(self.frame_mut().body.span);();3;M::unwind_terminate(self, +reason)?;;;return Ok(());;}};;Ok(())}#[instrument(skip(self),level="debug")]pub( +super)fn pop_stack_frame(&mut self,unwinding:bool)->InterpResult<'tcx>{();info!( +"popping stack frame ({})",if unwinding{"during unwinding"}else{//if let _=(){}; +"returning from function"});3;;assert_eq!(unwinding,match self.frame().loc{Left( +loc)=>self.body().basic_blocks[loc.block].is_cleanup,Right(_)=>true,});{();};if +unwinding&&self.frame_idx()==0{loop{break};loop{break};throw_ub_custom!(fluent:: +const_eval_unwind_past_top);3;}3;M::before_stack_pop(self,self.frame())?;3;3;let +copy_ret_result=if!unwinding{();let op=self.local_to_op(mir::RETURN_PLACE,None). +expect("return place should always be live");;let dest=self.frame().return_place +.clone();;let err=if self.stack().len()==1{self.copy_op_no_dest_validation(&op,& +dest)}else{self.copy_op_allow_transmute(&op,&dest)};;trace!("return value: {:?}" +,self.dump_place(&dest.into()));;err}else{Ok(())};let return_to_block=self.frame +().return_to_block;;;let cleanup=match return_to_block{StackPopCleanup::Goto{..} +=>true,StackPopCleanup::Root{cleanup,..}=>cleanup,};;if cleanup{let locals=mem:: +take(&mut self.frame_mut().locals);3;for local in&locals{;self.deallocate_local( +local.value)?;loop{break};}}loop{break};let frame=self.stack_mut().pop().expect( +"tried to pop a stack frame, but there were none");;copy_ret_result?;if!cleanup{ +assert!(self.stack( ).is_empty(),"only the topmost frame should ever be leaked") +;;assert!(!unwinding,"tried to skip cleanup during unwinding");return Ok(());}if +M::after_stack_pop(self,frame,unwinding)?==StackPopJump::NoJump{;return Ok(());; +}if unwinding{;let unwind=match return_to_block{StackPopCleanup::Goto{unwind,..} +=>unwind,StackPopCleanup::Root{..}=>{panic!(//((),());let _=();((),());let _=(); +"encountered StackPopCleanup::Root when unwinding!")}};{;};self.unwind_to_block( +unwind)}else{match return_to_block{StackPopCleanup::Goto{ret,..}=>self.//*&*&(); +return_to_block(ret),StackPopCleanup::Root{..}=>{;assert!(self.stack().is_empty( +),"only the topmost frame can have StackPopCleanup::Root");({});Ok(())}}}}pub fn +storage_live_for_always_live_locals(&mut self)->InterpResult<'tcx>{((),());self. +storage_live(mir::RETURN_PLACE)?;();();let body=self.body();3;3;let always_live= +always_storage_live_locals(body);{;};for local in body.vars_and_temps_iter(){if +always_live.contains(local){{();};self.storage_live(local)?;({});}}Ok(())}pub fn +storage_live_dyn(&mut self,local:mir::Local,meta:MemPlaceMeta,)// +->InterpResult<'tcx>{((),());trace!("{:?} is now live",local);((),());((),());fn +is_very_trivially_sized(ty:Ty<'_>)->bool{match ty.kind(){ty::Infer(ty::IntVar(_ +)|ty::FloatVar(_))|ty::Uint(_)|ty::Int(_)|ty::Bool|ty::Float(_)|ty::FnDef(..)|// +ty::FnPtr(_)|ty::RawPtr(..)|ty::Char|ty::Ref(..)|ty::Coroutine(..)|ty:://*&*&(); +CoroutineWitness(..)|ty::Array(..)|ty::Closure(..)|ty::CoroutineClosure(..)|ty// +::Never|ty::Error(_)|ty::Dynamic(_,_,ty ::DynStar)=>true,ty::Str|ty::Slice(_)|ty +::Dynamic(_,_,ty::Dyn)|ty::Foreign(..)=>false ,ty::Tuple(tys)=>tys.last().iter() +.all((|ty|is_very_trivially_sized(**ty))) ,ty::Adt(..)=>false,ty::Alias(..)|ty:: +Param(_)|ty::Placeholder(..)=>false,ty:: Infer(ty::TyVar(_))=>false,ty::Bound(.. +)|ty::Infer(ty::FreshTy(_)|ty::FreshIntTy(_)|ty::FreshFloatTy(_))=>{bug!(//({}); +"`is_very_trivially_sized` applied to unexpected type: {}",ty)}}};;let unsized_= +if is_very_trivially_sized(self.body().local_decls[local].ty){None}else{({});let +layout=self.layout_of_local(self.frame(),local,None)?;;if layout.is_sized(){None +}else{Some(layout)}};{;};{;};let local_val=LocalValue::Live(if let Some(layout)= +unsized_{if!meta.has_meta(){3;throw_unsup!(UnsizedLocal);;};let dest_place=self. +allocate_dyn(layout,MemoryKind::Stack,meta)?;({});Operand::Indirect(*dest_place. +mplace())}else{;assert!(!meta.has_meta());Operand::Immediate(Immediate::Uninit)} +);;let old=mem::replace(&mut self.frame_mut().locals[local].value,local_val);if! +matches!(old,LocalValue::Dead){loop{break};loop{break};throw_ub_custom!(fluent:: +const_eval_double_storage_live);3;}Ok(())}#[inline(always)]pub fn storage_live(& +mut self,local:mir::Local)->InterpResult<'tcx>{self.storage_live_dyn(local,//(); +MemPlaceMeta::None)}pub fn storage_dead(&mut self,local:mir::Local)->//let _=(); +InterpResult<'tcx>{if let _=(){};if let _=(){};assert!(local!=mir::RETURN_PLACE, +"Cannot make return place dead");;trace!("{:?} is now dead",local);let old=mem:: +replace(&mut self.frame_mut().locals[local].value,LocalValue::Dead);{;};();self. +deallocate_local(old)?;let _=();Ok(())}#[instrument(skip(self),level="debug")]fn +deallocate_local(&mut self,local:LocalValue )->InterpResult<'tcx> +{();if let LocalValue::Live(Operand::Indirect(MemPlace{ptr,..}))=local{3;trace!( +"deallocating local {:?}: {:?}",local,self.dump_alloc(ptr.provenance.unwrap().// +get_alloc_id().unwrap()));;self.deallocate_ptr(ptr,None,MemoryKind::Stack)?;};Ok +(((())))}pub fn ctfe_query(&self,query:impl FnOnce(TyCtxtAt<'tcx>)->Result,)->Result{(query((self.tcx.at(self.cur_span())))). +map_err(|err|{;err.emit_note(*self.tcx);err})}pub fn eval_global(&self,instance: +ty::Instance<'tcx>,)->InterpResult<'tcx,MPlaceTy<'tcx,M::Provenance>>{3;let gid= +GlobalId{instance,promoted:None};3;3;let val=if self.tcx.is_static(gid.instance. +def_id()){{();};let alloc_id=self.tcx.reserve_and_set_static_alloc(gid.instance. +def_id());3;3;let ty=instance.ty(self.tcx.tcx,self.param_env);3;mir::ConstAlloc{ +alloc_id,ty}}else{self.ctfe_query(|tcx|tcx.eval_to_allocation_raw(self.//*&*&(); +param_env.and(gid)))?};;self.raw_const_to_mplace(val)}pub fn eval_mir_constant(& +self,val:&mir::Const<'tcx>,span:Span,layout:Option>,)->//({}); +InterpResult<'tcx,OpTy<'tcx,M::Provenance>>{ M::eval_mir_constant(self,*val,span +,layout,|ecx,val,span,layout|{{;};let const_val=val.eval(*ecx.tcx,ecx.param_env, +span).map_err(|err|{();err.emit_note(*ecx.tcx);();err})?;();ecx.const_val_to_op( +const_val,val.ty(),layout)})} #[must_use]pub fn dump_place(&self,place:&PlaceTy< +'tcx,M::Provenance>,)->PlacePrinter<'_,'mir ,'tcx,M>{PlacePrinter{ecx:self,place +:(*place.place())}}#[ must_use]pub fn generate_stacktrace(&self)->Vec>{(Frame::generate_stacktrace_from_stack(self.stack( )))}}#[doc(hidden)]pub +struct PlacePrinter<'a,'mir,'tcx,M:Machine<'mir,'tcx>>{ecx:&'a InterpCx<'mir,//; +'tcx,M>,place:Place,}impl<'a,'mir,'tcx:'mir,M:Machine<'mir,'tcx// +>>std::fmt::Debug for PlacePrinter<'a,'mir,'tcx,M>{fn fmt(&self,fmt:&mut std::// +fmt::Formatter<'_>)->std::fmt::Result{match self.place{Place::Local{local,//{;}; +offset,locals_addr}=>{;debug_assert_eq!(locals_addr,self.ecx.frame().locals_addr +());;;let mut allocs=Vec::new();;;write!(fmt,"{local:?}")?;;if let Some(offset)= +offset{;write!(fmt,"+{:#x}",offset.bytes())?;;};write!(fmt,":")?;match self.ecx. +frame().locals[local].value{LocalValue::Dead=>(((((write!(fmt," is dead")))?))), +LocalValue::Live(Operand::Immediate(Immediate::Uninit))=>{write!(fmt,//let _=(); +" is uninitialized")?}LocalValue::Live(Operand::Indirect(mplace))=>{;write!(fmt, +" by {} ref {:?}:",match mplace.meta{MemPlaceMeta::Meta(meta)=>format!(//*&*&(); +" meta({meta:?})"),MemPlaceMeta::None=>String::new(),},mplace.ptr,)?;3;3;allocs. +extend(mplace.ptr.provenance.map(Provenance::get_alloc_id));3;}LocalValue::Live( +Operand::Immediate(Immediate::Scalar(val)))=>{3;write!(fmt," {val:?}")?;3;if let +Scalar::Ptr(ptr,_size)=val{{;};allocs.push(ptr.provenance.get_alloc_id());{;};}} +LocalValue::Live(Operand::Immediate(Immediate::ScalarPair(val1,val2)))=>{;write! +(fmt," ({val1:?}, {val2:?})")?;;if let Scalar::Ptr(ptr,_size)=val1{;allocs.push( +ptr.provenance.get_alloc_id());;}if let Scalar::Ptr(ptr,_size)=val2{allocs.push( +ptr.provenance.get_alloc_id());({});}}}write!(fmt,": {:?}",self.ecx.dump_allocs( +allocs.into_iter().flatten().collect()))}Place::Ptr(mplace)=>match mplace.ptr.// +provenance.and_then(Provenance::get_alloc_id){Some(alloc_id)=>{write!(fmt,//{;}; +"by ref {:?}: {:?}",mplace.ptr,self.ecx.dump_alloc(alloc_id))}ptr=>write!(fmt,// +" integral by ref: {ptr:?}"),},}}}//let _=||();let _=||();let _=||();let _=||(); diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index f4e46c9499e27..d9630c45ab087 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -1,340 +1,75 @@ -//! This module specifies the type based interner for constants. -//! -//! After a const evaluation has computed a value, before we destroy the const evaluator's session -//! memory, we need to extract all memory allocations to the global memory pool so they stay around. -//! -//! In principle, this is not very complicated: we recursively walk the final value, follow all the -//! pointers, and move all reachable allocations to the global `tcx` memory. The only complication -//! is picking the right mutability: the outermost allocation generally has a clear mutability, but -//! what about the other allocations it points to that have also been created with this value? We -//! don't want to do guesswork here. The rules are: `static`, `const`, and promoted can only create -//! immutable allocations that way. `static mut` can be initialized with expressions like `&mut 42`, -//! so all inner allocations are marked mutable. Some of them could potentially be made immutable, -//! but that would require relying on type information, and given how many ways Rust has to lie -//! about type information, we want to avoid doing that. - -use hir::def::DefKind; -use rustc_ast::Mutability; -use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; -use rustc_errors::ErrorGuaranteed; -use rustc_hir as hir; -use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; -use rustc_middle::mir::interpret::{ConstAllocation, CtfeProvenance, InterpResult}; -use rustc_middle::query::TyCtxtAt; -use rustc_middle::ty::layout::TyAndLayout; -use rustc_session::lint; -use rustc_span::def_id::LocalDefId; -use rustc_span::sym; - -use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy}; -use crate::const_eval; -use crate::errors::{DanglingPtrInFinal, MutablePtrInFinal}; - -pub trait CompileTimeMachine<'mir, 'tcx: 'mir, T> = Machine< - 'mir, - 'tcx, - MemoryKind = T, - Provenance = CtfeProvenance, - ExtraFnVal = !, - FrameExtra = (), - AllocExtra = (), - MemoryMap = FxIndexMap, Allocation)>, - > + HasStaticRootDefId; - -pub trait HasStaticRootDefId { - /// Returns the `DefId` of the static item that is currently being evaluated. - /// Used for interning to be able to handle nested allocations. - fn static_def_id(&self) -> Option; -} - -impl HasStaticRootDefId for const_eval::CompileTimeInterpreter<'_, '_> { - fn static_def_id(&self) -> Option { - Some(self.static_root_ids?.1) - } -} - -/// Intern an allocation. Returns `Err` if the allocation does not exist in the local memory. -/// -/// `mutability` can be used to force immutable interning: if it is `Mutability::Not`, the -/// allocation is interned immutably; if it is `Mutability::Mut`, then the allocation *must be* -/// already mutable (as a sanity check). -/// -/// Returns an iterator over all relocations referred to by this allocation. -fn intern_shallow<'rt, 'mir, 'tcx, T, M: CompileTimeMachine<'mir, 'tcx, T>>( - ecx: &'rt mut InterpCx<'mir, 'tcx, M>, - alloc_id: AllocId, - mutability: Mutability, -) -> Result + 'tcx, ()> { - trace!("intern_shallow {:?}", alloc_id); - // remove allocation - // FIXME(#120456) - is `swap_remove` correct? - let Some((_kind, mut alloc)) = ecx.memory.alloc_map.swap_remove(&alloc_id) else { - return Err(()); - }; - // Set allocation mutability as appropriate. This is used by LLVM to put things into - // read-only memory, and also by Miri when evaluating other globals that - // access this one. - match mutability { - Mutability::Not => { - alloc.mutability = Mutability::Not; - } - Mutability::Mut => { - // This must be already mutable, we won't "un-freeze" allocations ever. - assert_eq!(alloc.mutability, Mutability::Mut); - } - } - // link the alloc id to the actual allocation - let alloc = ecx.tcx.mk_const_alloc(alloc); - if let Some(static_id) = ecx.machine.static_def_id() { - intern_as_new_static(ecx.tcx, static_id, alloc_id, alloc); - } else { - ecx.tcx.set_alloc_id_memory(alloc_id, alloc); - } - Ok(alloc.0.0.provenance().ptrs().iter().map(|&(_, prov)| prov)) -} - -/// Creates a new `DefId` and feeds all the right queries to make this `DefId` -/// appear as if it were a user-written `static` (though it has no HIR). -fn intern_as_new_static<'tcx>( - tcx: TyCtxtAt<'tcx>, - static_id: LocalDefId, - alloc_id: AllocId, - alloc: ConstAllocation<'tcx>, -) { - let feed = tcx.create_def( - static_id, - sym::nested, - DefKind::Static { mutability: alloc.0.mutability, nested: true }, - ); - tcx.set_nested_alloc_id_static(alloc_id, feed.def_id()); - - // These do not inherit the codegen attrs of the parent static allocation, since - // it doesn't make sense for them to inherit their `#[no_mangle]` and `#[link_name = ..]` - // and the like. - feed.codegen_fn_attrs(CodegenFnAttrs::new()); - - feed.eval_static_initializer(Ok(alloc)); - feed.generics_of(tcx.generics_of(static_id).clone()); - feed.def_ident_span(tcx.def_ident_span(static_id)); - feed.explicit_predicates_of(tcx.explicit_predicates_of(static_id)); - feed.feed_hir(); -} - -/// How a constant value should be interned. -#[derive(Copy, Clone, Debug, PartialEq, Hash, Eq)] -pub enum InternKind { - /// The `mutability` of the static, ignoring the type which may have interior mutability. - Static(hir::Mutability), - /// A `const` item - Constant, - Promoted, -} - -/// Intern `ret` and everything it references. -/// -/// 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. -/// -/// For `InternKind::Static` the root allocation will not be interned, but must be handled by the caller. -#[instrument(level = "debug", skip(ecx))] -pub fn intern_const_alloc_recursive< - 'mir, - 'tcx: 'mir, - M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>, ->( - ecx: &mut InterpCx<'mir, 'tcx, M>, - intern_kind: InternKind, - ret: &MPlaceTy<'tcx>, -) -> Result<(), ErrorGuaranteed> { - // We are interning recursively, and for mutability we are distinguishing the "root" allocation - // that we are starting in, and all other allocations that we are encountering recursively. - let (base_mutability, inner_mutability, is_static) = match intern_kind { - InternKind::Constant | InternKind::Promoted => { - // Completely immutable. Interning anything mutably here can only lead to unsoundness, - // since all consts are conceptually independent values but share the same underlying - // memory. - (Mutability::Not, Mutability::Not, false) - } - InternKind::Static(Mutability::Not) => { - ( - // Outermost allocation is mutable if `!Freeze`. - if ret.layout.ty.is_freeze(*ecx.tcx, ecx.param_env) { - Mutability::Not - } else { - Mutability::Mut - }, - // Inner allocations are never mutable. They can only arise via the "tail - // expression" / "outer scope" rule, and we treat them consistently with `const`. - Mutability::Not, - true, - ) - } - InternKind::Static(Mutability::Mut) => { - // Just make everything mutable. We accept code like - // `static mut X = &mut [42]`, so even inner allocations need to be mutable. - (Mutability::Mut, Mutability::Mut, true) - } - }; - - // Intern the base allocation, and initialize todo list for recursive interning. - let base_alloc_id = ret.ptr().provenance.unwrap().alloc_id(); - trace!(?base_alloc_id, ?base_mutability); - // First we intern the base allocation, as it requires a different mutability. - // This gives us the initial set of nested allocations, which will then all be processed - // recursively in the loop below. - let mut todo: Vec<_> = if is_static { - // Do not steal the root allocation, we need it later to create the return value of `eval_static_initializer`. - // But still change its mutability to match the requested one. - let alloc = ecx.memory.alloc_map.get_mut(&base_alloc_id).unwrap(); - alloc.1.mutability = base_mutability; - alloc.1.provenance().ptrs().iter().map(|&(_, prov)| prov).collect() - } else { - intern_shallow(ecx, base_alloc_id, base_mutability).unwrap().collect() - }; - // We need to distinguish "has just been interned" from "was already in `tcx`", - // so we track this in a separate set. - let mut just_interned: FxHashSet<_> = std::iter::once(base_alloc_id).collect(); - // Whether we encountered a bad mutable pointer. - // We want to first report "dangling" and then "mutable", so we need to delay reporting these - // errors. - let mut found_bad_mutable_pointer = false; - - // Keep interning as long as there are things to intern. - // We show errors if there are dangling pointers, or mutable pointers in immutable contexts - // (i.e., everything except for `static mut`). When these errors affect references, it is - // unfortunate that we show these errors here and not during validation, since validation can - // show much nicer errors. However, we do need these checks to be run on all pointers, including - // raw pointers, so we cannot rely on validation to catch them -- and since interning runs - // before validation, and interning doesn't know the type of anything, this means we can't show - // better errors. Maybe we should consider doing validation before interning in the future. - while let Some(prov) = todo.pop() { - trace!(?prov); - let alloc_id = prov.alloc_id(); - - if base_alloc_id == alloc_id && is_static { - // This is a pointer to the static itself. It's ok for a static to refer to itself, - // even mutably. Whether that mutable pointer is legal at all is checked in validation. - // See tests/ui/statics/recursive_interior_mut.rs for how such a situation can occur. - // We also already collected all the nested allocations, so there's no need to do that again. - continue; - } - - // Crucially, we check this *before* checking whether the `alloc_id` - // has already been interned. The point of this check is to ensure that when - // there are multiple pointers to the same allocation, they are *all* immutable. - // Therefore it would be bad if we only checked the first pointer to any given - // allocation. - // (It is likely not possible to actually have multiple pointers to the same allocation, - // so alternatively we could also check that and ICE if there are multiple such pointers.) - if intern_kind != InternKind::Promoted - && inner_mutability == Mutability::Not - && !prov.immutable() - { - if ecx.tcx.try_get_global_alloc(alloc_id).is_some() - && !just_interned.contains(&alloc_id) - { - // This is a pointer to some memory from another constant. We encounter mutable - // pointers to such memory since we do not always track immutability through - // these "global" pointers. Allowing them is harmless; the point of these checks - // during interning is to justify why we intern the *new* allocations immutably, - // so we can completely ignore existing allocations. We also don't need to add - // this to the todo list, since after all it is already interned. - continue; - } - // Found a mutable pointer inside a const where inner allocations should be - // immutable. We exclude promoteds from this, since things like `&mut []` and - // `&None::>` lead to promotion that can produce mutable pointers. We rely - // on the promotion analysis not screwing up to ensure that it is sound to intern - // promoteds as immutable. - trace!("found bad mutable pointer"); - found_bad_mutable_pointer = true; - } - if ecx.tcx.try_get_global_alloc(alloc_id).is_some() { - // Already interned. - debug_assert!(!ecx.memory.alloc_map.contains_key(&alloc_id)); - continue; - } - just_interned.insert(alloc_id); - // We always intern with `inner_mutability`, and furthermore we ensured above that if - // that is "immutable", then there are *no* mutable pointers anywhere in the newly - // interned memory -- justifying that we can indeed intern immutably. However this also - // means we can *not* easily intern immutably here if `prov.immutable()` is true and - // `inner_mutability` is `Mut`: there might be other pointers to that allocation, and - // we'd have to somehow check that they are *all* immutable before deciding that this - // allocation can be made immutable. In the future we could consider analyzing all - // pointers before deciding which allocations can be made immutable; but for now we are - // okay with losing some potential for immutability here. This can anyway only affect - // `static mut`. - todo.extend(intern_shallow(ecx, alloc_id, inner_mutability).map_err(|()| { - ecx.tcx.dcx().emit_err(DanglingPtrInFinal { span: ecx.tcx.span, kind: intern_kind }) - })?); - } - if found_bad_mutable_pointer { - let err_diag = MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind }; - ecx.tcx.emit_node_span_lint( - lint::builtin::CONST_EVAL_MUTABLE_PTR_IN_FINAL_VALUE, - ecx.best_lint_scope(), - err_diag.span, - err_diag, - ) - } - - Ok(()) -} - -/// Intern `ret`. This function assumes that `ret` references no other allocation. -#[instrument(level = "debug", skip(ecx))] -pub fn intern_const_alloc_for_constprop< - 'mir, - 'tcx: 'mir, - T, - M: CompileTimeMachine<'mir, 'tcx, T>, ->( - ecx: &mut InterpCx<'mir, 'tcx, M>, - alloc_id: AllocId, -) -> InterpResult<'tcx, ()> { - if ecx.tcx.try_get_global_alloc(alloc_id).is_some() { - // The constant is already in global memory. Do nothing. - return Ok(()); - } - // Move allocation to `tcx`. - if let Some(_) = - (intern_shallow(ecx, alloc_id, Mutability::Not).map_err(|()| err_ub!(DeadLocal))?).next() - { - // We are not doing recursive interning, so we don't currently support provenance. - // (If this assertion ever triggers, we should just implement a - // proper recursive interning loop -- or just call `intern_const_alloc_recursive`. - panic!("`intern_const_alloc_for_constprop` called on allocation with nested provenance") - } - Ok(()) -} - -impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx, !>> - InterpCx<'mir, 'tcx, M> -{ - /// A helper function that allocates memory for the layout given and gives you access to mutate - /// it. Once your own mutation code is done, the backing `Allocation` is removed from the - /// current `Memory` and interned as read-only into the global memory. - pub fn intern_with_temp_alloc( - &mut self, - layout: TyAndLayout<'tcx>, - f: impl FnOnce( - &mut InterpCx<'mir, 'tcx, M>, - &PlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, ()>, - ) -> InterpResult<'tcx, AllocId> { - // `allocate` picks a fresh AllocId that we will associate with its data below. - let dest = self.allocate(layout, MemoryKind::Stack)?; - f(self, &dest.clone().into())?; - let alloc_id = dest.ptr().provenance.unwrap().alloc_id(); // this was just allocated, it must have provenance - for prov in intern_shallow(self, alloc_id, Mutability::Not).unwrap() { - // We are not doing recursive interning, so we don't currently support provenance. - // (If this assertion ever triggers, we should just implement a - // proper recursive interning loop -- or just call `intern_const_alloc_recursive`. - if self.tcx.try_get_global_alloc(prov.alloc_id()).is_none() { - panic!("`intern_with_temp_alloc` with nested allocations"); - } - } - Ok(alloc_id) - } -} +use hir::def::DefKind;use rustc_ast::Mutability;use rustc_data_structures::fx:: +{FxHashSet,FxIndexMap};use rustc_errors::ErrorGuaranteed;use rustc_hir as hir;// +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;use rustc_middle:://; +mir::interpret::{ConstAllocation,CtfeProvenance,InterpResult};use rustc_middle// +::query::TyCtxtAt;use rustc_middle:: ty::layout::TyAndLayout;use rustc_session:: +lint;use rustc_span::def_id::LocalDefId;use rustc_span::sym;use super::{AllocId +,Allocation,InterpCx,MPlaceTy,Machine, MemoryKind,PlaceTy};use crate::const_eval +;use crate::errors::{DanglingPtrInFinal,MutablePtrInFinal};pub trait//if true{}; +CompileTimeMachine<'mir,'tcx:'mir,T>= Machine<'mir,'tcx,MemoryKind=T,Provenance= +CtfeProvenance,ExtraFnVal=!,FrameExtra=(),AllocExtra=(),MemoryMap=FxIndexMap,Allocation)>,>+HasStaticRootDefId;pub trait//loop{break}; +HasStaticRootDefId{fn static_def_id(&self)->Option;}impl//if true{}; +HasStaticRootDefId for const_eval::CompileTimeInterpreter<'_,'_>{fn//let _=||(); +static_def_id(&self)->Option{((Some((self.static_root_ids?).1)))}}fn +intern_shallow<'rt,'mir,'tcx,T,M:CompileTimeMachine<'mir,'tcx,T>>(ecx:&'rt mut// +InterpCx<'mir,'tcx,M>,alloc_id:AllocId,mutability:Mutability,)->Result+'tcx,()>{;trace!("intern_shallow {:?}",alloc_id);; +let Some((_kind,mut alloc))=ecx.memory.alloc_map.swap_remove(&alloc_id)else{{;}; +return Err(());;};match mutability{Mutability::Not=>{alloc.mutability=Mutability +::Not;3;}Mutability::Mut=>{;assert_eq!(alloc.mutability,Mutability::Mut);;}};let +alloc=ecx.tcx.mk_const_alloc(alloc);let _=();if let Some(static_id)=ecx.machine. +static_def_id(){;intern_as_new_static(ecx.tcx,static_id,alloc_id,alloc);;}else{; +ecx.tcx.set_alloc_id_memory(alloc_id,alloc);3;}Ok(alloc.0.0.provenance().ptrs(). +iter().map((|&(_,prov)|prov)))}fn intern_as_new_static<'tcx>(tcx:TyCtxtAt<'tcx>, +static_id:LocalDefId,alloc_id:AllocId,alloc:ConstAllocation<'tcx>,){();let feed= +tcx.create_def(static_id,sym::nested,DefKind::Static{mutability:alloc.0.//{();}; +mutability,nested:true},);;tcx.set_nested_alloc_id_static(alloc_id,feed.def_id() +);;feed.codegen_fn_attrs(CodegenFnAttrs::new());feed.eval_static_initializer(Ok( +alloc));{;};{;};feed.generics_of(tcx.generics_of(static_id).clone());();();feed. +def_ident_span(tcx.def_ident_span(static_id));;;feed.explicit_predicates_of(tcx. +explicit_predicates_of(static_id));;;feed.feed_hir();}#[derive(Copy,Clone,Debug, +PartialEq,Hash,Eq)]pub enum InternKind{Static(hir::Mutability),Constant,//{();}; +Promoted,}#[instrument(level="debug",skip(ecx))]pub fn//loop{break};loop{break}; +intern_const_alloc_recursive<'mir,'tcx:'mir,M:CompileTimeMachine<'mir,'tcx,//(); +const_eval::MemoryKind>,>(ecx:&mut InterpCx<'mir,'tcx,M>,intern_kind:InternKind +,ret:&MPlaceTy<'tcx>,)->Result<(),ErrorGuaranteed>{let _=();let(base_mutability, +inner_mutability,is_static)=match intern_kind{InternKind::Constant|InternKind:: +Promoted=>{((((Mutability::Not,Mutability::Not,((false))))))}InternKind::Static( +Mutability::Not)=>{(if ((ret.layout.ty .is_freeze(((*ecx.tcx)),ecx.param_env))){ +Mutability::Not}else{Mutability::Mut},Mutability ::Not,true,)}InternKind::Static +(Mutability::Mut)=>{(Mutability::Mut,Mutability::Mut,true)}};;let base_alloc_id= +ret.ptr().provenance.unwrap().alloc_id();;trace!(?base_alloc_id,?base_mutability +);3;3;let mut todo:Vec<_>=if is_static{;let alloc=ecx.memory.alloc_map.get_mut(& +base_alloc_id).unwrap();;alloc.1.mutability=base_mutability;alloc.1.provenance() +.ptrs().iter().map((((((|&(_,prov)|prov)))))).collect()}else{intern_shallow(ecx, +base_alloc_id,base_mutability).unwrap().collect()};{;};();let mut just_interned: +FxHashSet<_>=std::iter::once(base_alloc_id).collect();if true{};let _=();let mut +found_bad_mutable_pointer=false;;while let Some(prov)=todo.pop(){;trace!(?prov); +let alloc_id=prov.alloc_id();;if base_alloc_id==alloc_id&&is_static{continue;}if +((intern_kind!=InternKind::Promoted)&&inner_mutability==Mutability::Not)&&!prov. +immutable(){if ecx.tcx .try_get_global_alloc(alloc_id).is_some()&&!just_interned +.contains(&alloc_id){();continue;();}();trace!("found bad mutable pointer");3;3; +found_bad_mutable_pointer=true;{();};}if ecx.tcx.try_get_global_alloc(alloc_id). +is_some(){;debug_assert!(!ecx.memory.alloc_map.contains_key(&alloc_id));continue +;3;}3;just_interned.insert(alloc_id);3;;todo.extend(intern_shallow(ecx,alloc_id, +inner_mutability).map_err(|()|{(ecx.tcx.dcx()).emit_err(DanglingPtrInFinal{span: +ecx.tcx.span,kind:intern_kind})})?);;}if found_bad_mutable_pointer{let err_diag= +MutablePtrInFinal{span:ecx.tcx.span,kind:intern_kind};let _=();let _=();ecx.tcx. +emit_node_span_lint(lint::builtin::CONST_EVAL_MUTABLE_PTR_IN_FINAL_VALUE,ecx.//; +best_lint_scope(),err_diag.span,err_diag,)}(Ok (()))}#[instrument(level="debug", +skip(ecx))]pub fn intern_const_alloc_for_constprop<'mir,'tcx:'mir,T,M://((),()); +CompileTimeMachine<'mir,'tcx,T>,>(ecx:&mut InterpCx<'mir,'tcx,M>,alloc_id://{;}; +AllocId,)->InterpResult<'tcx,()>{if ((ecx.tcx.try_get_global_alloc(alloc_id))). +is_some(){;return Ok(());}if let Some(_)=(intern_shallow(ecx,alloc_id,Mutability +::Not).map_err(((((((|()|((((((err_ub!(DeadLocal) )))))))))))))?).next(){panic!( +"`intern_const_alloc_for_constprop` called on allocation with nested provenance" +)}(Ok(()))}impl<'mir,'tcx:'mir,M:super::intern::CompileTimeMachine<'mir,'tcx,!>> +InterpCx<'mir,'tcx,M>{pub fn intern_with_temp_alloc(&mut self,layout://let _=(); +TyAndLayout<'tcx>,f:impl FnOnce(&mut InterpCx<'mir,'tcx,M>,&PlaceTy<'tcx,M:://3; +Provenance>,)->InterpResult<'tcx,()>,)->InterpResult<'tcx,AllocId>{{;};let dest= +self.allocate(layout,MemoryKind::Stack)?;3;3;f(self,&dest.clone().into())?;;;let +alloc_id=dest.ptr().provenance.unwrap().alloc_id();3;for prov in intern_shallow( +self,alloc_id,Mutability::Not).unwrap(){if self.tcx.try_get_global_alloc(prov.// +alloc_id()).is_none(){;panic!("`intern_with_temp_alloc` with nested allocations" +);*&*&();((),());((),());((),());*&*&();((),());((),());((),());}}Ok(alloc_id)}} diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index a8478f721c71b..c23e652f6114d 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -1,698 +1,226 @@ -//! Intrinsics and other functions that the interpreter executes without -//! looking at their MIR. Intrinsics/functions supported here are shared by CTFE -//! and miri. - -use rustc_hir::def_id::DefId; -use rustc_middle::ty; -use rustc_middle::ty::layout::{LayoutOf as _, ValidityRequirement}; -use rustc_middle::ty::GenericArgsRef; -use rustc_middle::ty::{Ty, TyCtxt}; -use rustc_middle::{ - mir::{ - self, - interpret::{ - Allocation, ConstAllocation, GlobalId, InterpResult, PointerArithmetic, Scalar, - }, - BinOp, ConstValue, NonDivergingIntrinsic, - }, - ty::layout::TyAndLayout, -}; -use rustc_span::symbol::{sym, Symbol}; -use rustc_target::abi::Size; - -use super::{ - memory::MemoryKind, util::ensure_monomorphic_enough, CheckInAllocMsg, ImmTy, InterpCx, - MPlaceTy, Machine, OpTy, Pointer, -}; - -use crate::fluent_generated as fluent; - -/// 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 = crate::util::type_name(tcx, ty); - let alloc = Allocation::from_bytes_byte_aligned_immutable(path.into_bytes()); - tcx.mk_const_alloc(alloc) -} - -/// The logic for all nullary intrinsics is implemented here. These intrinsics don't get evaluated -/// inside an `InterpCx` and instead have their value computed directly from rustc internal info. -pub(crate) fn eval_nullary_intrinsic<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - def_id: DefId, - args: GenericArgsRef<'tcx>, -) -> InterpResult<'tcx, ConstValue<'tcx>> { - let tp_ty = args.type_at(0); - let name = tcx.item_name(def_id); - Ok(match name { - sym::type_name => { - ensure_monomorphic_enough(tcx, tp_ty)?; - let alloc = alloc_type_name(tcx, tp_ty); - ConstValue::Slice { data: alloc, meta: alloc.inner().size().bytes() } - } - sym::needs_drop => { - ensure_monomorphic_enough(tcx, tp_ty)?; - ConstValue::from_bool(tp_ty.needs_drop(tcx, param_env)) - } - sym::pref_align_of => { - // Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough. - let layout = tcx.layout_of(param_env.and(tp_ty)).map_err(|e| err_inval!(Layout(*e)))?; - ConstValue::from_target_usize(layout.align.pref.bytes(), &tcx) - } - sym::type_id => { - ensure_monomorphic_enough(tcx, tp_ty)?; - ConstValue::from_u128(tcx.type_id_hash(tp_ty).as_u128()) - } - sym::variant_count => match tp_ty.kind() { - // Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough. - ty::Adt(adt, _) => ConstValue::from_target_usize(adt.variants().len() as u64, &tcx), - ty::Alias(..) | ty::Param(_) | ty::Placeholder(_) | ty::Infer(_) => { - throw_inval!(TooGeneric) - } - ty::Bound(_, _) => bug!("bound ty during ctfe"), - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Foreign(_) - | ty::Str - | ty::Array(_, _) - | ty::Slice(_) - | ty::RawPtr(_, _) - | ty::Ref(_, _, _) - | ty::FnDef(_, _) - | ty::FnPtr(_) - | ty::Dynamic(_, _, _) - | ty::Closure(_, _) - | ty::CoroutineClosure(_, _) - | ty::Coroutine(_, _) - | ty::CoroutineWitness(..) - | ty::Never - | ty::Tuple(_) - | ty::Error(_) => ConstValue::from_target_usize(0u64, &tcx), - }, - other => bug!("`{}` is not a zero arg intrinsic", other), - }) -} - -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - /// Returns `true` if emulation happened. - /// Here we implement the intrinsics that are common to all Miri instances; individual machines can add their own - /// intrinsic handling. - pub fn emulate_intrinsic( - &mut self, - instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, M::Provenance>], - dest: &MPlaceTy<'tcx, M::Provenance>, - ret: Option, - ) -> InterpResult<'tcx, bool> { - let instance_args = instance.args; - let intrinsic_name = self.tcx.item_name(instance.def_id()); - let Some(ret) = ret else { - // We don't support any intrinsic without return place. - return Ok(false); - }; - - match intrinsic_name { - sym::caller_location => { - let span = self.find_closest_untracked_caller_location(); - let val = self.tcx.span_as_caller_location(span); - let val = - self.const_val_to_op(val, self.tcx.caller_location_ty(), Some(dest.layout))?; - self.copy_op(&val, dest)?; - } - - sym::min_align_of_val | sym::size_of_val => { - // Avoid `deref_pointer` -- this is not a deref, the ptr does not have to be - // dereferenceable! - let place = self.ref_to_mplace(&self.read_immediate(&args[0])?)?; - let (size, align) = self - .size_and_align_of_mplace(&place)? - .ok_or_else(|| err_unsup_format!("`extern type` does not have known layout"))?; - - let result = match intrinsic_name { - sym::min_align_of_val => align.bytes(), - sym::size_of_val => size.bytes(), - _ => bug!(), - }; - - self.write_scalar(Scalar::from_target_usize(result, self), dest)?; - } - - sym::pref_align_of - | sym::needs_drop - | sym::type_id - | sym::type_name - | sym::variant_count => { - let gid = GlobalId { instance, promoted: None }; - let ty = match intrinsic_name { - sym::pref_align_of | sym::variant_count => self.tcx.types.usize, - sym::needs_drop => self.tcx.types.bool, - sym::type_id => self.tcx.types.u128, - sym::type_name => Ty::new_static_str(self.tcx.tcx), - _ => bug!(), - }; - let val = - self.ctfe_query(|tcx| tcx.const_eval_global_id(self.param_env, gid, tcx.span))?; - let val = self.const_val_to_op(val, ty, Some(dest.layout))?; - self.copy_op(&val, dest)?; - } - - sym::ctpop - | sym::cttz - | sym::cttz_nonzero - | sym::ctlz - | sym::ctlz_nonzero - | sym::bswap - | sym::bitreverse => { - let ty = instance_args.type_at(0); - let layout = self.layout_of(ty)?; - let val = self.read_scalar(&args[0])?; - let out_val = self.numeric_intrinsic(intrinsic_name, val, layout)?; - self.write_scalar(out_val, dest)?; - } - sym::saturating_add | sym::saturating_sub => { - let l = self.read_immediate(&args[0])?; - let r = self.read_immediate(&args[1])?; - let val = self.saturating_arith( - if intrinsic_name == sym::saturating_add { BinOp::Add } else { BinOp::Sub }, - &l, - &r, - )?; - self.write_scalar(val, dest)?; - } - sym::discriminant_value => { - let place = self.deref_pointer(&args[0])?; - let variant = self.read_discriminant(&place)?; - let discr = self.discriminant_for_variant(place.layout.ty, variant)?; - self.write_immediate(*discr, dest)?; - } - sym::exact_div => { - let l = self.read_immediate(&args[0])?; - let r = self.read_immediate(&args[1])?; - self.exact_div(&l, &r, dest)?; - } - sym::rotate_left | sym::rotate_right => { - // rotate_left: (X << (S % BW)) | (X >> ((BW - S) % BW)) - // rotate_right: (X << ((BW - S) % BW)) | (X >> (S % BW)) - let layout = self.layout_of(instance_args.type_at(0))?; - let val = self.read_scalar(&args[0])?; - let val_bits = val.to_bits(layout.size)?; - let raw_shift = self.read_scalar(&args[1])?; - let raw_shift_bits = raw_shift.to_bits(layout.size)?; - let width_bits = u128::from(layout.size.bits()); - let shift_bits = raw_shift_bits % width_bits; - let inv_shift_bits = (width_bits - shift_bits) % width_bits; - let result_bits = if intrinsic_name == sym::rotate_left { - (val_bits << shift_bits) | (val_bits >> inv_shift_bits) - } else { - (val_bits >> shift_bits) | (val_bits << inv_shift_bits) - }; - let truncated_bits = self.truncate(result_bits, layout); - let result = Scalar::from_uint(truncated_bits, layout.size); - self.write_scalar(result, dest)?; - } - sym::copy => { - self.copy_intrinsic(&args[0], &args[1], &args[2], /*nonoverlapping*/ false)?; - } - sym::write_bytes => { - self.write_bytes_intrinsic(&args[0], &args[1], &args[2])?; - } - sym::compare_bytes => { - let result = self.compare_bytes_intrinsic(&args[0], &args[1], &args[2])?; - self.write_scalar(result, dest)?; - } - sym::arith_offset => { - let ptr = self.read_pointer(&args[0])?; - let offset_count = self.read_target_isize(&args[1])?; - let pointee_ty = instance_args.type_at(0); - - let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap(); - let offset_bytes = offset_count.wrapping_mul(pointee_size); - let offset_ptr = ptr.wrapping_signed_offset(offset_bytes, self); - self.write_pointer(offset_ptr, dest)?; - } - sym::ptr_offset_from | sym::ptr_offset_from_unsigned => { - let a = self.read_pointer(&args[0])?; - let b = self.read_pointer(&args[1])?; - - let usize_layout = self.layout_of(self.tcx.types.usize)?; - let isize_layout = self.layout_of(self.tcx.types.isize)?; - - // Get offsets for both that are at least relative to the same base. - let (a_offset, b_offset) = - match (self.ptr_try_get_alloc_id(a), self.ptr_try_get_alloc_id(b)) { - (Err(a), Err(b)) => { - // Neither pointer points to an allocation. - // If these are inequal or null, this *will* fail the deref check below. - (a, b) - } - (Err(_), _) | (_, Err(_)) => { - // We managed to find a valid allocation for one pointer, but not the other. - // That means they are definitely not pointing to the same allocation. - throw_ub_custom!( - fluent::const_eval_different_allocations, - name = intrinsic_name, - ); - } - (Ok((a_alloc_id, a_offset, _)), Ok((b_alloc_id, b_offset, _))) => { - // Found allocation for both. They must be into the same allocation. - if a_alloc_id != b_alloc_id { - throw_ub_custom!( - fluent::const_eval_different_allocations, - name = intrinsic_name, - ); - } - // Use these offsets for distance calculation. - (a_offset.bytes(), b_offset.bytes()) - } - }; - - // Compute distance. - let dist = { - // Addresses are unsigned, so this is a `usize` computation. We have to do the - // overflow check separately anyway. - let (val, overflowed) = { - let a_offset = ImmTy::from_uint(a_offset, usize_layout); - let b_offset = ImmTy::from_uint(b_offset, usize_layout); - self.overflowing_binary_op(BinOp::Sub, &a_offset, &b_offset)? - }; - if overflowed { - // a < b - if intrinsic_name == sym::ptr_offset_from_unsigned { - throw_ub_custom!( - fluent::const_eval_unsigned_offset_from_overflow, - a_offset = a_offset, - b_offset = b_offset, - ); - } - // The signed form of the intrinsic allows this. If we interpret the - // difference as isize, we'll get the proper signed difference. If that - // seems *positive*, they were more than isize::MAX apart. - let dist = val.to_scalar().to_target_isize(self)?; - if dist >= 0 { - throw_ub_custom!( - fluent::const_eval_offset_from_underflow, - name = intrinsic_name, - ); - } - dist - } else { - // b >= a - let dist = val.to_scalar().to_target_isize(self)?; - // If converting to isize produced a *negative* result, we had an overflow - // because they were more than isize::MAX apart. - if dist < 0 { - throw_ub_custom!( - fluent::const_eval_offset_from_overflow, - name = intrinsic_name, - ); - } - dist - } - }; - - // Check that the range between them is dereferenceable ("in-bounds or one past the - // end of the same allocation"). This is like the check in ptr_offset_inbounds. - let min_ptr = if dist >= 0 { b } else { a }; - self.check_ptr_access( - min_ptr, - Size::from_bytes(dist.unsigned_abs()), - CheckInAllocMsg::OffsetFromTest, - )?; - - // Perform division by size to compute return value. - let ret_layout = if intrinsic_name == sym::ptr_offset_from_unsigned { - assert!(0 <= dist && dist <= self.target_isize_max()); - usize_layout - } else { - assert!(self.target_isize_min() <= dist && dist <= self.target_isize_max()); - isize_layout - }; - let pointee_layout = self.layout_of(instance_args.type_at(0))?; - // If ret_layout is unsigned, we checked that so is the distance, so we are good. - let val = ImmTy::from_int(dist, ret_layout); - let size = ImmTy::from_int(pointee_layout.size.bytes(), ret_layout); - self.exact_div(&val, &size, dest)?; - } - - sym::assert_inhabited - | sym::assert_zero_valid - | sym::assert_mem_uninitialized_valid => { - let ty = instance.args.type_at(0); - let requirement = ValidityRequirement::from_intrinsic(intrinsic_name).unwrap(); - - let should_panic = !self - .tcx - .check_validity_requirement((requirement, self.param_env.and(ty))) - .map_err(|_| err_inval!(TooGeneric))?; - - if should_panic { - let layout = self.layout_of(ty)?; - - let msg = match requirement { - // For *all* intrinsics we first check `is_uninhabited` to give a more specific - // error message. - _ if layout.abi.is_uninhabited() => format!( - "aborted execution: attempted to instantiate uninhabited type `{ty}`" - ), - ValidityRequirement::Inhabited => bug!("handled earlier"), - ValidityRequirement::Zero => format!( - "aborted execution: attempted to zero-initialize type `{ty}`, which is invalid" - ), - ValidityRequirement::UninitMitigated0x01Fill => format!( - "aborted execution: attempted to leave type `{ty}` uninitialized, which is invalid" - ), - ValidityRequirement::Uninit => bug!("assert_uninit_valid doesn't exist"), - }; - - M::panic_nounwind(self, &msg)?; - // Skip the `go_to_block` at the end. - return Ok(true); - } - } - sym::simd_insert => { - let index = u64::from(self.read_scalar(&args[1])?.to_u32()?); - let elem = &args[2]; - let (input, input_len) = self.operand_to_simd(&args[0])?; - let (dest, dest_len) = self.mplace_to_simd(dest)?; - assert_eq!(input_len, dest_len, "Return vector length must match input length"); - // Bounds are not checked by typeck so we have to do it ourselves. - if index >= input_len { - throw_ub_format!( - "`simd_insert` index {index} is out-of-bounds of vector with length {input_len}" - ); - } - - for i in 0..dest_len { - let place = self.project_index(&dest, i)?; - let value = if i == index { - elem.clone() - } else { - self.project_index(&input, i)?.into() - }; - self.copy_op(&value, &place)?; - } - } - sym::simd_extract => { - let index = u64::from(self.read_scalar(&args[1])?.to_u32()?); - let (input, input_len) = self.operand_to_simd(&args[0])?; - // Bounds are not checked by typeck so we have to do it ourselves. - if index >= input_len { - throw_ub_format!( - "`simd_extract` index {index} is out-of-bounds of vector with length {input_len}" - ); - } - self.copy_op(&self.project_index(&input, index)?, dest)?; - } - sym::likely | sym::unlikely | sym::black_box => { - // These just return their argument - self.copy_op(&args[0], dest)?; - } - sym::raw_eq => { - let result = self.raw_eq_intrinsic(&args[0], &args[1])?; - self.write_scalar(result, dest)?; - } - sym::typed_swap => { - self.typed_swap_intrinsic(&args[0], &args[1])?; - } - - sym::vtable_size => { - let ptr = self.read_pointer(&args[0])?; - let (size, _align) = self.get_vtable_size_and_align(ptr)?; - self.write_scalar(Scalar::from_target_usize(size.bytes(), self), dest)?; - } - sym::vtable_align => { - let ptr = self.read_pointer(&args[0])?; - let (_size, align) = self.get_vtable_size_and_align(ptr)?; - self.write_scalar(Scalar::from_target_usize(align.bytes(), self), dest)?; - } - - _ => return Ok(false), - } - - trace!("{:?}", self.dump_place(&dest.clone().into())); - self.go_to_block(ret); - Ok(true) - } - - pub(super) fn emulate_nondiverging_intrinsic( - &mut self, - intrinsic: &NonDivergingIntrinsic<'tcx>, - ) -> InterpResult<'tcx> { - match intrinsic { - NonDivergingIntrinsic::Assume(op) => { - let op = self.eval_operand(op, None)?; - let cond = self.read_scalar(&op)?.to_bool()?; - if !cond { - throw_ub_custom!(fluent::const_eval_assume_false); - } - Ok(()) - } - NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping { - count, - src, - dst, - }) => { - let src = self.eval_operand(src, None)?; - let dst = self.eval_operand(dst, None)?; - let count = self.eval_operand(count, None)?; - self.copy_intrinsic(&src, &dst, &count, /* nonoverlapping */ true) - } - } - } - - pub fn numeric_intrinsic( - &self, - name: Symbol, - val: Scalar, - layout: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, Scalar> { - assert!(layout.ty.is_integral(), "invalid type for numeric intrinsic: {}", layout.ty); - let bits = val.to_bits(layout.size)?; - let extra = 128 - u128::from(layout.size.bits()); - let bits_out = match name { - sym::ctpop => u128::from(bits.count_ones()), - sym::ctlz_nonzero | sym::cttz_nonzero if bits == 0 => { - throw_ub_custom!(fluent::const_eval_call_nonzero_intrinsic, name = name,); - } - sym::ctlz | sym::ctlz_nonzero => u128::from(bits.leading_zeros()) - extra, - sym::cttz | sym::cttz_nonzero => u128::from((bits << extra).trailing_zeros()) - extra, - sym::bswap => (bits << extra).swap_bytes(), - sym::bitreverse => (bits << extra).reverse_bits(), - _ => bug!("not a numeric intrinsic: {}", name), - }; - Ok(Scalar::from_uint(bits_out, layout.size)) - } - - pub fn exact_div( - &mut self, - a: &ImmTy<'tcx, M::Provenance>, - b: &ImmTy<'tcx, M::Provenance>, - dest: &MPlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx> { - assert_eq!(a.layout.ty, b.layout.ty); - assert!(matches!(a.layout.ty.kind(), ty::Int(..) | ty::Uint(..))); - - // Performs an exact division, resulting in undefined behavior where - // `x % y != 0` or `y == 0` or `x == T::MIN && y == -1`. - // First, check x % y != 0 (or if that computation overflows). - let (res, overflow) = self.overflowing_binary_op(BinOp::Rem, a, b)?; - assert!(!overflow); // All overflow is UB, so this should never return on overflow. - if res.to_scalar().assert_bits(a.layout.size) != 0 { - throw_ub_custom!( - fluent::const_eval_exact_div_has_remainder, - a = format!("{a}"), - b = format!("{b}") - ) - } - // `Rem` says this is all right, so we can let `Div` do its job. - self.binop_ignore_overflow(BinOp::Div, a, b, &dest.clone().into()) - } - - pub fn saturating_arith( - &self, - mir_op: BinOp, - l: &ImmTy<'tcx, M::Provenance>, - r: &ImmTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, Scalar> { - assert_eq!(l.layout.ty, r.layout.ty); - assert!(matches!(l.layout.ty.kind(), ty::Int(..) | ty::Uint(..))); - assert!(matches!(mir_op, BinOp::Add | BinOp::Sub)); - - let (val, overflowed) = self.overflowing_binary_op(mir_op, l, r)?; - Ok(if overflowed { - let size = l.layout.size; - let num_bits = size.bits(); - if l.layout.abi.is_signed() { - // For signed ints the saturated value depends on the sign of the first - // term since the sign of the second term can be inferred from this and - // the fact that the operation has overflowed (if either is 0 no - // overflow can occur) - let first_term: u128 = l.to_scalar().to_bits(l.layout.size)?; - let first_term_positive = first_term & (1 << (num_bits - 1)) == 0; - if first_term_positive { - // Negative overflow not possible since the positive first term - // can only increase an (in range) negative term for addition - // or corresponding negated positive term for subtraction - Scalar::from_int(size.signed_int_max(), size) - } else { - // Positive overflow not possible for similar reason - // max negative - Scalar::from_int(size.signed_int_min(), size) - } - } else { - // unsigned - if matches!(mir_op, BinOp::Add) { - // max unsigned - Scalar::from_uint(size.unsigned_int_max(), size) - } else { - // underflow to 0 - Scalar::from_uint(0u128, size) - } - } - } else { - val.to_scalar() - }) - } - - /// Offsets a pointer by some multiple of its type, returning an error if the pointer leaves its - /// allocation. For integer pointers, we consider each of them their own tiny allocation of size - /// 0, so offset-by-0 (and only 0) is okay -- except that null cannot be offset by _any_ value. - pub fn ptr_offset_inbounds( - &self, - ptr: Pointer>, - offset_bytes: i64, - ) -> InterpResult<'tcx, Pointer>> { - // The offset being in bounds cannot rely on "wrapping around" the address space. - // So, first rule out overflows in the pointer arithmetic. - let offset_ptr = ptr.signed_offset(offset_bytes, self)?; - // ptr and offset_ptr must be in bounds of the same allocated object. This means all of the - // memory between these pointers must be accessible. Note that we do not require the - // pointers to be properly aligned (unlike a read/write operation). - let min_ptr = if offset_bytes >= 0 { ptr } else { offset_ptr }; - // This call handles checking for integer/null pointers. - self.check_ptr_access( - min_ptr, - Size::from_bytes(offset_bytes.unsigned_abs()), - CheckInAllocMsg::PointerArithmeticTest, - )?; - Ok(offset_ptr) - } - - /// Copy `count*size_of::()` many bytes from `*src` to `*dst`. - pub(crate) fn copy_intrinsic( - &mut self, - src: &OpTy<'tcx, >::Provenance>, - dst: &OpTy<'tcx, >::Provenance>, - count: &OpTy<'tcx, >::Provenance>, - nonoverlapping: bool, - ) -> InterpResult<'tcx> { - let count = self.read_target_usize(count)?; - let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap().ty)?; - let (size, align) = (layout.size, layout.align.abi); - // `checked_mul` enforces a too small bound (the correct one would probably be target_isize_max), - // but no actual allocation can be big enough for the difference to be noticeable. - let size = size.checked_mul(count, self).ok_or_else(|| { - err_ub_custom!( - fluent::const_eval_size_overflow, - name = if nonoverlapping { "copy_nonoverlapping" } else { "copy" } - ) - })?; - - let src = self.read_pointer(src)?; - let dst = self.read_pointer(dst)?; - - self.check_ptr_align(src, align)?; - self.check_ptr_align(dst, align)?; - - self.mem_copy(src, dst, size, nonoverlapping) - } - - /// Does a *typed* swap of `*left` and `*right`. - fn typed_swap_intrinsic( - &mut self, - left: &OpTy<'tcx, >::Provenance>, - right: &OpTy<'tcx, >::Provenance>, - ) -> InterpResult<'tcx> { - let left = self.deref_pointer(left)?; - let right = self.deref_pointer(right)?; - debug_assert_eq!(left.layout, right.layout); - let kind = MemoryKind::Stack; - let temp = self.allocate(left.layout, kind)?; - self.copy_op(&left, &temp)?; - self.copy_op(&right, &left)?; - self.copy_op(&temp, &right)?; - self.deallocate_ptr(temp.ptr(), None, kind)?; - Ok(()) - } - - pub(crate) fn write_bytes_intrinsic( - &mut self, - dst: &OpTy<'tcx, >::Provenance>, - byte: &OpTy<'tcx, >::Provenance>, - count: &OpTy<'tcx, >::Provenance>, - ) -> InterpResult<'tcx> { - let layout = self.layout_of(dst.layout.ty.builtin_deref(true).unwrap().ty)?; - - let dst = self.read_pointer(dst)?; - let byte = self.read_scalar(byte)?.to_u8()?; - let count = self.read_target_usize(count)?; - - // `checked_mul` enforces a too small bound (the correct one would probably be target_isize_max), - // but no actual allocation can be big enough for the difference to be noticeable. - let len = layout.size.checked_mul(count, self).ok_or_else(|| { - err_ub_custom!(fluent::const_eval_size_overflow, name = "write_bytes") - })?; - - let bytes = std::iter::repeat(byte).take(len.bytes_usize()); - self.write_bytes_ptr(dst, bytes) - } - - pub(crate) fn compare_bytes_intrinsic( - &mut self, - left: &OpTy<'tcx, >::Provenance>, - right: &OpTy<'tcx, >::Provenance>, - byte_count: &OpTy<'tcx, >::Provenance>, - ) -> InterpResult<'tcx, Scalar> { - let left = self.read_pointer(left)?; - let right = self.read_pointer(right)?; - let n = Size::from_bytes(self.read_target_usize(byte_count)?); - - let left_bytes = self.read_bytes_ptr_strip_provenance(left, n)?; - let right_bytes = self.read_bytes_ptr_strip_provenance(right, n)?; - - // `Ordering`'s discriminants are -1/0/+1, so casting does the right thing. - let result = Ord::cmp(left_bytes, right_bytes) as i32; - Ok(Scalar::from_i32(result)) - } - - pub(crate) fn raw_eq_intrinsic( - &mut self, - lhs: &OpTy<'tcx, >::Provenance>, - rhs: &OpTy<'tcx, >::Provenance>, - ) -> InterpResult<'tcx, Scalar> { - let layout = self.layout_of(lhs.layout.ty.builtin_deref(true).unwrap().ty)?; - assert!(layout.is_sized()); - - let get_bytes = |this: &InterpCx<'mir, 'tcx, M>, - op: &OpTy<'tcx, >::Provenance>, - size| - -> InterpResult<'tcx, &[u8]> { - let ptr = this.read_pointer(op)?; - let Some(alloc_ref) = self.get_ptr_alloc(ptr, size)? else { - // zero-sized access - return Ok(&[]); - }; - if alloc_ref.has_provenance() { - throw_ub_custom!(fluent::const_eval_raw_eq_with_provenance); - } - alloc_ref.get_bytes_strip_provenance() - }; - - let lhs_bytes = get_bytes(self, lhs, layout.size)?; - let rhs_bytes = get_bytes(self, rhs, layout.size)?; - Ok(Scalar::from_bool(lhs_bytes == rhs_bytes)) - } -} +use rustc_hir::def_id::DefId;use rustc_middle::ty;use rustc_middle::ty::layout// +::{LayoutOf as _,ValidityRequirement};use rustc_middle::ty::GenericArgsRef;use// +rustc_middle::ty::{Ty,TyCtxt};use rustc_middle::{mir::{self,interpret::{//{();}; +Allocation,ConstAllocation,GlobalId,InterpResult,PointerArithmetic,Scalar,},//3; +BinOp,ConstValue,NonDivergingIntrinsic,},ty::layout::TyAndLayout,};use//((),()); +rustc_span::symbol::{sym,Symbol};use rustc_target::abi::Size;use super::{memory +::MemoryKind,util::ensure_monomorphic_enough,CheckInAllocMsg,ImmTy,InterpCx,//3; +MPlaceTy,Machine,OpTy,Pointer,};use crate::fluent_generated as fluent;pub(crate +)fn alloc_type_name<'tcx>(tcx:TyCtxt<'tcx>,ty:Ty<'tcx>)->ConstAllocation<'tcx>{; +let path=crate::util::type_name(tcx,ty);let _=();let _=();let alloc=Allocation:: +from_bytes_byte_aligned_immutable(path.into_bytes());;tcx.mk_const_alloc(alloc)} +pub(crate)fn eval_nullary_intrinsic<'tcx>(tcx:TyCtxt<'tcx>,param_env:ty:://({}); +ParamEnv<'tcx>,def_id:DefId,args:GenericArgsRef<'tcx>,)->InterpResult<'tcx,//(); +ConstValue<'tcx>>{;let tp_ty=args.type_at(0);;let name=tcx.item_name(def_id);Ok( +match name{sym::type_name=>{3;ensure_monomorphic_enough(tcx,tp_ty)?;;;let alloc= +alloc_type_name(tcx,tp_ty);;ConstValue::Slice{data:alloc,meta:alloc.inner().size +().bytes()}}sym::needs_drop=>{;ensure_monomorphic_enough(tcx,tp_ty)?;;ConstValue +::from_bool(tp_ty.needs_drop(tcx,param_env))}sym::pref_align_of=>{();let layout= +tcx.layout_of(param_env.and(tp_ty)).map_err(|e|err_inval!(Layout(*e)))?;((),()); +ConstValue::from_target_usize(layout.align.pref.bytes(),&tcx)}sym::type_id=>{(); +ensure_monomorphic_enough(tcx,tp_ty)?;();ConstValue::from_u128(tcx.type_id_hash( +tp_ty).as_u128())}sym::variant_count=>match (((tp_ty.kind()))){ty::Adt(adt,_)=> +ConstValue::from_target_usize(adt.variants().len()as u64,&tcx),ty::Alias(..)|ty +::Param(_)|ty::Placeholder(_)|ty::Infer (_)=>{throw_inval!(TooGeneric)}ty::Bound +(_,_)=>bug!("bound ty during ctfe"),ty::Bool| ty::Char|ty::Int(_)|ty::Uint(_)|ty +::Float(_)|ty::Foreign(_)|ty::Str|ty::Array(_,_)|ty::Slice(_)|ty::RawPtr(_,_)|// +ty::Ref(_,_,_)|ty::FnDef(_,_)|ty::FnPtr (_)|ty::Dynamic(_,_,_)|ty::Closure(_,_)| +ty::CoroutineClosure(_,_)|ty::Coroutine(_ ,_)|ty::CoroutineWitness(..)|ty::Never +|ty::Tuple(_)|ty::Error(_)=>(ConstValue::from_target_usize(0u64,&tcx)),},other=> +bug!("`{}` is not a zero arg intrinsic",other),}) }impl<'mir,'tcx:'mir,M:Machine +<'mir,'tcx>>InterpCx<'mir,'tcx,M>{pub fn emulate_intrinsic(&mut self,instance:// +ty::Instance<'tcx>,args:&[OpTy<'tcx,M::Provenance>],dest:&MPlaceTy<'tcx,M:://(); +Provenance>,ret:Option,)->InterpResult<'tcx,bool>{if true{};let +instance_args=instance.args;();3;let intrinsic_name=self.tcx.item_name(instance. +def_id());;;let Some(ret)=ret else{return Ok(false);};match intrinsic_name{sym:: +caller_location=>{3;let span=self.find_closest_untracked_caller_location();;;let +val=self.tcx.span_as_caller_location(span);3;3;let val=self.const_val_to_op(val, +self.tcx.caller_location_ty(),Some(dest.layout))?;;self.copy_op(&val,dest)?;}sym +::min_align_of_val|sym::size_of_val=>{*&*&();let place=self.ref_to_mplace(&self. +read_immediate(&args[0])?)?;();3;let(size,align)=self.size_and_align_of_mplace(& +place)?.ok_or_else(||err_unsup_format!(//let _=();if true{};if true{};if true{}; +"`extern type` does not have known layout"))?;;;let result=match intrinsic_name{ +sym::min_align_of_val=>align.bytes(),sym::size_of_val=> size.bytes(),_=>bug!(),} +;();();self.write_scalar(Scalar::from_target_usize(result,self),dest)?;();}sym:: +pref_align_of|sym::needs_drop|sym::type_id|sym::type_name|sym::variant_count=>{; +let gid=GlobalId{instance,promoted:None};();();let ty=match intrinsic_name{sym:: +pref_align_of|sym::variant_count=>self.tcx.types.usize,sym::needs_drop=>self.//; +tcx.types.bool,sym::type_id=>self.tcx.types.u128,sym::type_name=>Ty:://let _=(); +new_static_str(self.tcx.tcx),_=>bug!(),};();();let val=self.ctfe_query(|tcx|tcx. +const_eval_global_id(self.param_env,gid,tcx.span))?;((),());*&*&();let val=self. +const_val_to_op(val,ty,Some(dest.layout))?;;self.copy_op(&val,dest)?;}sym::ctpop +|sym::cttz|sym::cttz_nonzero|sym::ctlz|sym::ctlz_nonzero|sym::bswap|sym:://({}); +bitreverse=>{;let ty=instance_args.type_at(0);let layout=self.layout_of(ty)?;let +val=self.read_scalar(&args[0])?;*&*&();{();};let out_val=self.numeric_intrinsic( +intrinsic_name,val,layout)?;({});{;};self.write_scalar(out_val,dest)?;{;};}sym:: +saturating_add|sym::saturating_sub=>{;let l=self.read_immediate(&args[0])?;let r +=self.read_immediate(&args[1])?;;let val=self.saturating_arith(if intrinsic_name +==sym::saturating_add{BinOp::Add}else{BinOp::Sub},&l,&r,)?;3;;self.write_scalar( +val,dest)?;;}sym::discriminant_value=>{;let place=self.deref_pointer(&args[0])?; +let variant=self.read_discriminant(&place)?;let _=||();if true{};let discr=self. +discriminant_for_variant(place.layout.ty,variant)?;;self.write_immediate(*discr, +dest)?;3;}sym::exact_div=>{3;let l=self.read_immediate(&args[0])?;3;;let r=self. +read_immediate(&args[1])?;;;self.exact_div(&l,&r,dest)?;;}sym::rotate_left|sym:: +rotate_right=>{3;let layout=self.layout_of(instance_args.type_at(0))?;;;let val= +self.read_scalar(&args[0])?;();();let val_bits=val.to_bits(layout.size)?;3;3;let +raw_shift=self.read_scalar(&args[1])?;();3;let raw_shift_bits=raw_shift.to_bits( +layout.size)?;3;;let width_bits=u128::from(layout.size.bits());;;let shift_bits= +raw_shift_bits%width_bits;;let inv_shift_bits=(width_bits-shift_bits)%width_bits +;3;;let result_bits=if intrinsic_name==sym::rotate_left{(val_bits<>inv_shift_bits)}else{( val_bits>>shift_bits)|(val_bits<{;self.copy_intrinsic(&args[0],&args[1],&args[2],false)?;}sym::write_bytes +=>{;self.write_bytes_intrinsic(&args[0],&args[1],&args[2])?;;}sym::compare_bytes +=>{;let result=self.compare_bytes_intrinsic(&args[0],&args[1],&args[2])?;;;self. +write_scalar(result,dest)?;;}sym::arith_offset=>{let ptr=self.read_pointer(&args +[0])?;3;3;let offset_count=self.read_target_isize(&args[1])?;3;3;let pointee_ty= +instance_args.type_at(0);({});{;};let pointee_size=i64::try_from(self.layout_of( +pointee_ty)?.size.bytes()).unwrap();;let offset_bytes=offset_count.wrapping_mul( +pointee_size);;let offset_ptr=ptr.wrapping_signed_offset(offset_bytes,self);self +.write_pointer(offset_ptr,dest)?;if true{};if true{};}sym::ptr_offset_from|sym:: +ptr_offset_from_unsigned=>{();let a=self.read_pointer(&args[0])?;3;3;let b=self. +read_pointer(&args[1])?;;let usize_layout=self.layout_of(self.tcx.types.usize)?; +let isize_layout=self.layout_of(self.tcx.types.isize)?;;;let(a_offset,b_offset)= +match(self.ptr_try_get_alloc_id(a),self.ptr_try_get_alloc_id (b)){(Err(a),Err(b) +)=>{(a,b)}(Err(_),_)|(_,Err(_))=>{if true{};let _=||();throw_ub_custom!(fluent:: +const_eval_different_allocations,name=intrinsic_name,);((),());}(Ok((a_alloc_id, +a_offset,_)),Ok((b_alloc_id,b_offset,_)))=>{if a_alloc_id!=b_alloc_id{if true{}; +throw_ub_custom!(fluent::const_eval_different_allocations ,name=intrinsic_name,) +;3;}(a_offset.bytes(),b_offset.bytes())}};;;let dist={;let(val,overflowed)={;let +a_offset=ImmTy::from_uint(a_offset,usize_layout);;let b_offset=ImmTy::from_uint( +b_offset,usize_layout);((),());self.overflowing_binary_op(BinOp::Sub,&a_offset,& +b_offset)?};();if overflowed{if intrinsic_name==sym::ptr_offset_from_unsigned{3; +throw_ub_custom!(fluent::const_eval_unsigned_offset_from_overflow,a_offset=//(); +a_offset,b_offset=b_offset,);;};let dist=val.to_scalar().to_target_isize(self)?; +if dist>=0{{();};throw_ub_custom!(fluent::const_eval_offset_from_underflow,name= +intrinsic_name,);;}dist}else{let dist=val.to_scalar().to_target_isize(self)?;if +dist<0{let _=||();throw_ub_custom!(fluent::const_eval_offset_from_overflow,name= +intrinsic_name,);;}dist}};let min_ptr=if dist>=0{b}else{a};self.check_ptr_access +(min_ptr,Size::from_bytes(dist. unsigned_abs()),CheckInAllocMsg::OffsetFromTest, +)?;;;let ret_layout=if intrinsic_name==sym::ptr_offset_from_unsigned{assert!(0<= +dist&&dist<=self.target_isize_max());{();};usize_layout}else{{();};assert!(self. +target_isize_min()<=dist&&dist<=self.target_isize_max());3;isize_layout};3;3;let +pointee_layout=self.layout_of(instance_args.type_at(0))?;{;};{;};let val=ImmTy:: +from_int(dist,ret_layout);;let size=ImmTy::from_int(pointee_layout.size.bytes(), +ret_layout);();3;self.exact_div(&val,&size,dest)?;3;}sym::assert_inhabited|sym:: +assert_zero_valid|sym::assert_mem_uninitialized_valid=>{();let ty=instance.args. +type_at(0);;let requirement=ValidityRequirement::from_intrinsic(intrinsic_name). +unwrap();3;3;let should_panic=!self.tcx.check_validity_requirement((requirement, +self.param_env.and(ty))).map_err(|_|err_inval!(TooGeneric))?;3;if should_panic{; +let layout=self.layout_of(ty)?;{;};();let msg=match requirement{_ if layout.abi. +is_uninhabited()=>format!(//loop{break;};loop{break;};loop{break;};loop{break;}; +"aborted execution: attempted to instantiate uninhabited type `{ty}`"),//*&*&(); +ValidityRequirement::Inhabited=>(bug! ("handled earlier")),ValidityRequirement:: +Zero=>format!(//((),());((),());((),());((),());((),());((),());((),());((),()); + "aborted execution: attempted to zero-initialize type `{ty}`, which is invalid" +),ValidityRequirement::UninitMitigated0x01Fill=>format!(//let _=||();let _=||(); +"aborted execution: attempted to leave type `{ty}` uninitialized, which is invalid" +),ValidityRequirement::Uninit=>bug!("assert_uninit_valid doesn't exist"),};;;M:: +panic_nounwind(self,&msg)?;;return Ok(true);}}sym::simd_insert=>{let index=u64:: +from(self.read_scalar(&args[1])?.to_u32()?);3;3;let elem=&args[2];3;3;let(input, +input_len)=self.operand_to_simd(&args[0])?;*&*&();{();};let(dest,dest_len)=self. +mplace_to_simd(dest)?;if let _=(){};if let _=(){};assert_eq!(input_len,dest_len, +"Return vector length must match input length");{();};if index>=input_len{{();}; +throw_ub_format!(//*&*&();((),());*&*&();((),());*&*&();((),());((),());((),()); +"`simd_insert` index {index} is out-of-bounds of vector with length {input_len}" +);;}for i in 0..dest_len{let place=self.project_index(&dest,i)?;let value=if i== +index{elem.clone()}else{self.project_index(&input,i)?.into()};3;3;self.copy_op(& +value,&place)?;;}}sym::simd_extract=>{let index=u64::from(self.read_scalar(&args +[1])?.to_u32()?);;;let(input,input_len)=self.operand_to_simd(&args[0])?;if index +>=input_len{loop{break};loop{break;};loop{break;};loop{break;};throw_ub_format!( +"`simd_extract` index {index} is out-of-bounds of vector with length {input_len}" +);3;};self.copy_op(&self.project_index(&input,index)?,dest)?;;}sym::likely|sym:: +unlikely|sym::black_box=>{();self.copy_op(&args[0],dest)?;3;}sym::raw_eq=>{3;let +result=self.raw_eq_intrinsic(&args[0],&args[1])?;;self.write_scalar(result,dest) +?;();}sym::typed_swap=>{3;self.typed_swap_intrinsic(&args[0],&args[1])?;3;}sym:: +vtable_size=>{();let ptr=self.read_pointer(&args[0])?;3;3;let(size,_align)=self. +get_vtable_size_and_align(ptr)?;3;3;self.write_scalar(Scalar::from_target_usize( +size.bytes(),self),dest)?;;}sym::vtable_align=>{let ptr=self.read_pointer(&args[ +0])?;;;let(_size,align)=self.get_vtable_size_and_align(ptr)?;;self.write_scalar( +Scalar::from_target_usize(align.bytes(),self),dest)?;();}_=>return Ok(false),}3; +trace!("{:?}",self.dump_place(&dest.clone().into()));;;self.go_to_block(ret);Ok( +true)}pub(super)fn emulate_nondiverging_intrinsic(&mut self,intrinsic:&//*&*&(); +NonDivergingIntrinsic<'tcx>,)->InterpResult<'tcx>{match intrinsic{//loop{break}; +NonDivergingIntrinsic::Assume(op)=>{;let op=self.eval_operand(op,None)?;let cond +=self.read_scalar(&op)?.to_bool()?;{();};if!cond{{();};throw_ub_custom!(fluent:: +const_eval_assume_false);3;}Ok(())}NonDivergingIntrinsic::CopyNonOverlapping(mir +::CopyNonOverlapping{count,src,dst,})=>{;let src=self.eval_operand(src,None)?;;; +let dst=self.eval_operand(dst,None)?;;;let count=self.eval_operand(count,None)?; +self.copy_intrinsic((&src),(&dst),&count,true)}}}pub fn numeric_intrinsic(&self, +name:Symbol,val:Scalar ,layout:TyAndLayout<'tcx>,)->InterpResult< +'tcx,Scalar>{if true{};if true{};assert!(layout.ty.is_integral(), +"invalid type for numeric intrinsic: {}",layout.ty);;let bits=val.to_bits(layout +.size)?;;;let extra=128-u128::from(layout.size.bits());;let bits_out=match name{ +sym::ctpop=>(u128::from(bits.count_ones ())),sym::ctlz_nonzero|sym::cttz_nonzero +if bits==0=>{();throw_ub_custom!(fluent::const_eval_call_nonzero_intrinsic,name= +name,);;}sym::ctlz|sym::ctlz_nonzero=>u128::from(bits.leading_zeros())-extra,sym +::cttz|sym::cttz_nonzero=>(u128::from((bits<(bits<(bits<bug!("not a numeric intrinsic: {}",name),};;Ok(Scalar::from_uint(bits_out, +layout.size))}pub fn exact_div(&mut self ,a:&ImmTy<'tcx,M::Provenance>,b:&ImmTy< +'tcx,M::Provenance>,dest:&MPlaceTy<'tcx,M::Provenance>,)->InterpResult<'tcx>{(); +assert_eq!(a.layout.ty,b.layout.ty);;assert!(matches!(a.layout.ty.kind(),ty::Int +(..)|ty::Uint(..)));;let(res,overflow)=self.overflowing_binary_op(BinOp::Rem,a,b +)?;();();assert!(!overflow);();if res.to_scalar().assert_bits(a.layout.size)!=0{ +throw_ub_custom!(fluent::const_eval_exact_div_has_remainder,a =format!("{a}"),b= +format!("{b}"))}self.binop_ignore_overflow(BinOp::Div,a, b,&dest.clone().into()) +}pub fn saturating_arith(&self,mir_op:BinOp,l:&ImmTy<'tcx,M::Provenance>,r:&//3; +ImmTy<'tcx,M::Provenance>,)->InterpResult<'tcx,Scalar>{;assert_eq +!(l.layout.ty,r.layout.ty);;assert!(matches!(l.layout.ty.kind(),ty::Int(..)|ty:: +Uint(..)));;assert!(matches!(mir_op,BinOp::Add|BinOp::Sub));let(val,overflowed)= +self.overflowing_binary_op(mir_op,l,r)?;;Ok(if overflowed{let size=l.layout.size +;;;let num_bits=size.bits();;if l.layout.abi.is_signed(){;let first_term:u128=l. +to_scalar().to_bits(l.layout.size)?;3;3;let first_term_positive=first_term&(1<<( +num_bits-1))==0;3;if first_term_positive{Scalar::from_int(size.signed_int_max(), +size)}else{((Scalar::from_int((size.signed_int_min()),size)))}}else{if matches!( +mir_op,BinOp::Add){(Scalar::from_uint(size.unsigned_int_max(),size))}else{Scalar +::from_uint((0u128),size)}}}else{ val.to_scalar()})}pub fn ptr_offset_inbounds(& +self,ptr:Pointer>,offset_bytes:i64,)->InterpResult<'tcx,// +Pointer>>{3;let offset_ptr=ptr.signed_offset(offset_bytes, +self)?;{;};{;};let min_ptr=if offset_bytes>=0{ptr}else{offset_ptr};{;};{;};self. +check_ptr_access(min_ptr,((Size::from_bytes( ((offset_bytes.unsigned_abs()))))), +CheckInAllocMsg::PointerArithmeticTest,)?;let _=||();Ok(offset_ptr)}pub(crate)fn +copy_intrinsic(&mut self,src:&OpTy<'tcx, >::Provenance>, +dst:&OpTy<'tcx,>::Provenance>,count:&OpTy<'tcx,>::Provenance>,nonoverlapping:bool,)->InterpResult<'tcx>{3;let +count=self.read_target_usize(count)?;3;;let layout=self.layout_of(src.layout.ty. +builtin_deref(true).unwrap().ty)?;;let(size,align)=(layout.size,layout.align.abi +);3;;let size=size.checked_mul(count,self).ok_or_else(||{err_ub_custom!(fluent:: +const_eval_size_overflow,name=if nonoverlapping{"copy_nonoverlapping"}else{//(); +"copy"})})?;;;let src=self.read_pointer(src)?;;;let dst=self.read_pointer(dst)?; +self.check_ptr_align(src,align)?;;self.check_ptr_align(dst,align)?;self.mem_copy +(src,dst,size,nonoverlapping)}fn typed_swap_intrinsic(&mut self,left:&OpTy<'tcx +,>::Provenance>,right:&OpTy<'tcx,>::Provenance>,)->InterpResult<'tcx>{;let left=self.deref_pointer(left)?;;; +let right=self.deref_pointer(right)?;;debug_assert_eq!(left.layout,right.layout) +;;;let kind=MemoryKind::Stack;;;let temp=self.allocate(left.layout,kind)?;;self. +copy_op(&left,&temp)?;;;self.copy_op(&right,&left)?;self.copy_op(&temp,&right)?; +self.deallocate_ptr(temp.ptr(),None,kind)?;let _=();let _=();Ok(())}pub(crate)fn +write_bytes_intrinsic(&mut self,dst:&OpTy<'tcx,>:://{;}; +Provenance>,byte:&OpTy<'tcx,>::Provenance>,count:&OpTy< +'tcx,>::Provenance>,)->InterpResult<'tcx>{();let layout= +self.layout_of(dst.layout.ty.builtin_deref(true).unwrap().ty)?;3;3;let dst=self. +read_pointer(dst)?;;;let byte=self.read_scalar(byte)?.to_u8()?;;;let count=self. +read_target_usize(count)?;({});({});let len=layout.size.checked_mul(count,self). +ok_or_else(||{err_ub_custom!(fluent::const_eval_size_overflow,name=//let _=||(); +"write_bytes")})?;3;;let bytes=std::iter::repeat(byte).take(len.bytes_usize());; +self.write_bytes_ptr(dst,bytes)}pub (crate)fn compare_bytes_intrinsic(&mut self, +left:&OpTy<'tcx,>::Provenance>,right:&OpTy<'tcx,>::Provenance>,byte_count:&OpTy<'tcx,>::Provenance>,)->InterpResult<'tcx,Scalar>{{();};let left=self. +read_pointer(left)?;;let right=self.read_pointer(right)?;let n=Size::from_bytes( +self.read_target_usize(byte_count)?);loop{break};let _=||();let left_bytes=self. +read_bytes_ptr_strip_provenance(left,n)?;let _=();let _=();let right_bytes=self. +read_bytes_ptr_strip_provenance(right,n)?;{;};();let result=Ord::cmp(left_bytes, +right_bytes)as i32;;Ok(Scalar::from_i32(result))}pub(crate)fn raw_eq_intrinsic(& +mut self,lhs:&OpTy<'tcx,>::Provenance>,rhs:&OpTy<'tcx,< +M as Machine<'mir,'tcx>>::Provenance >,)->InterpResult<'tcx,Scalar>{;let layout=self.layout_of(lhs.layout.ty.builtin_deref(true).unwrap().ty)?;;; +assert!(layout.is_sized());;let get_bytes=|this:&InterpCx<'mir,'tcx,M>,op:&OpTy< +'tcx,>::Provenance>,size|->InterpResult<'tcx,&[u8]>{;let +ptr=this.read_pointer(op)?;3;3;let Some(alloc_ref)=self.get_ptr_alloc(ptr,size)? +else{;return Ok(&[]);;};;if alloc_ref.has_provenance(){throw_ub_custom!(fluent:: +const_eval_raw_eq_with_provenance);;}alloc_ref.get_bytes_strip_provenance()};let +lhs_bytes=get_bytes(self,lhs,layout.size)?;3;3;let rhs_bytes=get_bytes(self,rhs, +layout.size)?;if true{};let _=||();Ok(Scalar::from_bool(lhs_bytes==rhs_bytes))}} diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 827d8fd9417ce..50563668f920b 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -1,632 +1,134 @@ -//! This module contains everything needed to instantiate an interpreter. -//! This separation exists to ensure that no fancy miri features like -//! interpreting common C functions leak into CTFE. - -use std::borrow::{Borrow, Cow}; -use std::fmt::Debug; -use std::hash::Hash; - -use rustc_apfloat::{Float, FloatConvert}; -use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; -use rustc_middle::mir; -use rustc_middle::query::TyCtxtAt; -use rustc_middle::ty; -use rustc_middle::ty::layout::TyAndLayout; -use rustc_span::def_id::DefId; -use rustc_span::Span; -use rustc_target::abi::{Align, Size}; -use rustc_target::spec::abi::Abi as CallAbi; - -use super::{ - AllocBytes, AllocId, AllocKind, AllocRange, Allocation, ConstAllocation, CtfeProvenance, FnArg, - Frame, ImmTy, InterpCx, InterpResult, MPlaceTy, MemoryKind, Misalignment, OpTy, PlaceTy, - Pointer, Provenance, -}; - -/// Data returned by Machine::stack_pop, -/// to provide further control over the popping of the stack frame -#[derive(Eq, PartialEq, Debug, Copy, Clone)] -pub enum StackPopJump { - /// Indicates that no special handling should be - /// done - we'll either return normally or unwind - /// based on the terminator for the function - /// we're leaving. - Normal, - - /// Indicates that we should *not* jump to the return/unwind address, as the callback already - /// took care of everything. - NoJump, -} - -/// Whether this kind of memory is allowed to leak -pub trait MayLeak: Copy { - fn may_leak(self) -> bool; -} - -/// The functionality needed by memory to manage its allocations -pub trait AllocMap { - /// Tests if the map contains the given key. - /// Deliberately takes `&mut` because that is sufficient, and some implementations - /// can be more efficient then (using `RefCell::get_mut`). - fn contains_key(&mut self, k: &Q) -> bool - where - K: Borrow; - - /// Callers should prefer [`AllocMap::contains_key`] when it is possible to call because it may - /// be more efficient. This function exists for callers that only have a shared reference - /// (which might make it slightly less efficient than `contains_key`, e.g. if - /// the data is stored inside a `RefCell`). - fn contains_key_ref(&self, k: &Q) -> bool - where - K: Borrow; - - /// Inserts a new entry into the map. - fn insert(&mut self, k: K, v: V) -> Option; - - /// Removes an entry from the map. - fn remove(&mut self, k: &Q) -> Option - where - K: Borrow; - - /// Returns data based on the keys and values in the map. - fn filter_map_collect(&self, f: impl FnMut(&K, &V) -> Option) -> Vec; - - /// Returns a reference to entry `k`. If no such entry exists, call - /// `vacant` and either forward its error, or add its result to the map - /// and return a reference to *that*. - fn get_or(&self, k: K, vacant: impl FnOnce() -> Result) -> Result<&V, E>; - - /// Returns a mutable reference to entry `k`. If no such entry exists, call - /// `vacant` and either forward its error, or add its result to the map - /// and return a reference to *that*. - fn get_mut_or(&mut self, k: K, vacant: impl FnOnce() -> Result) -> Result<&mut V, E>; - - /// Read-only lookup. - fn get(&self, k: K) -> Option<&V> { - self.get_or(k, || Err(())).ok() - } - - /// Mutable lookup. - fn get_mut(&mut self, k: K) -> Option<&mut V> { - self.get_mut_or(k, || Err(())).ok() - } -} - -/// Methods of this trait signifies a point where CTFE evaluation would fail -/// and some use case dependent behaviour can instead be applied. -pub trait Machine<'mir, 'tcx: 'mir>: Sized { - /// Additional memory kinds a machine wishes to distinguish from the builtin ones - type MemoryKind: Debug + std::fmt::Display + MayLeak + Eq + 'static; - - /// Pointers are "tagged" with provenance information; typically the `AllocId` they belong to. - type Provenance: Provenance + Eq + Hash + 'static; - - /// When getting the AllocId of a pointer, some extra data is also obtained from the provenance - /// that is passed to memory access hooks so they can do things with it. - type ProvenanceExtra: Copy + 'static; - - /// Machines can define extra (non-instance) things that represent values of function pointers. - /// For example, Miri uses this to return a function pointer from `dlsym` - /// that can later be called to execute the right thing. - type ExtraFnVal: Debug + Copy; - - /// Extra data stored in every call frame. - type FrameExtra; - - /// Extra data stored in every allocation. - type AllocExtra: Debug + Clone + 'tcx; - - /// Type for the bytes of the allocation. - type Bytes: AllocBytes + 'static; - - /// Memory's allocation map - type MemoryMap: AllocMap< - AllocId, - ( - MemoryKind, - Allocation, - ), - > + Default - + Clone; - - /// The memory kind to use for copied global memory (held in `tcx`) -- - /// or None if such memory should not be mutated and thus any such attempt will cause - /// a `ModifiedStatic` error to be raised. - /// Statics are copied under two circumstances: When they are mutated, and when - /// `adjust_allocation` (see below) returns an owned allocation - /// that is added to the memory so that the work is not done twice. - const GLOBAL_KIND: Option; - - /// Should the machine panic on allocation failures? - const PANIC_ON_ALLOC_FAIL: bool; - - /// Should post-monomorphization checks be run when a stack frame is pushed? - const POST_MONO_CHECKS: bool = true; - - /// Whether memory accesses should be alignment-checked. - fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; - - /// Gives the machine a chance to detect more misalignment than the built-in checks would catch. - #[inline(always)] - fn alignment_check( - _ecx: &InterpCx<'mir, 'tcx, Self>, - _alloc_id: AllocId, - _alloc_align: Align, - _alloc_kind: AllocKind, - _offset: Size, - _align: Align, - ) -> Option { - None - } - - /// Whether to enforce the validity invariant for a specific layout. - fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>, layout: TyAndLayout<'tcx>) -> bool; - - /// Whether function calls should be [ABI](CallAbi)-checked. - fn enforce_abi(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { - true - } - - /// Whether Assert(OverflowNeg) and Assert(Overflow) MIR terminators should actually - /// check for overflow. - fn ignore_optional_overflow_checks(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; - - /// Entry point for obtaining the MIR of anything that should get evaluated. - /// So not just functions and shims, but also const/static initializers, anonymous - /// constants, ... - fn load_mir( - ecx: &InterpCx<'mir, 'tcx, Self>, - instance: ty::InstanceDef<'tcx>, - ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> { - Ok(ecx.tcx.instance_mir(instance)) - } - - /// Entry point to all function calls. - /// - /// Returns either the mir to use for the call, or `None` if execution should - /// just proceed (which usually means this hook did all the work that the - /// called function should usually have done). In the latter case, it is - /// this hook's responsibility to advance the instruction pointer! - /// (This is to support functions like `__rust_maybe_catch_panic` that neither find a MIR - /// nor just jump to `ret`, but instead push their own stack frame.) - /// Passing `dest`and `ret` in the same `Option` proved very annoying when only one of them - /// was used. - fn find_mir_or_eval_fn( - ecx: &mut InterpCx<'mir, 'tcx, Self>, - instance: ty::Instance<'tcx>, - abi: CallAbi, - args: &[FnArg<'tcx, Self::Provenance>], - destination: &MPlaceTy<'tcx, Self::Provenance>, - target: Option, - unwind: mir::UnwindAction, - ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>>; - - /// Execute `fn_val`. It is the hook's responsibility to advance the instruction - /// pointer as appropriate. - fn call_extra_fn( - ecx: &mut InterpCx<'mir, 'tcx, Self>, - fn_val: Self::ExtraFnVal, - abi: CallAbi, - args: &[FnArg<'tcx, Self::Provenance>], - destination: &MPlaceTy<'tcx, Self::Provenance>, - target: Option, - unwind: mir::UnwindAction, - ) -> InterpResult<'tcx>; - - /// Directly process an intrinsic without pushing a stack frame. It is the hook's - /// responsibility to advance the instruction pointer as appropriate. - fn call_intrinsic( - ecx: &mut InterpCx<'mir, 'tcx, Self>, - instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, Self::Provenance>], - destination: &MPlaceTy<'tcx, Self::Provenance>, - target: Option, - unwind: mir::UnwindAction, - ) -> InterpResult<'tcx>; - - /// Called to evaluate `Assert` MIR terminators that trigger a panic. - fn assert_panic( - ecx: &mut InterpCx<'mir, 'tcx, Self>, - msg: &mir::AssertMessage<'tcx>, - unwind: mir::UnwindAction, - ) -> InterpResult<'tcx>; - - /// Called to trigger a non-unwinding panic. - fn panic_nounwind(_ecx: &mut InterpCx<'mir, 'tcx, Self>, msg: &str) -> InterpResult<'tcx>; - - /// Called when unwinding reached a state where execution should be terminated. - fn unwind_terminate( - ecx: &mut InterpCx<'mir, 'tcx, Self>, - reason: mir::UnwindTerminateReason, - ) -> InterpResult<'tcx>; - - /// Called for all binary operations where the LHS has pointer type. - /// - /// Returns a (value, overflowed) pair if the operation succeeded - fn binary_ptr_op( - ecx: &InterpCx<'mir, 'tcx, Self>, - bin_op: mir::BinOp, - left: &ImmTy<'tcx, Self::Provenance>, - right: &ImmTy<'tcx, Self::Provenance>, - ) -> InterpResult<'tcx, (ImmTy<'tcx, Self::Provenance>, bool)>; - - /// Generate the NaN returned by a float operation, given the list of inputs. - /// (This is all inputs, not just NaN inputs!) - fn generate_nan, F2: Float>( - _ecx: &InterpCx<'mir, 'tcx, Self>, - _inputs: &[F1], - ) -> F2 { - // By default we always return the preferred NaN. - F2::NAN - } - - /// Called before a basic block terminator is executed. - #[inline] - fn before_terminator(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { - Ok(()) - } - - /// Called when the interpreter encounters a `StatementKind::ConstEvalCounter` instruction. - /// You can use this to detect long or endlessly running programs. - #[inline] - fn increment_const_eval_counter(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { - Ok(()) - } - - /// Called before a global allocation is accessed. - /// `def_id` is `Some` if this is the "lazy" allocation of a static. - #[inline] - fn before_access_global( - _tcx: TyCtxtAt<'tcx>, - _machine: &Self, - _alloc_id: AllocId, - _allocation: ConstAllocation<'tcx>, - _static_def_id: Option, - _is_write: bool, - ) -> InterpResult<'tcx> { - Ok(()) - } - - /// Return the `AllocId` for the given thread-local static in the current thread. - fn thread_local_static_base_pointer( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - def_id: DefId, - ) -> InterpResult<'tcx, Pointer> { - throw_unsup!(ThreadLocalStatic(def_id)) - } - - /// Return the root pointer for the given `extern static`. - fn extern_static_base_pointer( - ecx: &InterpCx<'mir, 'tcx, Self>, - def_id: DefId, - ) -> InterpResult<'tcx, Pointer>; - - /// Return a "base" pointer for the given allocation: the one that is used for direct - /// accesses to this static/const/fn allocation, or the one returned from the heap allocator. - /// - /// Not called on `extern` or thread-local statics (those use the methods above). - fn adjust_alloc_base_pointer( - ecx: &InterpCx<'mir, 'tcx, Self>, - ptr: Pointer, - ) -> InterpResult<'tcx, Pointer>; - - /// "Int-to-pointer cast" - fn ptr_from_addr_cast( - ecx: &InterpCx<'mir, 'tcx, Self>, - addr: u64, - ) -> InterpResult<'tcx, Pointer>>; - - /// Marks a pointer as exposed, allowing it's provenance - /// to be recovered. "Pointer-to-int cast" - fn expose_ptr( - ecx: &mut InterpCx<'mir, 'tcx, Self>, - ptr: Pointer, - ) -> InterpResult<'tcx>; - - /// Convert a pointer with provenance into an allocation-offset pair - /// and extra provenance info. - /// - /// The returned `AllocId` must be the same as `ptr.provenance.get_alloc_id()`. - /// - /// When this fails, that means the pointer does not point to a live allocation. - fn ptr_get_alloc( - ecx: &InterpCx<'mir, 'tcx, Self>, - ptr: Pointer, - ) -> Option<(AllocId, Size, Self::ProvenanceExtra)>; - - /// Called to adjust allocations to the Provenance and AllocExtra of this machine. - /// - /// The way we construct allocations is to always first construct it without extra and then add - /// the extra. This keeps uniform code paths for handling both allocations created by CTFE for - /// globals, and allocations created by Miri during evaluation. - /// - /// `kind` is the kind of the allocation being adjusted; it can be `None` when - /// it's a global and `GLOBAL_KIND` is `None`. - /// - /// This should avoid copying if no work has to be done! If this returns an owned - /// allocation (because a copy had to be done to adjust things), machine memory will - /// cache the result. (This relies on `AllocMap::get_or` being able to add the - /// owned allocation to the map even when the map is shared.) - /// - /// This must only fail if `alloc` contains provenance. - fn adjust_allocation<'b>( - ecx: &InterpCx<'mir, 'tcx, Self>, - id: AllocId, - alloc: Cow<'b, Allocation>, - kind: Option>, - ) -> InterpResult<'tcx, Cow<'b, Allocation>>; - - /// Evaluate the inline assembly. - /// - /// This should take care of jumping to the next block (one of `targets`) when asm goto - /// is triggered, `targets[0]` when the assembly falls through, or diverge in case of - /// `InlineAsmOptions::NORETURN` being set. - fn eval_inline_asm( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _template: &'tcx [InlineAsmTemplatePiece], - _operands: &[mir::InlineAsmOperand<'tcx>], - _options: InlineAsmOptions, - _targets: &[mir::BasicBlock], - ) -> InterpResult<'tcx> { - throw_unsup_format!("inline assembly is not supported") - } - - /// Hook for performing extra checks on a memory read access. - /// - /// This will *not* be called during validation! - /// - /// Takes read-only access to the allocation so we can keep all the memory read - /// operations take `&self`. Use a `RefCell` in `AllocExtra` if you - /// need to mutate. - /// - /// This is not invoked for ZST accesses, as no read actually happens. - #[inline(always)] - fn before_memory_read( - _tcx: TyCtxtAt<'tcx>, - _machine: &Self, - _alloc_extra: &Self::AllocExtra, - _prov: (AllocId, Self::ProvenanceExtra), - _range: AllocRange, - ) -> InterpResult<'tcx> { - Ok(()) - } - - /// Hook for performing extra checks on any memory read access, - /// that involves an allocation, even ZST reads. - /// - /// This will *not* be called during validation! - /// - /// Used to prevent statics from self-initializing by reading from their own memory - /// as it is being initialized. - fn before_alloc_read( - _ecx: &InterpCx<'mir, 'tcx, Self>, - _alloc_id: AllocId, - ) -> InterpResult<'tcx> { - Ok(()) - } - - /// Hook for performing extra checks on a memory write access. - /// This is not invoked for ZST accesses, as no write actually happens. - #[inline(always)] - fn before_memory_write( - _tcx: TyCtxtAt<'tcx>, - _machine: &mut Self, - _alloc_extra: &mut Self::AllocExtra, - _prov: (AllocId, Self::ProvenanceExtra), - _range: AllocRange, - ) -> InterpResult<'tcx> { - Ok(()) - } - - /// Hook for performing extra operations on a memory deallocation. - #[inline(always)] - fn before_memory_deallocation( - _tcx: TyCtxtAt<'tcx>, - _machine: &mut Self, - _alloc_extra: &mut Self::AllocExtra, - _prov: (AllocId, Self::ProvenanceExtra), - _size: Size, - _align: Align, - ) -> InterpResult<'tcx> { - Ok(()) - } - - /// Executes a retagging operation for a single pointer. - /// Returns the possibly adjusted pointer. - #[inline] - fn retag_ptr_value( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _kind: mir::RetagKind, - val: &ImmTy<'tcx, Self::Provenance>, - ) -> InterpResult<'tcx, ImmTy<'tcx, Self::Provenance>> { - Ok(val.clone()) - } - - /// Executes a retagging operation on a compound value. - /// Replaces all pointers stored in the given place. - #[inline] - fn retag_place_contents( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _kind: mir::RetagKind, - _place: &PlaceTy<'tcx, Self::Provenance>, - ) -> InterpResult<'tcx> { - Ok(()) - } - - /// Called on places used for in-place function argument and return value handling. - /// - /// These places need to be protected to make sure the program cannot tell whether the - /// argument/return value was actually copied or passed in-place.. - fn protect_in_place_function_argument( - ecx: &mut InterpCx<'mir, 'tcx, Self>, - mplace: &MPlaceTy<'tcx, Self::Provenance>, - ) -> InterpResult<'tcx> { - // Without an aliasing model, all we can do is put `Uninit` into the place. - // Conveniently this also ensures that the place actually points to suitable memory. - ecx.write_uninit(mplace) - } - - /// Called immediately before a new stack frame gets pushed. - fn init_frame_extra( - ecx: &mut InterpCx<'mir, 'tcx, Self>, - frame: Frame<'mir, 'tcx, Self::Provenance>, - ) -> InterpResult<'tcx, Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>>; - - /// Borrow the current thread's stack. - fn stack<'a>( - ecx: &'a InterpCx<'mir, 'tcx, Self>, - ) -> &'a [Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>]; - - /// Mutably borrow the current thread's stack. - fn stack_mut<'a>( - ecx: &'a mut InterpCx<'mir, 'tcx, Self>, - ) -> &'a mut Vec>; - - /// Called immediately after a stack frame got pushed and its locals got initialized. - fn after_stack_push(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { - Ok(()) - } - - /// Called just before the return value is copied to the caller-provided return place. - fn before_stack_pop( - _ecx: &InterpCx<'mir, 'tcx, Self>, - _frame: &Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>, - ) -> InterpResult<'tcx> { - Ok(()) - } - - /// Called immediately after a stack frame got popped, but before jumping back to the caller. - /// The `locals` have already been destroyed! - #[inline(always)] - fn after_stack_pop( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _frame: Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>, - unwinding: bool, - ) -> InterpResult<'tcx, StackPopJump> { - // By default, we do not support unwinding from panics - assert!(!unwinding); - Ok(StackPopJump::Normal) - } - - /// Called immediately after actual memory was allocated for a local - /// but before the local's stack frame is updated to point to that memory. - #[inline(always)] - fn after_local_allocated( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _local: mir::Local, - _mplace: &MPlaceTy<'tcx, Self::Provenance>, - ) -> InterpResult<'tcx> { - Ok(()) - } - - /// Evaluate the given constant. The `eval` function will do all the required evaluation, - /// but this hook has the chance to do some pre/postprocessing. - #[inline(always)] - fn eval_mir_constant( - ecx: &InterpCx<'mir, 'tcx, Self>, - val: mir::Const<'tcx>, - span: Span, - layout: Option>, - eval: F, - ) -> InterpResult<'tcx, OpTy<'tcx, Self::Provenance>> - where - F: Fn( - &InterpCx<'mir, 'tcx, Self>, - mir::Const<'tcx>, - Span, - Option>, - ) -> InterpResult<'tcx, OpTy<'tcx, Self::Provenance>>, - { - eval(ecx, val, span, layout) - } -} - -/// A lot of the flexibility above is just needed for `Miri`, but all "compile-time" machines -/// (CTFE and ConstProp) use the same instance. Here, we share that code. -pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { - type Provenance = CtfeProvenance; - type ProvenanceExtra = bool; // the "immutable" flag - - type ExtraFnVal = !; - - type MemoryMap = - rustc_data_structures::fx::FxIndexMap, Allocation)>; - const GLOBAL_KIND: Option = None; // no copying of globals from `tcx` to machine memory - - type AllocExtra = (); - type FrameExtra = (); - type Bytes = Box<[u8]>; - - #[inline(always)] - fn ignore_optional_overflow_checks(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { - false - } - - #[inline(always)] - fn unwind_terminate( - _ecx: &mut InterpCx<$mir, $tcx, Self>, - _reason: mir::UnwindTerminateReason, - ) -> InterpResult<$tcx> { - unreachable!("unwinding cannot happen during compile-time evaluation") - } - - #[inline(always)] - fn call_extra_fn( - _ecx: &mut InterpCx<$mir, $tcx, Self>, - fn_val: !, - _abi: CallAbi, - _args: &[FnArg<$tcx>], - _destination: &MPlaceTy<$tcx, Self::Provenance>, - _target: Option, - _unwind: mir::UnwindAction, - ) -> InterpResult<$tcx> { - match fn_val {} - } - - #[inline(always)] - fn adjust_allocation<'b>( - _ecx: &InterpCx<$mir, $tcx, Self>, - _id: AllocId, - alloc: Cow<'b, Allocation>, - _kind: Option>, - ) -> InterpResult<$tcx, Cow<'b, Allocation>> { - Ok(alloc) - } - - fn extern_static_base_pointer( - ecx: &InterpCx<$mir, $tcx, Self>, - def_id: DefId, - ) -> InterpResult<$tcx, Pointer> { - // Use the `AllocId` associated with the `DefId`. Any actual *access* will fail. - Ok(Pointer::new(ecx.tcx.reserve_and_set_static_alloc(def_id).into(), Size::ZERO)) - } - - #[inline(always)] - fn adjust_alloc_base_pointer( - _ecx: &InterpCx<$mir, $tcx, Self>, - ptr: Pointer, - ) -> InterpResult<$tcx, Pointer> { - Ok(ptr) - } - - #[inline(always)] - fn ptr_from_addr_cast( - _ecx: &InterpCx<$mir, $tcx, Self>, - addr: u64, - ) -> InterpResult<$tcx, Pointer>> { - // Allow these casts, but make the pointer not dereferenceable. - // (I.e., they behave like transmutation.) - // This is correct because no pointers can ever be exposed in compile-time evaluation. - Ok(Pointer::from_addr_invalid(addr)) - } - - #[inline(always)] - fn ptr_get_alloc( - _ecx: &InterpCx<$mir, $tcx, Self>, - ptr: Pointer, - ) -> Option<(AllocId, Size, Self::ProvenanceExtra)> { - // We know `offset` is relative to the allocation, so we can use `into_parts`. - let (prov, offset) = ptr.into_parts(); - Some((prov.alloc_id(), offset, prov.immutable())) - } -} +use std::borrow::{Borrow,Cow};use std::fmt::Debug;use std::hash::Hash;use//({}); +rustc_apfloat::{Float,FloatConvert};use rustc_ast::{InlineAsmOptions,//let _=(); +InlineAsmTemplatePiece};use rustc_middle::mir ;use rustc_middle::query::TyCtxtAt +;use rustc_middle::ty;use rustc_middle::ty::layout::TyAndLayout;use rustc_span// +::def_id::DefId;use rustc_span::Span;use rustc_target::abi::{Align,Size};use//3; +rustc_target::spec::abi::Abi as CallAbi;use super::{AllocBytes,AllocId,//*&*&(); +AllocKind,AllocRange,Allocation,ConstAllocation,CtfeProvenance,FnArg,Frame,//(); +ImmTy,InterpCx,InterpResult,MPlaceTy,MemoryKind,Misalignment,OpTy,PlaceTy,//{;}; +Pointer,Provenance,};#[derive(Eq,PartialEq,Debug,Copy,Clone)]pub enum//let _=(); +StackPopJump{Normal,NoJump,}pub trait MayLeak: Copy{fn may_leak(self)->bool;}pub +trait AllocMap{fn contains_key(&mut self,k:&Q)//; +->bool where K:Borrow;fn contains_key_ref(&self,k:&Q)->//3; +bool where K:Borrow;fn insert(&mut self,k:K,v:V)->Option;fn remove(&mut self,k:&Q)->Optionwhere K:Borrow;fn//((),());let _=(); +filter_map_collect(&self,f:impl FnMut(&K,& V)->Option)->Vec;fn get_or(&self,k:K,vacant:impl FnOnce()->Result)->Result<&V,E>;fn get_mut_or(& +mut self,k:K,vacant:impl FnOnce()->Result)->Result<&mut V,E>;fn get(&self, +k:K)->Option<&V>{((self.get_or(k,(||Err(())))).ok())}fn get_mut(&mut self,k:K)-> +Option<&mut V>{(self.get_mut_or(k,||Err(())).ok())}}pub trait Machine<'mir,'tcx: +'mir>:Sized{type MemoryKind:Debug+std::fmt::Display+MayLeak+Eq+'static;type//(); +Provenance:Provenance+Eq+Hash+'static;type ProvenanceExtra:Copy+'static;type//3; +ExtraFnVal:Debug+Copy;type FrameExtra;type AllocExtra:Debug+Clone+'tcx;type//(); +Bytes:AllocBytes+'static;type MemoryMap:AllocMap,Allocation,),>+//{;}; +Default+Clone;const GLOBAL_KIND:Option;const//((),());((),()); +PANIC_ON_ALLOC_FAIL:bool;const POST_MONO_CHECKS:bool =true;fn enforce_alignment( +ecx:&InterpCx<'mir,'tcx,Self>)->bool ;#[inline(always)]fn alignment_check(_ecx:& +InterpCx<'mir,'tcx,Self>,_alloc_id:AllocId,_alloc_align:Align,_alloc_kind://{;}; +AllocKind,_offset:Size,_align:Align,)->Option{None}fn//let _=||(); +enforce_validity(ecx:&InterpCx<'mir,'tcx,Self >,layout:TyAndLayout<'tcx>)->bool; +fn enforce_abi(_ecx:&InterpCx<'mir,'tcx,Self>)->bool{((((((((((true))))))))))}fn +ignore_optional_overflow_checks(_ecx:&InterpCx<'mir,'tcx,Self>)->bool;fn//{();}; +load_mir(ecx:&InterpCx<'mir,'tcx,Self>,instance:ty::InstanceDef<'tcx>,)->//({}); +InterpResult<'tcx,&'tcx mir::Body<'tcx>>{(Ok(ecx.tcx.instance_mir(instance)))}fn +find_mir_or_eval_fn(ecx:&mut InterpCx<'mir,'tcx,Self>,instance:ty::Instance,abi:CallAbi,args:&[FnArg<'tcx,Self::Provenance>],destination:&MPlaceTy,target:Option< mir::BasicBlock>,unwind:mir::UnwindAction, +)->InterpResult<'tcx,Option<(&'mir mir::Body<'tcx>,ty::Instance<'tcx>)>>;fn//(); +call_extra_fn(ecx:&mut InterpCx<'mir,'tcx,Self>,fn_val:Self::ExtraFnVal,abi://3; +CallAbi,args:&[FnArg<'tcx,Self::Provenance>],destination:&MPlaceTy<'tcx,Self::// +Provenance>,target:Option,unwind:mir::UnwindAction,)->//*&*&(); +InterpResult<'tcx>;fn call_intrinsic(ecx:& mut InterpCx<'mir,'tcx,Self>,instance +:ty::Instance<'tcx>,args:&[OpTy<'tcx,Self::Provenance>],destination:&MPlaceTy,target:Option< mir::BasicBlock>,unwind:mir::UnwindAction, +)->InterpResult<'tcx>;fn assert_panic(ecx:&mut InterpCx<'mir,'tcx,Self>,msg:&//; +mir::AssertMessage<'tcx>,unwind:mir::UnwindAction,)->InterpResult<'tcx>;fn//{;}; +panic_nounwind(_ecx:&mut InterpCx<'mir,'tcx, Self>,msg:&str)->InterpResult<'tcx> +;fn unwind_terminate(ecx:&mut InterpCx<'mir,'tcx,Self>,reason:mir:://let _=||(); +UnwindTerminateReason,)->InterpResult<'tcx>; fn binary_ptr_op(ecx:&InterpCx<'mir +,'tcx,Self>,bin_op:mir::BinOp,left:&ImmTy<'tcx,Self::Provenance>,right:&ImmTy,)->InterpResult<'tcx ,(ImmTy<'tcx,Self::Provenance>,bool) +>;fn generate_nan ,F2:Float>(_ecx:&InterpCx<'mir,'tcx, +Self>,_inputs:&[F1],)->F2{F2::NAN}#[inline]fn before_terminator(_ecx:&mut//({}); +InterpCx<'mir,'tcx,Self>)->InterpResult<'tcx>{((((Ok(((((())))))))))}#[inline]fn +increment_const_eval_counter(_ecx:&mut InterpCx< 'mir,'tcx,Self>)->InterpResult< +'tcx>{(Ok((())))}#[inline]fn before_access_global(_tcx:TyCtxtAt<'tcx>,_machine:& +Self,_alloc_id:AllocId,_allocation: ConstAllocation<'tcx>,_static_def_id:Option< +DefId>,_is_write:bool,)->InterpResult<'tcx >{(((((((Ok(((((((()))))))))))))))}fn +thread_local_static_base_pointer(_ecx:&mut InterpCx<'mir,'tcx,Self>,def_id://(); +DefId,)->InterpResult<'tcx,Pointer>{throw_unsup!(//let _=||(); +ThreadLocalStatic(def_id))}fn extern_static_base_pointer(ecx:&InterpCx<'mir,//3; +'tcx,Self>,def_id:DefId,)->InterpResult<'tcx,Pointer>;fn//{;}; +adjust_alloc_base_pointer(ecx:&InterpCx<'mir,'tcx,Self>,ptr:Pointer,)->//*&*&(); +InterpResult<'tcx,Pointer>;fn ptr_from_addr_cast(ecx:&//{();}; +InterpCx<'mir,'tcx,Self>,addr:u64,)->InterpResult<'tcx,Pointer>>;fn expose_ptr(ecx:&mut InterpCx<'mir,'tcx,Self>,ptr:Pointer,)->InterpResult<'tcx>;fn ptr_get_alloc(ecx:&InterpCx<'mir,'tcx,//; +Self>,ptr:Pointer,)->Option<(AllocId,Size,Self:://loop{break}; +ProvenanceExtra)>;fn adjust_allocation<'b>(ecx:&InterpCx<'mir,'tcx,Self>,id://3; +AllocId,alloc:Cow<'b,Allocation>,kind:Option>,)->// +InterpResult<'tcx,Cow<'b,Allocation>>;fn eval_inline_asm(_ecx:&mut InterpCx<'mir,'tcx,Self>,_template:&'tcx[ +InlineAsmTemplatePiece],_operands:&[mir::InlineAsmOperand<'tcx>],_options://{;}; +InlineAsmOptions,_targets:&[mir::BasicBlock],)->InterpResult<'tcx>{//let _=||(); +throw_unsup_format!("inline assembly is not supported")}#[inline(always)]fn//(); +before_memory_read(_tcx:TyCtxtAt<'tcx>,_machine:&Self,_alloc_extra:&Self:://{;}; +AllocExtra,_prov:(AllocId,Self::ProvenanceExtra),_range:AllocRange,)->//((),()); +InterpResult<'tcx>{(Ok(()))}fn before_alloc_read(_ecx:&InterpCx<'mir,'tcx,Self>, +_alloc_id:AllocId,)->InterpResult<'tcx>{((((Ok((((()))))))))}#[inline(always)]fn +before_memory_write(_tcx:TyCtxtAt<'tcx>,_machine:&mut Self,_alloc_extra:&mut//3; +Self::AllocExtra,_prov:(AllocId,Self::ProvenanceExtra),_range:AllocRange,)->//3; +InterpResult<'tcx>{(Ok(()))}#[inline(always)]fn before_memory_deallocation(_tcx: +TyCtxtAt<'tcx>,_machine:&mut Self,_alloc_extra:&mut Self::AllocExtra,_prov:(//3; +AllocId,Self::ProvenanceExtra),_size:Size,_align :Align,)->InterpResult<'tcx>{Ok +(())}#[inline]fn retag_ptr_value(_ecx :&mut InterpCx<'mir,'tcx,Self>,_kind:mir:: +RetagKind,val:&ImmTy<'tcx,Self::Provenance>,)->InterpResult<'tcx,ImmTy<'tcx,//3; +Self::Provenance>>{(Ok(val.clone() ))}#[inline]fn retag_place_contents(_ecx:&mut +InterpCx<'mir,'tcx,Self>,_kind:mir::RetagKind,_place:&PlaceTy<'tcx,Self:://({}); +Provenance>,)->InterpResult<'tcx>{Ok (())}fn protect_in_place_function_argument( +ecx:&mut InterpCx<'mir,'tcx,Self>,mplace:&MPlaceTy<'tcx,Self::Provenance>,)->//; +InterpResult<'tcx>{((((ecx.write_uninit(mplace)))))}fn init_frame_extra(ecx:&mut +InterpCx<'mir,'tcx,Self>,frame:Frame<'mir,'tcx,Self::Provenance>,)->//if true{}; +InterpResult<'tcx,Frame<'mir,'tcx,Self ::Provenance,Self::FrameExtra>>;fn stack< +'a>(ecx:&'a InterpCx<'mir,'tcx,Self>,)->&'a[Frame<'mir,'tcx,Self::Provenance,//; +Self::FrameExtra>];fn stack_mut<'a>(ecx:& 'a mut InterpCx<'mir,'tcx,Self>,)->&'a +mut Vec>;fn//((),());((),()); +after_stack_push(_ecx:&mut InterpCx<'mir,'tcx,Self> )->InterpResult<'tcx>{Ok(()) +}fn before_stack_pop(_ecx:&InterpCx<'mir,'tcx,Self>,_frame:&Frame<'mir,'tcx,//3; +Self::Provenance,Self::FrameExtra>,)->InterpResult<'tcx> {Ok(())}#[inline(always +)]fn after_stack_pop(_ecx:&mut InterpCx<'mir ,'tcx,Self>,_frame:Frame<'mir,'tcx, +Self::Provenance,Self::FrameExtra>,unwinding:bool,)->InterpResult<'tcx,//*&*&(); +StackPopJump>{;assert!(!unwinding);;Ok(StackPopJump::Normal)}#[inline(always)]fn +after_local_allocated(_ecx:&mut InterpCx<'mir,'tcx,Self>,_local:mir::Local,//(); +_mplace:&MPlaceTy<'tcx,Self::Provenance>,)->InterpResult< 'tcx>{Ok(())}#[inline( +always)]fn eval_mir_constant(ecx:&InterpCx<'mir,'tcx,Self>,val:mir::Const,span:Span,layout:Option>,eval:F,)->InterpResult<'tcx,//; +OpTy<'tcx,Self::Provenance>>where F:Fn(&InterpCx<'mir,'tcx,Self>,mir::Const,Span,Option>,)->InterpResult<'tcx,OpTy<'tcx,Self:://{;}; +Provenance>>,{(eval(ecx,val,span,layout))}}pub macro compile_time_machine(<$mir: +lifetime,$tcx:lifetime>){type Provenance=CtfeProvenance;type ProvenanceExtra=//; +bool;type ExtraFnVal=!;type MemoryMap=rustc_data_structures::fx::FxIndexMap,Allocation)>;const GLOBAL_KIND:Option=None;type AllocExtra=(); type FrameExtra=();type Bytes=Box<[u8 +]>;#[inline(always)]fn ignore_optional_overflow_checks(_ecx:&InterpCx<$mir,$tcx +,Self>)->bool{false}#[inline(always)]fn unwind_terminate(_ecx:&mut InterpCx<$//; +mir,$tcx,Self>,_reason:mir::UnwindTerminateReason,)->InterpResult<$tcx>{//{();}; +unreachable!("unwinding cannot happen during compile-time evaluation" )}#[inline +(always)]fn call_extra_fn(_ecx:&mut InterpCx<$mir,$tcx,Self>,fn_val:!,_abi://(); +CallAbi,_args:&[FnArg<$tcx>],_destination:&MPlaceTy<$tcx,Self::Provenance>,//(); +_target:Option,_unwind: mir::UnwindAction,)->InterpResult<$tcx> +{match fn_val{}}#[inline(always)]fn adjust_allocation<'b>(_ecx:&InterpCx<$mir,$ +tcx,Self>,_id:AllocId,alloc:Cow<'b,Allocation>,_kind:Option>,)->InterpResult<$tcx,Cow<'b,Allocation>>{Ok(//(); +alloc)}fn extern_static_base_pointer(ecx:&InterpCx< $mir,$tcx,Self>,def_id:DefId +,)->InterpResult<$tcx,Pointer>{Ok(Pointer::new(ecx.tcx.//let _=||();loop{break}; +reserve_and_set_static_alloc(def_id).into(),Size::ZERO))}#[inline(always)]fn//3; +adjust_alloc_base_pointer(_ecx:&InterpCx<$mir,$tcx,Self>,ptr:Pointer,)->InterpResult<$tcx,Pointer< CtfeProvenance>>{Ok(ptr)}#[inline( +always)]fn ptr_from_addr_cast(_ecx:&InterpCx<$mir,$tcx,Self>,addr:u64,)->//({}); +InterpResult<$tcx,Pointer>>{Ok(Pointer:://*&*&();((),()); +from_addr_invalid(addr))}#[inline(always) ]fn ptr_get_alloc(_ecx:&InterpCx<$mir, +$tcx,Self>,ptr:Pointer,)->Option<(AllocId,Size,Self:://let _=(); +ProvenanceExtra)>{let(prov,offset)=ptr.into_parts();Some((prov.alloc_id(),//{;}; +offset,prov.immutable()))}}//loop{break};loop{break;};loop{break;};loop{break;}; diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 9b1d9cf932bda..28fefc11febb2 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -1,1393 +1,357 @@ -//! The memory subsystem. -//! -//! Generally, we use `Pointer` to denote memory addresses. However, some operations -//! have a "size"-like parameter, and they take `Scalar` for the address because -//! if the size is 0, then the pointer can also be a (properly aligned, non-null) -//! integer. It is crucial that these operations call `check_align` *before* -//! short-circuiting the empty case! - -use std::assert_matches::assert_matches; -use std::borrow::Cow; -use std::cell::Cell; -use std::collections::VecDeque; -use std::fmt; -use std::ptr; - -use rustc_ast::Mutability; -use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; -use rustc_hir::def::DefKind; -use rustc_middle::mir::display_allocation; -use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt}; -use rustc_target::abi::{Align, HasDataLayout, Size}; - -use crate::fluent_generated as fluent; - -use super::{ - alloc_range, AllocBytes, AllocId, AllocMap, AllocRange, Allocation, CheckAlignMsg, - CheckInAllocMsg, CtfeProvenance, GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak, - Misalignment, Pointer, PointerArithmetic, Provenance, Scalar, -}; - -#[derive(Debug, PartialEq, Copy, Clone)] -pub enum MemoryKind { - /// Stack memory. Error if deallocated except during a stack pop. - Stack, - /// Memory allocated by `caller_location` intrinsic. Error if ever deallocated. - CallerLocation, - /// Additional memory kinds a machine wishes to distinguish from the builtin ones. - Machine(T), -} - -impl MayLeak for MemoryKind { - #[inline] - fn may_leak(self) -> bool { - match self { - MemoryKind::Stack => false, - MemoryKind::CallerLocation => true, - MemoryKind::Machine(k) => k.may_leak(), - } - } -} - -impl fmt::Display for MemoryKind { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - MemoryKind::Stack => write!(f, "stack variable"), - MemoryKind::CallerLocation => write!(f, "caller location"), - MemoryKind::Machine(m) => write!(f, "{m}"), - } - } -} - -/// The return value of `get_alloc_info` indicates the "kind" of the allocation. -#[derive(Copy, Clone, PartialEq, Debug)] -pub enum AllocKind { - /// A regular live data allocation. - LiveData, - /// A function allocation (that fn ptrs point to). - Function, - /// A (symbolic) vtable allocation. - VTable, - /// A dead allocation. - Dead, -} - -/// The value of a function pointer. -#[derive(Debug, Copy, Clone)] -pub enum FnVal<'tcx, Other> { - Instance(Instance<'tcx>), - Other(Other), -} - -impl<'tcx, Other> FnVal<'tcx, Other> { - pub fn as_instance(self) -> InterpResult<'tcx, Instance<'tcx>> { - match self { - FnVal::Instance(instance) => Ok(instance), - FnVal::Other(_) => { - throw_unsup_format!("'foreign' function pointers are not supported in this context") - } - } - } -} - -// `Memory` has to depend on the `Machine` because some of its operations -// (e.g., `get`) call a `Machine` hook. -pub struct Memory<'mir, 'tcx, M: Machine<'mir, 'tcx>> { - /// Allocations local to this instance of the interpreter. The kind - /// helps ensure that the same mechanism is used for allocation and - /// deallocation. When an allocation is not found here, it is a - /// global and looked up in the `tcx` for read access. Some machines may - /// have to mutate this map even on a read-only access to a global (because - /// they do pointer provenance tracking and the allocations in `tcx` have - /// the wrong type), so we let the machine override this type. - /// Either way, if the machine allows writing to a global, doing so will - /// create a copy of the global allocation here. - // FIXME: this should not be public, but interning currently needs access to it - pub(super) alloc_map: M::MemoryMap, - - /// Map for "extra" function pointers. - extra_fn_ptr_map: FxIndexMap, - - /// To be able to compare pointers with null, and to check alignment for accesses - /// to ZSTs (where pointers may dangle), we keep track of the size even for allocations - /// that do not exist any more. - // FIXME: this should not be public, but interning currently needs access to it - pub(super) dead_alloc_map: FxIndexMap, - - /// This stores whether we are currently doing reads purely for the purpose of validation. - /// Those reads do not trigger the machine's hooks for memory reads. - /// Needless to say, this must only be set with great care! - validation_in_progress: Cell, -} - -/// A reference to some allocation that was already bounds-checked for the given region -/// and had the on-access machine hooks run. -#[derive(Copy, Clone)] -pub struct AllocRef<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes = Box<[u8]>> { - alloc: &'a Allocation, - range: AllocRange, - tcx: TyCtxt<'tcx>, - alloc_id: AllocId, -} -/// A reference to some allocation that was already bounds-checked for the given region -/// and had the on-access machine hooks run. -pub struct AllocRefMut<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes = Box<[u8]>> { - alloc: &'a mut Allocation, - range: AllocRange, - tcx: TyCtxt<'tcx>, - alloc_id: AllocId, -} - -impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { - pub fn new() -> Self { - Memory { - alloc_map: M::MemoryMap::default(), - extra_fn_ptr_map: FxIndexMap::default(), - dead_alloc_map: FxIndexMap::default(), - validation_in_progress: Cell::new(false), - } - } - - /// This is used by [priroda](https://github.com/oli-obk/priroda) - pub fn alloc_map(&self) -> &M::MemoryMap { - &self.alloc_map - } -} - -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - /// Call this to turn untagged "global" pointers (obtained via `tcx`) into - /// the machine pointer to the allocation. Must never be used - /// for any other pointers, nor for TLS statics. - /// - /// Using the resulting pointer represents a *direct* access to that memory - /// (e.g. by directly using a `static`), - /// as opposed to access through a pointer that was created by the program. - /// - /// This function can fail only if `ptr` points to an `extern static`. - #[inline] - pub fn global_base_pointer( - &self, - ptr: Pointer, - ) -> InterpResult<'tcx, Pointer> { - let alloc_id = ptr.provenance.alloc_id(); - // We need to handle `extern static`. - match self.tcx.try_get_global_alloc(alloc_id) { - Some(GlobalAlloc::Static(def_id)) if self.tcx.is_thread_local_static(def_id) => { - // Thread-local statics do not have a constant address. They *must* be accessed via - // `ThreadLocalRef`; we can never have a pointer to them as a regular constant value. - bug!("global memory cannot point to thread-local static") - } - Some(GlobalAlloc::Static(def_id)) if self.tcx.is_foreign_item(def_id) => { - return M::extern_static_base_pointer(self, def_id); - } - _ => {} - } - // And we need to get the provenance. - M::adjust_alloc_base_pointer(self, ptr) - } - - pub fn fn_ptr(&mut self, fn_val: FnVal<'tcx, M::ExtraFnVal>) -> Pointer { - let id = match fn_val { - FnVal::Instance(instance) => self.tcx.reserve_and_set_fn_alloc(instance), - FnVal::Other(extra) => { - // FIXME(RalfJung): Should we have a cache here? - let id = self.tcx.reserve_alloc_id(); - let old = self.memory.extra_fn_ptr_map.insert(id, extra); - assert!(old.is_none()); - id - } - }; - // Functions are global allocations, so make sure we get the right base pointer. - // We know this is not an `extern static` so this cannot fail. - self.global_base_pointer(Pointer::from(id)).unwrap() - } - - pub fn allocate_ptr( - &mut self, - size: Size, - align: Align, - kind: MemoryKind, - ) -> InterpResult<'tcx, Pointer> { - let alloc = if M::PANIC_ON_ALLOC_FAIL { - Allocation::uninit(size, align) - } else { - Allocation::try_uninit(size, align)? - }; - self.allocate_raw_ptr(alloc, kind) - } - - pub fn allocate_bytes_ptr( - &mut self, - bytes: &[u8], - align: Align, - kind: MemoryKind, - mutability: Mutability, - ) -> InterpResult<'tcx, Pointer> { - let alloc = Allocation::from_bytes(bytes, align, mutability); - self.allocate_raw_ptr(alloc, kind) - } - - /// This can fail only if `alloc` contains provenance. - pub fn allocate_raw_ptr( - &mut self, - alloc: Allocation, - kind: MemoryKind, - ) -> InterpResult<'tcx, Pointer> { - let id = self.tcx.reserve_alloc_id(); - debug_assert_ne!( - Some(kind), - M::GLOBAL_KIND.map(MemoryKind::Machine), - "dynamically allocating global memory" - ); - let alloc = M::adjust_allocation(self, id, Cow::Owned(alloc), Some(kind))?; - self.memory.alloc_map.insert(id, (kind, alloc.into_owned())); - M::adjust_alloc_base_pointer(self, Pointer::from(id)) - } - - pub fn reallocate_ptr( - &mut self, - ptr: Pointer>, - old_size_and_align: Option<(Size, Align)>, - new_size: Size, - new_align: Align, - kind: MemoryKind, - ) -> InterpResult<'tcx, Pointer> { - let (alloc_id, offset, _prov) = self.ptr_get_alloc_id(ptr)?; - if offset.bytes() != 0 { - throw_ub_custom!( - fluent::const_eval_realloc_or_alloc_with_offset, - ptr = format!("{ptr:?}"), - kind = "realloc" - ); - } - - // For simplicities' sake, we implement reallocate as "alloc, copy, dealloc". - // This happens so rarely, the perf advantage is outweighed by the maintenance cost. - let new_ptr = self.allocate_ptr(new_size, new_align, kind)?; - let old_size = match old_size_and_align { - Some((size, _align)) => size, - None => self.get_alloc_raw(alloc_id)?.size(), - }; - // This will also call the access hooks. - self.mem_copy(ptr, new_ptr.into(), old_size.min(new_size), /*nonoverlapping*/ true)?; - self.deallocate_ptr(ptr, old_size_and_align, kind)?; - - Ok(new_ptr) - } - - #[instrument(skip(self), level = "debug")] - pub fn deallocate_ptr( - &mut self, - ptr: Pointer>, - old_size_and_align: Option<(Size, Align)>, - kind: MemoryKind, - ) -> InterpResult<'tcx> { - let (alloc_id, offset, prov) = self.ptr_get_alloc_id(ptr)?; - trace!("deallocating: {alloc_id:?}"); - - if offset.bytes() != 0 { - throw_ub_custom!( - fluent::const_eval_realloc_or_alloc_with_offset, - ptr = format!("{ptr:?}"), - kind = "dealloc", - ); - } - - let Some((alloc_kind, mut alloc)) = self.memory.alloc_map.remove(&alloc_id) else { - // Deallocating global memory -- always an error - return Err(match self.tcx.try_get_global_alloc(alloc_id) { - Some(GlobalAlloc::Function(..)) => { - err_ub_custom!( - fluent::const_eval_invalid_dealloc, - alloc_id = alloc_id, - kind = "fn", - ) - } - Some(GlobalAlloc::VTable(..)) => { - err_ub_custom!( - fluent::const_eval_invalid_dealloc, - alloc_id = alloc_id, - kind = "vtable", - ) - } - Some(GlobalAlloc::Static(..) | GlobalAlloc::Memory(..)) => { - err_ub_custom!( - fluent::const_eval_invalid_dealloc, - alloc_id = alloc_id, - kind = "static_mem" - ) - } - None => err_ub!(PointerUseAfterFree(alloc_id, CheckInAllocMsg::MemoryAccessTest)), - } - .into()); - }; - - if alloc.mutability.is_not() { - throw_ub_custom!(fluent::const_eval_dealloc_immutable, alloc = alloc_id,); - } - if alloc_kind != kind { - throw_ub_custom!( - fluent::const_eval_dealloc_kind_mismatch, - alloc = alloc_id, - alloc_kind = format!("{alloc_kind}"), - kind = format!("{kind}"), - ); - } - if let Some((size, align)) = old_size_and_align { - if size != alloc.size() || align != alloc.align { - throw_ub_custom!( - fluent::const_eval_dealloc_incorrect_layout, - alloc = alloc_id, - size = alloc.size().bytes(), - align = alloc.align.bytes(), - size_found = size.bytes(), - align_found = align.bytes(), - ) - } - } - - // Let the machine take some extra action - let size = alloc.size(); - M::before_memory_deallocation( - self.tcx, - &mut self.machine, - &mut alloc.extra, - (alloc_id, prov), - size, - alloc.align, - )?; - - // Don't forget to remember size and align of this now-dead allocation - let old = self.memory.dead_alloc_map.insert(alloc_id, (size, alloc.align)); - if old.is_some() { - bug!("Nothing can be deallocated twice"); - } - - Ok(()) - } - - /// Internal helper function to determine the allocation and offset of a pointer (if any). - #[inline(always)] - fn get_ptr_access( - &self, - ptr: Pointer>, - size: Size, - ) -> InterpResult<'tcx, Option<(AllocId, Size, M::ProvenanceExtra)>> { - self.check_and_deref_ptr( - ptr, - size, - CheckInAllocMsg::MemoryAccessTest, - |alloc_id, offset, prov| { - let (size, align) = self - .get_live_alloc_size_and_align(alloc_id, CheckInAllocMsg::MemoryAccessTest)?; - Ok((size, align, (alloc_id, offset, prov))) - }, - ) - } - - /// Check if the given pointer points to live memory of the given `size`. - /// The caller can control the error message for the out-of-bounds case. - #[inline(always)] - pub fn check_ptr_access( - &self, - ptr: Pointer>, - size: Size, - msg: CheckInAllocMsg, - ) -> InterpResult<'tcx> { - self.check_and_deref_ptr(ptr, size, msg, |alloc_id, _, _| { - let (size, align) = self.get_live_alloc_size_and_align(alloc_id, msg)?; - Ok((size, align, ())) - })?; - Ok(()) - } - - /// Low-level helper function to check if a ptr is in-bounds and potentially return a reference - /// to the allocation it points to. Supports both shared and mutable references, as the actual - /// checking is offloaded to a helper closure. - /// - /// Returns `None` if and only if the size is 0. - fn check_and_deref_ptr( - &self, - ptr: Pointer>, - size: Size, - msg: CheckInAllocMsg, - alloc_size: impl FnOnce( - AllocId, - Size, - M::ProvenanceExtra, - ) -> InterpResult<'tcx, (Size, Align, T)>, - ) -> InterpResult<'tcx, Option> { - Ok(match self.ptr_try_get_alloc_id(ptr) { - Err(addr) => { - // We couldn't get a proper allocation. This is only okay if the access size is 0, - // and the address is not null. - if size.bytes() > 0 || addr == 0 { - throw_ub!(DanglingIntPointer(addr, msg)); - } - None - } - Ok((alloc_id, offset, prov)) => { - let (alloc_size, _alloc_align, ret_val) = alloc_size(alloc_id, offset, prov)?; - // Test bounds. This also ensures non-null. - // It is sufficient to check this for the end pointer. Also check for overflow! - if offset.checked_add(size, &self.tcx).map_or(true, |end| end > alloc_size) { - throw_ub!(PointerOutOfBounds { - alloc_id, - alloc_size, - ptr_offset: self.target_usize_to_isize(offset.bytes()), - ptr_size: size, - msg, - }) - } - // Ensure we never consider the null pointer dereferenceable. - if M::Provenance::OFFSET_IS_ADDR { - assert_ne!(ptr.addr(), Size::ZERO); - } - - // We can still be zero-sized in this branch, in which case we have to - // return `None`. - if size.bytes() == 0 { None } else { Some(ret_val) } - } - }) - } - - pub(super) fn check_misalign( - &self, - misaligned: Option, - msg: CheckAlignMsg, - ) -> InterpResult<'tcx> { - if let Some(misaligned) = misaligned { - throw_ub!(AlignmentCheckFailed(misaligned, msg)) - } - Ok(()) - } - - pub(super) fn is_ptr_misaligned( - &self, - ptr: Pointer>, - align: Align, - ) -> Option { - if !M::enforce_alignment(self) || align.bytes() == 1 { - return None; - } - - #[inline] - fn offset_misalignment(offset: u64, align: Align) -> Option { - if offset % align.bytes() == 0 { - None - } else { - // The biggest power of two through which `offset` is divisible. - let offset_pow2 = 1 << offset.trailing_zeros(); - Some(Misalignment { has: Align::from_bytes(offset_pow2).unwrap(), required: align }) - } - } - - match self.ptr_try_get_alloc_id(ptr) { - Err(addr) => offset_misalignment(addr, align), - Ok((alloc_id, offset, _prov)) => { - let (_size, alloc_align, kind) = self.get_alloc_info(alloc_id); - if let Some(misalign) = - M::alignment_check(self, alloc_id, alloc_align, kind, offset, align) - { - Some(misalign) - } else if M::Provenance::OFFSET_IS_ADDR { - // `use_addr_for_alignment_check` can only be true if `OFFSET_IS_ADDR` is true. - offset_misalignment(ptr.addr().bytes(), align) - } else { - // Check allocation alignment and offset alignment. - if alloc_align.bytes() < align.bytes() { - Some(Misalignment { has: alloc_align, required: align }) - } else { - offset_misalignment(offset.bytes(), align) - } - } - } - } - } - - /// Checks a pointer for misalignment. - /// - /// The error assumes this is checking the pointer used directly for an access. - pub fn check_ptr_align( - &self, - ptr: Pointer>, - align: Align, - ) -> InterpResult<'tcx> { - self.check_misalign(self.is_ptr_misaligned(ptr, align), CheckAlignMsg::AccessedPtr) - } -} - -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - /// This function is used by Miri's provenance GC to remove unreachable entries from the dead_alloc_map. - pub fn remove_unreachable_allocs(&mut self, reachable_allocs: &FxHashSet) { - // Unlike all the other GC helpers where we check if an `AllocId` is found in the interpreter or - // is live, here all the IDs in the map are for dead allocations so we don't - // need to check for liveness. - #[allow(rustc::potential_query_instability)] // Only used from Miri, not queries. - self.memory.dead_alloc_map.retain(|id, _| reachable_allocs.contains(id)); - } -} - -/// Allocation accessors -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - /// Helper function to obtain a global (tcx) allocation. - /// This attempts to return a reference to an existing allocation if - /// one can be found in `tcx`. That, however, is only possible if `tcx` and - /// this machine use the same pointer provenance, so it is indirected through - /// `M::adjust_allocation`. - fn get_global_alloc( - &self, - id: AllocId, - is_write: bool, - ) -> InterpResult<'tcx, Cow<'tcx, Allocation>> { - let (alloc, def_id) = match self.tcx.try_get_global_alloc(id) { - Some(GlobalAlloc::Memory(mem)) => { - // Memory of a constant or promoted or anonymous memory referenced by a static. - (mem, None) - } - Some(GlobalAlloc::Function(..)) => throw_ub!(DerefFunctionPointer(id)), - Some(GlobalAlloc::VTable(..)) => throw_ub!(DerefVTablePointer(id)), - None => throw_ub!(PointerUseAfterFree(id, CheckInAllocMsg::MemoryAccessTest)), - Some(GlobalAlloc::Static(def_id)) => { - assert!(self.tcx.is_static(def_id)); - // Thread-local statics do not have a constant address. They *must* be accessed via - // `ThreadLocalRef`; we can never have a pointer to them as a regular constant value. - assert!(!self.tcx.is_thread_local_static(def_id)); - // Notice that every static has two `AllocId` that will resolve to the same - // thing here: one maps to `GlobalAlloc::Static`, this is the "lazy" ID, - // and the other one is maps to `GlobalAlloc::Memory`, this is returned by - // `eval_static_initializer` and it is the "resolved" ID. - // The resolved ID is never used by the interpreted program, it is hidden. - // This is relied upon for soundness of const-patterns; a pointer to the resolved - // ID would "sidestep" the checks that make sure consts do not point to statics! - // The `GlobalAlloc::Memory` branch here is still reachable though; when a static - // contains a reference to memory that was created during its evaluation (i.e., not - // to another static), those inner references only exist in "resolved" form. - if self.tcx.is_foreign_item(def_id) { - // This is unreachable in Miri, but can happen in CTFE where we actually *do* support - // referencing arbitrary (declared) extern statics. - throw_unsup!(ExternStatic(def_id)); - } - - // We don't give a span -- statics don't need that, they cannot be generic or associated. - let val = self.ctfe_query(|tcx| tcx.eval_static_initializer(def_id))?; - (val, Some(def_id)) - } - }; - M::before_access_global(self.tcx, &self.machine, id, alloc, def_id, is_write)?; - // We got tcx memory. Let the machine initialize its "extra" stuff. - M::adjust_allocation( - self, - id, // always use the ID we got as input, not the "hidden" one. - Cow::Borrowed(alloc.inner()), - M::GLOBAL_KIND.map(MemoryKind::Machine), - ) - } - - /// Gives raw access to the `Allocation`, without bounds or alignment checks. - /// The caller is responsible for calling the access hooks! - /// - /// You almost certainly want to use `get_ptr_alloc`/`get_ptr_alloc_mut` instead. - fn get_alloc_raw( - &self, - id: AllocId, - ) -> InterpResult<'tcx, &Allocation> { - // The error type of the inner closure here is somewhat funny. We have two - // ways of "erroring": An actual error, or because we got a reference from - // `get_global_alloc` that we can actually use directly without inserting anything anywhere. - // So the error type is `InterpResult<'tcx, &Allocation>`. - let a = self.memory.alloc_map.get_or(id, || { - let alloc = self.get_global_alloc(id, /*is_write*/ false).map_err(Err)?; - match alloc { - Cow::Borrowed(alloc) => { - // We got a ref, cheaply return that as an "error" so that the - // map does not get mutated. - Err(Ok(alloc)) - } - Cow::Owned(alloc) => { - // Need to put it into the map and return a ref to that - let kind = M::GLOBAL_KIND.expect( - "I got a global allocation that I have to copy but the machine does \ - not expect that to happen", - ); - Ok((MemoryKind::Machine(kind), alloc)) - } - } - }); - // Now unpack that funny error type - match a { - Ok(a) => Ok(&a.1), - Err(a) => a, - } - } - - /// Bounds-checked *but not align-checked* allocation access. - pub fn get_ptr_alloc<'a>( - &'a self, - ptr: Pointer>, - size: Size, - ) -> InterpResult<'tcx, Option>> - { - let ptr_and_alloc = self.check_and_deref_ptr( - ptr, - size, - CheckInAllocMsg::MemoryAccessTest, - |alloc_id, offset, prov| { - if !self.memory.validation_in_progress.get() { - // We want to call the hook on *all* accesses that involve an AllocId, - // including zero-sized accesses. That means we have to do it here - // rather than below in the `Some` branch. - M::before_alloc_read(self, alloc_id)?; - } - let alloc = self.get_alloc_raw(alloc_id)?; - Ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc))) - }, - )?; - - if let Some((alloc_id, offset, prov, alloc)) = ptr_and_alloc { - let range = alloc_range(offset, size); - if !self.memory.validation_in_progress.get() { - M::before_memory_read( - self.tcx, - &self.machine, - &alloc.extra, - (alloc_id, prov), - range, - )?; - } - Ok(Some(AllocRef { alloc, range, tcx: *self.tcx, alloc_id })) - } else { - Ok(None) - } - } - - /// Return the `extra` field of the given allocation. - pub fn get_alloc_extra<'a>(&'a self, id: AllocId) -> InterpResult<'tcx, &'a M::AllocExtra> { - Ok(&self.get_alloc_raw(id)?.extra) - } - - /// Return the `mutability` field of the given allocation. - pub fn get_alloc_mutability<'a>(&'a self, id: AllocId) -> InterpResult<'tcx, Mutability> { - Ok(self.get_alloc_raw(id)?.mutability) - } - - /// Gives raw mutable access to the `Allocation`, without bounds or alignment checks. - /// The caller is responsible for calling the access hooks! - /// - /// Also returns a ptr to `self.extra` so that the caller can use it in parallel with the - /// allocation. - fn get_alloc_raw_mut( - &mut self, - id: AllocId, - ) -> InterpResult<'tcx, (&mut Allocation, &mut M)> { - // We have "NLL problem case #3" here, which cannot be worked around without loss of - // efficiency even for the common case where the key is in the map. - // - // (Cannot use `get_mut_or` since `get_global_alloc` needs `&self`.) - if self.memory.alloc_map.get_mut(id).is_none() { - // Slow path. - // Allocation not found locally, go look global. - let alloc = self.get_global_alloc(id, /*is_write*/ true)?; - let kind = M::GLOBAL_KIND.expect( - "I got a global allocation that I have to copy but the machine does \ - not expect that to happen", - ); - self.memory.alloc_map.insert(id, (MemoryKind::Machine(kind), alloc.into_owned())); - } - - let (_kind, alloc) = self.memory.alloc_map.get_mut(id).unwrap(); - if alloc.mutability.is_not() { - throw_ub!(WriteToReadOnly(id)) - } - Ok((alloc, &mut self.machine)) - } - - /// Bounds-checked *but not align-checked* allocation access. - pub fn get_ptr_alloc_mut<'a>( - &'a mut self, - ptr: Pointer>, - size: Size, - ) -> InterpResult<'tcx, Option>> - { - let parts = self.get_ptr_access(ptr, size)?; - if let Some((alloc_id, offset, prov)) = parts { - let tcx = self.tcx; - // FIXME: can we somehow avoid looking up the allocation twice here? - // We cannot call `get_raw_mut` inside `check_and_deref_ptr` as that would duplicate `&mut self`. - let (alloc, machine) = self.get_alloc_raw_mut(alloc_id)?; - let range = alloc_range(offset, size); - M::before_memory_write(tcx, machine, &mut alloc.extra, (alloc_id, prov), range)?; - Ok(Some(AllocRefMut { alloc, range, tcx: *tcx, alloc_id })) - } else { - Ok(None) - } - } - - /// Return the `extra` field of the given allocation. - pub fn get_alloc_extra_mut<'a>( - &'a mut self, - id: AllocId, - ) -> InterpResult<'tcx, (&'a mut M::AllocExtra, &'a mut M)> { - let (alloc, machine) = self.get_alloc_raw_mut(id)?; - Ok((&mut alloc.extra, machine)) - } - - /// Check whether an allocation is live. This is faster than calling - /// [`InterpCx::get_alloc_info`] if all you need to check is whether the kind is - /// [`AllocKind::Dead`] because it doesn't have to look up the type and layout of statics. - pub fn is_alloc_live(&self, id: AllocId) -> bool { - self.tcx.try_get_global_alloc(id).is_some() - || self.memory.alloc_map.contains_key_ref(&id) - || self.memory.extra_fn_ptr_map.contains_key(&id) - } - - /// Obtain the size and alignment of an allocation, even if that allocation has - /// been deallocated. - pub fn get_alloc_info(&self, id: AllocId) -> (Size, Align, AllocKind) { - // # Regular allocations - // Don't use `self.get_raw` here as that will - // a) cause cycles in case `id` refers to a static - // b) duplicate a global's allocation in miri - if let Some((_, alloc)) = self.memory.alloc_map.get(id) { - return (alloc.size(), alloc.align, AllocKind::LiveData); - } - - // # Function pointers - // (both global from `alloc_map` and local from `extra_fn_ptr_map`) - if self.get_fn_alloc(id).is_some() { - return (Size::ZERO, Align::ONE, AllocKind::Function); - } - - // # Statics - // Can't do this in the match argument, we may get cycle errors since the lock would - // be held throughout the match. - match self.tcx.try_get_global_alloc(id) { - Some(GlobalAlloc::Static(def_id)) => { - // Thread-local statics do not have a constant address. They *must* be accessed via - // `ThreadLocalRef`; we can never have a pointer to them as a regular constant value. - assert!(!self.tcx.is_thread_local_static(def_id)); - - let DefKind::Static { nested, .. } = self.tcx.def_kind(def_id) else { - bug!("GlobalAlloc::Static is not a static") - }; - - let (size, align) = if nested { - // Nested anonymous statics are untyped, so let's get their - // size and alignment from the allocaiton itself. This always - // succeeds, as the query is fed at DefId creation time, so no - // evaluation actually occurs. - let alloc = self.tcx.eval_static_initializer(def_id).unwrap(); - (alloc.0.size(), alloc.0.align) - } else { - // Use size and align of the type for everything else. We need - // to do that to - // * avoid cycle errors in case of self-referential statics, - // * be able to get information on extern statics. - let ty = self - .tcx - .type_of(def_id) - .no_bound_vars() - .expect("statics should not have generic parameters"); - let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap(); - assert!(layout.is_sized()); - (layout.size, layout.align.abi) - }; - (size, align, AllocKind::LiveData) - } - Some(GlobalAlloc::Memory(alloc)) => { - // Need to duplicate the logic here, because the global allocations have - // different associated types than the interpreter-local ones. - let alloc = alloc.inner(); - (alloc.size(), alloc.align, AllocKind::LiveData) - } - Some(GlobalAlloc::Function(_)) => bug!("We already checked function pointers above"), - Some(GlobalAlloc::VTable(..)) => { - // No data to be accessed here. But vtables are pointer-aligned. - return (Size::ZERO, self.tcx.data_layout.pointer_align.abi, AllocKind::VTable); - } - // The rest must be dead. - None => { - // Deallocated pointers are allowed, we should be able to find - // them in the map. - let (size, align) = *self - .memory - .dead_alloc_map - .get(&id) - .expect("deallocated pointers should all be recorded in `dead_alloc_map`"); - (size, align, AllocKind::Dead) - } - } - } - - /// Obtain the size and alignment of a *live* allocation. - fn get_live_alloc_size_and_align( - &self, - id: AllocId, - msg: CheckInAllocMsg, - ) -> InterpResult<'tcx, (Size, Align)> { - let (size, align, kind) = self.get_alloc_info(id); - if matches!(kind, AllocKind::Dead) { - throw_ub!(PointerUseAfterFree(id, msg)) - } - Ok((size, align)) - } - - fn get_fn_alloc(&self, id: AllocId) -> Option> { - if let Some(extra) = self.memory.extra_fn_ptr_map.get(&id) { - Some(FnVal::Other(*extra)) - } else { - match self.tcx.try_get_global_alloc(id) { - Some(GlobalAlloc::Function(instance)) => Some(FnVal::Instance(instance)), - _ => None, - } - } - } - - pub fn get_ptr_fn( - &self, - ptr: Pointer>, - ) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> { - trace!("get_ptr_fn({:?})", ptr); - let (alloc_id, offset, _prov) = self.ptr_get_alloc_id(ptr)?; - if offset.bytes() != 0 { - throw_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset))) - } - self.get_fn_alloc(alloc_id) - .ok_or_else(|| err_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset))).into()) - } - - pub fn get_ptr_vtable( - &self, - ptr: Pointer>, - ) -> InterpResult<'tcx, (Ty<'tcx>, Option>)> { - trace!("get_ptr_vtable({:?})", ptr); - let (alloc_id, offset, _tag) = self.ptr_get_alloc_id(ptr)?; - if offset.bytes() != 0 { - throw_ub!(InvalidVTablePointer(Pointer::new(alloc_id, offset))) - } - match self.tcx.try_get_global_alloc(alloc_id) { - Some(GlobalAlloc::VTable(ty, trait_ref)) => Ok((ty, trait_ref)), - _ => throw_ub!(InvalidVTablePointer(Pointer::new(alloc_id, offset))), - } - } - - pub fn alloc_mark_immutable(&mut self, id: AllocId) -> InterpResult<'tcx> { - self.get_alloc_raw_mut(id)?.0.mutability = Mutability::Not; - Ok(()) - } - - /// Create a lazy debug printer that prints the given allocation and all allocations it points - /// to, recursively. - #[must_use] - pub fn dump_alloc<'a>(&'a self, id: AllocId) -> DumpAllocs<'a, 'mir, 'tcx, M> { - self.dump_allocs(vec![id]) - } - - /// Create a lazy debug printer for a list of allocations and all allocations they point to, - /// recursively. - #[must_use] - pub fn dump_allocs<'a>(&'a self, mut allocs: Vec) -> DumpAllocs<'a, 'mir, 'tcx, M> { - allocs.sort(); - allocs.dedup(); - DumpAllocs { ecx: self, allocs } - } - - /// Print the allocation's bytes, without any nested allocations. - pub fn print_alloc_bytes_for_diagnostics(&self, id: AllocId) -> String { - // Using the "raw" access to avoid the `before_alloc_read` hook, we specifically - // want to be able to read all memory for diagnostics, even if that is cyclic. - let alloc = self.get_alloc_raw(id).unwrap(); - let mut bytes = String::new(); - if alloc.size() != Size::ZERO { - bytes = "\n".into(); - // FIXME(translation) there might be pieces that are translatable. - rustc_middle::mir::pretty::write_allocation_bytes(*self.tcx, alloc, &mut bytes, " ") - .unwrap(); - } - bytes - } - - /// Find leaked allocations. Allocations reachable from `static_roots` or a `Global` allocation - /// are not considered leaked, as well as leaks whose kind's `may_leak()` returns true. - pub fn find_leaked_allocations( - &self, - static_roots: &[AllocId], - ) -> Vec<(AllocId, MemoryKind, Allocation)> - { - // Collect the set of allocations that are *reachable* from `Global` allocations. - let reachable = { - let mut reachable = FxHashSet::default(); - let global_kind = M::GLOBAL_KIND.map(MemoryKind::Machine); - let mut todo: Vec<_> = - self.memory.alloc_map.filter_map_collect(move |&id, &(kind, _)| { - if Some(kind) == global_kind { Some(id) } else { None } - }); - 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 `todo`. - if let Some((_, alloc)) = self.memory.alloc_map.get(id) { - todo.extend( - alloc.provenance().provenances().filter_map(|prov| prov.get_alloc_id()), - ); - } - } - } - reachable - }; - - // All allocations that are *not* `reachable` and *not* `may_leak` are considered leaking. - self.memory.alloc_map.filter_map_collect(|id, (kind, alloc)| { - if kind.may_leak() || reachable.contains(id) { - None - } else { - Some((*id, *kind, alloc.clone())) - } - }) - } - - /// Runs the close in "validation" mode, which means the machine's memory read hooks will be - /// suppressed. Needless to say, this must only be set with great care! Cannot be nested. - pub(super) fn run_for_validation(&self, f: impl FnOnce() -> R) -> R { - // This deliberately uses `==` on `bool` to follow the pattern - // `assert!(val.replace(new) == old)`. - assert!( - self.memory.validation_in_progress.replace(true) == false, - "`validation_in_progress` was already set" - ); - let res = f(); - assert!( - self.memory.validation_in_progress.replace(false) == true, - "`validation_in_progress` was unset by someone else" - ); - res - } -} - -#[doc(hidden)] -/// There's no way to use this directly, it's just a helper struct for the `dump_alloc(s)` methods. -pub struct DumpAllocs<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> { - ecx: &'a InterpCx<'mir, 'tcx, M>, - allocs: Vec, -} - -impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a, 'mir, 'tcx, M> { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - // Cannot be a closure because it is generic in `Prov`, `Extra`. - fn write_allocation_track_relocs<'tcx, Prov: Provenance, Extra, Bytes: AllocBytes>( - fmt: &mut std::fmt::Formatter<'_>, - tcx: TyCtxt<'tcx>, - allocs_to_print: &mut VecDeque, - alloc: &Allocation, - ) -> std::fmt::Result { - for alloc_id in alloc.provenance().provenances().filter_map(|prov| prov.get_alloc_id()) - { - allocs_to_print.push_back(alloc_id); - } - write!(fmt, "{}", display_allocation(tcx, alloc)) - } - - let mut allocs_to_print: VecDeque<_> = self.allocs.iter().copied().collect(); - // `allocs_printed` contains all allocations that we have already printed. - let mut allocs_printed = FxHashSet::default(); - - while let Some(id) = allocs_to_print.pop_front() { - if !allocs_printed.insert(id) { - // Already printed, so skip this. - continue; - } - - write!(fmt, "{id:?}")?; - match self.ecx.memory.alloc_map.get(id) { - Some((kind, alloc)) => { - // normal alloc - write!(fmt, " ({kind}, ")?; - write_allocation_track_relocs( - &mut *fmt, - *self.ecx.tcx, - &mut allocs_to_print, - alloc, - )?; - } - None => { - // global alloc - match self.ecx.tcx.try_get_global_alloc(id) { - Some(GlobalAlloc::Memory(alloc)) => { - write!(fmt, " (unchanged global, ")?; - write_allocation_track_relocs( - &mut *fmt, - *self.ecx.tcx, - &mut allocs_to_print, - alloc.inner(), - )?; - } - Some(GlobalAlloc::Function(func)) => { - write!(fmt, " (fn: {func})")?; - } - Some(GlobalAlloc::VTable(ty, Some(trait_ref))) => { - write!(fmt, " (vtable: impl {trait_ref} for {ty})")?; - } - Some(GlobalAlloc::VTable(ty, None)) => { - write!(fmt, " (vtable: impl for {ty})")?; - } - Some(GlobalAlloc::Static(did)) => { - write!(fmt, " (static: {})", self.ecx.tcx.def_path_str(did))?; - } - None => { - write!(fmt, " (deallocated)")?; - } - } - } - } - writeln!(fmt)?; - } - Ok(()) - } -} - -/// Reading and writing. -impl<'tcx, 'a, Prov: Provenance, Extra, Bytes: AllocBytes> - AllocRefMut<'a, 'tcx, Prov, Extra, Bytes> -{ - /// `range` is relative to this allocation reference, not the base of the allocation. - pub fn write_scalar(&mut self, range: AllocRange, val: Scalar) -> InterpResult<'tcx> { - let range = self.range.subrange(range); - debug!("write_scalar at {:?}{range:?}: {val:?}", self.alloc_id); - Ok(self - .alloc - .write_scalar(&self.tcx, range, val) - .map_err(|e| e.to_interp_error(self.alloc_id))?) - } - - /// `offset` is relative to this allocation reference, not the base of the allocation. - pub fn write_ptr_sized(&mut self, offset: Size, val: Scalar) -> InterpResult<'tcx> { - self.write_scalar(alloc_range(offset, self.tcx.data_layout().pointer_size), val) - } - - /// Mark the entire referenced range as uninitialized - pub fn write_uninit(&mut self) -> InterpResult<'tcx> { - Ok(self - .alloc - .write_uninit(&self.tcx, self.range) - .map_err(|e| e.to_interp_error(self.alloc_id))?) - } -} - -impl<'tcx, 'a, Prov: Provenance, Extra, Bytes: AllocBytes> AllocRef<'a, 'tcx, Prov, Extra, Bytes> { - /// `range` is relative to this allocation reference, not the base of the allocation. - pub fn read_scalar( - &self, - range: AllocRange, - read_provenance: bool, - ) -> InterpResult<'tcx, Scalar> { - let range = self.range.subrange(range); - let res = self - .alloc - .read_scalar(&self.tcx, range, read_provenance) - .map_err(|e| e.to_interp_error(self.alloc_id))?; - debug!("read_scalar at {:?}{range:?}: {res:?}", self.alloc_id); - Ok(res) - } - - /// `range` is relative to this allocation reference, not the base of the allocation. - pub fn read_integer(&self, range: AllocRange) -> InterpResult<'tcx, Scalar> { - self.read_scalar(range, /*read_provenance*/ false) - } - - /// `offset` is relative to this allocation reference, not the base of the allocation. - pub fn read_pointer(&self, offset: Size) -> InterpResult<'tcx, Scalar> { - self.read_scalar( - alloc_range(offset, self.tcx.data_layout().pointer_size), - /*read_provenance*/ true, - ) - } - - /// `range` is relative to this allocation reference, not the base of the allocation. - pub fn get_bytes_strip_provenance<'b>(&'b self) -> InterpResult<'tcx, &'a [u8]> { - Ok(self - .alloc - .get_bytes_strip_provenance(&self.tcx, self.range) - .map_err(|e| e.to_interp_error(self.alloc_id))?) - } - - /// Returns whether the allocation has provenance anywhere in the range of the `AllocRef`. - pub fn has_provenance(&self) -> bool { - !self.alloc.provenance().range_empty(self.range, &self.tcx) - } -} - -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - /// Reads the given number of bytes from memory, and strips their provenance if possible. - /// Returns them as a slice. - /// - /// Performs appropriate bounds checks. - pub fn read_bytes_ptr_strip_provenance( - &self, - ptr: Pointer>, - size: Size, - ) -> InterpResult<'tcx, &[u8]> { - let Some(alloc_ref) = self.get_ptr_alloc(ptr, size)? else { - // zero-sized access - return Ok(&[]); - }; - // Side-step AllocRef and directly access the underlying bytes more efficiently. - // (We are staying inside the bounds here so all is good.) - Ok(alloc_ref - .alloc - .get_bytes_strip_provenance(&alloc_ref.tcx, alloc_ref.range) - .map_err(|e| e.to_interp_error(alloc_ref.alloc_id))?) - } - - /// Writes the given stream of bytes into memory. - /// - /// Performs appropriate bounds checks. - pub fn write_bytes_ptr( - &mut self, - ptr: Pointer>, - src: impl IntoIterator, - ) -> InterpResult<'tcx> { - let mut src = src.into_iter(); - let (lower, upper) = src.size_hint(); - let len = upper.expect("can only write bounded iterators"); - assert_eq!(lower, len, "can only write iterators with a precise length"); - - let size = Size::from_bytes(len); - let Some(alloc_ref) = self.get_ptr_alloc_mut(ptr, size)? else { - // zero-sized access - assert_matches!(src.next(), None, "iterator said it was empty but returned an element"); - return Ok(()); - }; - - // Side-step AllocRef and directly access the underlying bytes more efficiently. - // (We are staying inside the bounds here and all bytes do get overwritten so all is good.) - let alloc_id = alloc_ref.alloc_id; - let bytes = alloc_ref - .alloc - .get_bytes_unchecked_for_overwrite(&alloc_ref.tcx, alloc_ref.range) - .map_err(move |e| e.to_interp_error(alloc_id))?; - // `zip` would stop when the first iterator ends; we want to definitely - // cover all of `bytes`. - for dest in bytes { - *dest = src.next().expect("iterator was shorter than it said it would be"); - } - assert_matches!(src.next(), None, "iterator was longer than it said it would be"); - Ok(()) - } - - pub fn mem_copy( - &mut self, - src: Pointer>, - dest: Pointer>, - size: Size, - nonoverlapping: bool, - ) -> InterpResult<'tcx> { - self.mem_copy_repeatedly(src, dest, size, 1, nonoverlapping) - } - - /// Performs `num_copies` many copies of `size` many bytes from `src` to `dest + i*size` (where - /// `i` is the index of the copy). - /// - /// Either `nonoverlapping` must be true or `num_copies` must be 1; doing repeated copies that - /// may overlap is not supported. - pub fn mem_copy_repeatedly( - &mut self, - src: Pointer>, - dest: Pointer>, - size: Size, - num_copies: u64, - nonoverlapping: bool, - ) -> InterpResult<'tcx> { - let tcx = self.tcx; - // We need to do our own bounds-checks. - let src_parts = self.get_ptr_access(src, size)?; - let dest_parts = self.get_ptr_access(dest, size * num_copies)?; // `Size` multiplication - - // FIXME: we look up both allocations twice here, once before for the `check_ptr_access` - // and once below to get the underlying `&[mut] Allocation`. - - // Source alloc preparations and access hooks. - let Some((src_alloc_id, src_offset, src_prov)) = src_parts else { - // Zero-sized *source*, that means dest is also zero-sized and we have nothing to do. - return Ok(()); - }; - let src_alloc = self.get_alloc_raw(src_alloc_id)?; - let src_range = alloc_range(src_offset, size); - assert!(!self.memory.validation_in_progress.get(), "we can't be copying during validation"); - M::before_memory_read( - tcx, - &self.machine, - &src_alloc.extra, - (src_alloc_id, src_prov), - src_range, - )?; - // We need the `dest` ptr for the next operation, so we get it now. - // We already did the source checks and called the hooks so we are good to return early. - let Some((dest_alloc_id, dest_offset, dest_prov)) = dest_parts else { - // Zero-sized *destination*. - return Ok(()); - }; - - // Prepare getting source provenance. - let src_bytes = src_alloc.get_bytes_unchecked(src_range).as_ptr(); // raw ptr, so we can also get a ptr to the destination allocation - // first copy the provenance to a temporary buffer, because - // `get_bytes_mut` will clear the provenance, which is correct, - // since we don't want to keep any provenance at the target. - // This will also error if copying partial provenance is not supported. - let provenance = src_alloc - .provenance() - .prepare_copy(src_range, dest_offset, num_copies, self) - .map_err(|e| e.to_interp_error(dest_alloc_id))?; - // Prepare a copy of the initialization mask. - let init = src_alloc.init_mask().prepare_copy(src_range); - - // Destination alloc preparations and access hooks. - let (dest_alloc, extra) = self.get_alloc_raw_mut(dest_alloc_id)?; - let dest_range = alloc_range(dest_offset, size * num_copies); - M::before_memory_write( - tcx, - extra, - &mut dest_alloc.extra, - (dest_alloc_id, dest_prov), - dest_range, - )?; - // Yes we do overwrite all bytes in `dest_bytes`. - let dest_bytes = dest_alloc - .get_bytes_unchecked_for_overwrite_ptr(&tcx, dest_range) - .map_err(|e| e.to_interp_error(dest_alloc_id))? - .as_mut_ptr(); - - if init.no_bytes_init() { - // Fast path: If all bytes are `uninit` then there is nothing to copy. The target range - // is marked as uninitialized but we otherwise omit changing the byte representation which may - // be arbitrary for uninitialized bytes. - // This also avoids writing to the target bytes so that the backing allocation is never - // touched if the bytes stay uninitialized for the whole interpreter execution. On contemporary - // operating system this can avoid physically allocating the page. - dest_alloc - .write_uninit(&tcx, dest_range) - .map_err(|e| e.to_interp_error(dest_alloc_id))?; - // We can forget about the provenance, this is all not initialized anyway. - return Ok(()); - } - - // SAFE: The above indexing would have panicked if there weren't at least `size` bytes - // behind `src` and `dest`. Also, we use the overlapping-safe `ptr::copy` if `src` and - // `dest` could possibly overlap. - // The pointers above remain valid even if the `HashMap` table is moved around because they - // point into the `Vec` storing the bytes. - unsafe { - if src_alloc_id == dest_alloc_id { - if nonoverlapping { - // `Size` additions - if (src_offset <= dest_offset && src_offset + size > dest_offset) - || (dest_offset <= src_offset && dest_offset + size > src_offset) - { - throw_ub_custom!(fluent::const_eval_copy_nonoverlapping_overlapping); - } - } - } - if num_copies > 1 { - assert!(nonoverlapping, "multi-copy only supported in non-overlapping mode"); - } - - let size_in_bytes = size.bytes_usize(); - // For particularly large arrays (where this is perf-sensitive) it's common that - // we're writing a single byte repeatedly. So, optimize that case to a memset. - if size_in_bytes == 1 { - debug_assert!(num_copies >= 1); // we already handled the zero-sized cases above. - // SAFETY: `src_bytes` would be read from anyway by `copy` below (num_copies >= 1). - let value = *src_bytes; - dest_bytes.write_bytes(value, (size * num_copies).bytes_usize()); - } else if src_alloc_id == dest_alloc_id { - let mut dest_ptr = dest_bytes; - for _ in 0..num_copies { - // Here we rely on `src` and `dest` being non-overlapping if there is more than - // one copy. - ptr::copy(src_bytes, dest_ptr, size_in_bytes); - dest_ptr = dest_ptr.add(size_in_bytes); - } - } else { - let mut dest_ptr = dest_bytes; - for _ in 0..num_copies { - ptr::copy_nonoverlapping(src_bytes, dest_ptr, size_in_bytes); - dest_ptr = dest_ptr.add(size_in_bytes); - } - } - } - - // now fill in all the "init" data - dest_alloc.init_mask_apply_copy( - init, - alloc_range(dest_offset, size), // just a single copy (i.e., not full `dest_range`) - num_copies, - ); - // copy the provenance to the destination - dest_alloc.provenance_apply_copy(provenance); - - Ok(()) - } -} - -/// Machine pointer introspection. -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - /// Test if this value might be null. - /// If the machine does not support ptr-to-int casts, this is conservative. - pub fn scalar_may_be_null(&self, scalar: Scalar) -> InterpResult<'tcx, bool> { - Ok(match scalar.try_to_int() { - Ok(int) => int.is_null(), - Err(_) => { - // Can only happen during CTFE. - let ptr = scalar.to_pointer(self)?; - match self.ptr_try_get_alloc_id(ptr) { - Ok((alloc_id, offset, _)) => { - let (size, _align, _kind) = self.get_alloc_info(alloc_id); - // If the pointer is out-of-bounds, it may be null. - // Note that one-past-the-end (offset == size) is still inbounds, and never null. - offset > size - } - Err(_offset) => bug!("a non-int scalar is always a pointer"), - } - } - }) - } - - /// Turning a "maybe pointer" into a proper pointer (and some information - /// about where it points), or an absolute address. - /// - /// The result must be used immediately; it is not allowed to convert - /// the returned data back into a `Pointer` and store that in machine state. - /// (In fact that's not even possible since `M::ProvenanceExtra` is generic and - /// we don't have an operation to turn it back into `M::Provenance`.) - pub fn ptr_try_get_alloc_id( - &self, - ptr: Pointer>, - ) -> Result<(AllocId, Size, M::ProvenanceExtra), u64> { - match ptr.into_pointer_or_addr() { - Ok(ptr) => match M::ptr_get_alloc(self, ptr) { - Some((alloc_id, offset, extra)) => Ok((alloc_id, offset, extra)), - None => { - assert!(M::Provenance::OFFSET_IS_ADDR); - let (_, addr) = ptr.into_parts(); - Err(addr.bytes()) - } - }, - Err(addr) => Err(addr.bytes()), - } - } - - /// Turning a "maybe pointer" into a proper pointer (and some information about where it points). - /// - /// The result must be used immediately; it is not allowed to convert - /// the returned data back into a `Pointer` and store that in machine state. - /// (In fact that's not even possible since `M::ProvenanceExtra` is generic and - /// we don't have an operation to turn it back into `M::Provenance`.) - #[inline(always)] - pub fn ptr_get_alloc_id( - &self, - ptr: Pointer>, - ) -> InterpResult<'tcx, (AllocId, Size, M::ProvenanceExtra)> { - self.ptr_try_get_alloc_id(ptr).map_err(|offset| { - err_ub!(DanglingIntPointer(offset, CheckInAllocMsg::InboundsTest)).into() - }) - } -} +use std::assert_matches::assert_matches;use std::borrow::Cow;use std::cell:://3; +Cell;use std::collections::VecDeque;use std::fmt;use std::ptr;use rustc_ast:://; +Mutability;use rustc_data_structures::fx::{FxHashSet,FxIndexMap};use rustc_hir// +::def::DefKind;use rustc_middle:: mir::display_allocation;use rustc_middle::ty:: +{self,Instance,ParamEnv,Ty,TyCtxt} ;use rustc_target::abi::{Align,HasDataLayout, +Size};use crate::fluent_generated as fluent;use super::{alloc_range,AllocBytes, +AllocId,AllocMap,AllocRange,Allocation,CheckAlignMsg,CheckInAllocMsg,//let _=(); +CtfeProvenance,GlobalAlloc,InterpCx,InterpResult,Machine,MayLeak,Misalignment,// +Pointer,PointerArithmetic,Provenance,Scalar,};#[derive(Debug,PartialEq,Copy,//3; +Clone)]pub enum MemoryKind{Stack,CallerLocation,Machine(T),}impl// +MayLeak for MemoryKind{#[inline]fn may_leak(self)->bool{match self{//((),()); +MemoryKind::Stack=>false,MemoryKind:: CallerLocation=>true,MemoryKind::Machine(k +)=>(k.may_leak()),}}}implfmt::Display for MemoryKind{fn fmt(& +self,f:&mut fmt::Formatter<'_>)->fmt::Result{match self{MemoryKind::Stack=>//(); +write!(f,"stack variable"),MemoryKind::CallerLocation=>write!(f,//if let _=(){}; +"caller location"),MemoryKind::Machine(m)=>((write!(f,"{m}"))),}}}#[derive(Copy, +Clone,PartialEq,Debug)]pub enum AllocKind{LiveData,Function,VTable,Dead,}#[//(); +derive(Debug,Copy,Clone)]pub enum FnVal<'tcx,Other>{Instance(Instance<'tcx>),//; +Other(Other),}impl<'tcx,Other>FnVal<'tcx,Other>{pub fn as_instance(self)->//{;}; +InterpResult<'tcx,Instance<'tcx>>{match self{FnVal::Instance(instance)=>Ok(//(); +instance),FnVal::Other(_)=>{throw_unsup_format!(//*&*&();((),());*&*&();((),()); +"'foreign' function pointers are not supported in this context")}}}}pub struct// +Memory<'mir,'tcx,M:Machine<'mir,'tcx>>{pub(super)alloc_map:M::MemoryMap,//{();}; +extra_fn_ptr_map:FxIndexMap,pub(super)dead_alloc_map://3; +FxIndexMap,validation_in_progress:Cell,}#[derive(//; +Copy,Clone)]pub struct AllocRef<'a ,'tcx,Prov:Provenance,Extra,Bytes:AllocBytes= +Box<[u8]>>{alloc:&'a Allocation,range:AllocRange,tcx:TyCtxt,alloc_id:AllocId,}pub struct AllocRefMut<'a,'tcx,Prov:Provenance,Extra,//; +Bytes:AllocBytes=Box<[u8]>>{alloc:&'a mut Allocation,range://; +AllocRange,tcx:TyCtxt<'tcx>,alloc_id:AllocId,}impl<'mir,'tcx,M:Machine<'mir,//3; +'tcx>>Memory<'mir,'tcx,M>{pub fn new()->Self{Memory{alloc_map:M::MemoryMap:://3; +default(),extra_fn_ptr_map:((FxIndexMap::default())),dead_alloc_map:FxIndexMap:: +default(),validation_in_progress:Cell::new(false) ,}}pub fn alloc_map(&self)->&M +::MemoryMap{&self.alloc_map}}impl<'mir ,'tcx:'mir,M:Machine<'mir,'tcx>>InterpCx< +'mir,'tcx,M>{#[inline]pub fn global_base_pointer(&self,ptr:Pointer,)->InterpResult<'tcx,Pointer>{3;let alloc_id=ptr. +provenance.alloc_id();*&*&();match self.tcx.try_get_global_alloc(alloc_id){Some( +GlobalAlloc::Static(def_id))if (self.tcx.is_thread_local_static(def_id))=>{bug!( +"global memory cannot point to thread-local static")}Some(GlobalAlloc::Static(// +def_id))if self.tcx.is_foreign_item(def_id)=>{loop{break};loop{break};return M:: +extern_static_base_pointer(self,def_id);{;};}_=>{}}M::adjust_alloc_base_pointer( +self,ptr)}pub fn fn_ptr(&mut self,fn_val:FnVal<'tcx,M::ExtraFnVal>)->Pointer{if true{};let id=match fn_val{FnVal::Instance(instance)=>self.tcx. +reserve_and_set_fn_alloc(instance),FnVal::Other(extra)=>{*&*&();let id=self.tcx. +reserve_alloc_id();;let old=self.memory.extra_fn_ptr_map.insert(id,extra);assert +!(old.is_none());;id}};;self.global_base_pointer(Pointer::from(id)).unwrap()}pub +fn allocate_ptr(&mut self,size:Size, align:Align,kind:MemoryKind, +)->InterpResult<'tcx,Pointer>{let _=();if true{};let alloc=if M:: +PANIC_ON_ALLOC_FAIL{Allocation::uninit(size,align )}else{Allocation::try_uninit( +size,align)?};3;self.allocate_raw_ptr(alloc,kind)}pub fn allocate_bytes_ptr(&mut +self,bytes:&[u8],align:Align,kind:MemoryKind,mutability://*&*&(); +Mutability,)->InterpResult<'tcx,Pointer>{3;let alloc=Allocation:: +from_bytes(bytes,align,mutability);({});self.allocate_raw_ptr(alloc,kind)}pub fn +allocate_raw_ptr(&mut self,alloc:Allocation,kind:MemoryKind,)->// +InterpResult<'tcx,Pointer>{;let id=self.tcx.reserve_alloc_id();;; +debug_assert_ne!(Some(kind),M::GLOBAL_KIND.map(MemoryKind::Machine),//if true{}; +"dynamically allocating global memory");;let alloc=M::adjust_allocation(self,id, +Cow::Owned(alloc),Some(kind))?;();3;self.memory.alloc_map.insert(id,(kind,alloc. +into_owned()));{();};M::adjust_alloc_base_pointer(self,Pointer::from(id))}pub fn +reallocate_ptr(&mut self,ptr:Pointer >,old_size_and_align: +Option<(Size,Align)>,new_size:Size,new_align:Align,kind:MemoryKind,)->InterpResult<'tcx,Pointer>{();let(alloc_id,offset, +_prov)=self.ptr_get_alloc_id(ptr)?;;if offset.bytes()!=0{throw_ub_custom!(fluent +::const_eval_realloc_or_alloc_with_offset,ptr=format! ("{ptr:?}"),kind="realloc" +);;};let new_ptr=self.allocate_ptr(new_size,new_align,kind)?;;let old_size=match +old_size_and_align{Some((size,_align))=>size ,None=>self.get_alloc_raw(alloc_id) +?.size(),};;self.mem_copy(ptr,new_ptr.into(),old_size.min(new_size),true)?;self. +deallocate_ptr(ptr,old_size_and_align,kind)?;;Ok(new_ptr)}#[instrument(skip(self +),level="debug")]pub fn deallocate_ptr(&mut self,ptr:Pointer>,old_size_and_align:Option<(Size,Align)>,kind:MemoryKind,)->InterpResult<'tcx>{*&*&();((),());let(alloc_id,offset,prov)=self. +ptr_get_alloc_id(ptr)?;;trace!("deallocating: {alloc_id:?}");if offset.bytes()!= +0{;throw_ub_custom!(fluent::const_eval_realloc_or_alloc_with_offset,ptr=format!( +"{ptr:?}"),kind="dealloc",);();}();let Some((alloc_kind,mut alloc))=self.memory. +alloc_map.remove(&alloc_id)else{;return Err(match self.tcx.try_get_global_alloc( +alloc_id){Some(GlobalAlloc::Function(..))=>{err_ub_custom!(fluent:://let _=||(); +const_eval_invalid_dealloc,alloc_id=alloc_id,kind="fn",)}Some(GlobalAlloc:://(); +VTable(..))=>{err_ub_custom!(fluent::const_eval_invalid_dealloc,alloc_id=//({}); +alloc_id,kind="vtable",)}Some(GlobalAlloc::Static(..)|GlobalAlloc::Memory(..))// +=>{err_ub_custom!(fluent::const_eval_invalid_dealloc,alloc_id=alloc_id,kind=//3; +"static_mem")}None=>err_ub!(PointerUseAfterFree(alloc_id,CheckInAllocMsg:://{;}; +MemoryAccessTest)),}.into());;};;if alloc.mutability.is_not(){;throw_ub_custom!( +fluent::const_eval_dealloc_immutable,alloc=alloc_id,);();}if alloc_kind!=kind{3; +throw_ub_custom!(fluent::const_eval_dealloc_kind_mismatch,alloc=alloc_id,//({}); +alloc_kind=format!("{alloc_kind}"),kind=format!("{kind}"),);;}if let Some((size, +align))=old_size_and_align{if (((size!=(alloc. size()))||(align!=alloc.align))){ +throw_ub_custom!(fluent::const_eval_dealloc_incorrect_layout,alloc=alloc_id,//3; +size=alloc.size().bytes(),align=alloc.align.bytes(),size_found=size.bytes(),//3; +align_found=align.bytes(),)}}let _=();let size=alloc.size();let _=();((),());M:: +before_memory_deallocation(self.tcx,((&mut self.machine)),((&mut alloc.extra)),( +alloc_id,prov),size,alloc.align,)?;3;;let old=self.memory.dead_alloc_map.insert( +alloc_id,(size,alloc.align));*&*&();((),());if old.is_some(){if let _=(){};bug!( +"Nothing can be deallocated twice");;}Ok(())}#[inline(always)]fn get_ptr_access( +&self,ptr:Pointer> ,size:Size,)->InterpResult<'tcx,Option< +(AllocId,Size,M::ProvenanceExtra)>>{self.check_and_deref_ptr(ptr,size,//((),()); +CheckInAllocMsg::MemoryAccessTest,|alloc_id,offset,prov|{3;let(size,align)=self. +get_live_alloc_size_and_align(alloc_id,CheckInAllocMsg::MemoryAccessTest)?;;Ok(( +size,align,(alloc_id,offset,prov))) },)}#[inline(always)]pub fn check_ptr_access +(&self,ptr:Pointer>,size:Size,msg:CheckInAllocMsg,)->//(); +InterpResult<'tcx>{3;self.check_and_deref_ptr(ptr,size,msg,|alloc_id,_,_|{3;let( +size,align)=self.get_live_alloc_size_and_align(alloc_id,msg)?;;Ok((size,align,() +))})?;;Ok(())}fn check_and_deref_ptr(&self,ptr:Pointer> +,size:Size,msg:CheckInAllocMsg,alloc_size:impl FnOnce(AllocId,Size,M:://((),()); +ProvenanceExtra,)->InterpResult<'tcx,(Size,Align,T)>,)->InterpResult<'tcx,//{;}; +Option>{Ok(match self.ptr_try_get_alloc_id(ptr){ Err(addr)=>{if size.bytes()> +0||addr==0{3;throw_ub!(DanglingIntPointer(addr,msg));;}None}Ok((alloc_id,offset, +prov))=>{;let(alloc_size,_alloc_align,ret_val)=alloc_size(alloc_id,offset,prov)? +;((),());if offset.checked_add(size,&self.tcx).map_or(true,|end|end>alloc_size){ +throw_ub!(PointerOutOfBounds{alloc_id,alloc_size,ptr_offset:self.//loop{break;}; +target_usize_to_isize(offset.bytes()),ptr_size:size,msg,})}if M::Provenance:://; +OFFSET_IS_ADDR{;assert_ne!(ptr.addr(),Size::ZERO);}if size.bytes()==0{None}else{ +Some(ret_val)}}})}pub(super)fn check_misalign(&self,misaligned:Option,msg:CheckAlignMsg,)->InterpResult<'tcx>{if let Some(misaligned)=// +misaligned{(throw_ub!(AlignmentCheckFailed(misaligned,msg)))}Ok(())}pub(super)fn +is_ptr_misaligned(&self,ptr:Pointer>,align:Align,)->//{;}; +Option{if!M::enforce_alignment(self)||align.bytes()==1{({});return +None;({});}({});#[inline]fn offset_misalignment(offset:u64,align:Align)->Option< +Misalignment>{if offset%align.bytes()==0{None}else{();let offset_pow2=1< +offset_misalignment(addr,align),Ok((alloc_id,offset,_prov))=>{((),());let(_size, +alloc_align,kind)=self.get_alloc_info(alloc_id);*&*&();if let Some(misalign)=M:: +alignment_check(self,alloc_id,alloc_align,kind,offset,align){((Some(misalign)))} +else if M::Provenance::OFFSET_IS_ADDR{offset_misalignment( (ptr.addr().bytes()), +align)}else{if (((alloc_align.bytes())< (align.bytes()))){Some(Misalignment{has: +alloc_align,required:align})}else{offset_misalignment( offset.bytes(),align)}}}} +}pub fn check_ptr_align(&self,ptr:Pointer>,align:Align,)// +->InterpResult<'tcx>{self.check_misalign( ((self.is_ptr_misaligned(ptr,align))), +CheckAlignMsg::AccessedPtr)}}impl<'mir,'tcx :'mir,M:Machine<'mir,'tcx>>InterpCx< +'mir,'tcx,M>{pub fn remove_unreachable_allocs(&mut self,reachable_allocs:&//{;}; +FxHashSet){{;};#[allow(rustc::potential_query_instability)]self.memory. +dead_alloc_map.retain(|id,_|reachable_allocs.contains(id));{;};}}impl<'mir,'tcx: +'mir,M:Machine<'mir,'tcx>>InterpCx<'mir,'tcx,M>{fn get_global_alloc(&self,id://; +AllocId,is_write:bool,)->InterpResult<'tcx,Cow<'tcx,Allocation>>{;let(alloc,def_id)=match self.tcx.try_get_global_alloc( +id){Some(GlobalAlloc::Memory(mem))=>{ (mem,None)}Some(GlobalAlloc::Function(..)) +=>throw_ub!(DerefFunctionPointer(id)),Some (GlobalAlloc::VTable(..))=>throw_ub!( +DerefVTablePointer(id)),None=>throw_ub!(PointerUseAfterFree(id,CheckInAllocMsg// +::MemoryAccessTest)),Some(GlobalAlloc::Static(def_id))=>{{();};assert!(self.tcx. +is_static(def_id));;;assert!(!self.tcx.is_thread_local_static(def_id));;if self. +tcx.is_foreign_item(def_id){;throw_unsup!(ExternStatic(def_id));;};let val=self. +ctfe_query(|tcx|tcx.eval_static_initializer(def_id))?;;(val,Some(def_id))}};;M:: +before_access_global(self.tcx,&self.machine,id,alloc,def_id,is_write)?;{();};M:: +adjust_allocation(self,id,((Cow::Borrowed((alloc.inner())))),M::GLOBAL_KIND.map( +MemoryKind::Machine),)}fn get_alloc_raw( &self,id:AllocId,)->InterpResult<'tcx,& +Allocation>{3;let a=self.memory.alloc_map. +get_or(id,||{();let alloc=self.get_global_alloc(id,false).map_err(Err)?;();match +alloc{Cow::Borrowed(alloc)=>{Err(Ok(alloc))}Cow::Owned(alloc)=>{{;};let kind=M:: +GLOBAL_KIND.expect(//if let _=(){};*&*&();((),());*&*&();((),());*&*&();((),()); +"I got a global allocation that I have to copy but the machine does \ + not expect that to happen" +,);;Ok((MemoryKind::Machine(kind),alloc))}}});match a{Ok(a)=>Ok(&a.1),Err(a)=>a, +}}pub fn get_ptr_alloc<'a>(&'a self,ptr:Pointer>,size://3; +Size,)->InterpResult<'tcx,Option>>{3;let ptr_and_alloc=self.check_and_deref_ptr(ptr,size,CheckInAllocMsg +::MemoryAccessTest,|alloc_id,offset,prov |{if!self.memory.validation_in_progress +.get(){3;M::before_alloc_read(self,alloc_id)?;3;}3;let alloc=self.get_alloc_raw( +alloc_id)?;3;Ok((alloc.size(),alloc.align,(alloc_id,offset,prov,alloc)))},)?;;if +let Some((alloc_id,offset,prov,alloc))=ptr_and_alloc{({});let range=alloc_range( +offset,size);;if!self.memory.validation_in_progress.get(){M::before_memory_read( +self.tcx,&self.machine,&alloc.extra,(alloc_id,prov),range,)?;;}Ok(Some(AllocRef{ +alloc,range,tcx:*self.tcx,alloc_id})) }else{Ok(None)}}pub fn get_alloc_extra<'a> +(&'a self,id:AllocId)->InterpResult<'tcx,&'a M::AllocExtra>{Ok(&self.//let _=(); +get_alloc_raw(id)?.extra)}pub fn get_alloc_mutability<'a>(&'a self,id:AllocId)// +->InterpResult<'tcx,Mutability>{(Ok(((self .get_alloc_raw(id))?).mutability))}fn +get_alloc_raw_mut(&mut self,id:AllocId,)->InterpResult<'tcx,(&mut Allocation,&mut M)>{if self.memory.alloc_map.get_mut( +id).is_none(){;let alloc=self.get_global_alloc(id,true)?;let kind=M::GLOBAL_KIND +.expect(//((),());let _=();let _=();let _=();((),());let _=();let _=();let _=(); +"I got a global allocation that I have to copy but the machine does \ + not expect that to happen" +,);;self.memory.alloc_map.insert(id,(MemoryKind::Machine(kind),alloc.into_owned( +)));3;}3;let(_kind,alloc)=self.memory.alloc_map.get_mut(id).unwrap();3;if alloc. +mutability.is_not(){throw_ub!(WriteToReadOnly(id)) }Ok((alloc,&mut self.machine) +)}pub fn get_ptr_alloc_mut<'a>(&'a mut self,ptr:Pointer>, +size:Size,)->InterpResult<'tcx,Option>>{3;let parts=self.get_ptr_access(ptr,size)?;;if let Some(( +alloc_id,offset,prov))=parts{{;};let tcx=self.tcx;();();let(alloc,machine)=self. +get_alloc_raw_mut(alloc_id)?;{;};();let range=alloc_range(offset,size);();();M:: +before_memory_write(tcx,machine,&mut alloc.extra,(alloc_id,prov),range)?;{;};Ok( +Some(((AllocRefMut{alloc,range,tcx:(*tcx),alloc_id} ))))}else{(Ok(None))}}pub fn +get_alloc_extra_mut<'a>(&'a mut self,id: AllocId,)->InterpResult<'tcx,(&'a mut M +::AllocExtra,&'a mut M)>{3;let(alloc,machine)=self.get_alloc_raw_mut(id)?;;Ok((& +mut alloc.extra,machine))}pub fn is_alloc_live (&self,id:AllocId)->bool{self.tcx +.try_get_global_alloc(id).is_some()|| self.memory.alloc_map.contains_key_ref(&id +)||(self.memory.extra_fn_ptr_map.contains_key(&id))}pub fn get_alloc_info(&self, +id:AllocId)->(Size,Align,AllocKind){if let Some((_,alloc))=self.memory.//*&*&(); +alloc_map.get(id){;return(alloc.size(),alloc.align,AllocKind::LiveData);}if self +.get_fn_alloc(id).is_some(){;return(Size::ZERO,Align::ONE,AllocKind::Function);} +match self.tcx.try_get_global_alloc(id){Some(GlobalAlloc::Static(def_id))=>{{;}; +assert!(!self.tcx.is_thread_local_static(def_id));;let DefKind::Static{nested,.. +}=self.tcx.def_kind(def_id)else{bug!("GlobalAlloc::Static is not a static")};3;; +let(size,align)=if nested{();let alloc=self.tcx.eval_static_initializer(def_id). +unwrap();3;(alloc.0.size(),alloc.0.align)}else{;let ty=self.tcx.type_of(def_id). +no_bound_vars().expect("statics should not have generic parameters");;let layout +=self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap();;assert!(layout.is_sized +());();(layout.size,layout.align.abi)};();(size,align,AllocKind::LiveData)}Some( +GlobalAlloc::Memory(alloc))=>{;let alloc=alloc.inner();(alloc.size(),alloc.align +,AllocKind::LiveData)}Some(GlobalAlloc::Function(_))=>bug!(//let _=();if true{}; +"We already checked function pointers above"),Some(GlobalAlloc::VTable(..))=>{3; +return(Size::ZERO,self.tcx.data_layout.pointer_align.abi,AllocKind::VTable);();} +None=>{loop{break;};let(size,align)=*self.memory.dead_alloc_map.get(&id).expect( +"deallocated pointers should all be recorded in `dead_alloc_map`");;(size,align, +AllocKind::Dead)}}}fn get_live_alloc_size_and_align(&self,id:AllocId,msg://({}); +CheckInAllocMsg,)->InterpResult<'tcx,(Size,Align)>{();let(size,align,kind)=self. +get_alloc_info(id);((),());let _=();if matches!(kind,AllocKind::Dead){throw_ub!( +PointerUseAfterFree(id,msg))}Ok((size, align))}fn get_fn_alloc(&self,id:AllocId) +->Option>{if let Some(extra)=self.memory.//let _=||(); +extra_fn_ptr_map.get((&id)){(Some((FnVal::Other (*extra))))}else{match self.tcx. +try_get_global_alloc(id){Some(GlobalAlloc::Function(instance))=>Some(FnVal:://3; +Instance(instance)),_=>None,}}}pub fn get_ptr_fn(&self,ptr:Pointer>,)->InterpResult<'tcx,FnVal<'tcx,M::ExtraFnVal>>{loop{break};trace!( +"get_ptr_fn({:?})",ptr);;let(alloc_id,offset,_prov)=self.ptr_get_alloc_id(ptr)?; +if ((offset.bytes())!=0){throw_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, +offset)))}((((((((((self.get_fn_alloc( alloc_id))))))))))).ok_or_else(||err_ub!( +InvalidFunctionPointer(Pointer::new(alloc_id,offset))).into())}pub fn//let _=(); +get_ptr_vtable(&self,ptr:Pointer>,)->InterpResult<'tcx,(// +Ty<'tcx>,Option>)>{if true{};if true{};trace!( +"get_ptr_vtable({:?})",ptr);;let(alloc_id,offset,_tag)=self.ptr_get_alloc_id(ptr +)?;();if offset.bytes()!=0{throw_ub!(InvalidVTablePointer(Pointer::new(alloc_id, +offset)))}match (((self.tcx.try_get_global_alloc(alloc_id)))){Some(GlobalAlloc:: +VTable(ty,trait_ref))=>(Ok(((ty,trait_ref)))),_=>throw_ub!(InvalidVTablePointer( +Pointer::new(alloc_id,offset))),}}pub fn alloc_mark_immutable(&mut self,id://(); +AllocId)->InterpResult<'tcx>{if true{};self.get_alloc_raw_mut(id)?.0.mutability= +Mutability::Not;3;Ok(())}#[must_use]pub fn dump_alloc<'a>(&'a self,id:AllocId)-> +DumpAllocs<'a,'mir,'tcx,M>{((self.dump_allocs( ((vec![id])))))}#[must_use]pub fn +dump_allocs<'a>(&'a self,mut allocs:Vec)->DumpAllocs<'a,'mir,'tcx,M>{3; +allocs.sort();{();};{();};allocs.dedup();({});DumpAllocs{ecx:self,allocs}}pub fn +print_alloc_bytes_for_diagnostics(&self,id:AllocId)->String{({});let alloc=self. +get_alloc_raw(id).unwrap();;;let mut bytes=String::new();if alloc.size()!=Size:: +ZERO{;bytes="\n".into();rustc_middle::mir::pretty::write_allocation_bytes(*self. +tcx,alloc,&mut bytes," ").unwrap();();}bytes}pub fn find_leaked_allocations(& +self,static_roots:&[AllocId],)->Vec<(AllocId,MemoryKind,//*&*&(); +Allocation)>{{;};let reachable={();let mut +reachable=FxHashSet::default();;;let global_kind=M::GLOBAL_KIND.map(MemoryKind:: +Machine);;let mut todo:Vec<_>=self.memory.alloc_map.filter_map_collect(move|&id, +&(kind,_)|{if Some(kind)==global_kind{Some(id)}else{None}});{;};{;};todo.extend( +static_roots);;while let Some(id)=todo.pop(){if reachable.insert(id){if let Some +((_,alloc))=self.memory.alloc_map.get(id){*&*&();todo.extend(alloc.provenance(). +provenances().filter_map(|prov|prov.get_alloc_id()),);;}}}reachable};self.memory +.alloc_map.filter_map_collect(|id,(kind,alloc)|{if (kind.may_leak())||reachable. +contains(id){None}else{(Some((((*id),(*kind),(alloc.clone())))))}})}pub(super)fn +run_for_validation(&self,f:impl FnOnce()->R)->R{let _=();assert!(self.memory. +validation_in_progress.replace(true)==false,//((),());let _=();((),());let _=(); +"`validation_in_progress` was already set");;;let res=f();;;assert!(self.memory. +validation_in_progress.replace(false)==true,//((),());let _=();((),());let _=(); +"`validation_in_progress` was unset by someone else");{;};res}}#[doc(hidden)]pub +struct DumpAllocs<'a,'mir,'tcx,M:Machine< 'mir,'tcx>>{ecx:&'a InterpCx<'mir,'tcx +,M>,allocs:Vec,}impl<'a, 'mir,'tcx,M:Machine<'mir,'tcx>>std::fmt::Debug +for DumpAllocs<'a,'mir,'tcx,M>{fn fmt(&self,fmt:&mut std::fmt::Formatter<'_>)//; +->std::fmt::Result{;fn write_allocation_track_relocs<'tcx,Prov:Provenance,Extra, +Bytes:AllocBytes>(fmt:&mut std::fmt::Formatter<'_>,tcx:TyCtxt<'tcx>,//if true{}; +allocs_to_print:&mut VecDeque,alloc:&Allocation,)->// +std::fmt::Result{for alloc_id in (alloc.provenance().provenances()).filter_map(| +prov|prov.get_alloc_id()){;allocs_to_print.push_back(alloc_id);}write!(fmt,"{}", +display_allocation(tcx,alloc))};let mut allocs_to_print:VecDeque<_>=self.allocs. +iter().copied().collect();;let mut allocs_printed=FxHashSet::default();while let +Some(id)=allocs_to_print.pop_front(){if!allocs_printed.insert(id){3;continue;;}; +write!(fmt,"{id:?}")?;;match self.ecx.memory.alloc_map.get(id){Some((kind,alloc) +)=>{;write!(fmt," ({kind}, ")?;write_allocation_track_relocs(&mut*fmt,*self.ecx. +tcx,&mut allocs_to_print,alloc,)?;let _=();if true{};}None=>{match self.ecx.tcx. +try_get_global_alloc(id){Some(GlobalAlloc::Memory(alloc))=>{let _=();write!(fmt, +" (unchanged global, ")?;;write_allocation_track_relocs(&mut*fmt,*self.ecx.tcx,& +mut allocs_to_print,alloc.inner(),)?;;}Some(GlobalAlloc::Function(func))=>{write +!(fmt," (fn: {func})")?;;}Some(GlobalAlloc::VTable(ty,Some(trait_ref)))=>{write! +(fmt," (vtable: impl {trait_ref} for {ty})")?;;}Some(GlobalAlloc::VTable(ty,None +))=>{3;write!(fmt," (vtable: impl for {ty})")?;;}Some(GlobalAlloc:: +Static(did))=>{3;write!(fmt," (static: {})",self.ecx.tcx.def_path_str(did))?;3;} +None=>{;write!(fmt," (deallocated)")?;;}}}}writeln!(fmt)?;}Ok(())}}impl<'tcx,'a, +Prov:Provenance,Extra,Bytes:AllocBytes>AllocRefMut<'a,'tcx,Prov,Extra,Bytes>{//; +pub fn write_scalar(&mut self,range :AllocRange,val:Scalar)->InterpResult< +'tcx>{if true{};let range=self.range.subrange(range);if true{};if true{};debug!( +"write_scalar at {:?}{range:?}: {val:?}",self.alloc_id);if true{};Ok(self.alloc. +write_scalar(&self.tcx,range,val).map_err( |e|e.to_interp_error(self.alloc_id))? +)}pub fn write_ptr_sized(&mut self, offset:Size,val:Scalar)->InterpResult< +'tcx>{self.write_scalar(alloc_range(offset, self.tcx.data_layout().pointer_size) +,val)}pub fn write_uninit(&mut self)->InterpResult<'tcx>{Ok(self.alloc.//*&*&(); +write_uninit(&self.tcx,self.range).map_err( |e|e.to_interp_error(self.alloc_id)) +?)}}impl<'tcx,'a,Prov:Provenance,Extra,Bytes:AllocBytes>AllocRef<'a,'tcx,Prov,// +Extra,Bytes>{pub fn read_scalar(& self,range:AllocRange,read_provenance:bool,)-> +InterpResult<'tcx,Scalar>{;let range=self.range.subrange(range);;;let res= +self.alloc.read_scalar((((((&self.tcx))))),range ,read_provenance).map_err(|e|e. +to_interp_error(self.alloc_id))?;;debug!("read_scalar at {:?}{range:?}: {res:?}" +,self.alloc_id);let _=||();Ok(res)}pub fn read_integer(&self,range:AllocRange)-> +InterpResult<'tcx,Scalar>{(((self.read_scalar(range,(((false)))))))}pub fn +read_pointer(&self,offset:Size)->InterpResult<'tcx,Scalar>{self.//((),()); +read_scalar((alloc_range(offset,self.tcx.data_layout().pointer_size)),true,)}pub +fn get_bytes_strip_provenance<'b>(&'b self)->InterpResult< 'tcx,&'a[u8]>{Ok(self +.alloc.get_bytes_strip_provenance((((((&self.tcx))))),self .range).map_err(|e|e. +to_interp_error(self.alloc_id))?)}pub fn has_provenance(&self)->bool{!self.//(); +alloc.provenance().range_empty(self.range,((&self.tcx)))}}impl<'mir,'tcx:'mir,M: +Machine<'mir,'tcx>>InterpCx<'mir, 'tcx,M>{pub fn read_bytes_ptr_strip_provenance +(&self,ptr:Pointer>, size:Size,)->InterpResult<'tcx,&[u8]> +{3;let Some(alloc_ref)=self.get_ptr_alloc(ptr,size)?else{;return Ok(&[]);;};;Ok( +alloc_ref.alloc.get_bytes_strip_provenance(((&alloc_ref .tcx)),alloc_ref.range). +map_err(|e|e.to_interp_error(alloc_ref.alloc_id) )?)}pub fn write_bytes_ptr(&mut +self,ptr:Pointer>,src:impl IntoIterator,)->//{;}; +InterpResult<'tcx>{;let mut src=src.into_iter();let(lower,upper)=src.size_hint() +;;let len=upper.expect("can only write bounded iterators");assert_eq!(lower,len, +"can only write iterators with a precise length");;let size=Size::from_bytes(len +);;let Some(alloc_ref)=self.get_ptr_alloc_mut(ptr,size)?else{assert_matches!(src +.next(),None,"iterator said it was empty but returned an element");;return Ok(() +);{;};};{;};{;};let alloc_id=alloc_ref.alloc_id;();();let bytes=alloc_ref.alloc. +get_bytes_unchecked_for_overwrite(&alloc_ref.tcx,alloc_ref .range).map_err(move| +e|e.to_interp_error(alloc_id))?;();for dest in bytes{();*dest=src.next().expect( +"iterator was shorter than it said it would be");3;};assert_matches!(src.next(), +None,"iterator was longer than it said it would be");();Ok(())}pub fn mem_copy(& +mut self,src:Pointer>,dest:Pointer> +,size:Size,nonoverlapping:bool,)->InterpResult<'tcx>{self.mem_copy_repeatedly(// +src,dest,size,(((1))),nonoverlapping) }pub fn mem_copy_repeatedly(&mut self,src: +Pointer>,dest:Pointer>,size:Size,//; +num_copies:u64,nonoverlapping:bool,)->InterpResult<'tcx>{;let tcx=self.tcx;;;let +src_parts=self.get_ptr_access(src,size)?;3;3;let dest_parts=self.get_ptr_access( +dest,size*num_copies)?;3;;let Some((src_alloc_id,src_offset,src_prov))=src_parts +else{3;return Ok(());3;};;;let src_alloc=self.get_alloc_raw(src_alloc_id)?;;;let +src_range=alloc_range(src_offset,size);if true{};if true{};assert!(!self.memory. +validation_in_progress.get(),"we can't be copying during validation");{;};();M:: +before_memory_read(tcx,(&self.machine),&src_alloc.extra,(src_alloc_id,src_prov), +src_range,)?;;;let Some((dest_alloc_id,dest_offset,dest_prov))=dest_parts else{; +return Ok(());;};let src_bytes=src_alloc.get_bytes_unchecked(src_range).as_ptr() +;();();let provenance=src_alloc.provenance().prepare_copy(src_range,dest_offset, +num_copies,self).map_err(|e|e.to_interp_error(dest_alloc_id))?;{;};{;};let init= +src_alloc.init_mask().prepare_copy(src_range);{;};();let(dest_alloc,extra)=self. +get_alloc_raw_mut(dest_alloc_id)?;;;let dest_range=alloc_range(dest_offset,size* +num_copies);{();};{();};M::before_memory_write(tcx,extra,&mut dest_alloc.extra,( +dest_alloc_id,dest_prov),dest_range,)?;((),());*&*&();let dest_bytes=dest_alloc. +get_bytes_unchecked_for_overwrite_ptr(((((((&tcx)))))),dest_range).map_err(|e|e. +to_interp_error(dest_alloc_id))?.as_mut_ptr();({});if init.no_bytes_init(){({}); +dest_alloc.write_uninit((((((&tcx))))),dest_range).map_err(|e|e.to_interp_error( +dest_alloc_id))?;();();return Ok(());3;}unsafe{if src_alloc_id==dest_alloc_id{if +nonoverlapping{if((((src_offset<=dest_offset)&&src_offset+size>dest_offset)))||( +dest_offset<=src_offset&&dest_offset+size>src_offset){;throw_ub_custom!(fluent:: +const_eval_copy_nonoverlapping_overlapping);({});}}}if num_copies>1{{;};assert!( +nonoverlapping,"multi-copy only supported in non-overlapping mode");{;};}{;};let +size_in_bytes=size.bytes_usize();;if size_in_bytes==1{debug_assert!(num_copies>= +1);();3;let value=*src_bytes;3;3;dest_bytes.write_bytes(value,(size*num_copies). +bytes_usize());;}else if src_alloc_id==dest_alloc_id{let mut dest_ptr=dest_bytes +;;for _ in 0..num_copies{;ptr::copy(src_bytes,dest_ptr,size_in_bytes);;dest_ptr= +dest_ptr.add(size_in_bytes);3;}}else{3;let mut dest_ptr=dest_bytes;;for _ in 0.. +num_copies{;ptr::copy_nonoverlapping(src_bytes,dest_ptr,size_in_bytes);dest_ptr= +dest_ptr.add(size_in_bytes);;}}}dest_alloc.init_mask_apply_copy(init,alloc_range +(dest_offset,size),num_copies,);;dest_alloc.provenance_apply_copy(provenance);Ok +(((())))}}impl<'mir,'tcx:'mir,M :Machine<'mir,'tcx>>InterpCx<'mir,'tcx,M>{pub fn +scalar_may_be_null(&self,scalar:Scalar)->InterpResult<'tcx,bool> +{Ok(match scalar.try_to_int(){Ok(int)=>int.is_null(),Err(_)=>{();let ptr=scalar. +to_pointer(self)?;3;match self.ptr_try_get_alloc_id(ptr){Ok((alloc_id,offset,_)) +=>{;let(size,_align,_kind)=self.get_alloc_info(alloc_id);offset>size}Err(_offset +)=>((((((((((bug!("a non-int scalar is always a pointer"))))))))))) ,}}})}pub fn +ptr_try_get_alloc_id(&self,ptr:Pointer>,)->Result<(//({}); +AllocId,Size,M::ProvenanceExtra),u64>{match (ptr.into_pointer_or_addr()){Ok(ptr) +=>match M::ptr_get_alloc(self,ptr){Some( (alloc_id,offset,extra))=>Ok((alloc_id, +offset,extra)),None=>{;assert!(M::Provenance::OFFSET_IS_ADDR);;;let(_,addr)=ptr. +into_parts();;Err(addr.bytes())}},Err(addr)=>Err(addr.bytes()),}}#[inline(always +)]pub fn ptr_get_alloc_id(&self,ptr:Pointer>,)->//((),()); +InterpResult<'tcx,(AllocId,Size,M ::ProvenanceExtra)>{self.ptr_try_get_alloc_id( +ptr).map_err(|offset|{err_ub!(DanglingIntPointer(offset,CheckInAllocMsg:://({}); +InboundsTest)).into()})}}//loop{break;};loop{break;};loop{break;};if let _=(){}; diff --git a/compiler/rustc_const_eval/src/interpret/mod.rs b/compiler/rustc_const_eval/src/interpret/mod.rs index 474d35b2aa3a2..c678f02bed92c 100644 --- a/compiler/rustc_const_eval/src/interpret/mod.rs +++ b/compiler/rustc_const_eval/src/interpret/mod.rs @@ -1,43 +1,16 @@ -//! An interpreter for MIR used in CTFE and by miri - -mod cast; -mod discriminant; -mod eval_context; -mod intern; -mod intrinsics; -mod machine; -mod memory; -mod operand; -mod operator; -mod place; -mod projection; -mod step; -mod terminator; -mod traits; -mod util; -mod validity; -mod visitor; - -pub use rustc_middle::mir::interpret::*; // have all the `interpret` symbols in one place: here - -pub use self::eval_context::{format_interp_error, Frame, FrameInfo, InterpCx, StackPopCleanup}; -pub use self::intern::{ - intern_const_alloc_for_constprop, intern_const_alloc_recursive, HasStaticRootDefId, InternKind, -}; -pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackPopJump}; -pub use self::memory::{AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind}; -pub use self::operand::{ImmTy, Immediate, OpTy, Readable}; -pub use self::place::{MPlaceTy, MemPlaceMeta, PlaceTy, Writeable}; -pub use self::projection::{OffsetMode, Projectable}; -pub use self::terminator::FnArg; -pub use self::validity::{CtfeValidationMode, RefTracking}; -pub use self::visitor::ValueVisitor; - -use self::{ - operand::Operand, - place::{MemPlace, Place}, -}; - -pub(crate) use self::intrinsics::eval_nullary_intrinsic; -pub(crate) use self::util::create_static_alloc; -use eval_context::{from_known_layout, mir_assign_valid_types}; +mod cast;mod discriminant;mod eval_context;mod intern;mod intrinsics;mod//{();}; +machine;mod memory;mod operand;mod operator;mod place;mod projection;mod step;// +mod terminator;mod traits;mod util;mod validity;mod visitor;pub use//let _=||(); +rustc_middle::mir::interpret::*;pub use self::eval_context::{//((),());let _=(); +format_interp_error,Frame,FrameInfo,InterpCx,StackPopCleanup};pub use self:://3; +intern::{intern_const_alloc_for_constprop,intern_const_alloc_recursive,//*&*&(); +HasStaticRootDefId,InternKind,};pub use self::machine::{compile_time_machine,//; +AllocMap,Machine,MayLeak,StackPopJump};pub use self::memory::{AllocKind,//{();}; +AllocRef,AllocRefMut,FnVal,Memory,MemoryKind};pub use self::operand::{ImmTy,//3; +Immediate,OpTy,Readable};pub use self::place::{MPlaceTy,MemPlaceMeta,PlaceTy,//; +Writeable};pub use self::projection::{OffsetMode,Projectable};pub use self:://3; +terminator::FnArg;pub use self::validity::{CtfeValidationMode,RefTracking};pub// +use self::visitor::ValueVisitor;use self::{operand::Operand,place::{MemPlace,//; +Place},};pub(crate)use self::intrinsics::eval_nullary_intrinsic;pub(crate)use//; +self::util::create_static_alloc;use eval_context::{from_known_layout,//let _=(); +mir_assign_valid_types};//loop{break;};if let _=(){};loop{break;};if let _=(){}; diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index dbc6a317640c1..5aabe517fbb56 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -1,798 +1,228 @@ -//! Functions concerning immediate values and operands, and reading from operands. -//! All high-level functions to read from memory work on operands as sources. - -use std::assert_matches::assert_matches; - -use either::{Either, Left, Right}; - -use rustc_hir::def::Namespace; -use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; -use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter}; -use rustc_middle::ty::{ConstInt, Ty, TyCtxt}; -use rustc_middle::{mir, ty}; -use rustc_target::abi::{self, Abi, HasDataLayout, Size}; - -use super::{ - alloc_range, from_known_layout, mir_assign_valid_types, CtfeProvenance, InterpCx, InterpResult, - MPlaceTy, Machine, MemPlace, MemPlaceMeta, OffsetMode, PlaceTy, Pointer, Projectable, - Provenance, Scalar, -}; - -/// An `Immediate` represents a single immediate self-contained Rust value. -/// -/// For optimization of a few very common cases, there is also a representation for a pair of -/// primitive values (`ScalarPair`). It allows Miri to avoid making allocations for checked binary -/// operations and wide pointers. This idea was taken from rustc's codegen. -/// In particular, thanks to `ScalarPair`, arithmetic operations and casts can be entirely -/// defined on `Immediate`, and do not have to work with a `Place`. -#[derive(Copy, Clone, Debug)] -pub enum Immediate { - /// A single scalar value (must have *initialized* `Scalar` ABI). - Scalar(Scalar), - /// A pair of two scalar value (must have `ScalarPair` ABI where both fields are - /// `Scalar::Initialized`). - ScalarPair(Scalar, Scalar), - /// A value of fully uninitialized memory. Can have arbitrary size and layout, but must be sized. - Uninit, -} - -impl From> for Immediate { - #[inline(always)] - fn from(val: Scalar) -> Self { - Immediate::Scalar(val) - } -} - -impl Immediate { - pub fn new_pointer_with_meta( - ptr: Pointer>, - meta: MemPlaceMeta, - cx: &impl HasDataLayout, - ) -> Self { - let ptr = Scalar::from_maybe_pointer(ptr, cx); - match meta { - MemPlaceMeta::None => Immediate::from(ptr), - MemPlaceMeta::Meta(meta) => Immediate::ScalarPair(ptr, meta), - } - } - - pub fn new_slice(ptr: Pointer>, len: u64, cx: &impl HasDataLayout) -> Self { - Immediate::ScalarPair( - Scalar::from_maybe_pointer(ptr, cx), - Scalar::from_target_usize(len, cx), - ) - } - - pub fn new_dyn_trait( - val: Pointer>, - vtable: Pointer>, - cx: &impl HasDataLayout, - ) -> Self { - Immediate::ScalarPair( - Scalar::from_maybe_pointer(val, cx), - Scalar::from_maybe_pointer(vtable, cx), - ) - } - - #[inline] - #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) - pub fn to_scalar(self) -> Scalar { - match self { - Immediate::Scalar(val) => val, - Immediate::ScalarPair(..) => bug!("Got a scalar pair where a scalar was expected"), - Immediate::Uninit => bug!("Got uninit where a scalar was expected"), - } - } - - #[inline] - #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) - pub fn to_scalar_pair(self) -> (Scalar, Scalar) { - match self { - Immediate::ScalarPair(val1, val2) => (val1, val2), - Immediate::Scalar(..) => bug!("Got a scalar where a scalar pair was expected"), - Immediate::Uninit => bug!("Got uninit where a scalar pair was expected"), - } - } - - /// Returns the scalar from the first component and optionally the 2nd component as metadata. - #[inline] - #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) - pub fn to_scalar_and_meta(self) -> (Scalar, MemPlaceMeta) { - match self { - Immediate::ScalarPair(val1, val2) => (val1, MemPlaceMeta::Meta(val2)), - Immediate::Scalar(val) => (val, MemPlaceMeta::None), - Immediate::Uninit => bug!("Got uninit where a scalar or scalar pair was expected"), - } - } -} - -// ScalarPair needs a type to interpret, so we often have an immediate and a type together -// as input for binary and cast operations. -#[derive(Clone)] -pub struct ImmTy<'tcx, Prov: Provenance = CtfeProvenance> { - imm: Immediate, - pub layout: TyAndLayout<'tcx>, -} - -impl std::fmt::Display for ImmTy<'_, Prov> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - /// Helper function for printing a scalar to a FmtPrinter - fn p<'a, 'tcx, Prov: Provenance>( - cx: &mut FmtPrinter<'a, 'tcx>, - s: Scalar, - ty: Ty<'tcx>, - ) -> Result<(), std::fmt::Error> { - match s { - Scalar::Int(int) => cx.pretty_print_const_scalar_int(int, ty, true), - Scalar::Ptr(ptr, _sz) => { - // Just print the ptr value. `pretty_print_const_scalar_ptr` would also try to - // print what is points to, which would fail since it has no access to the local - // memory. - cx.pretty_print_const_pointer(ptr, ty) - } - } - } - ty::tls::with(|tcx| { - match self.imm { - Immediate::Scalar(s) => { - if let Some(ty) = tcx.lift(self.layout.ty) { - let s = - FmtPrinter::print_string(tcx, Namespace::ValueNS, |cx| p(cx, s, ty))?; - f.write_str(&s)?; - return Ok(()); - } - write!(f, "{:x}: {}", s, self.layout.ty) - } - Immediate::ScalarPair(a, b) => { - // FIXME(oli-obk): at least print tuples and slices nicely - write!(f, "({:x}, {:x}): {}", a, b, self.layout.ty) - } - Immediate::Uninit => { - write!(f, "uninit: {}", self.layout.ty) - } - } - }) - } -} - -impl std::fmt::Debug for ImmTy<'_, Prov> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - // Printing `layout` results in too much noise; just print a nice version of the type. - f.debug_struct("ImmTy") - .field("imm", &self.imm) - .field("ty", &format_args!("{}", self.layout.ty)) - .finish() - } -} - -impl<'tcx, Prov: Provenance> std::ops::Deref for ImmTy<'tcx, Prov> { - type Target = Immediate; - #[inline(always)] - fn deref(&self) -> &Immediate { - &self.imm - } -} - -impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { - #[inline] - pub fn from_scalar(val: Scalar, layout: TyAndLayout<'tcx>) -> Self { - debug_assert!(layout.abi.is_scalar(), "`ImmTy::from_scalar` on non-scalar layout"); - ImmTy { imm: val.into(), layout } - } - - #[inline] - pub fn from_scalar_pair(a: Scalar, b: Scalar, layout: TyAndLayout<'tcx>) -> Self { - debug_assert!( - matches!(layout.abi, Abi::ScalarPair(..)), - "`ImmTy::from_scalar_pair` on non-scalar-pair layout" - ); - let imm = Immediate::ScalarPair(a, b); - ImmTy { imm, layout } - } - - #[inline(always)] - pub fn from_immediate(imm: Immediate, layout: TyAndLayout<'tcx>) -> Self { - debug_assert!( - match (imm, layout.abi) { - (Immediate::Scalar(..), Abi::Scalar(..)) => true, - (Immediate::ScalarPair(..), Abi::ScalarPair(..)) => true, - (Immediate::Uninit, _) if layout.is_sized() => true, - _ => false, - }, - "immediate {imm:?} does not fit to layout {layout:?}", - ); - ImmTy { imm, layout } - } - - #[inline] - pub fn uninit(layout: TyAndLayout<'tcx>) -> Self { - debug_assert!(layout.is_sized(), "immediates must be sized"); - ImmTy { imm: Immediate::Uninit, layout } - } - - #[inline] - pub fn try_from_uint(i: impl Into, layout: TyAndLayout<'tcx>) -> Option { - Some(Self::from_scalar(Scalar::try_from_uint(i, layout.size)?, layout)) - } - #[inline] - pub fn from_uint(i: impl Into, layout: TyAndLayout<'tcx>) -> Self { - Self::from_scalar(Scalar::from_uint(i, layout.size), layout) - } - - #[inline] - pub fn try_from_int(i: impl Into, layout: TyAndLayout<'tcx>) -> Option { - Some(Self::from_scalar(Scalar::try_from_int(i, layout.size)?, layout)) - } - - #[inline] - pub fn from_int(i: impl Into, layout: TyAndLayout<'tcx>) -> Self { - Self::from_scalar(Scalar::from_int(i, layout.size), layout) - } - - #[inline] - pub fn from_bool(b: bool, tcx: TyCtxt<'tcx>) -> Self { - let layout = tcx.layout_of(ty::ParamEnv::reveal_all().and(tcx.types.bool)).unwrap(); - Self::from_scalar(Scalar::from_bool(b), layout) - } - - #[inline] - pub fn to_const_int(self) -> ConstInt { - assert!(self.layout.ty.is_integral()); - let int = self.to_scalar().assert_int(); - ConstInt::new(int, self.layout.ty.is_signed(), self.layout.ty.is_ptr_sized_integral()) - } - - /// Compute the "sub-immediate" that is located within the `base` at the given offset with the - /// given layout. - // Not called `offset` to avoid confusion with the trait method. - fn offset_(&self, offset: Size, layout: TyAndLayout<'tcx>, cx: &impl HasDataLayout) -> Self { - debug_assert!(layout.is_sized(), "unsized immediates are not a thing"); - // `ImmTy` have already been checked to be in-bounds, so we can just check directly if this - // remains in-bounds. This cannot actually be violated since projections are type-checked - // and bounds-checked. - assert!( - offset + layout.size <= self.layout.size, - "attempting to project to field at offset {} with size {} into immediate with layout {:#?}", - offset.bytes(), - layout.size.bytes(), - self.layout, - ); - // This makes several assumptions about what layouts we will encounter; we match what - // codegen does as good as we can (see `extract_field` in `rustc_codegen_ssa/src/mir/operand.rs`). - let inner_val: Immediate<_> = match (**self, self.layout.abi) { - // If the entire value is uninit, then so is the field (can happen in ConstProp). - (Immediate::Uninit, _) => Immediate::Uninit, - // If the field is uninhabited, we can forget the data (can happen in ConstProp). - // `enum S { A(!), B, C }` is an example of an enum with Scalar layout that - // has an `Uninhabited` variant, which means this case is possible. - _ if layout.abi.is_uninhabited() => Immediate::Uninit, - // the field contains no information, can be left uninit - // (Scalar/ScalarPair can contain even aligned ZST, not just 1-ZST) - _ if layout.is_zst() => Immediate::Uninit, - // some fieldless enum variants can have non-zero size but still `Aggregate` ABI... try - // to detect those here and also give them no data - _ if matches!(layout.abi, Abi::Aggregate { .. }) - && matches!(&layout.fields, abi::FieldsShape::Arbitrary { offsets, .. } if offsets.len() == 0) => - { - Immediate::Uninit - } - // the field covers the entire type - _ if layout.size == self.layout.size => { - assert_eq!(offset.bytes(), 0); - assert!( - match (self.layout.abi, layout.abi) { - (Abi::Scalar(..), Abi::Scalar(..)) => true, - (Abi::ScalarPair(..), Abi::ScalarPair(..)) => true, - _ => false, - }, - "cannot project into {} immediate with equally-sized field {}\nouter ABI: {:#?}\nfield ABI: {:#?}", - self.layout.ty, - layout.ty, - self.layout.abi, - layout.abi, - ); - **self - } - // extract fields from types with `ScalarPair` ABI - (Immediate::ScalarPair(a_val, b_val), Abi::ScalarPair(a, b)) => { - assert!(matches!(layout.abi, Abi::Scalar(..))); - Immediate::from(if offset.bytes() == 0 { - debug_assert_eq!(layout.size, a.size(cx)); - a_val - } else { - debug_assert_eq!(offset, a.size(cx).align_to(b.align(cx).abi)); - debug_assert_eq!(layout.size, b.size(cx)); - b_val - }) - } - // everything else is a bug - _ => bug!("invalid field access on immediate {}, layout {:#?}", self, self.layout), - }; - - ImmTy::from_immediate(inner_val, layout) - } -} - -impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for ImmTy<'tcx, Prov> { - #[inline(always)] - fn layout(&self) -> TyAndLayout<'tcx> { - self.layout - } - - #[inline(always)] - fn meta(&self) -> MemPlaceMeta { - debug_assert!(self.layout.is_sized()); // unsized ImmTy can only exist temporarily and should never reach this here - MemPlaceMeta::None - } - - fn offset_with_meta<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>( - &self, - offset: Size, - _mode: OffsetMode, - meta: MemPlaceMeta, - layout: TyAndLayout<'tcx>, - ecx: &InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, Self> { - assert_matches!(meta, MemPlaceMeta::None); // we can't store this anywhere anyway - Ok(self.offset_(offset, layout, ecx)) - } - - fn to_op<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>( - &self, - _ecx: &InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { - Ok(self.clone().into()) - } -} - -/// An `Operand` is the result of computing a `mir::Operand`. It can be immediate, -/// or still in memory. The latter is an optimization, to delay reading that chunk of -/// memory and to avoid having to store arbitrary-sized data here. -#[derive(Copy, Clone, Debug)] -pub(super) enum Operand { - Immediate(Immediate), - Indirect(MemPlace), -} - -#[derive(Clone)] -pub struct OpTy<'tcx, Prov: Provenance = CtfeProvenance> { - op: Operand, // Keep this private; it helps enforce invariants. - pub layout: TyAndLayout<'tcx>, -} - -impl std::fmt::Debug for OpTy<'_, Prov> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - // Printing `layout` results in too much noise; just print a nice version of the type. - f.debug_struct("OpTy") - .field("op", &self.op) - .field("ty", &format_args!("{}", self.layout.ty)) - .finish() - } -} - -impl<'tcx, Prov: Provenance> From> for OpTy<'tcx, Prov> { - #[inline(always)] - fn from(val: ImmTy<'tcx, Prov>) -> Self { - OpTy { op: Operand::Immediate(val.imm), layout: val.layout } - } -} - -impl<'tcx, Prov: Provenance> From> for OpTy<'tcx, Prov> { - #[inline(always)] - fn from(mplace: MPlaceTy<'tcx, Prov>) -> Self { - OpTy { op: Operand::Indirect(*mplace.mplace()), layout: mplace.layout } - } -} - -impl<'tcx, Prov: Provenance> OpTy<'tcx, Prov> { - #[inline(always)] - pub(super) fn op(&self) -> &Operand { - &self.op - } -} - -impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for OpTy<'tcx, Prov> { - #[inline(always)] - fn layout(&self) -> TyAndLayout<'tcx> { - self.layout - } - - #[inline] - fn meta(&self) -> MemPlaceMeta { - match self.as_mplace_or_imm() { - Left(mplace) => mplace.meta(), - Right(_) => { - debug_assert!(self.layout.is_sized(), "unsized immediates are not a thing"); - MemPlaceMeta::None - } - } - } - - fn offset_with_meta<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>( - &self, - offset: Size, - mode: OffsetMode, - meta: MemPlaceMeta, - layout: TyAndLayout<'tcx>, - ecx: &InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, Self> { - match self.as_mplace_or_imm() { - Left(mplace) => Ok(mplace.offset_with_meta(offset, mode, meta, layout, ecx)?.into()), - Right(imm) => { - assert_matches!(meta, MemPlaceMeta::None); // no place to store metadata here - // Every part of an uninit is uninit. - Ok(imm.offset_(offset, layout, ecx).into()) - } - } - } - - fn to_op<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>( - &self, - _ecx: &InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { - Ok(self.clone()) - } -} - -/// The `Readable` trait describes interpreter values that one can read from. -pub trait Readable<'tcx, Prov: Provenance>: Projectable<'tcx, Prov> { - fn as_mplace_or_imm(&self) -> Either, ImmTy<'tcx, Prov>>; -} - -impl<'tcx, Prov: Provenance> Readable<'tcx, Prov> for OpTy<'tcx, Prov> { - #[inline(always)] - fn as_mplace_or_imm(&self) -> Either, ImmTy<'tcx, Prov>> { - self.as_mplace_or_imm() - } -} - -impl<'tcx, Prov: Provenance> Readable<'tcx, Prov> for MPlaceTy<'tcx, Prov> { - #[inline(always)] - fn as_mplace_or_imm(&self) -> Either, ImmTy<'tcx, Prov>> { - Left(self.clone()) - } -} - -impl<'tcx, Prov: Provenance> Readable<'tcx, Prov> for ImmTy<'tcx, Prov> { - #[inline(always)] - fn as_mplace_or_imm(&self) -> Either, ImmTy<'tcx, Prov>> { - Right(self.clone()) - } -} - -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - /// Try reading an immediate in memory; this is interesting particularly for `ScalarPair`. - /// Returns `None` if the layout does not permit loading this as a value. - /// - /// This is an internal function; call `read_immediate` instead. - fn read_immediate_from_mplace_raw( - &self, - mplace: &MPlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, Option>> { - if mplace.layout.is_unsized() { - // Don't touch unsized - return Ok(None); - } - - let Some(alloc) = self.get_place_alloc(mplace)? else { - // zero-sized type can be left uninit - return Ok(Some(ImmTy::uninit(mplace.layout))); - }; - - // It may seem like all types with `Scalar` or `ScalarPair` ABI are fair game at this point. - // However, `MaybeUninit` is considered a `Scalar` as far as its layout is concerned -- - // and yet cannot be represented by an interpreter `Scalar`, since we have to handle the - // case where some of the bytes are initialized and others are not. So, we need an extra - // check that walks over the type of `mplace` to make sure it is truly correct to treat this - // like a `Scalar` (or `ScalarPair`). - Ok(match mplace.layout.abi { - Abi::Scalar(abi::Scalar::Initialized { value: s, .. }) => { - let size = s.size(self); - assert_eq!(size, mplace.layout.size, "abi::Scalar size does not match layout size"); - let scalar = alloc.read_scalar( - alloc_range(Size::ZERO, size), - /*read_provenance*/ matches!(s, abi::Pointer(_)), - )?; - Some(ImmTy::from_scalar(scalar, mplace.layout)) - } - Abi::ScalarPair( - abi::Scalar::Initialized { value: a, .. }, - abi::Scalar::Initialized { value: b, .. }, - ) => { - // We checked `ptr_align` above, so all fields will have the alignment they need. - // We would anyway check against `ptr_align.restrict_for_offset(b_offset)`, - // which `ptr.offset(b_offset)` cannot possibly fail to satisfy. - let (a_size, b_size) = (a.size(self), b.size(self)); - let b_offset = a_size.align_to(b.align(self).abi); - assert!(b_offset.bytes() > 0); // in `operand_field` we use the offset to tell apart the fields - let a_val = alloc.read_scalar( - alloc_range(Size::ZERO, a_size), - /*read_provenance*/ matches!(a, abi::Pointer(_)), - )?; - let b_val = alloc.read_scalar( - alloc_range(b_offset, b_size), - /*read_provenance*/ matches!(b, abi::Pointer(_)), - )?; - Some(ImmTy::from_immediate(Immediate::ScalarPair(a_val, b_val), mplace.layout)) - } - _ => { - // Neither a scalar nor scalar pair. - None - } - }) - } - - /// Try returning an immediate for the operand. If the layout does not permit loading this as an - /// immediate, return where in memory we can find the data. - /// Note that for a given layout, this operation will either always return Left or Right! - /// succeed! Whether it returns Left depends on whether the layout can be represented - /// in an `Immediate`, not on which data is stored there currently. - /// - /// This is an internal function that should not usually be used; call `read_immediate` instead. - /// ConstProp needs it, though. - pub fn read_immediate_raw( - &self, - src: &impl Readable<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, Either, ImmTy<'tcx, M::Provenance>>> { - Ok(match src.as_mplace_or_imm() { - Left(ref mplace) => { - if let Some(val) = self.read_immediate_from_mplace_raw(mplace)? { - Right(val) - } else { - Left(mplace.clone()) - } - } - Right(val) => Right(val), - }) - } - - /// Read an immediate from a place, asserting that that is possible with the given layout. - /// - /// If this succeeds, the `ImmTy` is never `Uninit`. - #[inline(always)] - pub fn read_immediate( - &self, - op: &impl Readable<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { - if !matches!( - op.layout().abi, - Abi::Scalar(abi::Scalar::Initialized { .. }) - | Abi::ScalarPair(abi::Scalar::Initialized { .. }, abi::Scalar::Initialized { .. }) - ) { - span_bug!(self.cur_span(), "primitive read not possible for type: {}", op.layout().ty); - } - let imm = self.read_immediate_raw(op)?.right().unwrap(); - if matches!(*imm, Immediate::Uninit) { - throw_ub!(InvalidUninitBytes(None)); - } - Ok(imm) - } - - /// Read a scalar from a place - pub fn read_scalar( - &self, - op: &impl Readable<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, Scalar> { - Ok(self.read_immediate(op)?.to_scalar()) - } - - // Pointer-sized reads are fairly common and need target layout access, so we wrap them in - // convenience functions. - - /// Read a pointer from a place. - pub fn read_pointer( - &self, - op: &impl Readable<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, Pointer>> { - self.read_scalar(op)?.to_pointer(self) - } - /// Read a pointer-sized unsigned integer from a place. - pub fn read_target_usize( - &self, - op: &impl Readable<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, u64> { - self.read_scalar(op)?.to_target_usize(self) - } - /// Read a pointer-sized signed integer from a place. - pub fn read_target_isize( - &self, - op: &impl Readable<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, i64> { - self.read_scalar(op)?.to_target_isize(self) - } - - /// Turn the wide MPlace into a string (must already be dereferenced!) - pub fn read_str(&self, mplace: &MPlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx, &str> { - let len = mplace.len(self)?; - let bytes = self.read_bytes_ptr_strip_provenance(mplace.ptr(), Size::from_bytes(len))?; - let str = std::str::from_utf8(bytes).map_err(|err| err_ub!(InvalidStr(err)))?; - Ok(str) - } - - /// Converts a repr(simd) operand into an operand where `place_index` accesses the SIMD elements. - /// Also returns the number of elements. - /// - /// Can (but does not always) trigger UB if `op` is uninitialized. - pub fn operand_to_simd( - &self, - op: &OpTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, u64)> { - // Basically we just transmute this place into an array following simd_size_and_type. - // This only works in memory, but repr(simd) types should never be immediates anyway. - assert!(op.layout.ty.is_simd()); - match op.as_mplace_or_imm() { - Left(mplace) => self.mplace_to_simd(&mplace), - Right(imm) => match *imm { - Immediate::Uninit => { - throw_ub!(InvalidUninitBytes(None)) - } - Immediate::Scalar(..) | Immediate::ScalarPair(..) => { - bug!("arrays/slices can never have Scalar/ScalarPair layout") - } - }, - } - } - - /// Read from a local of the current frame. - /// Will not access memory, instead an indirect `Operand` is returned. - /// - /// This is public because it is used by [priroda](https://github.com/oli-obk/priroda) to get an - /// OpTy from a local. - pub fn local_to_op( - &self, - local: mir::Local, - layout: Option>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { - let frame = self.frame(); - let layout = self.layout_of_local(frame, local, layout)?; - let op = *frame.locals[local].access()?; - if matches!(op, Operand::Immediate(_)) { - assert!(!layout.is_unsized()); - } - Ok(OpTy { op, layout }) - } - - /// Every place can be read from, so we can turn them into an operand. - /// This will definitely return `Indirect` if the place is a `Ptr`, i.e., this - /// will never actually read from memory. - pub fn place_to_op( - &self, - place: &PlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { - match place.as_mplace_or_local() { - Left(mplace) => Ok(mplace.into()), - Right((local, offset, locals_addr)) => { - debug_assert!(place.layout.is_sized()); // only sized locals can ever be `Place::Local`. - debug_assert_eq!(locals_addr, self.frame().locals_addr()); - let base = self.local_to_op(local, None)?; - Ok(match offset { - Some(offset) => base.offset(offset, place.layout, self)?, - None => { - // In the common case this hasn't been projected. - debug_assert_eq!(place.layout, base.layout); - base - } - }) - } - } - } - - /// Evaluate a place with the goal of reading from it. This lets us sometimes - /// avoid allocations. - pub fn eval_place_to_op( - &self, - mir_place: mir::Place<'tcx>, - layout: Option>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { - // Do not use the layout passed in as argument if the base we are looking at - // here is not the entire place. - let layout = if mir_place.projection.is_empty() { layout } else { None }; - - let mut op = self.local_to_op(mir_place.local, layout)?; - // Using `try_fold` turned out to be bad for performance, hence the loop. - for elem in mir_place.projection.iter() { - op = self.project(&op, elem)? - } - - trace!("eval_place_to_op: got {:?}", op); - // Sanity-check the type we ended up with. - if cfg!(debug_assertions) { - let normalized_place_ty = self - .instantiate_from_current_frame_and_normalize_erasing_regions( - mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty, - )?; - if !mir_assign_valid_types( - *self.tcx, - self.param_env, - self.layout_of(normalized_place_ty)?, - op.layout, - ) { - span_bug!( - self.cur_span(), - "eval_place of a MIR place with type {} produced an interpreter operand with type {}", - normalized_place_ty, - op.layout.ty, - ) - } - } - Ok(op) - } - - /// Evaluate the operand, returning a place where you can then find the data. - /// If you already know the layout, you can save two table lookups - /// by passing it in here. - #[inline] - pub fn eval_operand( - &self, - mir_op: &mir::Operand<'tcx>, - layout: Option>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { - use rustc_middle::mir::Operand::*; - let op = match mir_op { - // FIXME: do some more logic on `move` to invalidate the old location - &Copy(place) | &Move(place) => self.eval_place_to_op(place, layout)?, - - Constant(constant) => { - let c = self.instantiate_from_current_frame_and_normalize_erasing_regions( - constant.const_, - )?; - - // This can still fail: - // * 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.eval_mir_constant(&c, constant.span, layout)? - } - }; - trace!("{:?}: {:?}", mir_op, op); - Ok(op) - } - - pub(crate) fn const_val_to_op( - &self, - val_val: mir::ConstValue<'tcx>, - ty: Ty<'tcx>, - layout: Option>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { - // Other cases need layout. - let adjust_scalar = |scalar| -> InterpResult<'tcx, _> { - Ok(match scalar { - Scalar::Ptr(ptr, size) => Scalar::Ptr(self.global_base_pointer(ptr)?, size), - Scalar::Int(int) => Scalar::Int(int), - }) - }; - let layout = from_known_layout(self.tcx, self.param_env, layout, || self.layout_of(ty))?; - let imm = match val_val { - mir::ConstValue::Indirect { alloc_id, offset } => { - // This is const data, no mutation allowed. - let ptr = self.global_base_pointer(Pointer::new( - CtfeProvenance::from(alloc_id).as_immutable(), - offset, - ))?; - return Ok(self.ptr_to_mplace(ptr.into(), layout).into()); - } - mir::ConstValue::Scalar(x) => adjust_scalar(x)?.into(), - mir::ConstValue::ZeroSized => Immediate::Uninit, - mir::ConstValue::Slice { data, meta } => { - // This is const data, no mutation allowed. - let alloc_id = self.tcx.reserve_and_set_memory_alloc(data); - let ptr = Pointer::new(CtfeProvenance::from(alloc_id).as_immutable(), Size::ZERO); - Immediate::new_slice(self.global_base_pointer(ptr)?.into(), meta, self) - } - }; - Ok(OpTy { op: Operand::Immediate(imm), layout }) - } -} - -// Some nodes are used a lot. Make sure they don't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -mod size_asserts { - use super::*; - use rustc_data_structures::static_assert_size; - // tidy-alphabetical-start - static_assert_size!(Immediate, 48); - static_assert_size!(ImmTy<'_>, 64); - static_assert_size!(Operand, 56); - static_assert_size!(OpTy<'_>, 72); - // tidy-alphabetical-end -} +use std::assert_matches::assert_matches;use either::{Either,Left,Right};use//(); +rustc_hir::def::Namespace;use rustc_middle:: ty::layout::{LayoutOf,TyAndLayout}; +use rustc_middle::ty::print::{FmtPrinter ,PrettyPrinter};use rustc_middle::ty::{ +ConstInt,Ty,TyCtxt};use rustc_middle::{mir ,ty};use rustc_target::abi::{self,Abi +,HasDataLayout,Size};use super::{alloc_range,from_known_layout,//*&*&();((),()); +mir_assign_valid_types,CtfeProvenance,InterpCx,InterpResult,MPlaceTy,Machine,//; +MemPlace,MemPlaceMeta,OffsetMode,PlaceTy, Pointer,Projectable,Provenance,Scalar, +};#[derive(Copy,Clone,Debug) ]pub enum Immediate +{Scalar(Scalar),ScalarPair(Scalar,Scalar),Uninit,}implFrom>for Immediate{#[inline(always)]fn from(val:// +Scalar)->Self{Immediate::Scalar( val)}}implImmediate{pub fn new_pointer_with_meta(ptr:Pointer >,meta:MemPlaceMeta,cx:&impl HasDataLayout,)->Self{3;let ptr=Scalar::from_maybe_pointer(ptr,cx);3; +match meta{MemPlaceMeta::None=>(Immediate::from(ptr)),MemPlaceMeta::Meta(meta)=> +Immediate::ScalarPair(ptr,meta),}}pub fn new_slice(ptr:Pointer>,//; +len:u64,cx:&impl HasDataLayout)->Self{Immediate::ScalarPair(Scalar:://if true{}; +from_maybe_pointer(ptr,cx),(((((Scalar::from_target_usize (len,cx)))))),)}pub fn +new_dyn_trait(val:Pointer>,vtable:Pointer>,cx:&impl//; +HasDataLayout,)->Self{Immediate::ScalarPair( Scalar::from_maybe_pointer(val,cx), +Scalar::from_maybe_pointer(vtable,cx),)}#[inline]#[cfg_attr(debug_assertions,//; +track_caller)]pub fn to_scalar(self)-> Scalar{match self{Immediate::Scalar +(val)=>val,Immediate::ScalarPair(..)=>bug!(//((),());let _=();let _=();let _=(); +"Got a scalar pair where a scalar was expected"),Immediate::Uninit=>bug!(//({}); +"Got uninit where a scalar was expected"),}}#[inline]#[cfg_attr(//if let _=(){}; +debug_assertions,track_caller)]pub fn to_scalar_pair(self)->(Scalar,//{;}; +Scalar){match self{Immediate::ScalarPair (val1,val2)=>(((((val1,val2))))), +Immediate::Scalar(..)=> (bug!("Got a scalar where a scalar pair was expected")), +Immediate::Uninit=>((bug!( "Got uninit where a scalar pair was expected"))),}}#[ +inline]#[cfg_attr(debug_assertions,track_caller )]pub fn to_scalar_and_meta(self +)->(Scalar,MemPlaceMeta ){match self{Immediate::ScalarPair(val1,val2 +)=>((val1,MemPlaceMeta::Meta(val2))),Immediate::Scalar(val)=>(val,MemPlaceMeta:: +None),Immediate::Uninit=>bug!(//loop{break};loop{break};loop{break};loop{break}; +"Got uninit where a scalar or scalar pair was expected"),}}} #[derive(Clone)]pub +struct ImmTy<'tcx,Prov:Provenance=CtfeProvenance>{imm:Immediate,pub//({}); +layout:TyAndLayout<'tcx>,}implstd::fmt::Display for ImmTy<'_,// +Prov>{fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{();fn p<'a, +'tcx,Prov:Provenance>(cx:&mut FmtPrinter<'a,'tcx>,s:Scalar,ty:Ty<'tcx>,)// +->Result<(),std::fmt::Error>{match s{Scalar::Int(int)=>cx.//if true{};if true{}; +pretty_print_const_scalar_int(int,ty,(((((true)))))), Scalar::Ptr(ptr,_sz)=>{cx. +pretty_print_const_pointer(ptr,ty)}}}((),());ty::tls::with(|tcx|{match self.imm{ +Immediate::Scalar(s)=>{if let Some(ty)=tcx.lift(self.layout.ty){if true{};let s= +FmtPrinter::print_string(tcx,Namespace::ValueNS,|cx|p(cx,s,ty))?;;f.write_str(&s +)?;;return Ok(());}write!(f,"{:x}: {}",s,self.layout.ty)}Immediate::ScalarPair(a +,b)=>{write!(f,"({:x}, {:x}): {}",a,b ,self.layout.ty)}Immediate::Uninit=>{write +!(f,"uninit: {}",self.layout.ty)}}})}}implstd::fmt::Debug for// +ImmTy<'_,Prov>{fn fmt(&self,f:&mut std ::fmt::Formatter<'_>)->std::fmt::Result{f +.debug_struct(("ImmTy")).field(("imm"),&self.imm).field("ty",&format_args!("{}", +self.layout.ty)).finish()}} impl<'tcx,Prov:Provenance>std::ops::Deref for ImmTy< +'tcx,Prov>{type Target=Immediate;#[inline(always)]fn deref(&self)->&//{;}; +Immediate{&self.imm}}impl<'tcx ,Prov:Provenance>ImmTy<'tcx,Prov>{#[inline] +pub fn from_scalar(val:Scalar,layout:TyAndLayout<'tcx>)->Self{loop{break}; +debug_assert!(layout.abi.is_scalar(),//if true{};if true{};if true{};let _=||(); +"`ImmTy::from_scalar` on non-scalar layout");{;};ImmTy{imm:val.into(),layout}}#[ +inline]pub fn from_scalar_pair(a:Scalar< Prov>,b:Scalar,layout:TyAndLayout +<'tcx>)->Self{let _=||();debug_assert!(matches!(layout.abi,Abi::ScalarPair(..)), +"`ImmTy::from_scalar_pair` on non-scalar-pair layout");();();let imm=Immediate:: +ScalarPair(a,b);();ImmTy{imm,layout}}#[inline(always)]pub fn from_immediate(imm: +Immediate,layout:TyAndLayout<'tcx>)->Self{;debug_assert!(match(imm,layout. +abi){(Immediate::Scalar(..),Abi::Scalar(..))=>true,(Immediate::ScalarPair(..),// +Abi::ScalarPair(..))=>true,(Immediate::Uninit,_)if layout.is_sized()=>true,_=>// +false,},"immediate {imm:?} does not fit to layout {layout:?}",);{();};ImmTy{imm, +layout}}#[inline]pub fn uninit(layout:TyAndLayout<'tcx>)->Self{();debug_assert!( +layout.is_sized(),"immediates must be sized");{();};ImmTy{imm:Immediate::Uninit, +layout}}#[inline]pub fn try_from_uint( i:impl Into,layout:TyAndLayout<'tcx +>)->Option{Some(Self::from_scalar((Scalar::try_from_uint(i,layout.size)?), +layout))}#[inline]pub fn from_uint(i:impl Into,layout:TyAndLayout<'tcx>)// +->Self{(Self::from_scalar(Scalar::from_uint(i,layout.size),layout))}#[inline]pub +fn try_from_int(i:impl Into,layout: TyAndLayout<'tcx>)->Option{Some( +Self::from_scalar(Scalar::try_from_int(i,layout.size) ?,layout))}#[inline]pub fn +from_int(i:impl Into,layout:TyAndLayout<'tcx>)->Self{Self::from_scalar(//; +Scalar::from_int(i,layout.size),layout)}#[inline]pub fn from_bool(b:bool,tcx://; +TyCtxt<'tcx>)->Self{;let layout=tcx.layout_of(ty::ParamEnv::reveal_all().and(tcx +.types.bool)).unwrap();;Self::from_scalar(Scalar::from_bool(b),layout)}#[inline] +pub fn to_const_int(self)->ConstInt{;assert!(self.layout.ty.is_integral());;;let +int=self.to_scalar().assert_int();;ConstInt::new(int,self.layout.ty.is_signed(), +self.layout.ty.is_ptr_sized_integral())}fn offset_(&self,offset:Size,layout://3; +TyAndLayout<'tcx>,cx:&impl HasDataLayout)->Self{;debug_assert!(layout.is_sized() +,"unsized immediates are not a thing");;assert!(offset+layout.size<=self.layout. +size,//let _=();let _=();let _=();let _=();let _=();let _=();let _=();if true{}; +"attempting to project to field at offset {} with size {} into immediate with layout {:#?}" +,offset.bytes(),layout.size.bytes(),self.layout,);3;;let inner_val:Immediate<_>= +match(((**self),self.layout.abi)){(Immediate::Uninit,_)=>Immediate::Uninit,_ if +layout.abi.is_uninhabited()=>Immediate::Uninit,_ if (layout.is_zst())=>Immediate +::Uninit,_ if matches!(layout.abi,Abi ::Aggregate{..})&&matches!(&layout.fields, +abi::FieldsShape::Arbitrary{offsets,..}if offsets .len()==0)=>{Immediate::Uninit +}_ if layout.size==self.layout.size=>{3;assert_eq!(offset.bytes(),0);3;;assert!( +match(self.layout.abi,layout.abi){(Abi::Scalar(..),Abi::Scalar(..))=>true,(Abi// +::ScalarPair(..),Abi::ScalarPair(..))=>true,_=>false,},//let _=||();loop{break}; +"cannot project into {} immediate with equally-sized field {}\nouter ABI: {:#?}\nfield ABI: {:#?}" +,self.layout.ty,layout.ty,self.layout.abi,layout.abi,);{();};**self}(Immediate:: +ScalarPair(a_val,b_val),Abi::ScalarPair(a,b))=>{;assert!(matches!(layout.abi,Abi +::Scalar(..)));3;Immediate::from(if offset.bytes()==0{3;debug_assert_eq!(layout. +size,a.size(cx));;a_val}else{debug_assert_eq!(offset,a.size(cx).align_to(b.align +(cx).abi));{;};{;};debug_assert_eq!(layout.size,b.size(cx));{;};b_val})}_=>bug!( +"invalid field access on immediate {}, layout {:#?}",self,self.layout),};3;ImmTy +::from_immediate(inner_val,layout)}}impl <'tcx,Prov:Provenance>Projectable<'tcx, +Prov>for ImmTy<'tcx,Prov>{#[inline( always)]fn layout(&self)->TyAndLayout<'tcx>{ +self.layout}#[inline(always)]fn meta(&self)->MemPlaceMeta{3;debug_assert!( +self.layout.is_sized());3;MemPlaceMeta::None}fn offset_with_meta<'mir,M:Machine< +'mir,'tcx,Provenance=Prov>>(&self,offset:Size,_mode:OffsetMode,meta://if true{}; +MemPlaceMeta,layout:TyAndLayout<'tcx>,ecx:&InterpCx<'mir,'tcx,M>,)->//{;}; +InterpResult<'tcx,Self>{{;};assert_matches!(meta,MemPlaceMeta::None);();Ok(self. +offset_(offset,layout,ecx))}fn to_op <'mir,M:Machine<'mir,'tcx,Provenance=Prov>> +(&self,_ecx:&InterpCx<'mir,'tcx,M >,)->InterpResult<'tcx,OpTy<'tcx,M::Provenance +>>{(Ok(self.clone().into()))}}#[derive(Copy,Clone,Debug)]pub(super)enum Operand< +Prov:Provenance=CtfeProvenance>{Immediate(Immediate),Indirect(MemPlace),}#[derive(Clone)]pub struct OpTy<'tcx,Prov:Provenance=CtfeProvenance>{op +:Operand,pub layout:TyAndLayout<'tcx>,}implstd::fmt:://3; +Debug for OpTy<'_,Prov>{fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt// +::Result{(f.debug_struct("OpTy").field("op",&self.op)).field("ty",&format_args!( +"{}",self.layout.ty)).finish()}}impl<'tcx,Prov:Provenance>From>for OpTy<'tcx,Prov>{#[inline(always)] fn from(val:ImmTy<'tcx,Prov>)->Self{OpTy +{op:(Operand::Immediate(val.imm)),layout:val.layout}}}impl<'tcx,Prov:Provenance> +From>for OpTy<'tcx,Prov>{#[inline(always)]fn from(mplace://; +MPlaceTy<'tcx,Prov>)->Self{OpTy{op:(Operand::Indirect(*mplace.mplace())),layout: +mplace.layout}}}impl<'tcx,Prov:Provenance> OpTy<'tcx,Prov>{#[inline(always)]pub( +super)fn op(&self)->&Operand{ ((((&self.op))))}}impl<'tcx,Prov:Provenance> +Projectable<'tcx,Prov>for OpTy<'tcx,Prov>{#[inline(always)]fn layout(&self)->//; +TyAndLayout<'tcx>{self.layout}#[inline] fn meta(&self)->MemPlaceMeta{match +self.as_mplace_or_imm(){Left(mplace)=>mplace.meta(),Right(_)=>{();debug_assert!( +self.layout.is_sized(),"unsized immediates are not a thing");;MemPlaceMeta::None +}}}fn offset_with_meta<'mir,M:Machine< 'mir,'tcx,Provenance=Prov>>(&self,offset: +Size,mode:OffsetMode,meta:MemPlaceMeta,layout:TyAndLayout<'tcx>,ecx:&//(); +InterpCx<'mir,'tcx,M>,)->InterpResult<'tcx ,Self>{match self.as_mplace_or_imm(){ +Left(mplace)=>Ok(mplace.offset_with_meta(offset,mode ,meta,layout,ecx)?.into()), +Right(imm)=>{3;assert_matches!(meta,MemPlaceMeta::None);3;Ok(imm.offset_(offset, +layout,ecx).into())}}}fn to_op <'mir,M:Machine<'mir,'tcx,Provenance=Prov>>(&self +,_ecx:&InterpCx<'mir,'tcx,M>,)->InterpResult <'tcx,OpTy<'tcx,M::Provenance>>{Ok( +self.clone())}}pub trait Readable <'tcx,Prov:Provenance>:Projectable<'tcx,Prov>{ +fn as_mplace_or_imm(&self)->Either,ImmTy<'tcx,Prov>>;}impl< +'tcx,Prov:Provenance>Readable<'tcx,Prov>for OpTy<'tcx,Prov>{#[inline(always)]fn +as_mplace_or_imm(&self)->Either,ImmTy<'tcx,Prov>>{self.//(); +as_mplace_or_imm()}}impl<'tcx,Prov:Provenance>Readable<'tcx,Prov>for MPlaceTy{#[inline(always)]fn as_mplace_or_imm(&self)->Either,ImmTy<'tcx,Prov>>{Left(self.clone ())}}impl<'tcx,Prov:Provenance>Readable< +'tcx,Prov>for ImmTy<'tcx,Prov>{#[inline(always)]fn as_mplace_or_imm(&self)->//3; +Either,ImmTy<'tcx,Prov>>{(Right((self.clone())))}}impl<'mir, +'tcx:'mir,M:Machine<'mir,'tcx>>InterpCx<'mir,'tcx,M>{fn//let _=||();loop{break}; +read_immediate_from_mplace_raw(&self,mplace:&MPlaceTy<'tcx,M::Provenance>,)->//; +InterpResult<'tcx,Option>>{if mplace.layout.//((),()); +is_unsized(){;return Ok(None);}let Some(alloc)=self.get_place_alloc(mplace)?else +{;return Ok(Some(ImmTy::uninit(mplace.layout)));};Ok(match mplace.layout.abi{Abi +::Scalar(abi::Scalar::Initialized{value:s,..})=>{();let size=s.size(self);();(); +assert_eq!(size,mplace.layout.size,//if true{};let _=||();let _=||();let _=||(); +"abi::Scalar size does not match layout size");3;3;let scalar=alloc.read_scalar( +alloc_range(Size::ZERO,size),matches!(s,abi::Pointer(_)),)?;((),());Some(ImmTy:: +from_scalar(scalar,mplace.layout))}Abi::ScalarPair(abi::Scalar::Initialized{//3; +value:a,..},abi::Scalar::Initialized{value:b,..},)=>{;let(a_size,b_size)=(a.size +(self),b.size(self));;;let b_offset=a_size.align_to(b.align(self).abi);;assert!( +b_offset.bytes()>0);;let a_val=alloc.read_scalar(alloc_range(Size::ZERO,a_size), +matches!(a,abi::Pointer(_)),)?;;let b_val=alloc.read_scalar(alloc_range(b_offset +,b_size),matches!(b,abi::Pointer(_)),)?;3;Some(ImmTy::from_immediate(Immediate:: +ScalarPair(a_val,b_val),mplace.layout))} _=>{None}})}pub fn read_immediate_raw(& +self,src:&impl Readable<'tcx,M::Provenance>,)->InterpResult<'tcx,Either,ImmTy<'tcx,M::Provenance>>>{Ok(match src.//((),()); +as_mplace_or_imm(){Left(ref mplace)=>{if let Some(val)=self.//let _=();let _=(); +read_immediate_from_mplace_raw(mplace)?{(Right(val))}else{Left(mplace.clone())}} +Right(val)=>Right(val),})}#[ inline(always)]pub fn read_immediate(&self,op:&impl +Readable<'tcx,M::Provenance>,)->InterpResult<'tcx,ImmTy<'tcx,M::Provenance>>{//; +if!matches!(op.layout().abi,Abi::Scalar(abi::Scalar::Initialized{..})|Abi:://(); +ScalarPair(abi::Scalar::Initialized{..},abi::Scalar::Initialized{..})){;span_bug +!(self.cur_span(),"primitive read not possible for type: {}",op.layout().ty);;}; +let imm=self.read_immediate_raw(op)?.right().unwrap();let _=();if matches!(*imm, +Immediate::Uninit){({});throw_ub!(InvalidUninitBytes(None));({});}Ok(imm)}pub fn +read_scalar(&self,op:&impl Readable<'tcx,M::Provenance>,)->InterpResult<'tcx,//; +Scalar>{((Ok((((self.read_immediate(op))?).to_scalar()))))}pub fn +read_pointer(&self,op:&impl Readable<'tcx,M::Provenance>,)->InterpResult<'tcx,// +Pointer>>{(self.read_scalar (op)?.to_pointer(self))}pub fn +read_target_usize(&self,op:&impl Readable<'tcx,M::Provenance>,)->InterpResult{self.read_scalar(op) ?.to_target_usize(self)}pub fn read_target_isize( +&self,op:&impl Readable<'tcx,M::Provenance>,)->InterpResult<'tcx,i64>{self.//(); +read_scalar(op)?.to_target_isize(self)}pub fn read_str(&self,mplace:&MPlaceTy)->InterpResult<'tcx,&str>{3;let len=mplace.len(self)?;3;;let +bytes=self.read_bytes_ptr_strip_provenance(mplace.ptr() ,Size::from_bytes(len))? +;;let str=std::str::from_utf8(bytes).map_err(|err|err_ub!(InvalidStr(err)))?;Ok( +str)}pub fn operand_to_simd(&self,op :&OpTy<'tcx,M::Provenance>,)->InterpResult< +'tcx,(MPlaceTy<'tcx,M::Provenance>,u64)>{;assert!(op.layout.ty.is_simd());match +op.as_mplace_or_imm(){Left(mplace)=>(self .mplace_to_simd(&mplace)),Right(imm)=> +match(*imm){Immediate::Uninit=>{ throw_ub!(InvalidUninitBytes(None))}Immediate:: +Scalar(..)|Immediate::ScalarPair(..)=>{bug!(//((),());let _=();((),());let _=(); +"arrays/slices can never have Scalar/ScalarPair layout")}}, }}pub fn local_to_op +(&self,local:mir::Local,layout:Option>,)->InterpResult<'tcx,// +OpTy<'tcx,M::Provenance>>{({});let frame=self.frame();({});({});let layout=self. +layout_of_local(frame,local,layout)?;;;let op=*frame.locals[local].access()?;if +matches!(op,Operand::Immediate(_)){3;assert!(!layout.is_unsized());;}Ok(OpTy{op, +layout})}pub fn place_to_op(&self,place:&PlaceTy<'tcx,M::Provenance>,)->//{();}; +InterpResult<'tcx,OpTy<'tcx,M::Provenance >>{match (place.as_mplace_or_local()){ +Left(mplace)=>Ok(mplace.into()),Right((local,offset,locals_addr))=>{loop{break}; +debug_assert!(place.layout.is_sized());;debug_assert_eq!(locals_addr,self.frame( +).locals_addr());;;let base=self.local_to_op(local,None)?;;Ok(match offset{Some( +offset)=>base.offset(offset,place.layout,self)?,None=>{3;debug_assert_eq!(place. +layout,base.layout);({});base}})}}}pub fn eval_place_to_op(&self,mir_place:mir:: +Place<'tcx>,layout:Option> ,)->InterpResult<'tcx,OpTy<'tcx,M:: +Provenance>>{;let layout=if mir_place.projection.is_empty(){layout}else{None};;; +let mut op=self.local_to_op(mir_place.local,layout)?;({});for elem in mir_place. +projection.iter(){op=self.project(&op,elem)?}if let _=(){};if let _=(){};trace!( +"eval_place_to_op: got {:?}",op);let _=();if cfg!(debug_assertions){let _=();let +normalized_place_ty=self.//loop{break;};loop{break;};loop{break;};if let _=(){}; +instantiate_from_current_frame_and_normalize_erasing_regions(mir_place. ty(&self +.frame().body.local_decls,*self.tcx).ty,)?;;if!mir_assign_valid_types(*self.tcx, +self.param_env,self.layout_of(normalized_place_ty)? ,op.layout,){span_bug!(self. +cur_span(),//((),());((),());((),());let _=();((),());let _=();((),());let _=(); +"eval_place of a MIR place with type {} produced an interpreter operand with type {}" +,normalized_place_ty,op.layout.ty,)}}Ok( op)}#[inline]pub fn eval_operand(&self, +mir_op:&mir::Operand<'tcx>,layout:Option>,)->InterpResult>{;use rustc_middle::mir::Operand::*;;;let op=match +mir_op{&Copy(place)|&Move(place)=> self.eval_place_to_op(place,layout)?,Constant +(constant)=>{if let _=(){};if let _=(){};if let _=(){};if let _=(){};let c=self. +instantiate_from_current_frame_and_normalize_erasing_regions(constant.const_ ,)? +;;self.eval_mir_constant(&c,constant.span,layout)?}};trace!("{:?}: {:?}",mir_op, +op);;Ok(op)}pub(crate)fn const_val_to_op(&self,val_val:mir::ConstValue<'tcx>,ty: +Ty<'tcx>,layout:Option>,)->InterpResult<'tcx,OpTy<'tcx,M:://3; +Provenance>>{3;let adjust_scalar=|scalar|->InterpResult<'tcx,_>{Ok(match scalar{ +Scalar::Ptr(ptr,size)=>(Scalar::Ptr(self.global_base_pointer(ptr)?,size)),Scalar +::Int(int)=>Scalar::Int(int),})};3;3;let layout=from_known_layout(self.tcx,self. +param_env,layout,||self.layout_of(ty))?;;let imm=match val_val{mir::ConstValue:: +Indirect{alloc_id,offset}=>{{();};let ptr=self.global_base_pointer(Pointer::new( +CtfeProvenance::from(alloc_id).as_immutable(),offset,))?;{;};{;};return Ok(self. +ptr_to_mplace(ptr.into(),layout).into());if true{};}mir::ConstValue::Scalar(x)=> +adjust_scalar(x)?.into(),mir::ConstValue::ZeroSized=>Immediate::Uninit,mir:://3; +ConstValue::Slice{data,meta}=>{loop{break;};if let _=(){};let alloc_id=self.tcx. +reserve_and_set_memory_alloc(data);3;;let ptr=Pointer::new(CtfeProvenance::from( +alloc_id).as_immutable(),Size::ZERO);((),());let _=();Immediate::new_slice(self. +global_base_pointer(ptr)?.into(),meta,self)}};;Ok(OpTy{op:Operand::Immediate(imm +),layout})}}#[cfg(all(target_arch="x86_64",target_pointer_width="64"))]mod//{;}; +size_asserts{use super::*;use rustc_data_structures::static_assert_size;//{();}; +static_assert_size!(Immediate,48);static_assert_size!(ImmTy<'_>,64);//if true{}; +static_assert_size!(Operand,56);static_assert_size!(OpTy<'_>,72);}//loop{break}; diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index 475c533077af5..e3d7e0940480d 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -1,510 +1,154 @@ -use rustc_apfloat::{Float, FloatConvert}; -use rustc_middle::mir; -use rustc_middle::mir::interpret::{InterpResult, Scalar}; -use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; -use rustc_middle::ty::{self, FloatTy, Ty}; -use rustc_span::symbol::sym; -use rustc_target::abi::Abi; - -use super::{ImmTy, Immediate, InterpCx, Machine, PlaceTy}; - -use crate::fluent_generated as fluent; - -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - /// Applies the binary operation `op` to the two operands and writes a tuple of the result - /// and a boolean signifying the potential overflow to the destination. - pub fn binop_with_overflow( - &mut self, - op: mir::BinOp, - left: &ImmTy<'tcx, M::Provenance>, - right: &ImmTy<'tcx, M::Provenance>, - dest: &PlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx> { - let (val, overflowed) = self.overflowing_binary_op(op, left, right)?; - debug_assert_eq!( - Ty::new_tup(self.tcx.tcx, &[val.layout.ty, self.tcx.types.bool]), - dest.layout.ty, - "type mismatch for result of {op:?}", - ); - // Write the result to `dest`. - if let Abi::ScalarPair(..) = dest.layout.abi { - // We can use the optimized path and avoid `place_field` (which might do - // `force_allocation`). - let pair = Immediate::ScalarPair(val.to_scalar(), Scalar::from_bool(overflowed)); - self.write_immediate(pair, dest)?; - } else { - assert!(self.tcx.sess.opts.unstable_opts.randomize_layout); - // With randomized layout, `(int, bool)` might cease to be a `ScalarPair`, so we have to - // do a component-wise write here. This code path is slower than the above because - // `place_field` will have to `force_allocate` locals here. - let val_field = self.project_field(dest, 0)?; - self.write_scalar(val.to_scalar(), &val_field)?; - let overflowed_field = self.project_field(dest, 1)?; - self.write_scalar(Scalar::from_bool(overflowed), &overflowed_field)?; - } - Ok(()) - } - - /// Applies the binary operation `op` to the arguments and writes the result to the - /// destination. - pub fn binop_ignore_overflow( - &mut self, - op: mir::BinOp, - left: &ImmTy<'tcx, M::Provenance>, - right: &ImmTy<'tcx, M::Provenance>, - dest: &PlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx> { - let val = self.wrapping_binary_op(op, left, right)?; - assert_eq!(val.layout.ty, dest.layout.ty, "type mismatch for result of {op:?}"); - self.write_immediate(*val, dest) - } -} - -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - fn binary_char_op( - &self, - bin_op: mir::BinOp, - l: char, - r: char, - ) -> (ImmTy<'tcx, M::Provenance>, bool) { - use rustc_middle::mir::BinOp::*; - - let res = match bin_op { - Eq => l == r, - Ne => l != r, - Lt => l < r, - Le => l <= r, - Gt => l > r, - Ge => l >= r, - _ => span_bug!(self.cur_span(), "Invalid operation on char: {:?}", bin_op), - }; - (ImmTy::from_bool(res, *self.tcx), false) - } - - fn binary_bool_op( - &self, - bin_op: mir::BinOp, - l: bool, - r: bool, - ) -> (ImmTy<'tcx, M::Provenance>, bool) { - use rustc_middle::mir::BinOp::*; - - let res = match bin_op { - Eq => l == r, - Ne => l != r, - Lt => l < r, - Le => l <= r, - Gt => l > r, - Ge => l >= r, - BitAnd => l & r, - BitOr => l | r, - BitXor => l ^ r, - _ => span_bug!(self.cur_span(), "Invalid operation on bool: {:?}", bin_op), - }; - (ImmTy::from_bool(res, *self.tcx), false) - } - - fn binary_float_op + Into>>( - &self, - bin_op: mir::BinOp, - layout: TyAndLayout<'tcx>, - l: F, - r: F, - ) -> (ImmTy<'tcx, M::Provenance>, bool) { - use rustc_middle::mir::BinOp::*; - - // Performs appropriate non-deterministic adjustments of NaN results. - let adjust_nan = - |f: F| -> F { if f.is_nan() { M::generate_nan(self, &[l, r]) } else { f } }; - - let val = match bin_op { - Eq => ImmTy::from_bool(l == r, *self.tcx), - Ne => ImmTy::from_bool(l != r, *self.tcx), - Lt => ImmTy::from_bool(l < r, *self.tcx), - Le => ImmTy::from_bool(l <= r, *self.tcx), - Gt => ImmTy::from_bool(l > r, *self.tcx), - Ge => ImmTy::from_bool(l >= r, *self.tcx), - Add => ImmTy::from_scalar(adjust_nan((l + r).value).into(), layout), - Sub => ImmTy::from_scalar(adjust_nan((l - r).value).into(), layout), - Mul => ImmTy::from_scalar(adjust_nan((l * r).value).into(), layout), - Div => ImmTy::from_scalar(adjust_nan((l / r).value).into(), layout), - Rem => ImmTy::from_scalar(adjust_nan((l % r).value).into(), layout), - _ => span_bug!(self.cur_span(), "invalid float op: `{:?}`", bin_op), - }; - (val, false) - } - - fn binary_int_op( - &self, - bin_op: mir::BinOp, - // passing in raw bits - l: u128, - left_layout: TyAndLayout<'tcx>, - r: u128, - right_layout: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, (ImmTy<'tcx, M::Provenance>, bool)> { - use rustc_middle::mir::BinOp::*; - - let throw_ub_on_overflow = match bin_op { - AddUnchecked => Some(sym::unchecked_add), - SubUnchecked => Some(sym::unchecked_sub), - MulUnchecked => Some(sym::unchecked_mul), - ShlUnchecked => Some(sym::unchecked_shl), - ShrUnchecked => Some(sym::unchecked_shr), - _ => None, - }; - - // Shift ops can have an RHS with a different numeric type. - if matches!(bin_op, Shl | ShlUnchecked | Shr | ShrUnchecked) { - let size = left_layout.size.bits(); - // The shift offset is implicitly masked to the type size. (This is the one MIR operator - // that does *not* directly map to a single LLVM operation.) Compute how much we - // actually shift and whether there was an overflow due to shifting too much. - let (shift_amount, overflow) = if right_layout.abi.is_signed() { - let shift_amount = self.sign_extend(r, right_layout) as i128; - let overflow = shift_amount < 0 || shift_amount >= i128::from(size); - let masked_amount = (shift_amount as u128) % u128::from(size); - debug_assert_eq!(overflow, shift_amount != (masked_amount as i128)); - (masked_amount, overflow) - } else { - let shift_amount = r; - let masked_amount = shift_amount % u128::from(size); - (masked_amount, shift_amount != masked_amount) - }; - let shift_amount = u32::try_from(shift_amount).unwrap(); // we masked so this will always fit - // Compute the shifted result. - let result = if left_layout.abi.is_signed() { - let l = self.sign_extend(l, left_layout) as i128; - let result = match bin_op { - Shl | ShlUnchecked => l.checked_shl(shift_amount).unwrap(), - Shr | ShrUnchecked => l.checked_shr(shift_amount).unwrap(), - _ => bug!(), - }; - result as u128 - } else { - match bin_op { - Shl | ShlUnchecked => l.checked_shl(shift_amount).unwrap(), - Shr | ShrUnchecked => l.checked_shr(shift_amount).unwrap(), - _ => bug!(), - } - }; - let truncated = self.truncate(result, left_layout); - - if overflow && let Some(intrinsic_name) = throw_ub_on_overflow { - throw_ub_custom!( - fluent::const_eval_overflow_shift, - val = if right_layout.abi.is_signed() { - (self.sign_extend(r, right_layout) as i128).to_string() - } else { - r.to_string() - }, - name = intrinsic_name - ); - } - - return Ok((ImmTy::from_uint(truncated, left_layout), overflow)); - } - - // For the remaining ops, the types must be the same on both sides - if left_layout.ty != right_layout.ty { - span_bug!( - self.cur_span(), - "invalid asymmetric binary op {bin_op:?}: {l:?} ({l_ty}), {r:?} ({r_ty})", - l_ty = left_layout.ty, - r_ty = right_layout.ty, - ) - } - - let size = left_layout.size; - - // Operations that need special treatment for signed integers - if left_layout.abi.is_signed() { - let op: Option bool> = match bin_op { - Lt => Some(i128::lt), - Le => Some(i128::le), - Gt => Some(i128::gt), - Ge => Some(i128::ge), - _ => None, - }; - if let Some(op) = op { - let l = self.sign_extend(l, left_layout) as i128; - let r = self.sign_extend(r, right_layout) as i128; - return Ok((ImmTy::from_bool(op(&l, &r), *self.tcx), false)); - } - let op: Option (i128, bool)> = match bin_op { - Div if r == 0 => throw_ub!(DivisionByZero), - Rem if r == 0 => throw_ub!(RemainderByZero), - Div => Some(i128::overflowing_div), - Rem => Some(i128::overflowing_rem), - Add | AddUnchecked => Some(i128::overflowing_add), - Sub | SubUnchecked => Some(i128::overflowing_sub), - Mul | MulUnchecked => Some(i128::overflowing_mul), - _ => None, - }; - if let Some(op) = op { - let l = self.sign_extend(l, left_layout) as i128; - let r = self.sign_extend(r, right_layout) as i128; - - // We need a special check for overflowing Rem and Div since they are *UB* - // on overflow, which can happen with "int_min $OP -1". - if matches!(bin_op, Rem | Div) { - if l == size.signed_int_min() && r == -1 { - if bin_op == Rem { - throw_ub!(RemainderOverflow) - } else { - throw_ub!(DivisionOverflow) - } - } - } - - let (result, oflo) = op(l, r); - // This may be out-of-bounds for the result type, so we have to truncate ourselves. - // If that truncation loses any information, we have an overflow. - let result = result as u128; - let truncated = self.truncate(result, left_layout); - let overflow = oflo || self.sign_extend(truncated, left_layout) != result; - if overflow && let Some(intrinsic_name) = throw_ub_on_overflow { - throw_ub_custom!(fluent::const_eval_overflow, name = intrinsic_name); - } - return Ok((ImmTy::from_uint(truncated, left_layout), overflow)); - } - } - - let val = match bin_op { - Eq => ImmTy::from_bool(l == r, *self.tcx), - Ne => ImmTy::from_bool(l != r, *self.tcx), - - Lt => ImmTy::from_bool(l < r, *self.tcx), - Le => ImmTy::from_bool(l <= r, *self.tcx), - Gt => ImmTy::from_bool(l > r, *self.tcx), - Ge => ImmTy::from_bool(l >= r, *self.tcx), - - BitOr => ImmTy::from_uint(l | r, left_layout), - BitAnd => ImmTy::from_uint(l & r, left_layout), - BitXor => ImmTy::from_uint(l ^ r, left_layout), - - Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Rem | Div => { - assert!(!left_layout.abi.is_signed()); - let op: fn(u128, u128) -> (u128, bool) = match bin_op { - Add | AddUnchecked => u128::overflowing_add, - Sub | SubUnchecked => u128::overflowing_sub, - Mul | MulUnchecked => u128::overflowing_mul, - Div if r == 0 => throw_ub!(DivisionByZero), - Rem if r == 0 => throw_ub!(RemainderByZero), - Div => u128::overflowing_div, - Rem => u128::overflowing_rem, - _ => bug!(), - }; - let (result, oflo) = op(l, r); - // Truncate to target type. - // If that truncation loses any information, we have an overflow. - let truncated = self.truncate(result, left_layout); - let overflow = oflo || truncated != result; - if overflow && let Some(intrinsic_name) = throw_ub_on_overflow { - throw_ub_custom!(fluent::const_eval_overflow, name = intrinsic_name); - } - return Ok((ImmTy::from_uint(truncated, left_layout), overflow)); - } - - _ => span_bug!( - self.cur_span(), - "invalid binary op {:?}: {:?}, {:?} (both {})", - bin_op, - l, - r, - right_layout.ty, - ), - }; - - Ok((val, false)) - } - - fn binary_ptr_op( - &self, - bin_op: mir::BinOp, - left: &ImmTy<'tcx, M::Provenance>, - right: &ImmTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, (ImmTy<'tcx, M::Provenance>, bool)> { - use rustc_middle::mir::BinOp::*; - - match bin_op { - // Pointer ops that are always supported. - Offset => { - let ptr = left.to_scalar().to_pointer(self)?; - let offset_count = right.to_scalar().to_target_isize(self)?; - let pointee_ty = left.layout.ty.builtin_deref(true).unwrap().ty; - - // We cannot overflow i64 as a type's size must be <= isize::MAX. - let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap(); - // The computed offset, in bytes, must not overflow an isize. - // `checked_mul` enforces a too small bound, but no actual allocation can be big enough for - // the difference to be noticeable. - let offset_bytes = - offset_count.checked_mul(pointee_size).ok_or(err_ub!(PointerArithOverflow))?; - - let offset_ptr = self.ptr_offset_inbounds(ptr, offset_bytes)?; - Ok(( - ImmTy::from_scalar(Scalar::from_maybe_pointer(offset_ptr, self), left.layout), - false, - )) - } - - // Fall back to machine hook so Miri can support more pointer ops. - _ => M::binary_ptr_op(self, bin_op, left, right), - } - } - - /// Returns the result of the specified operation, and whether it overflowed. - pub fn overflowing_binary_op( - &self, - bin_op: mir::BinOp, - left: &ImmTy<'tcx, M::Provenance>, - right: &ImmTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, (ImmTy<'tcx, M::Provenance>, bool)> { - trace!( - "Running binary op {:?}: {:?} ({}), {:?} ({})", - bin_op, - *left, - left.layout.ty, - *right, - right.layout.ty - ); - - match left.layout.ty.kind() { - ty::Char => { - assert_eq!(left.layout.ty, right.layout.ty); - let left = left.to_scalar(); - let right = right.to_scalar(); - Ok(self.binary_char_op(bin_op, left.to_char()?, right.to_char()?)) - } - ty::Bool => { - assert_eq!(left.layout.ty, right.layout.ty); - let left = left.to_scalar(); - let right = right.to_scalar(); - Ok(self.binary_bool_op(bin_op, left.to_bool()?, right.to_bool()?)) - } - ty::Float(fty) => { - assert_eq!(left.layout.ty, right.layout.ty); - let layout = left.layout; - let left = left.to_scalar(); - let right = right.to_scalar(); - Ok(match fty { - FloatTy::F16 => unimplemented!("f16_f128"), - FloatTy::F32 => { - self.binary_float_op(bin_op, layout, left.to_f32()?, right.to_f32()?) - } - FloatTy::F64 => { - self.binary_float_op(bin_op, layout, left.to_f64()?, right.to_f64()?) - } - FloatTy::F128 => unimplemented!("f16_f128"), - }) - } - _ if left.layout.ty.is_integral() => { - // the RHS type can be different, e.g. for shifts -- but it has to be integral, too - assert!( - right.layout.ty.is_integral(), - "Unexpected types for BinOp: {} {:?} {}", - left.layout.ty, - bin_op, - right.layout.ty - ); - - let l = left.to_scalar().to_bits(left.layout.size)?; - let r = right.to_scalar().to_bits(right.layout.size)?; - self.binary_int_op(bin_op, l, left.layout, r, right.layout) - } - _ if left.layout.ty.is_any_ptr() => { - // The RHS type must be a `pointer` *or an integer type* (for `Offset`). - // (Even when both sides are pointers, their type might differ, see issue #91636) - assert!( - right.layout.ty.is_any_ptr() || right.layout.ty.is_integral(), - "Unexpected types for BinOp: {} {:?} {}", - left.layout.ty, - bin_op, - right.layout.ty - ); - - self.binary_ptr_op(bin_op, left, right) - } - _ => span_bug!( - self.cur_span(), - "Invalid MIR: bad LHS type for binop: {}", - left.layout.ty - ), - } - } - - #[inline] - pub fn wrapping_binary_op( - &self, - bin_op: mir::BinOp, - left: &ImmTy<'tcx, M::Provenance>, - right: &ImmTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { - let (val, _overflow) = self.overflowing_binary_op(bin_op, left, right)?; - Ok(val) - } - - /// Returns the result of the specified operation, whether it overflowed, and - /// the result type. - pub fn overflowing_unary_op( - &self, - un_op: mir::UnOp, - val: &ImmTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, (ImmTy<'tcx, M::Provenance>, bool)> { - use rustc_middle::mir::UnOp::*; - - let layout = val.layout; - let val = val.to_scalar(); - trace!("Running unary op {:?}: {:?} ({})", un_op, val, layout.ty); - - match layout.ty.kind() { - ty::Bool => { - let val = val.to_bool()?; - let res = match un_op { - Not => !val, - _ => span_bug!(self.cur_span(), "Invalid bool op {:?}", un_op), - }; - Ok((ImmTy::from_bool(res, *self.tcx), false)) - } - ty::Float(fty) => { - // No NaN adjustment here, `-` is a bitwise operation! - let res = match (un_op, fty) { - (Neg, FloatTy::F32) => Scalar::from_f32(-val.to_f32()?), - (Neg, FloatTy::F64) => Scalar::from_f64(-val.to_f64()?), - _ => span_bug!(self.cur_span(), "Invalid float op {:?}", un_op), - }; - Ok((ImmTy::from_scalar(res, layout), false)) - } - _ => { - assert!(layout.ty.is_integral()); - let val = val.to_bits(layout.size)?; - let (res, overflow) = match un_op { - Not => (self.truncate(!val, layout), false), // bitwise negation, then truncate - Neg => { - // arithmetic negation - assert!(layout.abi.is_signed()); - let val = self.sign_extend(val, layout) as i128; - let (res, overflow) = val.overflowing_neg(); - let res = res as u128; - // Truncate to target type. - // If that truncation loses any information, we have an overflow. - let truncated = self.truncate(res, layout); - (truncated, overflow || self.sign_extend(truncated, layout) != res) - } - }; - Ok((ImmTy::from_uint(res, layout), overflow)) - } - } - } - - #[inline] - pub fn wrapping_unary_op( - &self, - un_op: mir::UnOp, - val: &ImmTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { - let (val, _overflow) = self.overflowing_unary_op(un_op, val)?; - Ok(val) - } -} +use rustc_apfloat::{Float,FloatConvert};use rustc_middle::mir;use rustc_middle// +::mir::interpret::{InterpResult,Scalar} ;use rustc_middle::ty::layout::{LayoutOf +,TyAndLayout};use rustc_middle::ty::{self,FloatTy,Ty};use rustc_span::symbol::// +sym;use rustc_target::abi::Abi;use super::{ImmTy,Immediate,InterpCx,Machine,//3; +PlaceTy};use crate::fluent_generated as fluent;impl<'mir,'tcx:'mir,M:Machine>InterpCx<'mir,'tcx,M>{pub fn binop_with_overflow(&mut self,op:mir::// +BinOp,left:&ImmTy<'tcx,M::Provenance>,right:&ImmTy<'tcx,M::Provenance>,dest:&//; +PlaceTy<'tcx,M::Provenance>,)->InterpResult<'tcx>{({});let(val,overflowed)=self. +overflowing_binary_op(op,left,right)?;;debug_assert_eq!(Ty::new_tup(self.tcx.tcx +,&[val.layout.ty,self.tcx.types.bool]),dest.layout.ty,//loop{break};loop{break}; +"type mismatch for result of {op:?}",);3;if let Abi::ScalarPair(..)=dest.layout. +abi{;let pair=Immediate::ScalarPair(val.to_scalar(),Scalar::from_bool(overflowed +));();();self.write_immediate(pair,dest)?;();}else{3;assert!(self.tcx.sess.opts. +unstable_opts.randomize_layout);;let val_field=self.project_field(dest,0)?;self. +write_scalar(val.to_scalar(),&val_field)?;{();};{();};let overflowed_field=self. +project_field(dest,1)?;{;};{;};self.write_scalar(Scalar::from_bool(overflowed),& +overflowed_field)?;;}Ok(())}pub fn binop_ignore_overflow(&mut self,op:mir::BinOp +,left:&ImmTy<'tcx,M::Provenance>,right :&ImmTy<'tcx,M::Provenance>,dest:&PlaceTy +<'tcx,M::Provenance>,)->InterpResult<'tcx>{3;let val=self.wrapping_binary_op(op, +left,right)?;if let _=(){};loop{break;};assert_eq!(val.layout.ty,dest.layout.ty, +"type mismatch for result of {op:?}");{;};self.write_immediate(*val,dest)}}impl< +'mir,'tcx:'mir,M:Machine<'mir,'tcx>>InterpCx<'mir,'tcx,M>{fn binary_char_op(&//; +self,bin_op:mir::BinOp,l:char,r:char,)->(ImmTy<'tcx,M::Provenance>,bool){{;};use +rustc_middle::mir::BinOp::*;;let res=match bin_op{Eq=>l==r,Ne=>l!=r,Lt=>l +l<=r,Gt=>(((((((l>r))))))),Ge=>((((((( l>=r))))))),_=>span_bug!(self.cur_span(), +"Invalid operation on char: {:?}",bin_op),};();(ImmTy::from_bool(res,*self.tcx), +false)}fn binary_bool_op(&self,bin_op:mir::BinOp ,l:bool,r:bool,)->(ImmTy<'tcx,M +::Provenance>,bool){;use rustc_middle::mir::BinOp::*;;let res=match bin_op{Eq=>l +==r,Ne=>l!=r,Lt=>ll<=r,Gt=>l >r,Ge=>l>=r,BitAnd=>l&r,BitOr=>l|r,BitXor=>l +^r,_=>span_bug!(self.cur_span(),"Invalid operation on bool: {:?}",bin_op),};();( +ImmTy::from_bool(res,*self.tcx), false)}fn binary_float_op+Into>>( &self,bin_op:mir::BinOp,layout:TyAndLayout<'tcx +>,l:F,r:F,)->(ImmTy<'tcx,M::Provenance>,bool){;use rustc_middle::mir::BinOp::*;; +let adjust_nan=|f:F|->F{if f.is_nan(){M::generate_nan(self,&[l,r])}else{f}};;let +val=match bin_op{Eq=>(ImmTy::from_bool(l==r,*self.tcx)),Ne=>ImmTy::from_bool(l!= +r,(*self.tcx)),Lt=>(ImmTy::from_bool(lImmTy::from_bool(l<=r,* +self.tcx),Gt=>(ImmTy::from_bool(l>r,*self.tcx)),Ge=>ImmTy::from_bool(l>=r,*self. +tcx),Add=>(ImmTy::from_scalar(adjust_nan((l+r).value).into(),layout)),Sub=>ImmTy +::from_scalar((adjust_nan((l-r).value) .into()),layout),Mul=>ImmTy::from_scalar( +adjust_nan((l*r).value).into(),layout ),Div=>ImmTy::from_scalar(adjust_nan((l/r) +.value).into(),layout),Rem=>ImmTy::from_scalar((adjust_nan((l%r).value).into()), +layout),_=>span_bug!(self.cur_span(),"invalid float op: `{:?}`",bin_op),};;(val, +false)}fn binary_int_op(&self,bin_op :mir::BinOp,l:u128,left_layout:TyAndLayout< +'tcx>,r:u128,right_layout:TyAndLayout<'tcx>,)->InterpResult<'tcx,(ImmTy<'tcx,M// +::Provenance>,bool)>{;use rustc_middle::mir::BinOp::*;;let throw_ub_on_overflow= +match bin_op{AddUnchecked=>((Some(sym::unchecked_add))),SubUnchecked=>Some(sym:: +unchecked_sub),MulUnchecked=>(Some(sym::unchecked_mul)),ShlUnchecked=>Some(sym:: +unchecked_shl),ShrUnchecked=>Some(sym::unchecked_shr),_=>None,};{;};if matches!( +bin_op,Shl|ShlUnchecked|Shr|ShrUnchecked){;let size=left_layout.size.bits();let( +shift_amount,overflow)=if right_layout.abi.is_signed(){();let shift_amount=self. +sign_extend(r,right_layout)as i128;;;let overflow=shift_amount<0||shift_amount>= +i128::from(size);3;;let masked_amount=(shift_amount as u128)%u128::from(size);;; +debug_assert_eq!(overflow,shift_amount!=(masked_amount as i128));;(masked_amount +,overflow)}else{;let shift_amount=r;;;let masked_amount=shift_amount%u128::from( +size);();(masked_amount,shift_amount!=masked_amount)};3;3;let shift_amount=u32:: +try_from(shift_amount).unwrap();;let result=if left_layout.abi.is_signed(){let l +=self.sign_extend(l,left_layout)as i128;{();};{();};let result=match bin_op{Shl| +ShlUnchecked=>((((l.checked_shl(shift_amount))). unwrap())),Shr|ShrUnchecked=>l. +checked_shr(shift_amount).unwrap(),_=>bug!(),};;result as u128}else{match bin_op +{Shl|ShlUnchecked=>((l.checked_shl(shift_amount)).unwrap()),Shr|ShrUnchecked=>l. +checked_shr(shift_amount).unwrap(),_=>bug!(),}};3;3;let truncated=self.truncate( +result,left_layout);;if overflow&&let Some(intrinsic_name)=throw_ub_on_overflow{ +throw_ub_custom!(fluent::const_eval_overflow_shift,val=if right_layout.abi.//(); +is_signed(){(self.sign_extend(r,right_layout)as i128).to_string()}else{r.//({}); +to_string()},name=intrinsic_name);{;};}();return Ok((ImmTy::from_uint(truncated, +left_layout),overflow));({});}if left_layout.ty!=right_layout.ty{span_bug!(self. +cur_span(),//((),());((),());((),());let _=();((),());let _=();((),());let _=(); +"invalid asymmetric binary op {bin_op:?}: {l:?} ({l_ty}), {r:?} ({r_ty})", l_ty= +left_layout.ty,r_ty=right_layout.ty,)};let size=left_layout.size;if left_layout. +abi.is_signed(){;let op:Optionbool>=match bin_op{Lt=>Some(i128 +::lt),Le=>Some(i128::le),Gt=>Some(i128::gt),Ge=>Some(i128::ge),_=>None,};;if let +Some(op)=op{{;};let l=self.sign_extend(l,left_layout)as i128;{;};{;};let r=self. +sign_extend(r,right_layout)as i128;;return Ok((ImmTy::from_bool(op(&l,&r),*self. +tcx),false));;}let op:Option(i128,bool)>=match bin_op{Div if r== +0=>throw_ub!(DivisionByZero),Rem if r ==0=>throw_ub!(RemainderByZero),Div=>Some( +i128::overflowing_div),Rem=>Some(i128 ::overflowing_rem),Add|AddUnchecked=>Some( +i128::overflowing_add),Sub|SubUnchecked=> (((Some(i128::overflowing_sub)))),Mul| +MulUnchecked=>Some(i128::overflowing_mul),_=>None,};3;if let Some(op)=op{;let l= +self.sign_extend(l,left_layout)as i128;;let r=self.sign_extend(r,right_layout)as +i128;();if matches!(bin_op,Rem|Div){if l==size.signed_int_min()&&r==-1{if bin_op +==Rem{throw_ub!(RemainderOverflow)}else{throw_ub!(DivisionOverflow)}}}{();};let( +result,oflo)=op(l,r);3;;let result=result as u128;;;let truncated=self.truncate( +result,left_layout);;;let overflow=oflo||self.sign_extend(truncated,left_layout) +!=result;{();};if overflow&&let Some(intrinsic_name)=throw_ub_on_overflow{{();}; +throw_ub_custom!(fluent::const_eval_overflow,name=intrinsic_name);;};return Ok(( +ImmTy::from_uint(truncated,left_layout),overflow));;}};let val=match bin_op{Eq=> +ImmTy::from_bool(l==r,*self.tcx),Ne=> ImmTy::from_bool(l!=r,*self.tcx),Lt=>ImmTy +::from_bool((lImmTy ::from_bool(l<=r,*self.tcx),Gt=>ImmTy:: +from_bool((l>r),(*self.tcx)),Ge=>ImmTy::from_bool(l>=r,*self.tcx),BitOr=>ImmTy:: +from_uint((l|r),left_layout),BitAnd=>ImmTy ::from_uint(l&r,left_layout),BitXor=> +ImmTy::from_uint(((((l^r)))),left_layout),Add|AddUnchecked|Sub|SubUnchecked|Mul| +MulUnchecked|Rem|Div=>{3;assert!(!left_layout.abi.is_signed());;;let op:fn(u128, +u128)->(u128,bool)=match bin_op{Add|AddUnchecked=>u128::overflowing_add,Sub|//3; +SubUnchecked=>u128::overflowing_sub,Mul |MulUnchecked=>u128::overflowing_mul,Div +if (r==0)=>throw_ub!(DivisionByZero),Rem if r==0=>throw_ub!(RemainderByZero),Div +=>u128::overflowing_div,Rem=>u128::overflowing_rem,_=>bug!(),};;let(result,oflo) +=op(l,r);;;let truncated=self.truncate(result,left_layout);;;let overflow=oflo|| +truncated!=result;3;if overflow&&let Some(intrinsic_name)=throw_ub_on_overflow{; +throw_ub_custom!(fluent::const_eval_overflow,name=intrinsic_name);;};return Ok(( +ImmTy::from_uint(truncated,left_layout),overflow));;}_=>span_bug!(self.cur_span( +),"invalid binary op {:?}: {:?}, {:?} (both {})",bin_op,l,r ,right_layout.ty,),} +;3;Ok((val,false))}fn binary_ptr_op(&self,bin_op:mir::BinOp,left:&ImmTy<'tcx,M:: +Provenance>,right:&ImmTy<'tcx,M::Provenance >,)->InterpResult<'tcx,(ImmTy<'tcx,M +::Provenance>,bool)>{;use rustc_middle::mir::BinOp::*;;match bin_op{Offset=>{let +ptr=left.to_scalar().to_pointer(self)?;();();let offset_count=right.to_scalar(). +to_target_isize(self)?;;let pointee_ty=left.layout.ty.builtin_deref(true).unwrap +().ty;;let pointee_size=i64::try_from(self.layout_of(pointee_ty)?.size.bytes()). +unwrap();;let offset_bytes=offset_count.checked_mul(pointee_size).ok_or(err_ub!( +PointerArithOverflow))?;{();};{();};let offset_ptr=self.ptr_offset_inbounds(ptr, +offset_bytes)?;{;};Ok((ImmTy::from_scalar(Scalar::from_maybe_pointer(offset_ptr, +self),left.layout),(false),))} _=>M::binary_ptr_op(self,bin_op,left,right),}}pub +fn overflowing_binary_op(&self,bin_op:mir:: BinOp,left:&ImmTy<'tcx,M::Provenance +>,right:&ImmTy<'tcx,M::Provenance>,)->InterpResult<'tcx,(ImmTy<'tcx,M:://*&*&(); +Provenance>,bool)>{;trace!("Running binary op {:?}: {:?} ({}), {:?} ({})",bin_op +,*left,left.layout.ty,*right,right.layout.ty);3;match left.layout.ty.kind(){ty:: +Char=>{;assert_eq!(left.layout.ty,right.layout.ty);let left=left.to_scalar();let +right=right.to_scalar();{;};Ok(self.binary_char_op(bin_op,left.to_char()?,right. +to_char()?))}ty::Bool=>{3;assert_eq!(left.layout.ty,right.layout.ty);;;let left= +left.to_scalar();;let right=right.to_scalar();Ok(self.binary_bool_op(bin_op,left +.to_bool()?,right.to_bool()?))}ty::Float(fty)=>{;assert_eq!(left.layout.ty,right +.layout.ty);;;let layout=left.layout;;let left=left.to_scalar();let right=right. +to_scalar();3;Ok(match fty{FloatTy::F16=>unimplemented!("f16_f128"),FloatTy::F32 +=>{self.binary_float_op(bin_op,layout,left.to_f32() ?,right.to_f32()?)}FloatTy:: +F64=>{(self.binary_float_op(bin_op,layout,((left.to_f64( ))?),right.to_f64()?))} +FloatTy::F128=>(unimplemented!("f16_f128")),})}_ if left.layout.ty.is_integral() +=>{let _=();if true{};if true{};if true{};assert!(right.layout.ty.is_integral(), +"Unexpected types for BinOp: {} {:?} {}",left.layout.ty, bin_op,right.layout.ty) +;3;;let l=left.to_scalar().to_bits(left.layout.size)?;;;let r=right.to_scalar(). +to_bits(right.layout.size)?;{;};self.binary_int_op(bin_op,l,left.layout,r,right. +layout)}_ if left.layout.ty.is_any_ptr()=>{;assert!(right.layout.ty.is_any_ptr() +||right.layout.ty.is_integral(),"Unexpected types for BinOp: {} {:?} {}",left.// +layout.ty,bin_op,right.layout.ty);({});self.binary_ptr_op(bin_op,left,right)}_=> +span_bug!(self.cur_span( ),"Invalid MIR: bad LHS type for binop: {}",left.layout +.ty),}}#[inline]pub fn wrapping_binary_op(&self,bin_op:mir::BinOp,left:&ImmTy,right:&ImmTy<'tcx ,M::Provenance>,)->InterpResult<'tcx,ImmTy +<'tcx,M::Provenance>>{;let(val,_overflow)=self.overflowing_binary_op(bin_op,left +,right)?;3;Ok(val)}pub fn overflowing_unary_op(&self,un_op:mir::UnOp,val:&ImmTy< +'tcx,M::Provenance>,)->InterpResult<'tcx,(ImmTy<'tcx,M::Provenance>,bool)>{3;use +rustc_middle::mir::UnOp::*;;let layout=val.layout;let val=val.to_scalar();trace! +("Running unary op {:?}: {:?} ({})",un_op,val,layout.ty);;match layout.ty.kind() +{ty::Bool=>{;let val=val.to_bool()?;;let res=match un_op{Not=>!val,_=>span_bug!( +self.cur_span(),"Invalid bool op {:?}",un_op),};;Ok((ImmTy::from_bool(res,*self. +tcx),false))}ty::Float(fty)=>{({});let res=match(un_op,fty){(Neg,FloatTy::F32)=> +Scalar::from_f32((-(val.to_f32()?))) ,(Neg,FloatTy::F64)=>Scalar::from_f64(-val. +to_f64()?),_=>span_bug!(self.cur_span(),"Invalid float op {:?}",un_op),};();Ok(( +ImmTy::from_scalar(res,layout),false))}_=>{;assert!(layout.ty.is_integral());let +val=val.to_bits(layout.size)?;({});{;};let(res,overflow)=match un_op{Not=>(self. +truncate(!val,layout),false),Neg=>{;assert!(layout.abi.is_signed());let val=self +.sign_extend(val,layout)as i128;;let(res,overflow)=val.overflowing_neg();let res +=res as u128;;let truncated=self.truncate(res,layout);(truncated,overflow||self. +sign_extend(truncated,layout)!=res)}};;Ok((ImmTy::from_uint(res,layout),overflow +))}}}#[inline]pub fn wrapping_unary_op(&self,un_op:mir::UnOp,val:&ImmTy<'tcx,M// +::Provenance>,)->InterpResult<'tcx,ImmTy<'tcx,M::Provenance>>{;let(val,_overflow +)=self.overflowing_unary_op(un_op,val)?;*&*&();((),());((),());((),());Ok(val)}} diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 1a2f1194f89a2..9bb3c5fb2c635 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -1,1072 +1,293 @@ -//! Computations on places -- field projections, going from mir::Place, and writing -//! into a place. -//! All high-level functions to write to memory work on places as destinations. - -use std::assert_matches::assert_matches; - -use either::{Either, Left, Right}; - -use rustc_ast::Mutability; -use rustc_middle::mir; -use rustc_middle::ty; -use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; -use rustc_middle::ty::Ty; -use rustc_target::abi::{Abi, Align, HasDataLayout, Size}; - -use super::{ - alloc_range, mir_assign_valid_types, AllocRef, AllocRefMut, CheckAlignMsg, CtfeProvenance, - ImmTy, Immediate, InterpCx, InterpResult, Machine, MemoryKind, Misalignment, OffsetMode, OpTy, - Operand, Pointer, PointerArithmetic, Projectable, Provenance, Readable, Scalar, -}; - -#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)] -/// Information required for the sound usage of a `MemPlace`. -pub enum MemPlaceMeta { - /// The unsized payload (e.g. length for slices or vtable pointer for trait objects). - Meta(Scalar), - /// `Sized` types or unsized `extern type` - None, -} - -impl MemPlaceMeta { - #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) - pub fn unwrap_meta(self) -> Scalar { - match self { - Self::Meta(s) => s, - Self::None => { - bug!("expected wide pointer extra data (e.g. slice length or trait object vtable)") - } - } - } - - #[inline(always)] - pub fn has_meta(self) -> bool { - match self { - Self::Meta(_) => true, - Self::None => false, - } - } -} - -#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)] -pub(super) struct MemPlace { - /// The pointer can be a pure integer, with the `None` provenance. - pub ptr: Pointer>, - /// Metadata for unsized places. Interpretation is up to the type. - /// Must not be present for sized types, but can be missing for unsized types - /// (e.g., `extern type`). - pub meta: MemPlaceMeta, - /// Stores whether this place was created based on a sufficiently aligned pointer. - misaligned: Option, -} - -impl MemPlace { - /// Adjust the provenance of the main pointer (metadata is unaffected). - pub fn map_provenance(self, f: impl FnOnce(Prov) -> Prov) -> Self { - MemPlace { ptr: self.ptr.map_provenance(|p| p.map(f)), ..self } - } - - /// Turn a mplace into a (thin or wide) pointer, as a reference, pointing to the same space. - #[inline] - pub fn to_ref(self, cx: &impl HasDataLayout) -> Immediate { - Immediate::new_pointer_with_meta(self.ptr, self.meta, cx) - } - - #[inline] - // Not called `offset_with_meta` to avoid confusion with the trait method. - fn offset_with_meta_<'mir, 'tcx, M: Machine<'mir, 'tcx, Provenance = Prov>>( - self, - offset: Size, - mode: OffsetMode, - meta: MemPlaceMeta, - ecx: &InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, Self> { - debug_assert!( - !meta.has_meta() || self.meta.has_meta(), - "cannot use `offset_with_meta` to add metadata to a place" - ); - if offset > ecx.data_layout().max_size_of_val() { - throw_ub!(PointerArithOverflow); - } - let ptr = match mode { - OffsetMode::Inbounds => { - ecx.ptr_offset_inbounds(self.ptr, offset.bytes().try_into().unwrap())? - } - OffsetMode::Wrapping => self.ptr.wrapping_offset(offset, ecx), - }; - Ok(MemPlace { ptr, meta, misaligned: self.misaligned }) - } -} - -/// A MemPlace with its layout. Constructing it is only possible in this module. -#[derive(Clone, Hash, Eq, PartialEq)] -pub struct MPlaceTy<'tcx, Prov: Provenance = CtfeProvenance> { - mplace: MemPlace, - pub layout: TyAndLayout<'tcx>, -} - -impl std::fmt::Debug for MPlaceTy<'_, Prov> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - // Printing `layout` results in too much noise; just print a nice version of the type. - f.debug_struct("MPlaceTy") - .field("mplace", &self.mplace) - .field("ty", &format_args!("{}", self.layout.ty)) - .finish() - } -} - -impl<'tcx, Prov: Provenance> MPlaceTy<'tcx, Prov> { - /// Produces a MemPlace that works for ZST but nothing else. - /// Conceptually this is a new allocation, but it doesn't actually create an allocation so you - /// don't need to worry about memory leaks. - #[inline] - pub fn fake_alloc_zst(layout: TyAndLayout<'tcx>) -> Self { - assert!(layout.is_zst()); - let align = layout.align.abi; - let ptr = Pointer::from_addr_invalid(align.bytes()); // no provenance, absolute address - MPlaceTy { mplace: MemPlace { ptr, meta: MemPlaceMeta::None, misaligned: None }, layout } - } - - /// Adjust the provenance of the main pointer (metadata is unaffected). - pub fn map_provenance(self, f: impl FnOnce(Prov) -> Prov) -> Self { - MPlaceTy { mplace: self.mplace.map_provenance(f), ..self } - } - - #[inline(always)] - pub(super) fn mplace(&self) -> &MemPlace { - &self.mplace - } - - #[inline(always)] - pub fn ptr(&self) -> Pointer> { - self.mplace.ptr - } - - #[inline(always)] - pub fn to_ref(&self, cx: &impl HasDataLayout) -> Immediate { - self.mplace.to_ref(cx) - } -} - -impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for MPlaceTy<'tcx, Prov> { - #[inline(always)] - fn layout(&self) -> TyAndLayout<'tcx> { - self.layout - } - - #[inline(always)] - fn meta(&self) -> MemPlaceMeta { - self.mplace.meta - } - - fn offset_with_meta<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>( - &self, - offset: Size, - mode: OffsetMode, - meta: MemPlaceMeta, - layout: TyAndLayout<'tcx>, - ecx: &InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, Self> { - Ok(MPlaceTy { mplace: self.mplace.offset_with_meta_(offset, mode, meta, ecx)?, layout }) - } - - fn to_op<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>( - &self, - _ecx: &InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { - Ok(self.clone().into()) - } -} - -#[derive(Copy, Clone, Debug)] -pub(super) enum Place { - /// A place referring to a value allocated in the `Memory` system. - Ptr(MemPlace), - - /// To support alloc-free locals, we are able to write directly to a local. The offset indicates - /// where in the local this place is located; if it is `None`, no projection has been applied. - /// Such projections are meaningful even if the offset is 0, since they can change layouts. - /// (Without that optimization, we'd just always be a `MemPlace`.) - /// `Local` places always refer to the current stack frame, so they are unstable under - /// function calls/returns and switching betweens stacks of different threads! - /// We carry around the address of the `locals` buffer of the correct stack frame as a sanity - /// chec to be able to catch some cases of using a dangling `Place`. - /// - /// This variant shall not be used for unsized types -- those must always live in memory. - Local { local: mir::Local, offset: Option, locals_addr: usize }, -} - -/// An evaluated place, together with its type. -/// -/// This may reference a stack frame by its index, so `PlaceTy` should generally not be kept around -/// for longer than a single operation. Popping and then pushing a stack frame can make `PlaceTy` -/// point to the wrong destination. If the interpreter has multiple stacks, stack switching will -/// also invalidate a `PlaceTy`. -#[derive(Clone)] -pub struct PlaceTy<'tcx, Prov: Provenance = CtfeProvenance> { - place: Place, // Keep this private; it helps enforce invariants. - pub layout: TyAndLayout<'tcx>, -} - -impl std::fmt::Debug for PlaceTy<'_, Prov> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - // Printing `layout` results in too much noise; just print a nice version of the type. - f.debug_struct("PlaceTy") - .field("place", &self.place) - .field("ty", &format_args!("{}", self.layout.ty)) - .finish() - } -} - -impl<'tcx, Prov: Provenance> From> for PlaceTy<'tcx, Prov> { - #[inline(always)] - fn from(mplace: MPlaceTy<'tcx, Prov>) -> Self { - PlaceTy { place: Place::Ptr(mplace.mplace), layout: mplace.layout } - } -} - -impl<'tcx, Prov: Provenance> PlaceTy<'tcx, Prov> { - #[inline(always)] - pub(super) fn place(&self) -> &Place { - &self.place - } - - /// A place is either an mplace or some local. - #[inline(always)] - pub fn as_mplace_or_local( - &self, - ) -> Either, (mir::Local, Option, usize)> { - match self.place { - Place::Ptr(mplace) => Left(MPlaceTy { mplace, layout: self.layout }), - Place::Local { local, offset, locals_addr } => Right((local, offset, locals_addr)), - } - } - - #[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> { - self.as_mplace_or_local().left().unwrap_or_else(|| { - bug!( - "PlaceTy of type {} was a local when it was expected to be an MPlace", - self.layout.ty - ) - }) - } -} - -impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for PlaceTy<'tcx, Prov> { - #[inline(always)] - fn layout(&self) -> TyAndLayout<'tcx> { - self.layout - } - - #[inline] - fn meta(&self) -> MemPlaceMeta { - match self.as_mplace_or_local() { - Left(mplace) => mplace.meta(), - Right(_) => { - debug_assert!(self.layout.is_sized(), "unsized locals should live in memory"); - MemPlaceMeta::None - } - } - } - - fn offset_with_meta<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>( - &self, - offset: Size, - mode: OffsetMode, - meta: MemPlaceMeta, - layout: TyAndLayout<'tcx>, - ecx: &InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, Self> { - Ok(match self.as_mplace_or_local() { - Left(mplace) => mplace.offset_with_meta(offset, mode, meta, layout, ecx)?.into(), - Right((local, old_offset, locals_addr)) => { - debug_assert!(layout.is_sized(), "unsized locals should live in memory"); - assert_matches!(meta, MemPlaceMeta::None); // we couldn't store it anyway... - // `Place::Local` are always in-bounds of their surrounding local, so we can just - // check directly if this remains in-bounds. This cannot actually be violated since - // projections are type-checked and bounds-checked. - assert!(offset + layout.size <= self.layout.size); - - let new_offset = Size::from_bytes( - ecx.data_layout() - .offset(old_offset.unwrap_or(Size::ZERO).bytes(), offset.bytes())?, - ); - - PlaceTy { - place: Place::Local { local, offset: Some(new_offset), locals_addr }, - layout, - } - } - }) - } - - fn to_op<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>( - &self, - ecx: &InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { - ecx.place_to_op(self) - } -} - -// These are defined here because they produce a place. -impl<'tcx, Prov: Provenance> OpTy<'tcx, Prov> { - #[inline(always)] - pub fn as_mplace_or_imm(&self) -> Either, ImmTy<'tcx, Prov>> { - match self.op() { - Operand::Indirect(mplace) => Left(MPlaceTy { mplace: *mplace, layout: self.layout }), - Operand::Immediate(imm) => Right(ImmTy::from_immediate(*imm, self.layout)), - } - } - - #[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> { - self.as_mplace_or_imm().left().unwrap_or_else(|| { - bug!( - "OpTy of type {} was immediate when it was expected to be an MPlace", - self.layout.ty - ) - }) - } -} - -/// The `Weiteable` trait describes interpreter values that can be written to. -pub trait Writeable<'tcx, Prov: Provenance>: Projectable<'tcx, Prov> { - fn as_mplace_or_local( - &self, - ) -> Either, (mir::Local, Option, usize, TyAndLayout<'tcx>)>; - - fn force_mplace<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>( - &self, - ecx: &mut InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, Prov>>; -} - -impl<'tcx, Prov: Provenance> Writeable<'tcx, Prov> for PlaceTy<'tcx, Prov> { - #[inline(always)] - fn as_mplace_or_local( - &self, - ) -> Either, (mir::Local, Option, usize, TyAndLayout<'tcx>)> { - self.as_mplace_or_local() - .map_right(|(local, offset, locals_addr)| (local, offset, locals_addr, self.layout)) - } - - #[inline(always)] - fn force_mplace<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>( - &self, - ecx: &mut InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, Prov>> { - ecx.force_allocation(self) - } -} - -impl<'tcx, Prov: Provenance> Writeable<'tcx, Prov> for MPlaceTy<'tcx, Prov> { - #[inline(always)] - fn as_mplace_or_local( - &self, - ) -> Either, (mir::Local, Option, usize, TyAndLayout<'tcx>)> { - Left(self.clone()) - } - - #[inline(always)] - fn force_mplace<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>( - &self, - _ecx: &mut InterpCx<'mir, 'tcx, M>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, Prov>> { - Ok(self.clone()) - } -} - -// FIXME: Working around https://github.com/rust-lang/rust/issues/54385 -impl<'mir, 'tcx: 'mir, Prov, M> InterpCx<'mir, 'tcx, M> -where - Prov: Provenance, - M: Machine<'mir, 'tcx, Provenance = Prov>, -{ - pub fn ptr_with_meta_to_mplace( - &self, - ptr: Pointer>, - meta: MemPlaceMeta, - layout: TyAndLayout<'tcx>, - ) -> MPlaceTy<'tcx, M::Provenance> { - let misaligned = self.is_ptr_misaligned(ptr, layout.align.abi); - MPlaceTy { mplace: MemPlace { ptr, meta, misaligned }, layout } - } - - pub fn ptr_to_mplace( - &self, - ptr: Pointer>, - layout: TyAndLayout<'tcx>, - ) -> MPlaceTy<'tcx, M::Provenance> { - assert!(layout.is_sized()); - self.ptr_with_meta_to_mplace(ptr, MemPlaceMeta::None, layout) - } - - /// Take a value, which represents a (thin or wide) reference, and make it a place. - /// Alignment is just based on the type. This is the inverse of `mplace_to_ref()`. - /// - /// Only call this if you are sure the place is "valid" (aligned and inbounds), or do not - /// want to ever use the place for memory access! - /// Generally prefer `deref_pointer`. - pub fn ref_to_mplace( - &self, - val: &ImmTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { - let pointee_type = - val.layout.ty.builtin_deref(true).expect("`ref_to_mplace` called on non-ptr type").ty; - let layout = self.layout_of(pointee_type)?; - let (ptr, meta) = val.to_scalar_and_meta(); - - // `ref_to_mplace` is called on raw pointers even if they don't actually get dereferenced; - // we hence can't call `size_and_align_of` since that asserts more validity than we want. - let ptr = ptr.to_pointer(self)?; - Ok(self.ptr_with_meta_to_mplace(ptr, meta, layout)) - } - - /// Turn a mplace into a (thin or wide) mutable raw pointer, pointing to the same space. - /// `align` information is lost! - /// This is the inverse of `ref_to_mplace`. - pub fn mplace_to_ref( - &self, - mplace: &MPlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { - let imm = mplace.mplace.to_ref(self); - let layout = self.layout_of(Ty::new_mut_ptr(self.tcx.tcx, mplace.layout.ty))?; - Ok(ImmTy::from_immediate(imm, layout)) - } - - /// Take an operand, representing a pointer, and dereference it to a place. - /// Corresponds to the `*` operator in Rust. - #[instrument(skip(self), level = "debug")] - pub fn deref_pointer( - &self, - src: &impl Readable<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { - let val = self.read_immediate(src)?; - trace!("deref to {} on {:?}", val.layout.ty, *val); - - if val.layout.ty.is_box() { - // Derefer should have removed all Box derefs - bug!("dereferencing {}", val.layout.ty); - } - - let mplace = self.ref_to_mplace(&val)?; - Ok(mplace) - } - - #[inline] - pub(super) fn get_place_alloc( - &self, - mplace: &MPlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, Option>> - { - let (size, _align) = self - .size_and_align_of_mplace(mplace)? - .unwrap_or((mplace.layout.size, mplace.layout.align.abi)); - // We check alignment separately, and *after* checking everything else. - // If an access is both OOB and misaligned, we want to see the bounds error. - let a = self.get_ptr_alloc(mplace.ptr(), size)?; - self.check_misalign(mplace.mplace.misaligned, CheckAlignMsg::BasedOn)?; - Ok(a) - } - - #[inline] - pub(super) fn get_place_alloc_mut( - &mut self, - mplace: &MPlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, Option>> - { - let (size, _align) = self - .size_and_align_of_mplace(mplace)? - .unwrap_or((mplace.layout.size, mplace.layout.align.abi)); - // We check alignment separately, and raise that error *after* checking everything else. - // If an access is both OOB and misaligned, we want to see the bounds error. - // However we have to call `check_misalign` first to make the borrow checker happy. - let misalign_err = self.check_misalign(mplace.mplace.misaligned, CheckAlignMsg::BasedOn); - let a = self.get_ptr_alloc_mut(mplace.ptr(), size)?; - misalign_err?; - Ok(a) - } - - /// Converts a repr(simd) place into a place where `place_index` accesses the SIMD elements. - /// Also returns the number of elements. - pub fn mplace_to_simd( - &self, - mplace: &MPlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, u64)> { - // Basically we just transmute this place into an array following simd_size_and_type. - // (Transmuting is okay since this is an in-memory place. We also double-check the size - // stays the same.) - let (len, e_ty) = mplace.layout.ty.simd_size_and_type(*self.tcx); - let array = Ty::new_array(self.tcx.tcx, e_ty, len); - let layout = self.layout_of(array)?; - let mplace = mplace.transmute(layout, self)?; - Ok((mplace, len)) - } - - /// Turn a local in the current frame into a place. - pub fn local_to_place( - &self, - local: mir::Local, - ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> { - // Other parts of the system rely on `Place::Local` never being unsized. - // So we eagerly check here if this local has an MPlace, and if yes we use it. - let frame = self.frame(); - let layout = self.layout_of_local(frame, local, None)?; - let place = if layout.is_sized() { - // We can just always use the `Local` for sized values. - Place::Local { local, offset: None, locals_addr: frame.locals_addr() } - } else { - // Unsized `Local` isn't okay (we cannot store the metadata). - match frame.locals[local].access()? { - Operand::Immediate(_) => bug!(), - Operand::Indirect(mplace) => Place::Ptr(*mplace), - } - }; - Ok(PlaceTy { place, layout }) - } - - /// Computes a place. You should only use this if you intend to write into this - /// place; for reading, a more efficient alternative is `eval_place_to_op`. - #[instrument(skip(self), level = "debug")] - pub fn eval_place( - &self, - mir_place: mir::Place<'tcx>, - ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> { - let mut place = self.local_to_place(mir_place.local)?; - // Using `try_fold` turned out to be bad for performance, hence the loop. - for elem in mir_place.projection.iter() { - place = self.project(&place, elem)? - } - - trace!("{:?}", self.dump_place(&place)); - // Sanity-check the type we ended up with. - if cfg!(debug_assertions) { - let normalized_place_ty = self - .instantiate_from_current_frame_and_normalize_erasing_regions( - mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty, - )?; - if !mir_assign_valid_types( - *self.tcx, - self.param_env, - self.layout_of(normalized_place_ty)?, - place.layout, - ) { - span_bug!( - self.cur_span(), - "eval_place of a MIR place with type {} produced an interpreter place with type {}", - normalized_place_ty, - place.layout.ty, - ) - } - } - Ok(place) - } - - /// Write an immediate to a place - #[inline(always)] - #[instrument(skip(self), level = "debug")] - pub fn write_immediate( - &mut self, - src: Immediate, - dest: &impl Writeable<'tcx, M::Provenance>, - ) -> InterpResult<'tcx> { - self.write_immediate_no_validate(src, dest)?; - - if M::enforce_validity(self, dest.layout()) { - // Data got changed, better make sure it matches the type! - self.validate_operand(&dest.to_op(self)?)?; - } - - Ok(()) - } - - /// Write a scalar to a place - #[inline(always)] - pub fn write_scalar( - &mut self, - val: impl Into>, - dest: &impl Writeable<'tcx, M::Provenance>, - ) -> InterpResult<'tcx> { - self.write_immediate(Immediate::Scalar(val.into()), dest) - } - - /// Write a pointer to a place - #[inline(always)] - pub fn write_pointer( - &mut self, - ptr: impl Into>>, - dest: &impl Writeable<'tcx, M::Provenance>, - ) -> InterpResult<'tcx> { - self.write_scalar(Scalar::from_maybe_pointer(ptr.into(), self), dest) - } - - /// Write an immediate to a place. - /// If you use this you are responsible for validating that things got copied at the - /// right type. - fn write_immediate_no_validate( - &mut self, - src: Immediate, - dest: &impl Writeable<'tcx, M::Provenance>, - ) -> InterpResult<'tcx> { - assert!(dest.layout().is_sized(), "Cannot write unsized immediate data"); - - // See if we can avoid an allocation. This is the counterpart to `read_immediate_raw`, - // but not factored as a separate function. - let mplace = match dest.as_mplace_or_local() { - Right((local, offset, locals_addr, layout)) => { - if offset.is_some() { - // This has been projected to a part of this local. We could have complicated - // logic to still keep this local as an `Operand`... but it's much easier to - // just fall back to the indirect path. - dest.force_mplace(self)? - } else { - debug_assert_eq!(locals_addr, self.frame().locals_addr()); - match self.frame_mut().locals[local].access_mut()? { - Operand::Immediate(local_val) => { - // Local can be updated in-place. - *local_val = src; - // Double-check that the value we are storing and the local fit to each other. - // (*After* doing the update for borrow checker reasons.) - if cfg!(debug_assertions) { - let local_layout = - self.layout_of_local(&self.frame(), local, None)?; - match (src, local_layout.abi) { - (Immediate::Scalar(scalar), Abi::Scalar(s)) => { - assert_eq!(scalar.size(), s.size(self)) - } - ( - Immediate::ScalarPair(a_val, b_val), - Abi::ScalarPair(a, b), - ) => { - assert_eq!(a_val.size(), a.size(self)); - assert_eq!(b_val.size(), b.size(self)); - } - (Immediate::Uninit, _) => {} - (src, abi) => { - bug!( - "value {src:?} cannot be written into local with type {} (ABI {abi:?})", - local_layout.ty - ) - } - }; - } - return Ok(()); - } - Operand::Indirect(mplace) => { - // The local is in memory, go on below. - MPlaceTy { mplace: *mplace, layout } - } - } - } - } - Left(mplace) => mplace, // already referring to memory - }; - - // This is already in memory, write there. - self.write_immediate_to_mplace_no_validate(src, mplace.layout, mplace.mplace) - } - - /// Write an immediate to memory. - /// If you use this you are responsible for validating that things got copied at the - /// right layout. - fn write_immediate_to_mplace_no_validate( - &mut self, - value: Immediate, - layout: TyAndLayout<'tcx>, - dest: MemPlace, - ) -> InterpResult<'tcx> { - // Note that it is really important that the type here is the right one, and matches the - // type things are read at. In case `value` is a `ScalarPair`, we don't do any magic here - // to handle padding properly, which is only correct if we never look at this data with the - // wrong type. - - let tcx = *self.tcx; - let Some(mut alloc) = self.get_place_alloc_mut(&MPlaceTy { mplace: dest, layout })? else { - // zero-sized access - return Ok(()); - }; - - match value { - Immediate::Scalar(scalar) => { - let Abi::Scalar(s) = layout.abi else { - span_bug!( - self.cur_span(), - "write_immediate_to_mplace: invalid Scalar layout: {layout:#?}", - ) - }; - let size = s.size(&tcx); - assert_eq!(size, layout.size, "abi::Scalar size does not match layout size"); - alloc.write_scalar(alloc_range(Size::ZERO, size), scalar) - } - Immediate::ScalarPair(a_val, b_val) => { - let Abi::ScalarPair(a, b) = layout.abi else { - span_bug!( - self.cur_span(), - "write_immediate_to_mplace: invalid ScalarPair layout: {:#?}", - layout - ) - }; - let (a_size, b_size) = (a.size(&tcx), b.size(&tcx)); - let b_offset = a_size.align_to(b.align(&tcx).abi); - assert!(b_offset.bytes() > 0); // in `operand_field` we use the offset to tell apart the fields - - // It is tempting to verify `b_offset` against `layout.fields.offset(1)`, - // but that does not work: We could be a newtype around a pair, then the - // fields do not match the `ScalarPair` components. - - alloc.write_scalar(alloc_range(Size::ZERO, a_size), a_val)?; - alloc.write_scalar(alloc_range(b_offset, b_size), b_val) - } - Immediate::Uninit => alloc.write_uninit(), - } - } - - pub fn write_uninit( - &mut self, - dest: &impl Writeable<'tcx, M::Provenance>, - ) -> InterpResult<'tcx> { - let mplace = match dest.as_mplace_or_local() { - Left(mplace) => mplace, - Right((local, offset, locals_addr, layout)) => { - if offset.is_some() { - // This has been projected to a part of this local. We could have complicated - // logic to still keep this local as an `Operand`... but it's much easier to - // just fall back to the indirect path. - // FIXME: share the logic with `write_immediate_no_validate`. - dest.force_mplace(self)? - } else { - debug_assert_eq!(locals_addr, self.frame().locals_addr()); - match self.frame_mut().locals[local].access_mut()? { - Operand::Immediate(local) => { - *local = Immediate::Uninit; - return Ok(()); - } - Operand::Indirect(mplace) => { - // The local is in memory, go on below. - MPlaceTy { mplace: *mplace, layout } - } - } - } - } - }; - let Some(mut alloc) = self.get_place_alloc_mut(&mplace)? else { - // Zero-sized access - return Ok(()); - }; - alloc.write_uninit()?; - Ok(()) - } - - /// Copies the data from an operand to a place. - /// The layouts of the `src` and `dest` may disagree. - /// Does not perform validation of the destination. - /// The only known use case for this function is checking the return - /// value of a static during stack frame popping. - #[inline(always)] - pub(super) fn copy_op_no_dest_validation( - &mut self, - src: &impl Readable<'tcx, M::Provenance>, - dest: &impl Writeable<'tcx, M::Provenance>, - ) -> InterpResult<'tcx> { - self.copy_op_inner( - src, dest, /* allow_transmute */ true, /* validate_dest */ false, - ) - } - - /// Copies the data from an operand to a place. - /// The layouts of the `src` and `dest` may disagree. - #[inline(always)] - pub fn copy_op_allow_transmute( - &mut self, - src: &impl Readable<'tcx, M::Provenance>, - dest: &impl Writeable<'tcx, M::Provenance>, - ) -> InterpResult<'tcx> { - self.copy_op_inner( - src, dest, /* allow_transmute */ true, /* validate_dest */ true, - ) - } - - /// Copies the data from an operand to a place. - /// `src` and `dest` must have the same layout and the copied value will be validated. - #[inline(always)] - pub fn copy_op( - &mut self, - src: &impl Readable<'tcx, M::Provenance>, - dest: &impl Writeable<'tcx, M::Provenance>, - ) -> InterpResult<'tcx> { - self.copy_op_inner( - src, dest, /* allow_transmute */ false, /* validate_dest */ true, - ) - } - - /// Copies the data from an operand to a place. - /// `allow_transmute` indicates whether the layouts may disagree. - #[inline(always)] - #[instrument(skip(self), level = "debug")] - fn copy_op_inner( - &mut self, - src: &impl Readable<'tcx, M::Provenance>, - dest: &impl Writeable<'tcx, M::Provenance>, - allow_transmute: bool, - validate_dest: bool, - ) -> InterpResult<'tcx> { - // Generally for transmutation, data must be valid both at the old and new type. - // But if the types are the same, the 2nd validation below suffices. - if src.layout().ty != dest.layout().ty && M::enforce_validity(self, src.layout()) { - self.validate_operand(&src.to_op(self)?)?; - } - - // Do the actual copy. - self.copy_op_no_validate(src, dest, allow_transmute)?; - - if validate_dest && M::enforce_validity(self, dest.layout()) { - // Data got changed, better make sure it matches the type! - self.validate_operand(&dest.to_op(self)?)?; - } - - Ok(()) - } - - /// Copies the data from an operand to a place. - /// `allow_transmute` indicates whether the layouts may disagree. - /// Also, if you use this you are responsible for validating that things get copied at the - /// right type. - #[instrument(skip(self), level = "debug")] - fn copy_op_no_validate( - &mut self, - src: &impl Readable<'tcx, M::Provenance>, - dest: &impl Writeable<'tcx, M::Provenance>, - allow_transmute: bool, - ) -> InterpResult<'tcx> { - // We do NOT compare the types for equality, because well-typed code can - // actually "transmute" `&mut T` to `&T` in an assignment without a cast. - let layout_compat = - mir_assign_valid_types(*self.tcx, self.param_env, src.layout(), dest.layout()); - if !allow_transmute && !layout_compat { - span_bug!( - self.cur_span(), - "type mismatch when copying!\nsrc: {},\ndest: {}", - src.layout().ty, - dest.layout().ty, - ); - } - - // Let us see if the layout is simple so we take a shortcut, - // avoid force_allocation. - let src = match self.read_immediate_raw(src)? { - Right(src_val) => { - assert!(!src.layout().is_unsized()); - assert!(!dest.layout().is_unsized()); - assert_eq!(src.layout().size, dest.layout().size); - // Yay, we got a value that we can write directly. - return if layout_compat { - self.write_immediate_no_validate(*src_val, dest) - } else { - // This is tricky. The problematic case is `ScalarPair`: the `src_val` was - // loaded using the offsets defined by `src.layout`. When we put this back into - // the destination, we have to use the same offsets! So (a) we make sure we - // write back to memory, and (b) we use `dest` *with the source layout*. - let dest_mem = dest.force_mplace(self)?; - self.write_immediate_to_mplace_no_validate( - *src_val, - src.layout(), - dest_mem.mplace, - ) - }; - } - Left(mplace) => mplace, - }; - // Slow path, this does not fit into an immediate. Just memcpy. - trace!("copy_op: {:?} <- {:?}: {}", *dest, src, dest.layout().ty); - - let dest = dest.force_mplace(self)?; - let Some((dest_size, _)) = self.size_and_align_of_mplace(&dest)? else { - span_bug!(self.cur_span(), "copy_op needs (dynamically) sized values") - }; - if cfg!(debug_assertions) { - let src_size = self.size_and_align_of_mplace(&src)?.unwrap().0; - assert_eq!(src_size, dest_size, "Cannot copy differently-sized data"); - } else { - // As a cheap approximation, we compare the fixed parts of the size. - assert_eq!(src.layout.size, dest.layout.size); - } - - // Setting `nonoverlapping` here only has an effect when we don't hit the fast-path above, - // but that should at least match what LLVM does where `memcpy` is also only used when the - // type does not have Scalar/ScalarPair layout. - // (Or as the `Assign` docs put it, assignments "not producing primitives" must be - // non-overlapping.) - // We check alignment separately, and *after* checking everything else. - // If an access is both OOB and misaligned, we want to see the bounds error. - self.mem_copy(src.ptr(), dest.ptr(), dest_size, /*nonoverlapping*/ true)?; - self.check_misalign(src.mplace.misaligned, CheckAlignMsg::BasedOn)?; - self.check_misalign(dest.mplace.misaligned, CheckAlignMsg::BasedOn)?; - Ok(()) - } - - /// Ensures that a place is in memory, and returns where it is. - /// If the place currently refers to a local that doesn't yet have a matching allocation, - /// create such an allocation. - /// This is essentially `force_to_memplace`. - #[instrument(skip(self), level = "debug")] - pub fn force_allocation( - &mut self, - place: &PlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { - let mplace = match place.place { - Place::Local { local, offset, locals_addr } => { - debug_assert_eq!(locals_addr, self.frame().locals_addr()); - let whole_local = match self.frame_mut().locals[local].access_mut()? { - &mut Operand::Immediate(local_val) => { - // We need to make an allocation. - - // We need the layout of the local. We can NOT use the layout we got, - // that might e.g., be an inner field of a struct with `Scalar` layout, - // that has different alignment than the outer field. - let local_layout = self.layout_of_local(&self.frame(), local, None)?; - assert!(local_layout.is_sized(), "unsized locals cannot be immediate"); - let mplace = self.allocate(local_layout, MemoryKind::Stack)?; - // Preserve old value. (As an optimization, we can skip this if it was uninit.) - if !matches!(local_val, Immediate::Uninit) { - // We don't have to validate as we can assume the local was already - // valid for its type. We must not use any part of `place` here, that - // could be a projection to a part of the local! - self.write_immediate_to_mplace_no_validate( - local_val, - local_layout, - mplace.mplace, - )?; - } - M::after_local_allocated(self, local, &mplace)?; - // Now we can call `access_mut` again, asserting it goes well, and actually - // overwrite things. This points to the entire allocation, not just the part - // the place refers to, i.e. we do this before we apply `offset`. - *self.frame_mut().locals[local].access_mut().unwrap() = - Operand::Indirect(mplace.mplace); - mplace.mplace - } - &mut Operand::Indirect(mplace) => mplace, // this already was an indirect local - }; - if let Some(offset) = offset { - // This offset is always inbounds, no need to check it again. - whole_local.offset_with_meta_( - offset, - OffsetMode::Wrapping, - MemPlaceMeta::None, - self, - )? - } else { - // Preserve wide place metadata, do not call `offset`. - whole_local - } - } - Place::Ptr(mplace) => mplace, - }; - // Return with the original layout and align, so that the caller can go on - Ok(MPlaceTy { mplace, layout: place.layout }) - } - - pub fn allocate_dyn( - &mut self, - layout: TyAndLayout<'tcx>, - kind: MemoryKind, - meta: MemPlaceMeta, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { - let Some((size, align)) = self.size_and_align_of(&meta, &layout)? else { - span_bug!(self.cur_span(), "cannot allocate space for `extern` type, size is not known") - }; - let ptr = self.allocate_ptr(size, align, kind)?; - Ok(self.ptr_with_meta_to_mplace(ptr.into(), meta, layout)) - } - - pub fn allocate( - &mut self, - layout: TyAndLayout<'tcx>, - kind: MemoryKind, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { - assert!(layout.is_sized()); - self.allocate_dyn(layout, kind, MemPlaceMeta::None) - } - - /// Returns a wide MPlace of type `str` to a new 1-aligned allocation. - pub fn allocate_str( - &mut self, - str: &str, - kind: MemoryKind, - mutbl: Mutability, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { - let ptr = self.allocate_bytes_ptr(str.as_bytes(), Align::ONE, kind, mutbl)?; - let meta = Scalar::from_target_usize(u64::try_from(str.len()).unwrap(), self); - let layout = self.layout_of(self.tcx.types.str_).unwrap(); - Ok(self.ptr_with_meta_to_mplace(ptr.into(), MemPlaceMeta::Meta(meta), layout)) - } - - pub fn raw_const_to_mplace( - &self, - raw: mir::ConstAlloc<'tcx>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { - // This must be an allocation in `tcx` - let _ = self.tcx.global_alloc(raw.alloc_id); - let ptr = self.global_base_pointer(Pointer::from(raw.alloc_id))?; - let layout = self.layout_of(raw.ty)?; - Ok(self.ptr_to_mplace(ptr.into(), layout)) - } - - /// Turn a place with a `dyn Trait` type into a place with the actual dynamic type. - /// Aso returns the vtable. - pub(super) fn unpack_dyn_trait( - &self, - mplace: &MPlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, Pointer>)> { - assert!( - matches!(mplace.layout.ty.kind(), ty::Dynamic(_, _, ty::Dyn)), - "`unpack_dyn_trait` only makes sense on `dyn*` types" - ); - let vtable = mplace.meta().unwrap_meta().to_pointer(self)?; - let (ty, _) = self.get_ptr_vtable(vtable)?; - let layout = self.layout_of(ty)?; - // This is a kind of transmute, from a place with unsized type and metadata to - // a place with sized type and no metadata. - let mplace = - MPlaceTy { mplace: MemPlace { meta: MemPlaceMeta::None, ..mplace.mplace }, layout }; - Ok((mplace, vtable)) - } - - /// Turn a `dyn* Trait` type into an value with the actual dynamic type. - /// Also returns the vtable. - pub(super) fn unpack_dyn_star>( - &self, - val: &P, - ) -> InterpResult<'tcx, (P, Pointer>)> { - assert!( - matches!(val.layout().ty.kind(), ty::Dynamic(_, _, ty::DynStar)), - "`unpack_dyn_star` only makes sense on `dyn*` types" - ); - let data = self.project_field(val, 0)?; - let vtable = self.project_field(val, 1)?; - let vtable = self.read_pointer(&vtable.to_op(self)?)?; - let (ty, _) = self.get_ptr_vtable(vtable)?; - let layout = self.layout_of(ty)?; - // `data` is already the right thing but has the wrong type. So we transmute it, by - // projecting with offset 0. - let data = data.transmute(layout, self)?; - Ok((data, vtable)) - } -} - -// Some nodes are used a lot. Make sure they don't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -mod size_asserts { - use super::*; - use rustc_data_structures::static_assert_size; - // tidy-alphabetical-start - static_assert_size!(MemPlace, 48); - static_assert_size!(MemPlaceMeta, 24); - static_assert_size!(MPlaceTy<'_>, 64); - static_assert_size!(Place, 48); - static_assert_size!(PlaceTy<'_>, 64); - // tidy-alphabetical-end -} +use std::assert_matches::assert_matches;use either::{Either,Left,Right};use//(); +rustc_ast::Mutability;use rustc_middle::mir;use rustc_middle::ty;use//if true{}; +rustc_middle::ty::layout::{LayoutOf,TyAndLayout};use rustc_middle::ty::Ty;use//; +rustc_target::abi::{Abi,Align,HasDataLayout,Size};use super::{alloc_range,//{;}; +mir_assign_valid_types,AllocRef,AllocRefMut, CheckAlignMsg,CtfeProvenance,ImmTy, +Immediate,InterpCx,InterpResult,Machine ,MemoryKind,Misalignment,OffsetMode,OpTy +,Operand,Pointer,PointerArithmetic,Projectable,Provenance,Readable,Scalar,};#[// +derive(Copy,Clone,Hash,PartialEq,Eq,Debug)]pub enum MemPlaceMeta{Meta(Scalar),None,}impl//({}); +MemPlaceMeta{#[cfg_attr( debug_assertions,track_caller)]pub fn unwrap_meta +(self)->Scalar{match self{Self::Meta(s)=>s,Self::None=>{bug!(//let _=||(); +"expected wide pointer extra data (e.g. slice length or trait object vtable)") } +}}#[inline(always)]pub fn has_meta(self)->bool{match self{Self::Meta(_)=>(true), +Self::None=>((false)),}}}#[derive(Copy,Clone,Hash,PartialEq,Eq,Debug)]pub(super) +struct MemPlace{pub ptr:Pointer>,// +pub meta:MemPlaceMeta,misaligned:Option,}implMemPlace{pub fn map_provenance( self,f:impl FnOnce(Prov)->Prov) +->Self{(MemPlace{ptr:self.ptr.map_provenance(|p| p.map(f)),..self})}#[inline]pub +fn to_ref(self,cx:&impl HasDataLayout)->Immediate{Immediate:://let _=||(); +new_pointer_with_meta(self.ptr,self.meta,cx )}#[inline]fn offset_with_meta_<'mir +,'tcx,M:Machine<'mir,'tcx,Provenance=Prov>>(self,offset:Size,mode:OffsetMode,//; +meta:MemPlaceMeta,ecx:&InterpCx<'mir,'tcx,M>,)->InterpResult<'tcx,Self>{3; +debug_assert!(!meta.has_meta()||self.meta.has_meta(),//loop{break};loop{break;}; +"cannot use `offset_with_meta` to add metadata to a place");{();};if offset>ecx. +data_layout().max_size_of_val(){;throw_ub!(PointerArithOverflow);;}let ptr=match +mode{OffsetMode::Inbounds=>{ecx.ptr_offset_inbounds(self.ptr,((offset.bytes())). +try_into().unwrap())?} OffsetMode::Wrapping=>self.ptr.wrapping_offset(offset,ecx +),};3;Ok(MemPlace{ptr,meta,misaligned:self.misaligned})}}#[derive(Clone,Hash,Eq, +PartialEq)]pub struct MPlaceTy<'tcx,Prov:Provenance=CtfeProvenance>{mplace://(); +MemPlace,pub layout:TyAndLayout<'tcx>,}implstd::fmt:://3; +Debug for MPlaceTy<'_,Prov>{fn fmt(&self ,f:&mut std::fmt::Formatter<'_>)->std:: +fmt::Result{f.debug_struct("MPlaceTy").field( "mplace",&self.mplace).field("ty", +&((((format_args!("{}",self.layout.ty)))))).finish()}}impl<'tcx,Prov:Provenance> +MPlaceTy<'tcx,Prov>{#[inline]pub fn fake_alloc_zst(layout:TyAndLayout<'tcx>)->// +Self{3;assert!(layout.is_zst());;;let align=layout.align.abi;;;let ptr=Pointer:: +from_addr_invalid(align.bytes());;MPlaceTy{mplace:MemPlace{ptr,meta:MemPlaceMeta +::None,misaligned:None},layout}}pub fn map_provenance(self,f:impl FnOnce(Prov)// +->Prov)->Self{(MPlaceTy{mplace:self.mplace .map_provenance(f),..self})}#[inline( +always)]pub(super)fn mplace(&self)->&MemPlace{(((&self.mplace)))}#[inline( +always)]pub fn ptr(&self)->Pointer>{self.mplace.ptr}#[inline(//{;}; +always)]pub fn to_ref(&self,cx:&impl HasDataLayout)->Immediate{self.//{;}; +mplace.to_ref(cx)}}impl<'tcx, Prov:Provenance>Projectable<'tcx,Prov>for MPlaceTy +<'tcx,Prov>{#[inline(always)]fn layout (&self)->TyAndLayout<'tcx>{self.layout}#[ +inline(always)]fn meta(&self)->MemPlaceMeta{self.mplace.meta}fn//let _=(); +offset_with_meta<'mir,M:Machine<'mir,'tcx,Provenance=Prov>>(&self,offset:Size,// +mode:OffsetMode,meta:MemPlaceMeta, layout:TyAndLayout<'tcx>,ecx:&InterpCx< +'mir,'tcx,M>,)->InterpResult<'tcx,Self>{Ok(MPlaceTy{mplace:self.mplace.//*&*&(); +offset_with_meta_(offset,mode,meta,ecx)?,layout} )}fn to_op<'mir,M:Machine<'mir, +'tcx,Provenance=Prov>>(&self,_ecx:&InterpCx<'mir,'tcx,M>,)->InterpResult<'tcx,// +OpTy<'tcx,M::Provenance>>{(Ok(self.clone().into()))}}#[derive(Copy,Clone,Debug)] +pub(super)enum Place{Ptr(MemPlace),Local{ +local:mir::Local,offset:Option,locals_addr:usize},}#[derive(Clone)]pub//3; +struct PlaceTy<'tcx,Prov:Provenance=CtfeProvenance>{place:Place,pub//({}); +layout:TyAndLayout<'tcx>,}implstd::fmt::Debug for PlaceTy<'_,// +Prov>{fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{f.//*&*&(); +debug_struct(("PlaceTy")).field(("place"),&self.place).field("ty",&format_args!( +"{}",self.layout.ty)).finish()}}impl<'tcx,Prov:Provenance>From>for PlaceTy<'tcx,Prov>{#[inline (always)]fn from(mplace:MPlaceTy<'tcx,Prov +>)->Self{(PlaceTy{place:Place::Ptr(mplace .mplace),layout:mplace.layout})}}impl< +'tcx,Prov:Provenance>PlaceTy<'tcx,Prov>{#[inline(always)]pub(super)fn place(&//; +self)->&Place{((&self.place))}#[inline(always)]pub fn as_mplace_or_local(& +self,)->Either,(mir ::Local,Option,usize)>{match self. +place{Place::Ptr(mplace)=>(Left((MPlaceTy {mplace,layout:self.layout}))),Place:: +Local{local,offset,locals_addr}=>(Right((local,offset,locals_addr))),}}#[inline( +always)]#[cfg_attr(debug_assertions,track_caller )]pub fn assert_mem_place(&self +)->MPlaceTy<'tcx,Prov>{self.as_mplace_or_local( ).left().unwrap_or_else(||{bug!( +"PlaceTy of type {} was a local when it was expected to be an MPlace",self.//(); +layout.ty)})}}impl<'tcx, Prov:Provenance>Projectable<'tcx,Prov>for PlaceTy<'tcx, +Prov>{#[inline(always)]fn layout(& self)->TyAndLayout<'tcx>{self.layout}#[inline +]fn meta(&self)->MemPlaceMeta {match self.as_mplace_or_local(){Left(mplace +)=>mplace.meta(),Right(_)=>{*&*&();((),());debug_assert!(self.layout.is_sized(), +"unsized locals should live in memory");((),());let _=();MemPlaceMeta::None}}}fn +offset_with_meta<'mir,M:Machine<'mir,'tcx,Provenance=Prov>>(&self,offset:Size,// +mode:OffsetMode,meta:MemPlaceMeta, layout:TyAndLayout<'tcx>,ecx:&InterpCx< +'mir,'tcx,M>,)->InterpResult<'tcx,Self> {Ok(match self.as_mplace_or_local(){Left +(mplace)=>(mplace.offset_with_meta(offset,mode,meta,layout,ecx)?.into()),Right(( +local,old_offset,locals_addr))=>{*&*&();((),());debug_assert!(layout.is_sized(), +"unsized locals should live in memory");;assert_matches!(meta,MemPlaceMeta::None +);;assert!(offset+layout.size<=self.layout.size);let new_offset=Size::from_bytes +(ecx.data_layout().offset(old_offset. unwrap_or(Size::ZERO).bytes(),offset.bytes +())?,);();PlaceTy{place:Place::Local{local,offset:Some(new_offset),locals_addr}, +layout,}}})}fn to_op<'mir,M:Machine<'mir,'tcx,Provenance=Prov>>(&self,ecx:&//(); +InterpCx<'mir,'tcx,M>,)->InterpResult<'tcx,OpTy<'tcx,M::Provenance>>{ecx.//({}); +place_to_op(self)}}impl<'tcx,Prov:Provenance>OpTy<'tcx,Prov>{#[inline(always)]// +pub fn as_mplace_or_imm(&self)->Either,ImmTy<'tcx,Prov>>{//; +match self.op(){Operand::Indirect(mplace) =>Left(MPlaceTy{mplace:*mplace,layout: +self.layout}),Operand::Immediate(imm)=> Right(ImmTy::from_immediate((*imm),self. +layout)),}}#[inline(always)]#[cfg_attr(debug_assertions,track_caller)]pub fn//3; +assert_mem_place(&self)->MPlaceTy<'tcx,Prov>{((self.as_mplace_or_imm()).left()). +unwrap_or_else(||{bug!(//loop{break;};if let _=(){};if let _=(){};if let _=(){}; +"OpTy of type {} was immediate when it was expected to be an MPlace",self.//{;}; +layout.ty)})}}pub trait Writeable<'tcx,Prov:Provenance>:Projectable<'tcx,Prov>{ +fn as_mplace_or_local(&self,)->Either,(mir::Local,Option,usize,TyAndLayout<'tcx>)>;fn force_mplace<'mir,M:Machine<'mir,'tcx,//({}); +Provenance=Prov>>(&self,ecx:&mut InterpCx<'mir,'tcx,M>,)->InterpResult<'tcx,//3; +MPlaceTy<'tcx,Prov>>;}impl<'tcx, Prov:Provenance>Writeable<'tcx,Prov>for PlaceTy +<'tcx,Prov>{#[inline(always)]fn as_mplace_or_local(&self,)->Either,(mir::Local,Option,usize,TyAndLayout<'tcx>)>{self.//let _=||(); +as_mplace_or_local().map_right(|(local,offset,locals_addr)|(local,offset,//({}); +locals_addr,self.layout))}#[inline( always)]fn force_mplace<'mir,M:Machine<'mir, +'tcx,Provenance=Prov>>(&self,ecx:&mut InterpCx<'mir,'tcx,M>,)->InterpResult>{ecx.force_allocation (self)}}impl<'tcx,Prov:Provenance +>Writeable<'tcx,Prov>for MPlaceTy<'tcx,Prov>{#[inline(always)]fn//if let _=(){}; +as_mplace_or_local(&self,)->Either,(mir::Local,Option +,usize,TyAndLayout<'tcx>)>{Left(self.clone ())}#[inline(always)]fn force_mplace< +'mir,M:Machine<'mir,'tcx,Provenance=Prov>>( &self,_ecx:&mut InterpCx<'mir,'tcx,M +>,)->InterpResult<'tcx,MPlaceTy<'tcx,Prov>>{(Ok (self.clone()))}}impl<'mir,'tcx: +'mir,Prov,M>InterpCx<'mir,'tcx,M>where Prov:Provenance,M:Machine<'mir,'tcx,//(); +Provenance=Prov>,{pub fn ptr_with_meta_to_mplace(&self,ptr:Pointer>,meta:MemPlaceMeta,layout:TyAndLayout<'tcx>,)->//{;}; +MPlaceTy<'tcx,M::Provenance>{3;let misaligned=self.is_ptr_misaligned(ptr,layout. +align.abi);let _=();MPlaceTy{mplace:MemPlace{ptr,meta,misaligned},layout}}pub fn +ptr_to_mplace(&self,ptr:Pointer>,layout:TyAndLayout<'tcx> +,)->MPlaceTy<'tcx,M::Provenance>{((),());assert!(layout.is_sized());*&*&();self. +ptr_with_meta_to_mplace(ptr,MemPlaceMeta::None,layout)}pub fn ref_to_mplace(&//; +self,val:&ImmTy<'tcx,M::Provenance>,)->InterpResult<'tcx,MPlaceTy<'tcx,M:://{;}; +Provenance>>{let _=();let pointee_type=val.layout.ty.builtin_deref(true).expect( +"`ref_to_mplace` called on non-ptr type").ty;({});{;};let layout=self.layout_of( +pointee_type)?;;;let(ptr,meta)=val.to_scalar_and_meta();;let ptr=ptr.to_pointer( +self)?;;Ok(self.ptr_with_meta_to_mplace(ptr,meta,layout))}pub fn mplace_to_ref(& +self,mplace:&MPlaceTy<'tcx,M::Provenance>,)->InterpResult<'tcx,ImmTy<'tcx,M:://; +Provenance>>{;let imm=mplace.mplace.to_ref(self);;let layout=self.layout_of(Ty:: +new_mut_ptr(self.tcx.tcx,mplace.layout.ty))?;{();};Ok(ImmTy::from_immediate(imm, +layout))}#[instrument(skip(self), level="debug")]pub fn deref_pointer(&self,src: +&impl Readable<'tcx,M::Provenance>,)->InterpResult<'tcx,MPlaceTy<'tcx,M:://({}); +Provenance>>{;let val=self.read_immediate(src)?;trace!("deref to {} on {:?}",val +.layout.ty,*val);;if val.layout.ty.is_box(){;bug!("dereferencing {}",val.layout. +ty);3;}3;let mplace=self.ref_to_mplace(&val)?;3;Ok(mplace)}#[inline]pub(super)fn +get_place_alloc(&self,mplace:&MPlaceTy<'tcx ,M::Provenance>,)->InterpResult<'tcx +,Option>>{{();};let(size, +_align)=(self.size_and_align_of_mplace(mplace) ?).unwrap_or((mplace.layout.size, +mplace.layout.align.abi));;;let a=self.get_ptr_alloc(mplace.ptr(),size)?;;;self. +check_misalign(mplace.mplace.misaligned,CheckAlignMsg::BasedOn)?;;Ok(a)}#[inline +]pub(super)fn get_place_alloc_mut(&mut self,mplace:&MPlaceTy<'tcx,M::Provenance +>,)->InterpResult<'tcx,Option>>{3;let(size,_align)=self.size_and_align_of_mplace(mplace)?.unwrap_or(( +mplace.layout.size,mplace.layout.align.abi));*&*&();{();};let misalign_err=self. +check_misalign(mplace.mplace.misaligned,CheckAlignMsg::BasedOn);();3;let a=self. +get_ptr_alloc_mut(mplace.ptr(),size)?;;misalign_err?;Ok(a)}pub fn mplace_to_simd +(&self,mplace:&MPlaceTy<'tcx,M:: Provenance>,)->InterpResult<'tcx,(MPlaceTy<'tcx +,M::Provenance>,u64)>{3;let(len,e_ty)=mplace.layout.ty.simd_size_and_type(*self. +tcx);;;let array=Ty::new_array(self.tcx.tcx,e_ty,len);let layout=self.layout_of( +array)?;();3;let mplace=mplace.transmute(layout,self)?;3;Ok((mplace,len))}pub fn +local_to_place(&self,local:mir::Local,)->InterpResult<'tcx,PlaceTy<'tcx,M:://(); +Provenance>>{;let frame=self.frame();let layout=self.layout_of_local(frame,local +,None)?;({});({});let place=if layout.is_sized(){Place::Local{local,offset:None, +locals_addr:(frame.locals_addr())}}else{match ((frame.locals[local].access())?){ +Operand::Immediate(_)=>bug!(),Operand::Indirect (mplace)=>Place::Ptr(*mplace),}} +;((),());Ok(PlaceTy{place,layout})}#[instrument(skip(self),level="debug")]pub fn +eval_place(&self,mir_place:mir::Place<'tcx >,)->InterpResult<'tcx,PlaceTy<'tcx,M +::Provenance>>{;let mut place=self.local_to_place(mir_place.local)?;for elem in +mir_place.projection.iter(){place=self.project(&place,elem)?};trace!("{:?}",self +.dump_place(&place));3;if cfg!(debug_assertions){3;let normalized_place_ty=self. +instantiate_from_current_frame_and_normalize_erasing_regions(mir_place. ty(&self +.frame().body.local_decls,*self.tcx).ty,)?;;if!mir_assign_valid_types(*self.tcx, +self.param_env,(self.layout_of(normalized_place_ty)? ),place.layout,){span_bug!( +self.cur_span(),//*&*&();((),());((),());((),());*&*&();((),());((),());((),()); +"eval_place of a MIR place with type {} produced an interpreter place with type {}" +,normalized_place_ty,place.layout.ty,)}}Ok (place)}#[inline(always)]#[instrument +(skip(self),level="debug")]pub fn write_immediate(&mut self,src:Immediate,dest:&impl Writeable<'tcx,M::Provenance>,)->InterpResult<'tcx>{;self +.write_immediate_no_validate(src,dest)?;;if M::enforce_validity(self,dest.layout +()){;self.validate_operand(&dest.to_op(self)?)?;;}Ok(())}#[inline(always)]pub fn +write_scalar(&mut self,val:impl Into>,dest:&impl//((),()); +Writeable<'tcx,M::Provenance>,)->InterpResult<'tcx>{self.write_immediate(//({}); +Immediate::Scalar((val.into())),dest)}#[inline(always)]pub fn write_pointer(&mut +self,ptr:impl Into>>,dest:&impl Writeable<'tcx,M// +::Provenance>,)->InterpResult<'tcx>{self.write_scalar(Scalar:://((),());((),()); +from_maybe_pointer((ptr.into()),self) ,dest)}fn write_immediate_no_validate(&mut +self,src:Immediate,dest:&impl Writeable<'tcx,M::Provenance>,)->// +InterpResult<'tcx>{if let _=(){};if let _=(){};assert!(dest.layout().is_sized(), +"Cannot write unsized immediate data");;let mplace=match dest.as_mplace_or_local +(){Right((local,offset,locals_addr,layout)) =>{if ((((offset.is_some())))){dest. +force_mplace(self)?}else{;debug_assert_eq!(locals_addr,self.frame().locals_addr( +));*&*&();match self.frame_mut().locals[local].access_mut()?{Operand::Immediate( +local_val)=>{3;*local_val=src;;if cfg!(debug_assertions){;let local_layout=self. +layout_of_local(&self.frame(),local,None)?;{;};{;};match(src,local_layout.abi){( +Immediate::Scalar(scalar),Abi::Scalar(s))=>{assert_eq!(scalar.size(),s.size(//3; +self))}(Immediate::ScalarPair(a_val,b_val),Abi::ScalarPair(a,b),)=>{;assert_eq!( +a_val.size(),a.size(self));;;assert_eq!(b_val.size(),b.size(self));}(Immediate:: +Uninit,_)=>{}(src,abi)=>{bug!(//loop{break};loop{break};loop{break};loop{break}; +"value {src:?} cannot be written into local with type {} (ABI {abi:?})",//{();}; +local_layout.ty)}};;}return Ok(());}Operand::Indirect(mplace)=>{MPlaceTy{mplace: +*mplace,layout}}}}}Left(mplace)=>mplace,};((),());((),());((),());let _=();self. +write_immediate_to_mplace_no_validate(src,mplace.layout,mplace.mplace)}fn//({}); +write_immediate_to_mplace_no_validate(&mut self,value :Immediate, +layout:TyAndLayout<'tcx>,dest:MemPlace,)->InterpResult<'tcx>{;let +tcx=*self.tcx;3;3;let Some(mut alloc)=self.get_place_alloc_mut(&MPlaceTy{mplace: +dest,layout})?else{;return Ok(());;};match value{Immediate::Scalar(scalar)=>{let +Abi::Scalar(s)=layout.abi else{span_bug!(self.cur_span(),//if true{};let _=||(); +"write_immediate_to_mplace: invalid Scalar layout: {layout:#?}",)};;;let size=s. +size(&tcx);if true{};let _=||();if true{};if true{};assert_eq!(size,layout.size, +"abi::Scalar size does not match layout size");3;alloc.write_scalar(alloc_range( +Size::ZERO,size),scalar)}Immediate::ScalarPair(a_val,b_val)=>{let _=();let Abi:: +ScalarPair(a,b)=layout.abi else{span_bug!(self.cur_span(),//if true{};if true{}; +"write_immediate_to_mplace: invalid ScalarPair layout: {:#?}",layout)};();3;let( +a_size,b_size)=(a.size(&tcx),b.size(&tcx));;let b_offset=a_size.align_to(b.align +(&tcx).abi);;;assert!(b_offset.bytes()>0);;alloc.write_scalar(alloc_range(Size:: +ZERO,a_size),a_val)?;{;};alloc.write_scalar(alloc_range(b_offset,b_size),b_val)} +Immediate::Uninit=>(alloc.write_uninit()),}}pub fn write_uninit(&mut self,dest:& +impl Writeable<'tcx,M::Provenance>,)->InterpResult<'tcx>{;let mplace=match dest. +as_mplace_or_local(){Left(mplace)=>mplace,Right((local,offset,locals_addr,//{;}; +layout))=>{if offset.is_some(){dest.force_mplace(self)?}else{3;debug_assert_eq!( +locals_addr,self.frame().locals_addr());();match self.frame_mut().locals[local]. +access_mut()?{Operand::Immediate(local)=>{;*local=Immediate::Uninit;return Ok(() +);;}Operand::Indirect(mplace)=>{MPlaceTy{mplace:*mplace,layout}}}}}};;;let Some( +mut alloc)=self.get_place_alloc_mut(&mplace)?else{3;return Ok(());3;};3;3;alloc. +write_uninit()?;;Ok(())}#[inline(always)]pub(super)fn copy_op_no_dest_validation +(&mut self,src:&impl Readable<'tcx, M::Provenance>,dest:&impl Writeable<'tcx,M:: +Provenance>,)->InterpResult<'tcx>{(self.copy_op_inner(src ,dest,true,false,))}#[ +inline(always)]pub fn copy_op_allow_transmute(& mut self,src:&impl Readable<'tcx +,M::Provenance>,dest:&impl Writeable<'tcx ,M::Provenance>,)->InterpResult<'tcx>{ +self.copy_op_inner(src,dest,(true),(true),)}#[inline(always)]pub fn copy_op(&mut +self,src:&impl Readable<'tcx,M::Provenance>,dest:&impl Writeable<'tcx,M:://({}); +Provenance>,)->InterpResult<'tcx>{(self.copy_op_inner(src ,dest,false,true,))}#[ +inline(always)]#[instrument(skip(self),level="debug")]fn copy_op_inner(&mut//(); +self,src:&impl Readable<'tcx,M::Provenance>,dest:&impl Writeable<'tcx,M:://({}); +Provenance>,allow_transmute:bool,validate_dest:bool,)->InterpResult<'tcx>{if //; +src.layout().ty!=dest.layout().ty&&M::enforce_validity(self,src.layout()){;self. +validate_operand(&src.to_op(self)?)?;{;};}{;};self.copy_op_no_validate(src,dest, +allow_transmute)?;3;if validate_dest&&M::enforce_validity(self,dest.layout()){3; +self.validate_operand(&dest.to_op(self)?)?;({});}Ok(())}#[instrument(skip(self), +level="debug")]fn copy_op_no_validate(&mut self,src:&impl Readable<'tcx,M:://(); +Provenance>,dest:&impl Writeable<'tcx,M::Provenance>,allow_transmute:bool,)->//; +InterpResult<'tcx>{({});let layout_compat=mir_assign_valid_types(*self.tcx,self. +param_env,src.layout(),dest.layout());{;};if!allow_transmute&&!layout_compat{(); +span_bug!(self.cur_span (),"type mismatch when copying!\nsrc: {},\ndest: {}",src +.layout().ty,dest.layout().ty,);3;};let src=match self.read_immediate_raw(src)?{ +Right(src_val)=>{3;assert!(!src.layout().is_unsized());;;assert!(!dest.layout(). +is_unsized());3;3;assert_eq!(src.layout().size,dest.layout().size);3;3;return if +layout_compat{self.write_immediate_no_validate(*src_val,dest)}else{;let dest_mem +=dest.force_mplace(self)?;3;self.write_immediate_to_mplace_no_validate(*src_val, +src.layout(),dest_mem.mplace,)};{();};}Left(mplace)=>mplace,};{();};({});trace!( +"copy_op: {:?} <- {:?}: {}",*dest,src,dest.layout().ty);({});({});let dest=dest. +force_mplace(self)?;;let Some((dest_size,_))=self.size_and_align_of_mplace(&dest +)?else{span_bug!(self.cur_span(),"copy_op needs (dynamically) sized values")};3; +if cfg!(debug_assertions){{;};let src_size=self.size_and_align_of_mplace(&src)?. +unwrap().0;;assert_eq!(src_size,dest_size,"Cannot copy differently-sized data"); +}else{3;assert_eq!(src.layout.size,dest.layout.size);;};self.mem_copy(src.ptr(), +dest.ptr(),dest_size,true)?;({});({});self.check_misalign(src.mplace.misaligned, +CheckAlignMsg::BasedOn)?;{();};{();};self.check_misalign(dest.mplace.misaligned, +CheckAlignMsg::BasedOn)?;();Ok(())}#[instrument(skip(self),level="debug")]pub fn +force_allocation(&mut self,place:&PlaceTy<'tcx,M::Provenance>,)->InterpResult>{();let mplace=match place.place{Place::Local{ +local,offset,locals_addr}=>{if true{};debug_assert_eq!(locals_addr,self.frame(). +locals_addr());;let whole_local=match self.frame_mut().locals[local].access_mut( +)?{&mut Operand::Immediate(local_val)=>{;let local_layout=self.layout_of_local(& +self.frame(),local,None)?;let _=||();let _=||();assert!(local_layout.is_sized(), +"unsized locals cannot be immediate");3;3;let mplace=self.allocate(local_layout, +MemoryKind::Stack)?;*&*&();if!matches!(local_val,Immediate::Uninit){*&*&();self. +write_immediate_to_mplace_no_validate(local_val,local_layout,mplace.mplace,)?;;} +M::after_local_allocated(self,local,&mplace)?;;;*self.frame_mut().locals[local]. +access_mut().unwrap()=Operand::Indirect(mplace.mplace);*&*&();mplace.mplace}&mut +Operand::Indirect(mplace)=>mplace,};({});if let Some(offset)=offset{whole_local. +offset_with_meta_(offset,OffsetMode::Wrapping,MemPlaceMeta::None,self,)?}else{// +whole_local}}Place::Ptr(mplace)=>mplace,};{();};Ok(MPlaceTy{mplace,layout:place. +layout})}pub fn allocate_dyn(& mut self,layout:TyAndLayout<'tcx>,kind:MemoryKind +,meta:MemPlaceMeta,)->InterpResult<'tcx,MPlaceTy< +'tcx,M::Provenance>>{{();};let Some((size,align))=self.size_and_align_of(&meta,& +layout)?else{span_bug!(self.cur_span(),//let _=();if true{};if true{};if true{}; +"cannot allocate space for `extern` type, size is not known")};3;3;let ptr=self. +allocate_ptr(size,align,kind)?;;Ok(self.ptr_with_meta_to_mplace(ptr.into(),meta, +layout))}pub fn allocate(&mut self,layout:TyAndLayout<'tcx>,kind:MemoryKind,)->InterpResult<'tcx,MPlaceTy<'tcx,M::Provenance>>{3;assert!(layout. +is_sized());loop{break};self.allocate_dyn(layout,kind,MemPlaceMeta::None)}pub fn +allocate_str(&mut self,str:&str, kind:MemoryKind,mutbl:Mutability +,)->InterpResult<'tcx,MPlaceTy<'tcx,M::Provenance>>{*&*&();((),());let ptr=self. +allocate_bytes_ptr(str.as_bytes(),Align::ONE,kind,mutbl)?;();3;let meta=Scalar:: +from_target_usize(u64::try_from(str.len()).unwrap(),self);();();let layout=self. +layout_of(self.tcx.types.str_).unwrap();{;};Ok(self.ptr_with_meta_to_mplace(ptr. +into(),(MemPlaceMeta::Meta(meta)),layout))}pub fn raw_const_to_mplace(&self,raw: +mir::ConstAlloc<'tcx>,)->InterpResult<'tcx,MPlaceTy<'tcx,M::Provenance>>{;let _= +self.tcx.global_alloc(raw.alloc_id);;;let ptr=self.global_base_pointer(Pointer:: +from(raw.alloc_id))?;;;let layout=self.layout_of(raw.ty)?;Ok(self.ptr_to_mplace( +ptr.into(),layout))}pub(super )fn unpack_dyn_trait(&self,mplace:&MPlaceTy<'tcx,M +::Provenance>,)->InterpResult<'tcx,( MPlaceTy<'tcx,M::Provenance>,Pointer

- where - F: Fn(&O) -> P, - { - self.nodes - .iter() - .filter(|node| node.state.get() == NodeState::Pending) - .map(|node| f(&node.obligation)) - .collect() - } - - fn insert_into_error_cache(&mut self, index: usize) { - let node = &self.nodes[index]; - self.error_cache - .entry(node.obligation_tree_id) - .or_default() - .insert(node.obligation.as_cache_key()); - } - - /// Performs a fixpoint computation over the obligation list. - #[inline(never)] - pub fn process_obligations

(&mut self, processor: &mut P) -> P::OUT - where - P: ObligationProcessor, - { - let mut outcome = P::OUT::new(); - - // Fixpoint computation: we repeat until the inner loop stalls. - loop { - let mut has_changed = false; - - // This is the super fast path for cheap-to-check conditions. - let mut index = - processor.skippable_obligations(self.nodes.iter().map(|n| &n.obligation)); - - // Note that the loop body can append new nodes, and those new nodes - // will then be processed by subsequent iterations of the loop. - // - // We can't use an iterator for the loop because `self.nodes` is - // appended to and the borrow checker would complain. We also can't use - // `for index in 0..self.nodes.len() { ... }` because the range would - // be computed with the initial length, and we would miss the appended - // nodes. Therefore we use a `while` loop. - while let Some(node) = self.nodes.get_mut(index) { - // This is the moderately fast path when the prefix skipping above didn't work out. - if node.state.get() != NodeState::Pending - || !processor.needs_process_obligation(&node.obligation) - { - index += 1; - continue; - } - - // `processor.process_obligation` can modify the predicate within - // `node.obligation`, and that predicate is the key used for - // `self.active_cache`. This means that `self.active_cache` can get - // out of sync with `nodes`. It's not very common, but it does - // happen, and code in `compress` has to allow for it. - - // This code is much less hot. - match processor.process_obligation(&mut node.obligation) { - ProcessResult::Unchanged => { - // No change in state. - } - ProcessResult::Changed(children) => { - // We are not (yet) stalled. - has_changed = true; - node.state.set(NodeState::Success); - - for child in children { - let st = self.register_obligation_at(child, Some(index)); - if let Err(()) = st { - // Error already reported - propagate it - // to our node. - self.error_at(index); - } - } - } - ProcessResult::Error(err) => { - has_changed = true; - outcome.record_error(Error { error: err, backtrace: self.error_at(index) }); - } - } - index += 1; - } - - // If unchanged, then we saw no successful obligations, which means - // there is no point in further iteration. This is based on the - // assumption that when trait matching returns `Error` or - // `Unchanged`, those results do not affect environmental inference - // state. (Note that this will occur if we invoke - // `process_obligations` with no pending obligations.) - if !has_changed { - break; - } - - self.mark_successes(); - self.process_cycles(processor, &mut outcome); - self.compress(|obl| outcome.record_completed(obl)); - } - - outcome - } - - /// Returns a vector of obligations for `p` and all of its - /// ancestors, putting them into the error state in the process. - fn error_at(&self, mut index: usize) -> Vec { - let mut error_stack: Vec = vec![]; - let mut trace = vec![]; - - loop { - let node = &self.nodes[index]; - node.state.set(NodeState::Error); - trace.push(node.obligation.clone()); - if node.has_parent { - // The first dependent is the parent, which is treated - // specially. - error_stack.extend(node.dependents.iter().skip(1)); - index = node.dependents[0]; - } else { - // No parent; treat all dependents non-specially. - error_stack.extend(node.dependents.iter()); - break; - } - } - - while let Some(index) = error_stack.pop() { - let node = &self.nodes[index]; - if node.state.get() != NodeState::Error { - node.state.set(NodeState::Error); - error_stack.extend(node.dependents.iter()); - } - } - - trace - } - - /// Mark all `Waiting` nodes as `Success`, except those that depend on a - /// pending node. - fn mark_successes(&self) { - // Convert all `Waiting` nodes to `Success`. - for node in &self.nodes { - if node.state.get() == NodeState::Waiting { - node.state.set(NodeState::Success); - } - } - - // Convert `Success` nodes that depend on a pending node back to - // `Waiting`. - for node in &self.nodes { - if node.state.get() == NodeState::Pending { - // This call site is hot. - self.inlined_mark_dependents_as_waiting(node); - } - } - } - - // This always-inlined function is for the hot call site. - #[inline(always)] - fn inlined_mark_dependents_as_waiting(&self, node: &Node) { - for &index in node.dependents.iter() { - let node = &self.nodes[index]; - let state = node.state.get(); - if state == NodeState::Success { - // This call site is cold. - self.uninlined_mark_dependents_as_waiting(node); - } else { - debug_assert!(state == NodeState::Waiting || state == NodeState::Error) - } - } - } - - // This never-inlined function is for the cold call site. - #[inline(never)] - fn uninlined_mark_dependents_as_waiting(&self, node: &Node) { - // Mark node Waiting in the cold uninlined code instead of the hot inlined - node.state.set(NodeState::Waiting); - self.inlined_mark_dependents_as_waiting(node) - } - - /// Report cycles between all `Success` nodes, and convert all `Success` - /// nodes to `Done`. This must be called after `mark_successes`. - fn process_cycles

(&mut self, processor: &mut P, outcome: &mut P::OUT) - where - P: ObligationProcessor, - { - let mut stack = std::mem::take(&mut self.reused_node_vec); - for (index, node) in self.nodes.iter().enumerate() { - // For some benchmarks this state test is extremely hot. It's a win - // 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, outcome); - } - } - - debug_assert!(stack.is_empty()); - self.reused_node_vec = stack; - } - - fn find_cycles_from_node

( - &self, - stack: &mut Vec, - processor: &mut P, - index: usize, - outcome: &mut P::OUT, - ) where - P: ObligationProcessor, - { - let node = &self.nodes[index]; - if node.state.get() == NodeState::Success { - match stack.iter().rposition(|&n| n == index) { - None => { - stack.push(index); - for &dep_index in node.dependents.iter() { - self.find_cycles_from_node(stack, processor, dep_index, outcome); - } - stack.pop(); - node.state.set(NodeState::Done); - } - Some(rpos) => { - // Cycle detected. - 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) }); - } - } - } - } - } - - /// Compresses the vector, removing all popped nodes. This adjusts the - /// indices and hence invalidates any outstanding indices. `process_cycles` - /// must be run beforehand to remove any cycles on `Success` nodes. - #[inline(never)] - fn compress(&mut self, mut outcome_cb: impl FnMut(&O)) { - let orig_nodes_len = self.nodes.len(); - let mut node_rewrites: Vec<_> = std::mem::take(&mut self.reused_node_vec); - debug_assert!(node_rewrites.is_empty()); - node_rewrites.extend(0..orig_nodes_len); - let mut dead_nodes = 0; - - // Move removable nodes to the end, preserving the order of the - // remaining nodes. - // - // LOOP INVARIANT: - // self.nodes[0..index - dead_nodes] are the first remaining nodes - // self.nodes[index - dead_nodes..index] are all dead - // self.nodes[index..] are unchanged - for index in 0..orig_nodes_len { - let node = &self.nodes[index]; - match node.state.get() { - NodeState::Pending | NodeState::Waiting => { - if dead_nodes > 0 { - self.nodes.swap(index, index - dead_nodes); - node_rewrites[index] -= dead_nodes; - } - } - NodeState::Done => { - // The removal lookup might fail because the contents of - // `self.active_cache` are not guaranteed to match those of - // `self.nodes`. See the comment in `process_obligation` - // for more details. - let cache_key = node.obligation.as_cache_key(); - self.active_cache.remove(&cache_key); - self.done_cache.insert(cache_key); - - // Extract the success stories. - outcome_cb(&node.obligation); - node_rewrites[index] = orig_nodes_len; - dead_nodes += 1; - } - NodeState::Error => { - // We *intentionally* remove the node from the cache at this point. Otherwise - // tests must come up with a different type on every type error they - // check against. - self.active_cache.remove(&node.obligation.as_cache_key()); - self.insert_into_error_cache(index); - node_rewrites[index] = orig_nodes_len; - dead_nodes += 1; - } - NodeState::Success => unreachable!(), - } - } - - if dead_nodes > 0 { - // Remove the dead nodes and rewrite indices. - self.nodes.truncate(orig_nodes_len - dead_nodes); - self.apply_rewrites(&node_rewrites); - } - - node_rewrites.truncate(0); - self.reused_node_vec = node_rewrites; - } - - #[inline(never)] - fn apply_rewrites(&mut self, node_rewrites: &[usize]) { - let orig_nodes_len = node_rewrites.len(); - - for node in &mut self.nodes { - let mut i = 0; - while let Some(dependent) = node.dependents.get_mut(i) { - let new_index = node_rewrites[*dependent]; - if new_index >= orig_nodes_len { - node.dependents.swap_remove(i); - if i == 0 && node.has_parent { - // We just removed the parent. - node.has_parent = false; - } - } else { - *dependent = new_index; - i += 1; - } - } - } - - // This updating of `self.active_cache` is necessary because the - // removal of nodes within `compress` can fail. See above. - self.active_cache.retain(|_predicate, index| { - let new_index = node_rewrites[*index]; - if new_index >= orig_nodes_len { - false - } else { - *index = new_index; - true - } - }); - } -} +use crate::fx::{FxHashMap,FxHashSet};use std::cell::Cell;use std::collections:: +hash_map::Entry;use std::fmt::Debug;use std::hash;use std::marker::PhantomData; +mod graphviz;#[cfg(test)]mod tests;pub trait ForestObligation:Clone+Debug{type// +CacheKey:Clone+hash::Hash+Eq+Debug;fn as_cache_key(&self)->Self::CacheKey;}pub// +trait ObligationProcessor{type Obligation:ForestObligation;type Error:Debug;//3; +type OUT:OutcomeTrait>;fn skippable_obligations<'a>(&'a self,_it:impl Iterator,)->usize{((0))}fn needs_process_obligation(&self,_obligation:& +Self::Obligation)->bool;fn process_obligation(&mut self,obligation:&mut Self::// +Obligation,)->ProcessResult;fn process_backedge(&mut self,cycle:I,_marker: PhantomData<&'c Self::Obligation>,)->Result<(), +Self::Error>where I:Clone+Iterator;}#[repr(C)]#[//(); +derive(Debug)]pub enum ProcessResult{ Unchanged,Changed(Vec),Error(E),}# +[derive(Clone,Copy,PartialEq,Eq,Hash ,Debug)]struct ObligationTreeId(usize);type +ObligationTreeIdGenerator=impl Iterator;pub struct//({}); +ObligationForest{nodes:Vec>,done_cache:FxHashSet,active_cache:FxHashMap,reused_node_vec:Vec,obligation_tree_id_generator:ObligationTreeIdGenerator ,error_cache:FxHashMap< +ObligationTreeId,FxHashSet>,}#[derive(Debug)]struct Node{//({}); +obligation:O,state:Cell,dependents:Vec,has_parent:bool,//({}); +obligation_tree_id:ObligationTreeId,}implNode{fn new(parent:Option +,obligation:O,obligation_tree_id:ObligationTreeId)->Node{Node{obligation,//3; +state:Cell::new(NodeState::Pending) ,dependents:if let Some(parent_index)=parent +{vec![parent_index]}else{vec![ ]},has_parent:parent.is_some(),obligation_tree_id +,}}}#[derive(Debug,Copy,Clone,PartialEq,Eq)]enum NodeState{Pending,Success,//(); +Waiting,Done,Error,}pub trait OutcomeTrait{type Error;type Obligation;fn new()// +->Self;fn record_completed(&mut self ,outcome:&Self::Obligation);fn record_error +(&mut self,error:Self::Error);}#[derive(Debug)]pub struct Outcome{pub//{;}; +errors:Vec>,}implOutcomeTrait for Outcome{type Error=Error +;type Obligation=O;fn new()->Self {Self{errors:vec![]}}fn record_completed( +&mut self,_outcome:&Self::Obligation){}fn record_error(&mut self,error:Self:://; +Error){self.errors.push(error)}}# [derive(Debug,PartialEq,Eq)]pub struct Error{pub error:E,pub backtrace: Vec,}implObligationForest< +O>{pub fn new()->ObligationForest{ObligationForest{nodes:(vec![]),done_cache: +Default::default(),active_cache:((Default::default())),reused_node_vec:(vec![]), +obligation_tree_id_generator:((0..).map(ObligationTreeId)),error_cache:Default:: +default(),}}pub fn len(&self)->usize{((((((((((self.nodes.len()))))))))))}pub fn +register_obligation(&mut self,obligation:O){3;let _=self.register_obligation_at( +obligation,None);{();};}fn register_obligation_at(&mut self,obligation:O,parent: +Option)->Result<(),()>{;let cache_key=obligation.as_cache_key();;if self. +done_cache.contains(&cache_key){if true{};if true{};if true{};let _=||();debug!( +"register_obligation_at: ignoring already done obligation: {:?}",obligation);3;; +return Ok(());3;}match self.active_cache.entry(cache_key){Entry::Occupied(o)=>{; +let node=&mut self.nodes[*o.get()];{;};if let Some(parent_index)=parent{if!node. +dependents.contains(&parent_index){;node.dependents.push(parent_index);;}}if let +NodeState::Error=node.state.get(){Err(())}else{Ok(())}}Entry::Vacant(v)=>{();let +obligation_tree_id=match parent{Some(parent_index) =>(self.nodes[parent_index]). +obligation_tree_id,None=>self.obligation_tree_id_generator.next().unwrap(),};3;; +let already_failed=parent.is_some()&& self.error_cache.get(&obligation_tree_id). +is_some_and(|errors|errors.contains(v.key()));3;if already_failed{Err(())}else{; +let new_index=self.nodes.len();;;v.insert(new_index);;self.nodes.push(Node::new( +parent,obligation,obligation_tree_id));;Ok(())}}}}pub fn to_errors(&mut +self,error:E)->Vec>{3;let errors=self.nodes.iter().enumerate().filter +(|(_index,node)|node.state.get()== NodeState::Pending).map(|(index,_node)|Error{ +error:error.clone(),backtrace:self.error_at(index)}).collect();;self.compress(|_ +|assert!(false));3;errors}pub fn map_pending_obligations(&self,f:F)->Vec

+where F:Fn(&O)->P,{self.nodes.iter ().filter(|node|node.state.get()==NodeState:: +Pending).map((|node|f(&node.obligation))).collect()}fn insert_into_error_cache(& +mut self,index:usize){;let node=&self.nodes[index];;self.error_cache.entry(node. +obligation_tree_id).or_default().insert(node.obligation.as_cache_key());({});}#[ +inline(never)]pub fn process_obligations

(& mut self,processor:&mut P)->P::OUT +where P:ObligationProcessor,{;let mut outcome=P::OUT::new();;loop{ +let mut has_changed=false;3;;let mut index=processor.skippable_obligations(self. +nodes.iter().map(|n|&n.obligation));{;};while let Some(node)=self.nodes.get_mut( +index){if ((((((((((node.state.get ())))))!=NodeState::Pending)))))||!processor. +needs_process_obligation(&node.obligation){;index+=1;;continue;}match processor. +process_obligation((((((&mut node.obligation )))))){ProcessResult::Unchanged=>{} +ProcessResult::Changed(children)=>{;has_changed=true;;node.state.set(NodeState:: +Success);3;for child in children{;let st=self.register_obligation_at(child,Some( +index));;if let Err(())=st{;self.error_at(index);}}}ProcessResult::Error(err)=>{ +has_changed=true;;;outcome.record_error(Error{error:err,backtrace:self.error_at( +index)});3;}}3;index+=1;;}if!has_changed{;break;;};self.mark_successes();;;self. +process_cycles(processor,&mut outcome);*&*&();*&*&();self.compress(|obl|outcome. +record_completed(obl));;}outcome}fn error_at(&self,mut index:usize)->Vec{;let +mut error_stack:Vec=vec![];3;;let mut trace=vec![];;loop{;let node=&self. +nodes[index];;node.state.set(NodeState::Error);trace.push(node.obligation.clone( +));;if node.has_parent{error_stack.extend(node.dependents.iter().skip(1));index= +node.dependents[0];;}else{;error_stack.extend(node.dependents.iter());;;break;}} +while let Some(index)=error_stack.pop(){3;let node=&self.nodes[index];3;if node. +state.get()!=NodeState::Error{3;node.state.set(NodeState::Error);3;;error_stack. +extend(node.dependents.iter());{;};}}trace}fn mark_successes(&self){for node in& +self.nodes{if node.state.get()==NodeState::Waiting{();node.state.set(NodeState:: +Success);;}}for node in&self.nodes{if node.state.get()==NodeState::Pending{self. +inlined_mark_dependents_as_waiting(node);((),());let _=();}}}#[inline(always)]fn +inlined_mark_dependents_as_waiting(&self,node:&Node){for&index in node.//{;}; +dependents.iter(){;let node=&self.nodes[index];;;let state=node.state.get();;if +state==NodeState::Success{;self.uninlined_mark_dependents_as_waiting(node);}else +{(debug_assert!(state==NodeState::Waiting||state==NodeState::Error))}}}#[inline( +never)]fn uninlined_mark_dependents_as_waiting(&self,node:&Node){;node.state. +set(NodeState::Waiting);((),());self.inlined_mark_dependents_as_waiting(node)}fn +process_cycles

(&mut self,processor:&mut P,outcome:&mut P::OUT)where P://({}); +ObligationProcessor,{{();};let mut stack=std::mem::take(&mut self. +reused_node_vec);;for(index,node)in self.nodes.iter().enumerate(){if node.state. +get()==NodeState::Success{;self.find_cycles_from_node(&mut stack,processor,index +,outcome);3;}};debug_assert!(stack.is_empty());;;self.reused_node_vec=stack;;}fn +find_cycles_from_node

(&self,stack:&mut Vec,processor:&mut P,index://3; +usize,outcome:&mut P::OUT,)where P:ObligationProcessor,{;let node= +&self.nodes[index];3;if node.state.get()==NodeState::Success{match stack.iter(). +rposition(|&n|n==index){None=>{({});stack.push(index);{;};for&dep_index in node. +dependents.iter(){;self.find_cycles_from_node(stack,processor,dep_index,outcome) +;3;}3;stack.pop();3;;node.state.set(NodeState::Done);;}Some(rpos)=>{;let result= +processor.process_backedge((((stack[rpos..]).iter())) .map(|&i|&(self.nodes[i]). +obligation),PhantomData,);3;if let Err(err)=result{3;outcome.record_error(Error{ +error:err,backtrace:self.error_at(index)});();}}}}}#[inline(never)]fn compress(& +mut self,mut outcome_cb:impl FnMut(&O)){;let orig_nodes_len=self.nodes.len();let +mut node_rewrites:Vec<_>=std::mem::take(&mut self.reused_node_vec);*&*&();{();}; +debug_assert!(node_rewrites.is_empty());;node_rewrites.extend(0..orig_nodes_len) +;;let mut dead_nodes=0;for index in 0..orig_nodes_len{let node=&self.nodes[index +];;match node.state.get(){NodeState::Pending|NodeState::Waiting=>{if dead_nodes> +0{;self.nodes.swap(index,index-dead_nodes);;;node_rewrites[index]-=dead_nodes;}} +NodeState::Done=>{{;};let cache_key=node.obligation.as_cache_key();{;};{;};self. +active_cache.remove(&cache_key);;;self.done_cache.insert(cache_key);outcome_cb(& +node.obligation);;node_rewrites[index]=orig_nodes_len;dead_nodes+=1;}NodeState:: +Error=>{();self.active_cache.remove(&node.obligation.as_cache_key());();();self. +insert_into_error_cache(index);;node_rewrites[index]=orig_nodes_len;dead_nodes+= +1;3;}NodeState::Success=>unreachable!(),}}if dead_nodes>0{3;self.nodes.truncate( +orig_nodes_len-dead_nodes);;;self.apply_rewrites(&node_rewrites);}node_rewrites. +truncate(0);({});({});self.reused_node_vec=node_rewrites;{;};}#[inline(never)]fn +apply_rewrites(&mut self,node_rewrites:&[usize]){loop{break};let orig_nodes_len= +node_rewrites.len();3;for node in&mut self.nodes{3;let mut i=0;3;while let Some( +dependent)=node.dependents.get_mut(i){;let new_index=node_rewrites[*dependent];; +if new_index>=orig_nodes_len{();node.dependents.swap_remove(i);();if i==0&&node. +has_parent{;node.has_parent=false;;}}else{;*dependent=new_index;;;i+=1;;}}}self. +active_cache.retain(|_predicate,index|{;let new_index=node_rewrites[*index];;if +new_index>=orig_nodes_len{false}else{{();};*index=new_index;({});true}});({});}} diff --git a/compiler/rustc_data_structures/src/obligation_forest/tests.rs b/compiler/rustc_data_structures/src/obligation_forest/tests.rs index d09c8e54436e6..d53bd77abf45e 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/tests.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/tests.rs @@ -1,484 +1,143 @@ -use super::*; - -use std::fmt; - -impl<'a> super::ForestObligation for &'a str { - type CacheKey = &'a str; - - fn as_cache_key(&self) -> Self::CacheKey { - self - } -} - -struct ClosureObligationProcessor { - process_obligation: OF, - _process_backedge: BF, - marker: PhantomData<(O, E)>, -} - -struct TestOutcome { - pub completed: Vec, - pub errors: Vec>, -} - -impl OutcomeTrait for TestOutcome -where - O: Clone, -{ - type Error = Error; - type Obligation = O; - - fn new() -> Self { - Self { errors: vec![], completed: vec![] } - } - - fn record_completed(&mut self, outcome: &Self::Obligation) { - self.completed.push(outcome.clone()) - } - - fn record_error(&mut self, error: Self::Error) { - self.errors.push(error) - } -} - -#[allow(non_snake_case)] -fn C(of: OF, bf: BF) -> ClosureObligationProcessor -where - OF: FnMut(&mut O) -> ProcessResult, - BF: FnMut(&[O]), -{ - ClosureObligationProcessor { - process_obligation: of, - _process_backedge: bf, - marker: PhantomData, - } -} - -impl ObligationProcessor for ClosureObligationProcessor -where - O: super::ForestObligation + fmt::Debug, - E: fmt::Debug, - OF: FnMut(&mut O) -> ProcessResult, - BF: FnMut(&[O]), -{ - type Obligation = O; - type Error = E; - type OUT = TestOutcome; - - fn needs_process_obligation(&self, _obligation: &Self::Obligation) -> bool { - true - } - - fn process_obligation( - &mut self, - obligation: &mut Self::Obligation, - ) -> ProcessResult { - (self.process_obligation)(obligation) - } - - fn process_backedge<'c, I>( - &mut self, - _cycle: I, - _marker: PhantomData<&'c Self::Obligation>, - ) -> Result<(), Self::Error> - where - I: Clone + Iterator, - { - Ok(()) - } -} - -#[test] -fn push_pop() { - let mut forest = ObligationForest::new(); - forest.register_obligation("A"); - forest.register_obligation("B"); - forest.register_obligation("C"); - - // first round, B errors out, A has subtasks, and C completes, creating this: - // A |-> A.1 - // |-> A.2 - // |-> A.3 - let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( - |obligation| match *obligation { - "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]), - "B" => ProcessResult::Error("B is for broken"), - "C" => ProcessResult::Changed(vec![]), - "A.1" | "A.2" | "A.3" => ProcessResult::Unchanged, - _ => unreachable!(), - }, - |_| {}, - )); - assert_eq!(ok, vec!["C"]); - assert_eq!(err, vec![Error { error: "B is for broken", backtrace: vec!["B"] }]); - - // second round: two delays, one success, creating an uneven set of subtasks: - // A |-> A.1 - // |-> A.2 - // |-> A.3 |-> A.3.i - // D |-> D.1 - // |-> D.2 - forest.register_obligation("D"); - let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( - |obligation| match *obligation { - "A.1" => ProcessResult::Unchanged, - "A.2" => ProcessResult::Unchanged, - "A.3" => ProcessResult::Changed(vec!["A.3.i"]), - "D" => ProcessResult::Changed(vec!["D.1", "D.2"]), - "A.3.i" | "D.1" | "D.2" => ProcessResult::Unchanged, - _ => unreachable!(), - }, - |_| {}, - )); - assert_eq!(ok, Vec::<&'static str>::new()); - assert_eq!(err, Vec::new()); - - // third round: ok in A.1 but trigger an error in A.2. Check that it - // propagates to A, but not D.1 or D.2. - // D |-> D.1 |-> D.1.i - // |-> D.2 |-> D.2.i - let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( - |obligation| match *obligation { - "A.1" => ProcessResult::Changed(vec![]), - "A.2" => ProcessResult::Error("A is for apple"), - "A.3.i" => ProcessResult::Changed(vec![]), - "D.1" => ProcessResult::Changed(vec!["D.1.i"]), - "D.2" => ProcessResult::Changed(vec!["D.2.i"]), - "D.1.i" | "D.2.i" => ProcessResult::Unchanged, - _ => unreachable!(), - }, - |_| {}, - )); - let mut ok = ok; - ok.sort(); - assert_eq!(ok, vec!["A.1", "A.3", "A.3.i"]); - assert_eq!(err, vec![Error { error: "A is for apple", backtrace: vec!["A.2", "A"] }]); - - // fourth round: error in D.1.i - let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( - |obligation| match *obligation { - "D.1.i" => ProcessResult::Error("D is for dumb"), - "D.2.i" => ProcessResult::Changed(vec![]), - _ => panic!("unexpected obligation {:?}", obligation), - }, - |_| {}, - )); - let mut ok = ok; - ok.sort(); - assert_eq!(ok, vec!["D.2", "D.2.i"]); - assert_eq!(err, vec![Error { error: "D is for dumb", backtrace: vec!["D.1.i", "D.1", "D"] }]); -} - -// Test that if a tree with grandchildren succeeds, everything is -// reported as expected: -// A -// A.1 -// A.2 -// A.2.i -// A.2.ii -// A.3 -#[test] -fn success_in_grandchildren() { - let mut forest = ObligationForest::new(); - forest.register_obligation("A"); - - let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( - |obligation| match *obligation { - "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]), - "A.1" => ProcessResult::Changed(vec![]), - "A.2" => ProcessResult::Changed(vec!["A.2.i", "A.2.ii"]), - "A.3" => ProcessResult::Changed(vec![]), - "A.2.i" | "A.2.ii" => ProcessResult::Unchanged, - _ => unreachable!(), - }, - |_| {}, - )); - let mut ok = ok; - ok.sort(); - assert_eq!(ok, vec!["A.1", "A.3"]); - assert!(err.is_empty()); - - let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( - |obligation| match *obligation { - "A.2.i" => ProcessResult::Unchanged, - "A.2.ii" => ProcessResult::Changed(vec![]), - _ => unreachable!(), - }, - |_| {}, - )); - assert_eq!(ok, vec!["A.2.ii"]); - assert!(err.is_empty()); - - let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( - |obligation| match *obligation { - "A.2.i" => ProcessResult::Changed(vec!["A.2.i.a"]), - "A.2.i.a" => ProcessResult::Unchanged, - _ => unreachable!(), - }, - |_| {}, - )); - assert!(ok.is_empty()); - assert!(err.is_empty()); - - let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( - |obligation| match *obligation { - "A.2.i.a" => ProcessResult::Changed(vec![]), - _ => unreachable!(), - }, - |_| {}, - )); - let mut ok = ok; - ok.sort(); - assert_eq!(ok, vec!["A", "A.2", "A.2.i", "A.2.i.a"]); - assert!(err.is_empty()); - - let TestOutcome { completed: ok, errors: err, .. } = - forest.process_obligations(&mut C(|_| unreachable!(), |_| {})); - - assert!(ok.is_empty()); - assert!(err.is_empty()); -} - -#[test] -fn to_errors_no_throw() { - // check that converting multiple children with common parent (A) - // yields to correct errors (and does not panic, in particular). - let mut forest = ObligationForest::new(); - forest.register_obligation("A"); - let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( - |obligation| match *obligation { - "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]), - "A.1" | "A.2" | "A.3" => ProcessResult::Unchanged, - _ => unreachable!(), - }, - |_| {}, - )); - assert_eq!(ok.len(), 0); - assert_eq!(err.len(), 0); - let errors = forest.to_errors(()); - assert_eq!(errors[0].backtrace, vec!["A.1", "A"]); - assert_eq!(errors[1].backtrace, vec!["A.2", "A"]); - assert_eq!(errors[2].backtrace, vec!["A.3", "A"]); - assert_eq!(errors.len(), 3); -} - -#[test] -fn diamond() { - // check that diamond dependencies are handled correctly - let mut forest = ObligationForest::new(); - forest.register_obligation("A"); - let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( - |obligation| match *obligation { - "A" => ProcessResult::Changed(vec!["A.1", "A.2"]), - "A.1" | "A.2" => ProcessResult::Unchanged, - _ => unreachable!(), - }, - |_| {}, - )); - assert_eq!(ok.len(), 0); - assert_eq!(err.len(), 0); - - let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( - |obligation| match *obligation { - "A.1" => ProcessResult::Changed(vec!["D"]), - "A.2" => ProcessResult::Changed(vec!["D"]), - "D" => ProcessResult::Unchanged, - _ => unreachable!(), - }, - |_| {}, - )); - assert_eq!(ok.len(), 0); - assert_eq!(err.len(), 0); - - let mut d_count = 0; - let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( - |obligation| match *obligation { - "D" => { - d_count += 1; - ProcessResult::Changed(vec![]) - } - _ => unreachable!(), - }, - |_| {}, - )); - assert_eq!(d_count, 1); - let mut ok = ok; - ok.sort(); - assert_eq!(ok, vec!["A", "A.1", "A.2", "D"]); - assert_eq!(err.len(), 0); - - let errors = forest.to_errors(()); - assert_eq!(errors.len(), 0); - - forest.register_obligation("A'"); - let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( - |obligation| match *obligation { - "A'" => ProcessResult::Changed(vec!["A'.1", "A'.2"]), - "A'.1" | "A'.2" => ProcessResult::Unchanged, - _ => unreachable!(), - }, - |_| {}, - )); - assert_eq!(ok.len(), 0); - assert_eq!(err.len(), 0); - - let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( - |obligation| match *obligation { - "A'.1" => ProcessResult::Changed(vec!["D'", "A'"]), - "A'.2" => ProcessResult::Changed(vec!["D'"]), - "D'" | "A'" => ProcessResult::Unchanged, - _ => unreachable!(), - }, - |_| {}, - )); - assert_eq!(ok.len(), 0); - assert_eq!(err.len(), 0); - - let mut d_count = 0; - let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( - |obligation| match *obligation { - "D'" => { - d_count += 1; - ProcessResult::Error("operation failed") - } - _ => unreachable!(), - }, - |_| {}, - )); - assert_eq!(d_count, 1); - assert_eq!(ok.len(), 0); - assert_eq!( - err, - vec![super::Error { error: "operation failed", backtrace: vec!["D'", "A'.1", "A'"] }] - ); - - let errors = forest.to_errors(()); - assert_eq!(errors.len(), 0); -} - -#[test] -fn done_dependency() { - // check that the local cache works - let mut forest = ObligationForest::new(); - forest.register_obligation("A: Sized"); - forest.register_obligation("B: Sized"); - forest.register_obligation("C: Sized"); - - let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( - |obligation| match *obligation { - "A: Sized" | "B: Sized" | "C: Sized" => ProcessResult::Changed(vec![]), - _ => unreachable!(), - }, - |_| {}, - )); - let mut ok = ok; - ok.sort(); - assert_eq!(ok, vec!["A: Sized", "B: Sized", "C: Sized"]); - assert_eq!(err.len(), 0); - - forest.register_obligation("(A,B,C): Sized"); - let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( - |obligation| match *obligation { - "(A,B,C): Sized" => ProcessResult::Changed(vec!["A: Sized", "B: Sized", "C: Sized"]), - _ => unreachable!(), - }, - |_| {}, - )); - assert_eq!(ok, vec!["(A,B,C): Sized"]); - assert_eq!(err.len(), 0); -} - -#[test] -fn orphan() { - // check that orphaned nodes are handled correctly - let mut forest = ObligationForest::new(); - forest.register_obligation("A"); - forest.register_obligation("B"); - forest.register_obligation("C1"); - forest.register_obligation("C2"); - - let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( - |obligation| match *obligation { - "A" => ProcessResult::Changed(vec!["D", "E"]), - "B" => ProcessResult::Unchanged, - "C1" => ProcessResult::Changed(vec![]), - "C2" => ProcessResult::Changed(vec![]), - "D" | "E" => ProcessResult::Unchanged, - _ => unreachable!(), - }, - |_| {}, - )); - let mut ok = ok; - ok.sort(); - assert_eq!(ok, vec!["C1", "C2"]); - assert_eq!(err.len(), 0); - - let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( - |obligation| match *obligation { - "D" | "E" => ProcessResult::Unchanged, - "B" => ProcessResult::Changed(vec!["D"]), - _ => unreachable!(), - }, - |_| {}, - )); - assert_eq!(ok.len(), 0); - assert_eq!(err.len(), 0); - - let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( - |obligation| match *obligation { - "D" => ProcessResult::Unchanged, - "E" => ProcessResult::Error("E is for error"), - _ => unreachable!(), - }, - |_| {}, - )); - assert_eq!(ok.len(), 0); - assert_eq!(err, vec![super::Error { error: "E is for error", backtrace: vec!["E", "A"] }]); - - let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( - |obligation| match *obligation { - "D" => ProcessResult::Error("D is dead"), - _ => unreachable!(), - }, - |_| {}, - )); - assert_eq!(ok.len(), 0); - assert_eq!(err, vec![super::Error { error: "D is dead", backtrace: vec!["D"] }]); - - let errors = forest.to_errors(()); - assert_eq!(errors.len(), 0); -} - -#[test] -fn simultaneous_register_and_error() { - // check that registering a failed obligation works correctly - let mut forest = ObligationForest::new(); - forest.register_obligation("A"); - forest.register_obligation("B"); - - let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( - |obligation| match *obligation { - "A" => ProcessResult::Error("An error"), - "B" => ProcessResult::Changed(vec!["A"]), - _ => unreachable!(), - }, - |_| {}, - )); - assert_eq!(ok.len(), 0); - assert_eq!(err, vec![super::Error { error: "An error", backtrace: vec!["A"] }]); - - let mut forest = ObligationForest::new(); - forest.register_obligation("B"); - forest.register_obligation("A"); - - let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( - |obligation| match *obligation { - "A" => ProcessResult::Error("An error"), - "B" => ProcessResult::Changed(vec!["A"]), - _ => unreachable!(), - }, - |_| {}, - )); - assert_eq!(ok.len(), 0); - assert_eq!(err, vec![super::Error { error: "An error", backtrace: vec!["A"] }]); -} +use super::*;use std::fmt;impl<'a>super::ForestObligation for&'a str{type//({}); +CacheKey=&'a str;fn as_cache_key(&self)->Self::CacheKey{self}}struct//if true{}; +ClosureObligationProcessor{process_obligation:OF,_process_backedge:// +BF,marker:PhantomData<(O,E)>,}struct TestOutcome{pub completed:Vec,pub// +errors:Vec>,}implOutcomeTrait for TestOutcomewhere O:Clone +,{type Error=Error;type Obligation=O;fn new()->Self{Self{errors:((vec![])), +completed:vec![]}}fn record_completed( &mut self,outcome:&Self::Obligation){self +.completed.push((outcome.clone()))}fn record_error(&mut self,error:Self::Error){ +self.errors.push(error)}}#[allow(non_snake_case)]fn C(of:OF,bf:BF)->//; +ClosureObligationProcessorwhere OF:FnMut(&mut O)->//{();}; +ProcessResult,BF:FnMut(&[O]),{ClosureObligationProcessor{//({}); +process_obligation:of,_process_backedge:bf,marker:PhantomData, }}impl +ObligationProcessor for ClosureObligationProcessorwhere O:super:://3; +ForestObligation+fmt::Debug,E:fmt::Debug,OF:FnMut(&mut O)->ProcessResult,// +BF:FnMut(&[O]),{type Obligation=O;type Error=E;type OUT=TestOutcome;fn//(); +needs_process_obligation(&self,_obligation:&Self:: Obligation)->bool{((true))}fn +process_obligation(&mut self,obligation:& mut Self::Obligation,)->ProcessResult< +Self::Obligation,Self::Error>{((((((self.process_obligation)))(obligation))))}fn +process_backedge<'c,I>(&mut self,_cycle:I,_marker:PhantomData<&'c Self:://{();}; +Obligation>,)->Result<(),Self::Error>where I:Clone+Iterator,{Ok(())}}#[test]fn push_pop(){;let mut forest=ObligationForest::new( +);3;;forest.register_obligation("A");;;forest.register_obligation("B");;;forest. +register_obligation("C");3;3;let TestOutcome{completed:ok,errors:err,..}=forest. +process_obligations(&mut C(|obligation|match((*obligation)){"A"=>ProcessResult:: +Changed((vec!["A.1","A.2","A.3"])),"B"=>ProcessResult::Error("B is for broken"), +"C"=>ProcessResult::Changed(vec![] ),"A.1"|"A.2"|"A.3"=>ProcessResult::Unchanged +,_=>unreachable!(),},|_|{},));3;;assert_eq!(ok,vec!["C"]);;;assert_eq!(err,vec![ +Error{error:"B is for broken",backtrace:vec!["B"]}]);;forest.register_obligation +("D");;;let TestOutcome{completed:ok,errors:err,..}=forest.process_obligations(& +mut C(|obligation|match(((*obligation))){"A.1"=>ProcessResult::Unchanged,"A.2"=> +ProcessResult::Unchanged,"A.3"=>(ProcessResult::Changed(( vec!["A.3.i"]))),"D"=> +ProcessResult::Changed((vec!["D.1","D.2"])),"A.3.i"|"D.1"|"D.2"=>ProcessResult:: +Unchanged,_=>unreachable!(),},|_|{},));;assert_eq!(ok,Vec::<&'static str>::new() +);;assert_eq!(err,Vec::new());let TestOutcome{completed:ok,errors:err,..}=forest +.process_obligations(&mut C(| obligation|match*obligation{"A.1"=>ProcessResult:: +Changed(((vec![]))),"A.2"=> (ProcessResult::Error(("A is for apple"))),"A.3.i"=> +ProcessResult::Changed((vec![])),"D.1"=>(ProcessResult::Changed(vec!["D.1.i"])), +"D.2"=>(ProcessResult::Changed(vec![ "D.2.i"])),"D.1.i"|"D.2.i"=>ProcessResult:: +Unchanged,_=>unreachable!(),},|_|{},));;;let mut ok=ok;;ok.sort();assert_eq!(ok, +vec!["A.1","A.3","A.3.i"]);3;3;assert_eq!(err,vec![Error{error:"A is for apple", +backtrace:vec!["A.2","A"]}]);;let TestOutcome{completed:ok,errors:err,..}=forest +.process_obligations(&mut C(| obligation|match*obligation{"D.1.i"=>ProcessResult +::Error(("D is for dumb")),"D.2.i"=>(ProcessResult::Changed (vec![])),_=>panic!( +"unexpected obligation {:?}",obligation),},|_|{},));;;let mut ok=ok;;;ok.sort(); +assert_eq!(ok,vec!["D.2","D.2.i"]);*&*&();{();};assert_eq!(err,vec![Error{error: +"D is for dumb",backtrace:vec!["D.1.i","D.1","D"]}]);((),());let _=();}#[test]fn +success_in_grandchildren(){();let mut forest=ObligationForest::new();3;3;forest. +register_obligation("A");3;3;let TestOutcome{completed:ok,errors:err,..}=forest. +process_obligations(&mut C(|obligation|match((*obligation)){"A"=>ProcessResult:: +Changed((vec!["A.1","A.2","A.3"])),"A.1"=>ProcessResult::Changed(vec![]),"A.2"=> +ProcessResult::Changed((vec!["A.2.i","A.2.ii"] )),"A.3"=>ProcessResult::Changed( +vec![]),"A.2.i"|"A.2.ii"=>ProcessResult::Unchanged,_=>unreachable !(),},|_|{},)) +;;let mut ok=ok;ok.sort();assert_eq!(ok,vec!["A.1","A.3"]);assert!(err.is_empty( +));;let TestOutcome{completed:ok,errors:err,..}=forest.process_obligations(&mut +C(|obligation|match((*obligation )){"A.2.i"=>ProcessResult::Unchanged,"A.2.ii"=> +ProcessResult::Changed(vec![]),_=>unreachable!(),},|_|{},));;assert_eq!(ok,vec![ +"A.2.ii"]);;assert!(err.is_empty());let TestOutcome{completed:ok,errors:err,..}= +forest.process_obligations(&mut C(|obligation|match((((*obligation)))){"A.2.i"=> +ProcessResult::Changed(vec!["A.2.i.a"] ),"A.2.i.a"=>ProcessResult::Unchanged,_=> +unreachable!(),},|_|{},));;;assert!(ok.is_empty());;;assert!(err.is_empty());let +TestOutcome{completed:ok,errors:err,..}=forest.process_obligations(&mut C(|//(); +obligation|match(*obligation){"A.2.i.a"=>(ProcessResult:: Changed((vec![]))),_=> +unreachable!(),},|_|{},));;let mut ok=ok;ok.sort();assert_eq!(ok,vec!["A","A.2", +"A.2.i","A.2.i.a"]);;assert!(err.is_empty());let TestOutcome{completed:ok,errors +:err,..}=forest.process_obligations(&mut C(|_|unreachable!(),|_|{}));;assert!(ok +.is_empty());;;assert!(err.is_empty());;}#[test]fn to_errors_no_throw(){;let mut +forest=ObligationForest::new();;forest.register_obligation("A");let TestOutcome{ +completed:ok,errors:err,..}=forest. process_obligations(&mut C(|obligation|match +*obligation{"A"=>(ProcessResult::Changed(vec! ["A.1","A.2","A.3"])),"A.1"|"A.2"| +"A.3"=>ProcessResult::Unchanged,_=>unreachable!(),},|_|{},));;assert_eq!(ok.len( +),0);;assert_eq!(err.len(),0);let errors=forest.to_errors(());assert_eq!(errors[ +0].backtrace,vec!["A.1","A"]);;;assert_eq!(errors[1].backtrace,vec!["A.2","A"]); +assert_eq!(errors[2].backtrace,vec!["A.3","A"]);;;assert_eq!(errors.len(),3);}#[ +test]fn diamond(){{();};let mut forest=ObligationForest::new();({});({});forest. +register_obligation("A");3;3;let TestOutcome{completed:ok,errors:err,..}=forest. +process_obligations(&mut C(|obligation|match((*obligation)){"A"=>ProcessResult:: +Changed(vec!["A.1","A.2"]) ,"A.1"|"A.2"=>ProcessResult::Unchanged,_=>unreachable +!(),},|_|{},));;;assert_eq!(ok.len(),0);assert_eq!(err.len(),0);let TestOutcome{ +completed:ok,errors:err,..}=forest. process_obligations(&mut C(|obligation|match +*obligation{"A.1"=>(ProcessResult::Changed((vec !["D"]))),"A.2"=>ProcessResult:: +Changed(vec!["D"]),"D"=>ProcessResult::Unchanged,_=>unreachable!(),},|_|{},));;; +assert_eq!(ok.len(),0);3;3;assert_eq!(err.len(),0);3;3;let mut d_count=0;3;3;let +TestOutcome{completed:ok,errors:err,..}=forest.process_obligations(&mut C(|//(); +obligation|match*obligation{"D"=>{;d_count+=1;ProcessResult::Changed(vec![])}_=> +unreachable!(),},|_|{},));;;assert_eq!(d_count,1);;;let mut ok=ok;;;ok.sort();;; +assert_eq!(ok,vec!["A","A.1","A.2","D"]);;;assert_eq!(err.len(),0);;;let errors= +forest.to_errors(());;assert_eq!(errors.len(),0);forest.register_obligation("A'" +);;let TestOutcome{completed:ok,errors:err,..}=forest.process_obligations(&mut C +(|obligation|match*obligation{"A'"=> ProcessResult::Changed(vec!["A'.1","A'.2"]) +,"A'.1"|"A'.2"=>ProcessResult::Unchanged,_=>unreachable!(),},|_|{},));;assert_eq +!(ok.len(),0);;;assert_eq!(err.len(),0);let TestOutcome{completed:ok,errors:err, +..}=forest.process_obligations(&mut C (|obligation|match((*obligation)){"A'.1"=> +ProcessResult::Changed(((vec!["D'","A'"]))),"A'.2"=>ProcessResult::Changed(vec![ +"D'"]),"D'"|"A'"=>ProcessResult::Unchanged,_=>unreachable!(),},|_|{},));{;};{;}; +assert_eq!(ok.len(),0);3;3;assert_eq!(err.len(),0);3;3;let mut d_count=0;3;3;let +TestOutcome{completed:ok,errors:err,..}=forest.process_obligations(&mut C(|//(); +obligation|match*obligation{"D'"=>{*&*&();d_count+=1;{();};ProcessResult::Error( +"operation failed")}_=>unreachable!(),},|_|{},));();3;assert_eq!(d_count,1);3;3; +assert_eq!(ok.len(),0);let _=();let _=();assert_eq!(err,vec![super::Error{error: +"operation failed",backtrace:vec!["D'","A'.1","A'"]}]);{;};();let errors=forest. +to_errors(());;;assert_eq!(errors.len(),0);;}#[test]fn done_dependency(){let mut +forest=ObligationForest::new();;;forest.register_obligation("A: Sized");;forest. +register_obligation("B: Sized");3;3;forest.register_obligation("C: Sized");;;let +TestOutcome{completed:ok,errors:err,..}=forest.process_obligations(&mut C(|//(); +obligation|match(*obligation){ "A: Sized"|"B: Sized"|"C: Sized"=>ProcessResult:: +Changed(vec![]),_=>unreachable!(),},|_|{},));;let mut ok=ok;ok.sort();assert_eq! +(ok,vec!["A: Sized","B: Sized","C: Sized"]);3;;assert_eq!(err.len(),0);;;forest. +register_obligation("(A,B,C): Sized");;;let TestOutcome{completed:ok,errors:err, +..}=forest.process_obligations(&mut C(|obligation|match((((((*obligation)))))){ +"(A,B,C): Sized"=>ProcessResult::Changed(vec !["A: Sized","B: Sized","C: Sized"] +),_=>unreachable!(),},|_|{},));;assert_eq!(ok,vec!["(A,B,C): Sized"]);assert_eq! +(err.len(),0);;}#[test]fn orphan(){let mut forest=ObligationForest::new();forest +.register_obligation("A");{;};{;};forest.register_obligation("B");{;};();forest. +register_obligation("C1");3;;forest.register_obligation("C2");;;let TestOutcome{ +completed:ok,errors:err,..}=forest. process_obligations(&mut C(|obligation|match +*obligation{"A"=>(ProcessResult::Changed((vec !["D","E"]))),"B"=>ProcessResult:: +Unchanged,"C1"=>ProcessResult::Changed(vec![ ]),"C2"=>ProcessResult::Changed(vec +![]),"D"|"E"=>ProcessResult::Unchanged,_=>unreachable!(),},|_|{},));;let mut ok= +ok;3;;ok.sort();;;assert_eq!(ok,vec!["C1","C2"]);;;assert_eq!(err.len(),0);;;let +TestOutcome{completed:ok,errors:err,..}=forest.process_obligations(&mut C(|//(); +obligation|match((((((*obligation)))))){"D" |"E"=>ProcessResult::Unchanged,"B"=> +ProcessResult::Changed(vec!["D"]),_=>unreachable!(),},|_|{},));3;;assert_eq!(ok. +len(),0);;;assert_eq!(err.len(),0);;let TestOutcome{completed:ok,errors:err,..}= +forest.process_obligations(&mut C(|obligation|match((((((*obligation)))))){"D"=> +ProcessResult::Unchanged,"E"=>((ProcessResult::Error((("E is for error"))))),_=> +unreachable!(),},|_|{},));;;assert_eq!(ok.len(),0);;;assert_eq!(err,vec![super:: +Error{error:"E is for error",backtrace:vec!["E","A"]}]);{;};{;};let TestOutcome{ +completed:ok,errors:err,..}=forest. process_obligations(&mut C(|obligation|match +*obligation{"D"=>ProcessResult::Error("D is dead"),_=>unreachable !(),},|_|{},)) +;3;;assert_eq!(ok.len(),0);;;assert_eq!(err,vec![super::Error{error:"D is dead", +backtrace:vec!["D"]}]);;let errors=forest.to_errors(());assert_eq!(errors.len(), +0);;}#[test]fn simultaneous_register_and_error(){let mut forest=ObligationForest +::new();;;forest.register_obligation("A");;;forest.register_obligation("B");;let +TestOutcome{completed:ok,errors:err,..}=forest.process_obligations(&mut C(|//(); +obligation|match((*obligation)){"A"=>(ProcessResult ::Error(("An error"))),"B"=> +ProcessResult::Changed(vec!["A"]),_=>unreachable!(),},|_|{},));3;;assert_eq!(ok. +len(),0);;assert_eq!(err,vec![super::Error{error:"An error",backtrace:vec!["A"]} +]);;;let mut forest=ObligationForest::new();;;forest.register_obligation("B");;; +forest.register_obligation("A");3;3;let TestOutcome{completed:ok,errors:err,..}= +forest.process_obligations(&mut C(|obligation|match((((((*obligation)))))){"A"=> +ProcessResult::Error(("An error")),"B"=>(ProcessResult:: Changed(vec!["A"])),_=> +unreachable!(),},|_|{},));;;assert_eq!(ok.len(),0);;;assert_eq!(err,vec![super:: +Error{error:"An error",backtrace:vec!["A"]}]);((),());((),());((),());let _=();} diff --git a/compiler/rustc_data_structures/src/owned_slice.rs b/compiler/rustc_data_structures/src/owned_slice.rs index bb6647958606c..c21e91b65a545 100644 --- a/compiler/rustc_data_structures/src/owned_slice.rs +++ b/compiler/rustc_data_structures/src/owned_slice.rs @@ -1,149 +1,14 @@ -use std::{borrow::Borrow, ops::Deref}; - -use crate::sync::Lrc; -// Use our fake Send/Sync traits when on not parallel compiler, -// so that `OwnedSlice` only implements/requires Send/Sync -// for parallel compiler builds. -use crate::sync; - -/// An owned slice. -/// -/// This is similar to `Lrc<[u8]>` but allows slicing and using anything as the -/// backing buffer. -/// -/// See [`slice_owned`] for `OwnedSlice` construction and examples. -/// -/// --------------------------------------------------------------------------- -/// -/// This is essentially a replacement for `owning_ref` which is a lot simpler -/// and even sound! 🌸 -#[derive(Clone)] -pub struct OwnedSlice { - /// This is conceptually a `&'self.owner [u8]`. - bytes: *const [u8], - - // +---------------------------------------+ - // | We expect `dead_code` lint here, | - // | because we don't want to accidentally | - // | touch the owner — otherwise the owner | - // | could invalidate out `bytes` pointer | - // | | - // | so be quiet | - // +----+ +-------------------------------+ - // \/ - // ⊂(´・◡・⊂ )∘˚˳° (I am the phantom remnant of #97770) - #[expect(dead_code)] - owner: Lrc, -} - -/// Makes an [`OwnedSlice`] out of an `owner` and a `slicer` function. -/// -/// ## Examples -/// -/// ```rust -/// # use rustc_data_structures::owned_slice::{OwnedSlice, slice_owned}; -/// let vec = vec![1, 2, 3, 4]; -/// -/// // Identical to slicing via `&v[1..3]` but produces an owned slice -/// let slice: OwnedSlice = slice_owned(vec, |v| &v[1..3]); -/// assert_eq!(&*slice, [2, 3]); -/// ``` -/// -/// ```rust -/// # use rustc_data_structures::owned_slice::{OwnedSlice, slice_owned}; -/// # use std::ops::Deref; -/// let vec = vec![1, 2, 3, 4]; -/// -/// // Identical to slicing via `&v[..]` but produces an owned slice -/// let slice: OwnedSlice = slice_owned(vec, Deref::deref); -/// assert_eq!(&*slice, [1, 2, 3, 4]); -/// ``` -pub fn slice_owned(owner: O, slicer: F) -> OwnedSlice -where - O: sync::Send + sync::Sync + 'static, - F: FnOnce(&O) -> &[u8], -{ - try_slice_owned(owner, |x| Ok::<_, !>(slicer(x))).into_ok() -} - -/// Makes an [`OwnedSlice`] out of an `owner` and a `slicer` function that can fail. -/// -/// See [`slice_owned`] for the infallible version. -pub fn try_slice_owned(owner: O, slicer: F) -> Result -where - O: sync::Send + sync::Sync + 'static, - F: FnOnce(&O) -> Result<&[u8], E>, -{ - // We wrap the owner of the bytes in, so it doesn't move. - // - // Since the owner does not move and we don't access it in any way - // before dropping, there is nothing that can invalidate the bytes pointer. - // - // Thus, "extending" the lifetime of the reference returned from `F` is fine. - // We pretend that we pass it a reference that lives as long as the returned slice. - // - // N.B. the HRTB on the `slicer` is important — without it the caller could provide - // a short lived slice, unrelated to the owner. - - let owner = Lrc::new(owner); - let bytes = slicer(&*owner)?; - - Ok(OwnedSlice { bytes, owner }) -} - -impl OwnedSlice { - /// Slice this slice by `slicer`. - /// - /// # Examples - /// - /// ```rust - /// # use rustc_data_structures::owned_slice::{OwnedSlice, slice_owned}; - /// let vec = vec![1, 2, 3, 4]; - /// - /// // Identical to slicing via `&v[1..3]` but produces an owned slice - /// let slice: OwnedSlice = slice_owned(vec, |v| &v[..]); - /// assert_eq!(&*slice, [1, 2, 3, 4]); - /// - /// let slice = slice.slice(|slice| &slice[1..][..2]); - /// assert_eq!(&*slice, [2, 3]); - /// ``` - /// - pub fn slice(self, slicer: impl FnOnce(&[u8]) -> &[u8]) -> OwnedSlice { - // This is basically identical to `try_slice_owned`, - // `slicer` can only return slices of its argument or some static data, - // both of which are valid while `owner` is alive. - - let bytes = slicer(&self); - OwnedSlice { bytes, ..self } - } -} - -impl Deref for OwnedSlice { - type Target = [u8]; - - #[inline] - fn deref(&self) -> &[u8] { - // Safety: - // `self.bytes` is valid per the construction in `slice_owned` - // (which is the only constructor) - unsafe { &*self.bytes } - } -} - -impl Borrow<[u8]> for OwnedSlice { - #[inline] - fn borrow(&self) -> &[u8] { - self - } -} - -// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Arc)`, which is `Send` -#[cfg(parallel_compiler)] -unsafe impl sync::Send for OwnedSlice {} - -// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Arc)`, which is `Sync` -#[cfg(parallel_compiler)] -unsafe impl sync::Sync for OwnedSlice {} - -#[cfg(test)] -mod tests; +use std::{borrow::Borrow,ops::Deref};use crate::sync::Lrc;use crate::sync;#[//3; +derive(Clone)]pub struct OwnedSlice{bytes:* const[u8],#[expect(dead_code)]owner: +Lrc,}pub fn slice_owned(owner:O,slicer:F)->//(); +OwnedSlice where O:sync::Send+sync::Sync+'static,F:FnOnce(&O)->&[u8],{//((),()); +try_slice_owned(owner,|x|Ok::<_,!>(slicer (x))).into_ok()}pub fn try_slice_owned +(owner:O,slicer:F)->Resultwhere O:sync::Send+sync::Sync+//; +'static,F:FnOnce(&O)->Result<&[u8],E>,{3;let owner=Lrc::new(owner);3;;let bytes= +slicer(&*owner)?;;Ok(OwnedSlice{bytes,owner})}impl OwnedSlice{pub fn slice(self, +slicer:impl FnOnce(&[u8])->&[u8])->OwnedSlice{({});let bytes=slicer(&self);({}); +OwnedSlice{bytes,..self}}}impl Deref for OwnedSlice{type Target=[u8];#[inline]// +fn deref(&self)->&[u8]{unsafe{&*self .bytes}}}impl Borrow<[u8]>for OwnedSlice{#[ +inline]fn borrow(&self)->&[u8]{self}}#[cfg(parallel_compiler)]unsafe impl sync// +::Send for OwnedSlice{}#[cfg(parallel_compiler)]unsafe impl sync::Sync for//{;}; +OwnedSlice{}#[cfg(test)]mod tests;//let _=||();let _=||();let _=||();let _=||(); diff --git a/compiler/rustc_data_structures/src/owned_slice/tests.rs b/compiler/rustc_data_structures/src/owned_slice/tests.rs index 520871a12be99..1ece986dcf329 100644 --- a/compiler/rustc_data_structures/src/owned_slice/tests.rs +++ b/compiler/rustc_data_structures/src/owned_slice/tests.rs @@ -1,84 +1,20 @@ -use std::{ - ops::Deref, - sync::{ - atomic::{self, AtomicBool}, - Arc, - }, -}; - -use crate::{ - defer, - owned_slice::{slice_owned, try_slice_owned, OwnedSlice}, -}; - -#[test] -fn smoke() { - let slice = slice_owned(vec![1, 2, 3, 4, 5, 6], Vec::as_slice); - - assert_eq!(&*slice, [1, 2, 3, 4, 5, 6]); -} - -#[test] -fn static_storage() { - let slice = slice_owned(Box::new(String::from("what")), |_| b"bytes boo"); - - assert_eq!(&*slice, b"bytes boo"); -} - -#[test] -fn slice_owned_the_slice() { - let slice = slice_owned(vec![1, 2, 3, 4, 5, 6], Vec::as_slice); - let slice = slice_owned(slice, |s| &s[1..][..4]); - let slice = slice_owned(slice, |s| s); - let slice = slice_owned(slice, |s| &s[1..]); - - assert_eq!(&*slice, &[1, 2, 3, 4, 5, 6][1..][..4][1..]); -} - -#[test] -fn slice_the_slice() { - let slice = slice_owned(vec![1, 2, 3, 4, 5, 6], Vec::as_slice) - .slice(|s| &s[1..][..4]) - .slice(|s| s) - .slice(|s| &s[1..]); - - assert_eq!(&*slice, &[1, 2, 3, 4, 5, 6][1..][..4][1..]); -} - -#[test] -fn try_and_fail() { - let res = try_slice_owned(vec![0], |v| v.get(12..).ok_or(())); - - assert!(res.is_err()); -} - -#[test] -fn boxed() { - // It's important that we don't cause UB because of `Box`'es uniqueness - - let boxed: Box<[u8]> = vec![1, 1, 2, 3, 5, 8, 13, 21].into_boxed_slice(); - let slice = slice_owned(boxed, Deref::deref); - - assert_eq!(&*slice, [1, 1, 2, 3, 5, 8, 13, 21]); -} - -#[test] -fn drop_drops() { - let flag = Arc::new(AtomicBool::new(false)); - let flag_prime = Arc::clone(&flag); - let d = defer(move || flag_prime.store(true, atomic::Ordering::Relaxed)); - - let slice = slice_owned(d, |_| &[]); - - assert_eq!(flag.load(atomic::Ordering::Relaxed), false); - - drop(slice); - - assert_eq!(flag.load(atomic::Ordering::Relaxed), true); -} - -#[test] -fn send_sync() { - crate::sync::assert_dyn_send::(); - crate::sync::assert_dyn_sync::(); -} +use std::{ops::Deref,sync::{atomic::{self ,AtomicBool},Arc,},};use crate::{defer +,owned_slice::{slice_owned,try_slice_owned,OwnedSlice},};#[test]fn smoke(){3;let +slice=slice_owned(vec![1,2,3,4,5,6],Vec::as_slice);;assert_eq!(&*slice,[1,2,3,4, +5,6]);;}#[test]fn static_storage(){;let slice=slice_owned(Box::new(String::from( +"what")),|_|b"bytes boo");{;};{;};assert_eq!(&*slice,b"bytes boo");();}#[test]fn +slice_owned_the_slice(){;let slice=slice_owned(vec![1,2,3,4,5,6],Vec::as_slice); +let slice=slice_owned(slice,|s|&s[1..][..4]);;let slice=slice_owned(slice,|s|s); +let slice=slice_owned(slice,|s|&s[1..]);;assert_eq!(&*slice,&[1,2,3,4,5,6][1..][ +..4][1..]);;}#[test]fn slice_the_slice(){let slice=slice_owned(vec![1,2,3,4,5,6] +,Vec::as_slice).slice(|s|&s[1..][..4]).slice(|s|s).slice(|s|&s[1..]);;assert_eq! +(&*slice,&[1,2,3,4,5,6][1..][..4][1..]);();}#[test]fn try_and_fail(){();let res= +try_slice_owned(vec![0],|v|v.get(12..).ok_or(()));;assert!(res.is_err());}#[test +]fn boxed(){;let boxed:Box<[u8]>=vec![1,1,2,3,5,8,13,21].into_boxed_slice();;let +slice=slice_owned(boxed,Deref::deref);;assert_eq!(&*slice,[1,1,2,3,5,8,13,21]);} +#[test]fn drop_drops(){;let flag=Arc::new(AtomicBool::new(false));let flag_prime +=Arc::clone(&flag);3;;let d=defer(move||flag_prime.store(true,atomic::Ordering:: +Relaxed));;let slice=slice_owned(d,|_|&[]);assert_eq!(flag.load(atomic::Ordering +::Relaxed),false);;;drop(slice);assert_eq!(flag.load(atomic::Ordering::Relaxed), +true);;}#[test]fn send_sync(){crate::sync::assert_dyn_send::();crate +::sync::assert_dyn_sync::();let _=();if true{};if true{};if true{};} diff --git a/compiler/rustc_data_structures/src/packed.rs b/compiler/rustc_data_structures/src/packed.rs index b8d4b295dfa10..9bd0d76708d6d 100644 --- a/compiler/rustc_data_structures/src/packed.rs +++ b/compiler/rustc_data_structures/src/packed.rs @@ -1,71 +1,15 @@ -use crate::stable_hasher::{HashStable, StableHasher}; -use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; -use std::cmp::Ordering; -use std::fmt; - -#[repr(packed(8))] -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Pu128(pub u128); - -impl Pu128 { - #[inline] - pub fn get(self) -> u128 { - self.0 - } -} - -impl From for Pu128 { - #[inline] - fn from(value: u128) -> Self { - Self(value) - } -} - -impl PartialEq for Pu128 { - #[inline] - fn eq(&self, other: &u128) -> bool { - ({ self.0 }) == *other - } -} - -impl PartialOrd for Pu128 { - #[inline] - fn partial_cmp(&self, other: &u128) -> Option { - { self.0 }.partial_cmp(other) - } -} - -impl fmt::Display for Pu128 { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - { self.0 }.fmt(f) - } -} - -impl fmt::UpperHex for Pu128 { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - { self.0 }.fmt(f) - } -} - -impl HashStable for Pu128 { - #[inline] - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - { self.0 }.hash_stable(ctx, hasher) - } -} - -impl Encodable for Pu128 { - #[inline] - fn encode(&self, s: &mut S) { - { self.0 }.encode(s); - } -} - -impl Decodable for Pu128 { - #[inline] - fn decode(d: &mut D) -> Self { - Self(u128::decode(d)) - } -} +use crate::stable_hasher::{HashStable,StableHasher};use rustc_serialize::{//{;}; +Decodable,Decoder,Encodable,Encoder};use std:: cmp::Ordering;use std::fmt;#[repr +(packed(8))]#[derive(Copy,Clone,Debug,Hash,PartialEq,Eq,PartialOrd,Ord)]pub//(); +struct Pu128(pub u128);impl Pu128{#[inline]pub fn get(self)->u128{self.0}}impl// +Fromfor Pu128{#[inline]fn from(value:u128)->Self{((((Self(value)))))}}impl +PartialEqfor Pu128{#[inline]fn eq(&self,other:&u128)->bool{(({self.0}))==* +other}}impl PartialOrdfor Pu128{ #[inline]fn partial_cmp(&self,other:&u128 +)->Option{{self.0}.partial_cmp( other)}}impl fmt::Display for Pu128{#[ +inline]fn fmt(&self,f:&mut fmt::Formatter<'_> )->fmt::Result{({self.0}.fmt(f))}} +impl fmt::UpperHex for Pu128{#[inline]fn fmt (&self,f:&mut fmt::Formatter<'_>)-> +fmt::Result{((({self.0}.fmt(f))))}}implHashStablefor Pu128{#[inline]fn +hash_stable(&self,ctx:&mut CTX,hasher:&mut StableHasher){{self.0}.hash_stable(// +ctx,hasher)}}implEncodablefor Pu128{#[inline]fn encode(&self,s:&// +mut S){3;{self.0}.encode(s);3;}}implDecodablefor Pu128{#[inline]fn +decode(d:&mut D)->Self{(((((((((Self(((((((((u128::decode(d)))))))))))))))))))}} diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs index 2569684df3fc0..7b9fe07243686 100644 --- a/compiler/rustc_data_structures/src/profiling.rs +++ b/compiler/rustc_data_structures/src/profiling.rs @@ -1,925 +1,233 @@ -//! # Rust Compiler Self-Profiling -//! -//! This module implements the basic framework for the compiler's self- -//! profiling support. It provides the `SelfProfiler` type which enables -//! recording "events". An event is something that starts and ends at a given -//! point in time and has an ID and a kind attached to it. This allows for -//! tracing the compiler's activity. -//! -//! Internally this module uses the custom tailored [measureme][mm] crate for -//! efficiently recording events to disk in a compact format that can be -//! post-processed and analyzed by the suite of tools in the `measureme` -//! project. The highest priority for the tracing framework is on incurring as -//! little overhead as possible. -//! -//! -//! ## Event Overview -//! -//! Events have a few properties: -//! -//! - The `event_kind` designates the broad category of an event (e.g. does it -//! correspond to the execution of a query provider or to loading something -//! from the incr. comp. on-disk cache, etc). -//! - The `event_id` designates the query invocation or function call it -//! corresponds to, possibly including the query key or function arguments. -//! - Each event stores the ID of the thread it was recorded on. -//! - The timestamp stores beginning and end of the event, or the single point -//! in time it occurred at for "instant" events. -//! -//! -//! ## Event Filtering -//! -//! Event generation can be filtered by event kind. Recording all possible -//! events generates a lot of data, much of which is not needed for most kinds -//! of analysis. So, in order to keep overhead as low as possible for a given -//! use case, the `SelfProfiler` will only record the kinds of events that -//! pass the filter specified as a command line argument to the compiler. -//! -//! -//! ## `event_id` Assignment -//! -//! As far as `measureme` is concerned, `event_id`s are just strings. However, -//! it would incur too much overhead to generate and persist each `event_id` -//! string at the point where the event is recorded. In order to make this more -//! efficient `measureme` has two features: -//! -//! - Strings can share their content, so that re-occurring parts don't have to -//! be copied over and over again. One allocates a string in `measureme` and -//! gets back a `StringId`. This `StringId` is then used to refer to that -//! string. `measureme` strings are actually DAGs of string components so that -//! arbitrary sharing of substrings can be done efficiently. This is useful -//! because `event_id`s contain lots of redundant text like query names or -//! def-path components. -//! -//! - `StringId`s can be "virtual" which means that the client picks a numeric -//! ID according to some application-specific scheme and can later make that -//! ID be mapped to an actual string. This is used to cheaply generate -//! `event_id`s while the events actually occur, causing little timing -//! distortion, and then later map those `StringId`s, in bulk, to actual -//! `event_id` strings. This way the largest part of the tracing overhead is -//! localized to one contiguous chunk of time. -//! -//! How are these `event_id`s generated in the compiler? For things that occur -//! infrequently (e.g. "generic activities"), we just allocate the string the -//! first time it is used and then keep the `StringId` in a hash table. This -//! is implemented in `SelfProfiler::get_or_alloc_cached_string()`. -//! -//! For queries it gets more interesting: First we need a unique numeric ID for -//! each query invocation (the `QueryInvocationId`). This ID is used as the -//! virtual `StringId` we use as `event_id` for a given event. This ID has to -//! be available both when the query is executed and later, together with the -//! query key, when we allocate the actual `event_id` strings in bulk. -//! -//! We could make the compiler generate and keep track of such an ID for each -//! query invocation but luckily we already have something that fits all the -//! the requirements: the query's `DepNodeIndex`. So we use the numeric value -//! of the `DepNodeIndex` as `event_id` when recording the event and then, -//! just before the query context is dropped, we walk the entire query cache -//! (which stores the `DepNodeIndex` along with the query key for each -//! invocation) and allocate the corresponding strings together with a mapping -//! for `DepNodeIndex as StringId`. -//! -//! [mm]: https://github.com/rust-lang/measureme/ - -use crate::fx::FxHashMap; -use crate::outline; - -use std::borrow::Borrow; -use std::collections::hash_map::Entry; -use std::error::Error; -use std::fmt::Display; -use std::fs; -use std::intrinsics::unlikely; -use std::path::Path; -use std::process; -use std::sync::Arc; -use std::time::{Duration, Instant}; - -pub use measureme::EventId; -use measureme::{EventIdBuilder, Profiler, SerializableString, StringId}; -use parking_lot::RwLock; -use smallvec::SmallVec; - -bitflags::bitflags! { - #[derive(Clone, Copy)] - struct EventFilter: u16 { - const GENERIC_ACTIVITIES = 1 << 0; - const QUERY_PROVIDERS = 1 << 1; - const QUERY_CACHE_HITS = 1 << 2; - const QUERY_BLOCKED = 1 << 3; - const INCR_CACHE_LOADS = 1 << 4; - - const QUERY_KEYS = 1 << 5; - const FUNCTION_ARGS = 1 << 6; - const LLVM = 1 << 7; - const INCR_RESULT_HASHING = 1 << 8; - const ARTIFACT_SIZES = 1 << 9; - - const DEFAULT = Self::GENERIC_ACTIVITIES.bits() | - Self::QUERY_PROVIDERS.bits() | - Self::QUERY_BLOCKED.bits() | - Self::INCR_CACHE_LOADS.bits() | - Self::INCR_RESULT_HASHING.bits() | - Self::ARTIFACT_SIZES.bits(); - - const ARGS = Self::QUERY_KEYS.bits() | Self::FUNCTION_ARGS.bits(); - } -} - -// keep this in sync with the `-Z self-profile-events` help message in rustc_session/options.rs -const EVENT_FILTERS_BY_NAME: &[(&str, EventFilter)] = &[ - ("none", EventFilter::empty()), - ("all", EventFilter::all()), - ("default", EventFilter::DEFAULT), - ("generic-activity", EventFilter::GENERIC_ACTIVITIES), - ("query-provider", EventFilter::QUERY_PROVIDERS), - ("query-cache-hit", EventFilter::QUERY_CACHE_HITS), - ("query-blocked", EventFilter::QUERY_BLOCKED), - ("incr-cache-load", EventFilter::INCR_CACHE_LOADS), - ("query-keys", EventFilter::QUERY_KEYS), - ("function-args", EventFilter::FUNCTION_ARGS), - ("args", EventFilter::ARGS), - ("llvm", EventFilter::LLVM), - ("incr-result-hashing", EventFilter::INCR_RESULT_HASHING), - ("artifact-sizes", EventFilter::ARTIFACT_SIZES), -]; - -/// Something that uniquely identifies a query invocation. -pub struct QueryInvocationId(pub u32); - -/// Which format to use for `-Z time-passes` -#[derive(Clone, Copy, PartialEq, Hash, Debug)] -pub enum TimePassesFormat { - /// Emit human readable text - Text, - /// Emit structured JSON - Json, -} - -/// A reference to the SelfProfiler. It can be cloned and sent across thread -/// boundaries at will. -#[derive(Clone)] -pub struct SelfProfilerRef { - // This field is `None` if self-profiling is disabled for the current - // compilation session. - profiler: Option>, - - // We store the filter mask directly in the reference because that doesn't - // cost anything and allows for filtering with checking if the profiler is - // actually enabled. - event_filter_mask: EventFilter, - - // Print verbose generic activities to stderr. - print_verbose_generic_activities: Option, -} - -impl SelfProfilerRef { - pub fn new( - profiler: Option>, - print_verbose_generic_activities: Option, - ) -> 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 } - } - - /// This shim makes sure that calls only get executed if the filter mask - /// lets them pass. It also contains some trickery to make sure that - /// code is optimized for non-profiling compilation sessions, i.e. anything - /// past the filter check is never inlined so it doesn't clutter the fast - /// path. - #[inline(always)] - fn exec(&self, event_filter: EventFilter, f: F) -> TimingGuard<'_> - where - F: for<'a> FnOnce(&'a SelfProfiler) -> TimingGuard<'a>, - { - #[inline(never)] - #[cold] - fn cold_call(profiler_ref: &SelfProfilerRef, f: F) -> TimingGuard<'_> - where - F: for<'a> FnOnce(&'a SelfProfiler) -> TimingGuard<'a>, - { - let profiler = profiler_ref.profiler.as_ref().unwrap(); - f(profiler) - } - - if self.event_filter_mask.contains(event_filter) { - cold_call(self, f) - } else { - TimingGuard::none() - } - } - - /// 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 - /// stderr if the compiler is invoked with -Ztime-passes. - pub fn verbose_generic_activity(&self, event_label: &'static str) -> VerboseTimingGuard<'_> { - let message_and_format = - self.print_verbose_generic_activities.map(|format| (event_label.to_owned(), format)); - - VerboseTimingGuard::start(message_and_format, self.generic_activity(event_label)) - } - - /// Like `verbose_generic_activity`, but with an extra arg. - pub fn verbose_generic_activity_with_arg( - &self, - event_label: &'static str, - event_arg: A, - ) -> VerboseTimingGuard<'_> - where - A: Borrow + Into, - { - let message_and_format = self - .print_verbose_generic_activities - .map(|format| (format!("{}({})", event_label, event_arg.borrow()), format)); - - VerboseTimingGuard::start( - message_and_format, - self.generic_activity_with_arg(event_label, event_arg), - ) - } - - /// Start profiling a generic activity. Profiling continues until the - /// TimingGuard returned from this call is dropped. - #[inline(always)] - pub fn generic_activity(&self, event_label: &'static str) -> TimingGuard<'_> { - self.exec(EventFilter::GENERIC_ACTIVITIES, |profiler| { - let event_label = profiler.get_or_alloc_cached_string(event_label); - let event_id = EventId::from_label(event_label); - TimingGuard::start(profiler, profiler.generic_activity_event_kind, event_id) - }) - } - - /// Start profiling with some event filter for a given event. Profiling continues until the - /// TimingGuard returned from this call is dropped. - #[inline(always)] - pub fn generic_activity_with_event_id(&self, event_id: EventId) -> TimingGuard<'_> { - self.exec(EventFilter::GENERIC_ACTIVITIES, |profiler| { - TimingGuard::start(profiler, profiler.generic_activity_event_kind, event_id) - }) - } - - /// Start profiling a generic activity. Profiling continues until the - /// TimingGuard returned from this call is dropped. - #[inline(always)] - pub fn generic_activity_with_arg( - &self, - event_label: &'static str, - event_arg: A, - ) -> TimingGuard<'_> - where - A: Borrow + Into, - { - self.exec(EventFilter::GENERIC_ACTIVITIES, |profiler| { - let builder = EventIdBuilder::new(&profiler.profiler); - let event_label = profiler.get_or_alloc_cached_string(event_label); - let event_id = if profiler.event_filter_mask.contains(EventFilter::FUNCTION_ARGS) { - let event_arg = profiler.get_or_alloc_cached_string(event_arg); - builder.from_label_and_arg(event_label, event_arg) - } else { - builder.from_label(event_label) - }; - TimingGuard::start(profiler, profiler.generic_activity_event_kind, event_id) - }) - } - - /// Start profiling a generic activity, allowing costly arguments to be recorded. Profiling - /// continues until the `TimingGuard` returned from this call is dropped. - /// - /// If the arguments to a generic activity are cheap to create, use `generic_activity_with_arg` - /// or `generic_activity_with_args` for their simpler API. However, if they are costly or - /// require allocation in sufficiently hot contexts, then this allows for a closure to be called - /// only when arguments were asked to be recorded via `-Z self-profile-events=args`. - /// - /// In this case, the closure will be passed a `&mut EventArgRecorder`, to help with recording - /// one or many arguments within the generic activity being profiled, by calling its - /// `record_arg` method for example. - /// - /// This `EventArgRecorder` may implement more specific traits from other rustc crates, e.g. for - /// richer handling of rustc-specific argument types, while keeping this single entry-point API - /// for recording arguments. - /// - /// Note: recording at least one argument is *required* for the self-profiler to create the - /// `TimingGuard`. A panic will be triggered if that doesn't happen. This function exists - /// explicitly to record arguments, so it fails loudly when there are none to record. - /// - #[inline(always)] - pub fn generic_activity_with_arg_recorder( - &self, - event_label: &'static str, - mut f: F, - ) -> TimingGuard<'_> - where - F: FnMut(&mut EventArgRecorder<'_>), - { - // Ensure this event will only be recorded when self-profiling is turned on. - self.exec(EventFilter::GENERIC_ACTIVITIES, |profiler| { - let builder = EventIdBuilder::new(&profiler.profiler); - let event_label = profiler.get_or_alloc_cached_string(event_label); - - // Ensure the closure to create event arguments will only be called when argument - // recording is turned on. - let event_id = if profiler.event_filter_mask.contains(EventFilter::FUNCTION_ARGS) { - // Set up the builder and call the user-provided closure to record potentially - // costly event arguments. - let mut recorder = EventArgRecorder { profiler, args: SmallVec::new() }; - f(&mut recorder); - - // It is expected that the closure will record at least one argument. If that - // doesn't happen, it's a bug: we've been explicitly called in order to record - // arguments, so we fail loudly when there are none to record. - if recorder.args.is_empty() { - panic!( - "The closure passed to `generic_activity_with_arg_recorder` needs to \ +use crate::fx::FxHashMap;use crate::outline;use std::borrow::Borrow;use std:://; +collections::hash_map::Entry;use std::error::Error;use std::fmt::Display;use//3; +std::fs;use std::intrinsics::unlikely;use std::path::Path;use std::process;use// +std::sync::Arc;use std::time::{ Duration,Instant};pub use measureme::EventId;use +measureme::{EventIdBuilder,Profiler,SerializableString,StringId};use//if true{}; +parking_lot::RwLock;use smallvec::SmallVec;bitflags::bitflags!{#[derive(Clone,// +Copy)]struct EventFilter:u16{const GENERIC_ACTIVITIES=1<<0;const//if let _=(){}; +QUERY_PROVIDERS=1<<1;const QUERY_CACHE_HITS=1 <<2;const QUERY_BLOCKED=1<<3;const +INCR_CACHE_LOADS=1<<4;const QUERY_KEYS=1<<5;const FUNCTION_ARGS=1<<6;const//{;}; +LLVM=1<<7;const INCR_RESULT_HASHING=1<<8;const ARTIFACT_SIZES=1<<9;const//{();}; +DEFAULT=Self::GENERIC_ACTIVITIES.bits()|Self::QUERY_PROVIDERS.bits()|Self:://(); +QUERY_BLOCKED.bits()|Self::INCR_CACHE_LOADS.bits()|Self::INCR_RESULT_HASHING.//; +bits()|Self::ARTIFACT_SIZES.bits();const ARGS=Self::QUERY_KEYS.bits()|Self:://3; +FUNCTION_ARGS.bits();}}const EVENT_FILTERS_BY_NAME:&[(&str,EventFilter)]=&[(//3; +"none",(EventFilter::empty())),("all",EventFilter::all()),("default",EventFilter +::DEFAULT),(((((((("generic-activity"))) ,EventFilter::GENERIC_ACTIVITIES))))),( +"query-provider",EventFilter::QUERY_PROVIDERS) ,("query-cache-hit",EventFilter:: +QUERY_CACHE_HITS),((((((((("query-blocked")))),EventFilter::QUERY_BLOCKED))))),( +"incr-cache-load",EventFilter::INCR_CACHE_LOADS),((("query-keys")),EventFilter:: +QUERY_KEYS),(("function-args",EventFilter::FUNCTION_ARGS)),("args",EventFilter:: +ARGS),((((("llvm")),EventFilter:: LLVM))),(("incr-result-hashing"),EventFilter:: +INCR_RESULT_HASHING),(((("artifact-sizes"), EventFilter::ARTIFACT_SIZES))),];pub +struct QueryInvocationId(pub u32);#[derive (Clone,Copy,PartialEq,Hash,Debug)]pub +enum TimePassesFormat{Text,Json,}#[derive(Clone)]pub struct SelfProfilerRef{//3; +profiler:Option>,event_filter_mask:EventFilter,//loop{break;}; +print_verbose_generic_activities:Option,}impl SelfProfilerRef +{pub fn new(profiler :Option>,print_verbose_generic_activities +:Option,)->SelfProfilerRef{{;};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}}#[inline(always)]// +fn exec(&self,event_filter:EventFilter,f:F)->TimingGuard<'_>where F:for<'a>// +FnOnce(&'a SelfProfiler)->TimingGuard<'a>,{;#[inline(never)]#[cold]fn cold_call< +F>(profiler_ref:&SelfProfilerRef,f:F)->TimingGuard <'_>where F:for<'a>FnOnce(&'a +SelfProfiler)->TimingGuard<'a>,{{;};let profiler=profiler_ref.profiler.as_ref(). +unwrap();;f(profiler)}if self.event_filter_mask.contains(event_filter){cold_call +(self,f)}else{(((TimingGuard::none ())))}}pub fn verbose_generic_activity(&self, +event_label:&'static str)->VerboseTimingGuard<'_>{3;let message_and_format=self. +print_verbose_generic_activities.map(|format|(event_label.to_owned(),format));3; +VerboseTimingGuard::start(message_and_format, self.generic_activity(event_label) +)}pub fn verbose_generic_activity_with_arg(&self,event_label:&'static str,//; +event_arg:A,)->VerboseTimingGuard<'_>where A:Borrow+Into,{{();};let +message_and_format=self.print_verbose_generic_activities.map(|format|(format!(// +"{}({})",event_label,event_arg.borrow()),format));{;};VerboseTimingGuard::start( +message_and_format,(self.generic_activity_with_arg(event_label, event_arg)),)}#[ +inline(always)]pub fn generic_activity(&self,event_label:&'static str)->//{();}; +TimingGuard<'_>{self.exec(EventFilter::GENERIC_ACTIVITIES,|profiler|{((),());let +event_label=profiler.get_or_alloc_cached_string(event_label);();();let event_id= +EventId::from_label(event_label);if true{};TimingGuard::start(profiler,profiler. +generic_activity_event_kind,event_id)})}#[inline(always)]pub fn//*&*&();((),()); +generic_activity_with_event_id(&self,event_id:EventId)->TimingGuard<'_>{self.//; +exec(EventFilter::GENERIC_ACTIVITIES,|profiler|{TimingGuard::start(profiler,//3; +profiler.generic_activity_event_kind,event_id)})}#[inline(always)]pub fn//{();}; +generic_activity_with_arg(&self,event_label:&'static str,event_arg:A,)->//(); +TimingGuard<'_>where A:Borrow+Into,{self.exec(EventFilter:://{();}; +GENERIC_ACTIVITIES,|profiler|{((),());let builder=EventIdBuilder::new(&profiler. +profiler);;;let event_label=profiler.get_or_alloc_cached_string(event_label);let +event_id=if profiler.event_filter_mask.contains(EventFilter::FUNCTION_ARGS){;let +event_arg=profiler.get_or_alloc_cached_string(event_arg);*&*&();((),());builder. +from_label_and_arg(event_label,event_arg)}else {builder.from_label(event_label)} +;;TimingGuard::start(profiler,profiler.generic_activity_event_kind,event_id)})}# +[inline(always)]pub fn generic_activity_with_arg_recorder(&self,event_label: +&'static str,mut f:F,)->TimingGuard< '_>where F:FnMut(&mut EventArgRecorder<'_>) +,{self.exec(EventFilter::GENERIC_ACTIVITIES,|profiler|{loop{break;};let builder= +EventIdBuilder::new(&profiler.profiler);((),());*&*&();let event_label=profiler. +get_or_alloc_cached_string(event_label);((),());*&*&();let event_id=if profiler. +event_filter_mask.contains(EventFilter::FUNCTION_ARGS){((),());let mut recorder= +EventArgRecorder{profiler,args:SmallVec::new()};;;f(&mut recorder);;if recorder. +args.is_empty(){if let _=(){};if let _=(){};if let _=(){};*&*&();((),());panic!( +"The closure passed to `generic_activity_with_arg_recorder` needs to \ record at least one argument" - ); - } - - builder.from_label_and_args(event_label, &recorder.args) - } else { - builder.from_label(event_label) - }; - TimingGuard::start(profiler, profiler.generic_activity_event_kind, event_id) - }) - } - - /// Record the size of an artifact that the compiler produces - /// - /// `artifact_kind` is the class of artifact (e.g., query_cache, object_file, etc.) - /// `artifact_name` is an identifier to the specific artifact being stored (usually a filename) - #[inline(always)] - pub fn artifact_size(&self, artifact_kind: &str, artifact_name: A, size: u64) - where - A: Borrow + Into, - { - drop(self.exec(EventFilter::ARTIFACT_SIZES, |profiler| { - let builder = EventIdBuilder::new(&profiler.profiler); - let event_label = profiler.get_or_alloc_cached_string(artifact_kind); - let event_arg = profiler.get_or_alloc_cached_string(artifact_name); - let event_id = builder.from_label_and_arg(event_label, event_arg); - let thread_id = get_thread_id(); - - profiler.profiler.record_integer_event( - profiler.artifact_size_event_kind, - event_id, - thread_id, - size, - ); - - TimingGuard::none() - })) - } - - #[inline(always)] - pub fn generic_activity_with_args( - &self, - event_label: &'static str, - event_args: &[String], - ) -> TimingGuard<'_> { - self.exec(EventFilter::GENERIC_ACTIVITIES, |profiler| { - let builder = EventIdBuilder::new(&profiler.profiler); - let event_label = profiler.get_or_alloc_cached_string(event_label); - let event_id = if profiler.event_filter_mask.contains(EventFilter::FUNCTION_ARGS) { - let event_args: Vec<_> = event_args - .iter() - .map(|s| profiler.get_or_alloc_cached_string(&s[..])) - .collect(); - builder.from_label_and_args(event_label, &event_args) - } else { - builder.from_label(event_label) - }; - TimingGuard::start(profiler, profiler.generic_activity_event_kind, event_id) - }) - } - - /// Start profiling a query provider. Profiling continues until the - /// TimingGuard returned from this call is dropped. - #[inline(always)] - pub fn query_provider(&self) -> TimingGuard<'_> { - self.exec(EventFilter::QUERY_PROVIDERS, |profiler| { - TimingGuard::start(profiler, profiler.query_event_kind, EventId::INVALID) - }) - } - - /// Record a query in-memory cache hit. - #[inline(always)] - pub fn query_cache_hit(&self, query_invocation_id: QueryInvocationId) { - #[inline(never)] - #[cold] - fn cold_call(profiler_ref: &SelfProfilerRef, query_invocation_id: QueryInvocationId) { - profiler_ref.instant_query_event( - |profiler| profiler.query_cache_hit_event_kind, - query_invocation_id, - ); - } - - if unlikely(self.event_filter_mask.contains(EventFilter::QUERY_CACHE_HITS)) { - cold_call(self, query_invocation_id); - } - } - - /// Start profiling a query being blocked on a concurrent execution. - /// Profiling continues until the TimingGuard returned from this call is - /// dropped. - #[inline(always)] - pub fn query_blocked(&self) -> TimingGuard<'_> { - self.exec(EventFilter::QUERY_BLOCKED, |profiler| { - TimingGuard::start(profiler, profiler.query_blocked_event_kind, EventId::INVALID) - }) - } - - /// Start profiling how long it takes to load a query result from the - /// incremental compilation on-disk cache. Profiling continues until the - /// TimingGuard returned from this call is dropped. - #[inline(always)] - pub fn incr_cache_loading(&self) -> TimingGuard<'_> { - self.exec(EventFilter::INCR_CACHE_LOADS, |profiler| { - TimingGuard::start( - profiler, - profiler.incremental_load_result_event_kind, - EventId::INVALID, - ) - }) - } - - /// Start profiling how long it takes to hash query results for incremental compilation. - /// Profiling continues until the TimingGuard returned from this call is dropped. - #[inline(always)] - pub fn incr_result_hashing(&self) -> TimingGuard<'_> { - self.exec(EventFilter::INCR_RESULT_HASHING, |profiler| { - TimingGuard::start( - profiler, - profiler.incremental_result_hashing_event_kind, - EventId::INVALID, - ) - }) - } - - #[inline(always)] - fn instant_query_event( - &self, - event_kind: fn(&SelfProfiler) -> StringId, - query_invocation_id: QueryInvocationId, - ) { - let event_id = StringId::new_virtual(query_invocation_id.0); - let thread_id = get_thread_id(); - let profiler = self.profiler.as_ref().unwrap(); - profiler.profiler.record_instant_event( - event_kind(profiler), - EventId::from_virtual(event_id), - thread_id, - ); - } - - pub fn with_profiler(&self, f: impl FnOnce(&SelfProfiler)) { - if let Some(profiler) = &self.profiler { - f(profiler) - } - } - - /// Gets a `StringId` for the given string. This method makes sure that - /// any strings going through it will only be allocated once in the - /// profiling data. - /// Returns `None` if the self-profiling is not enabled. - pub fn get_or_alloc_cached_string(&self, s: &str) -> Option { - self.profiler.as_ref().map(|p| p.get_or_alloc_cached_string(s)) - } - - #[inline] - pub fn enabled(&self) -> bool { - self.profiler.is_some() - } - - #[inline] - pub fn llvm_recording_enabled(&self) -> bool { - self.event_filter_mask.contains(EventFilter::LLVM) - } - #[inline] - pub fn get_self_profiler(&self) -> Option> { - self.profiler.clone() - } -} - -/// A helper for recording costly arguments to self-profiling events. Used with -/// `SelfProfilerRef::generic_activity_with_arg_recorder`. -pub struct EventArgRecorder<'p> { - /// The `SelfProfiler` used to intern the event arguments that users will ask to record. - profiler: &'p SelfProfiler, - - /// The interned event arguments to be recorded in the generic activity event. - /// - /// The most common case, when actually recording event arguments, is to have one argument. Then - /// followed by recording two, in a couple places. - args: SmallVec<[StringId; 2]>, -} - -impl EventArgRecorder<'_> { - /// Records a single argument within the current generic activity being profiled. - /// - /// Note: when self-profiling with costly event arguments, at least one argument - /// needs to be recorded. A panic will be triggered if that doesn't happen. - pub fn record_arg(&mut self, event_arg: A) - where - A: Borrow + Into, - { - let event_arg = self.profiler.get_or_alloc_cached_string(event_arg); - self.args.push(event_arg); - } -} - -pub struct SelfProfiler { - profiler: Profiler, - event_filter_mask: EventFilter, - - string_cache: RwLock>, - - query_event_kind: StringId, - generic_activity_event_kind: StringId, - incremental_load_result_event_kind: StringId, - incremental_result_hashing_event_kind: StringId, - query_blocked_event_kind: StringId, - query_cache_hit_event_kind: StringId, - artifact_size_event_kind: StringId, -} - -impl SelfProfiler { - pub fn new( - output_directory: &Path, - crate_name: Option<&str>, - event_filters: Option<&[String]>, - counter_name: &str, - ) -> Result> { - fs::create_dir_all(output_directory)?; - - let crate_name = crate_name.unwrap_or("unknown-crate"); - // HACK(eddyb) we need to pad the PID, strange as it may seem, as its - // length can behave as a source of entropy for heap addresses, when - // ASLR is disabled and the heap is otherwise deterministic. - let pid: u32 = process::id(); - let filename = format!("{crate_name}-{pid:07}.rustc_profile"); - let path = output_directory.join(&filename); - let profiler = - Profiler::with_counter(&path, measureme::counters::Counter::by_name(counter_name)?)?; - - let query_event_kind = profiler.alloc_string("Query"); - let generic_activity_event_kind = profiler.alloc_string("GenericActivity"); - let incremental_load_result_event_kind = profiler.alloc_string("IncrementalLoadResult"); - let incremental_result_hashing_event_kind = - profiler.alloc_string("IncrementalResultHashing"); - let query_blocked_event_kind = profiler.alloc_string("QueryBlocked"); - let query_cache_hit_event_kind = profiler.alloc_string("QueryCacheHit"); - let artifact_size_event_kind = profiler.alloc_string("ArtifactSize"); - - let mut event_filter_mask = EventFilter::empty(); - - if let Some(event_filters) = event_filters { - let mut unknown_events = vec![]; - for item in event_filters { - if let Some(&(_, mask)) = - EVENT_FILTERS_BY_NAME.iter().find(|&(name, _)| name == item) - { - event_filter_mask |= mask; - } else { - unknown_events.push(item.clone()); - } - } - - // Warn about any unknown event names - if !unknown_events.is_empty() { - unknown_events.sort(); - unknown_events.dedup(); - - warn!( - "Unknown self-profiler events specified: {}. Available options are: {}.", - unknown_events.join(", "), - EVENT_FILTERS_BY_NAME - .iter() - .map(|&(name, _)| name.to_string()) - .collect::>() - .join(", ") - ); - } - } else { - event_filter_mask = EventFilter::DEFAULT; - } - - Ok(SelfProfiler { - profiler, - event_filter_mask, - string_cache: RwLock::new(FxHashMap::default()), - query_event_kind, - generic_activity_event_kind, - incremental_load_result_event_kind, - incremental_result_hashing_event_kind, - query_blocked_event_kind, - query_cache_hit_event_kind, - artifact_size_event_kind, - }) - } - - /// Allocates a new string in the profiling data. Does not do any caching - /// or deduplication. - pub fn alloc_string(&self, s: &STR) -> StringId { - self.profiler.alloc_string(s) - } - - /// Gets a `StringId` for the given string. This method makes sure that - /// any strings going through it will only be allocated once in the - /// profiling data. - pub fn get_or_alloc_cached_string(&self, s: A) -> StringId - where - A: Borrow + Into, - { - // Only acquire a read-lock first since we assume that the string is - // already present in the common case. - { - let string_cache = self.string_cache.read(); - - if let Some(&id) = string_cache.get(s.borrow()) { - return id; - } - } - - let mut string_cache = self.string_cache.write(); - // Check if the string has already been added in the small time window - // between dropping the read lock and acquiring the write lock. - match string_cache.entry(s.into()) { - Entry::Occupied(e) => *e.get(), - Entry::Vacant(e) => { - let string_id = self.profiler.alloc_string(&e.key()[..]); - *e.insert(string_id) - } - } - } - - pub fn map_query_invocation_id_to_string(&self, from: QueryInvocationId, to: StringId) { - let from = StringId::new_virtual(from.0); - self.profiler.map_virtual_to_concrete_string(from, to); - } - - pub fn bulk_map_query_invocation_id_to_single_string(&self, from: I, to: StringId) - where - I: Iterator + ExactSizeIterator, - { - let from = from.map(|qid| StringId::new_virtual(qid.0)); - self.profiler.bulk_map_virtual_to_single_concrete_string(from, to); - } - - pub fn query_key_recording_enabled(&self) -> bool { - self.event_filter_mask.contains(EventFilter::QUERY_KEYS) - } - - pub fn event_id_builder(&self) -> EventIdBuilder<'_> { - EventIdBuilder::new(&self.profiler) - } -} - -#[must_use] -pub struct TimingGuard<'a>(Option>); - -impl<'a> TimingGuard<'a> { - #[inline] - pub fn start( - profiler: &'a SelfProfiler, - event_kind: StringId, - event_id: EventId, - ) -> TimingGuard<'a> { - let thread_id = get_thread_id(); - let raw_profiler = &profiler.profiler; - let timing_guard = - raw_profiler.start_recording_interval_event(event_kind, event_id, thread_id); - TimingGuard(Some(timing_guard)) - } - - #[inline] - pub fn finish_with_query_invocation_id(self, query_invocation_id: QueryInvocationId) { - if let Some(guard) = self.0 { - outline(|| { - let event_id = StringId::new_virtual(query_invocation_id.0); - let event_id = EventId::from_virtual(event_id); - guard.finish_with_override_event_id(event_id); - }); - } - } - - #[inline] - pub fn none() -> TimingGuard<'a> { - TimingGuard(None) - } - - #[inline(always)] - pub fn run(self, f: impl FnOnce() -> R) -> R { - let _timer = self; - f() - } -} - -struct VerboseInfo { - start_time: Instant, - start_rss: Option, - message: String, - format: TimePassesFormat, -} - -#[must_use] -pub struct VerboseTimingGuard<'a> { - info: Option, - _guard: TimingGuard<'a>, -} - -impl<'a> VerboseTimingGuard<'a> { - pub fn start( - message_and_format: Option<(String, TimePassesFormat)>, - _guard: TimingGuard<'a>, - ) -> Self { - VerboseTimingGuard { - _guard, - info: message_and_format.map(|(message, format)| VerboseInfo { - start_time: Instant::now(), - start_rss: get_resident_set_size(), - message, - format, - }), - } - } - - #[inline(always)] - pub fn run(self, f: impl FnOnce() -> R) -> R { - let _timer = self; - f() - } -} - -impl Drop for VerboseTimingGuard<'_> { - fn drop(&mut self) { - if let Some(info) = &self.info { - let end_rss = get_resident_set_size(); - let dur = info.start_time.elapsed(); - print_time_passes_entry(&info.message, dur, info.start_rss, end_rss, info.format); - } - } -} - -struct JsonTimePassesEntry<'a> { - pass: &'a str, - time: f64, - start_rss: Option, - end_rss: Option, -} - -impl Display for JsonTimePassesEntry<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let Self { pass: what, time, start_rss, end_rss } = self; - write!(f, r#"{{"pass":"{what}","time":{time},"rss_start":"#).unwrap(); - match start_rss { - Some(rss) => write!(f, "{rss}")?, - None => write!(f, "null")?, - } - write!(f, r#","rss_end":"#)?; - match end_rss { - Some(rss) => write!(f, "{rss}")?, - None => write!(f, "null")?, - } - write!(f, "}}")?; - Ok(()) - } -} - -pub fn print_time_passes_entry( - what: &str, - dur: Duration, - start_rss: Option, - end_rss: Option, - format: TimePassesFormat, -) { - match format { - TimePassesFormat::Json => { - let entry = - JsonTimePassesEntry { pass: what, time: dur.as_secs_f64(), start_rss, end_rss }; - - eprintln!(r#"time: {entry}"#); - return; - } - TimePassesFormat::Text => (), - } - - // 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; - - let mem_string = match (start_rss, end_rss) { - (Some(start_rss), Some(end_rss)) => { - let change_rss = end_rss as i128 - start_rss as i128; - - format!( - "; rss: {:>4}MB -> {:>4}MB ({:>+5}MB)", - rss_to_mb(start_rss), - rss_to_mb(end_rss), - rss_change_to_mb(change_rss), - ) - } - (Some(start_rss), None) => format!("; rss start: {:>4}MB", rss_to_mb(start_rss)), - (None, Some(end_rss)) => format!("; rss end: {:>4}MB", rss_to_mb(end_rss)), - (None, None) => String::new(), - }; - - eprintln!("time: {:>7}{}\t{}", duration_to_secs_str(dur), mem_string, what); -} - -// Hack up our own formatting for the duration to make it easier for scripts -// to parse (always use the same number of decimal places and the same unit). -pub fn duration_to_secs_str(dur: std::time::Duration) -> String { - format!("{:.3}", dur.as_secs_f64()) -} - -fn get_thread_id() -> u32 { - std::thread::current().id().as_u64().get() as u32 -} - -// Memory reporting -cfg_match! { - cfg(windows) => { - pub fn get_resident_set_size() -> Option { - use std::mem; - - use windows::{ - Win32::System::ProcessStatus::{K32GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS}, - Win32::System::Threading::GetCurrentProcess, - }; - - let mut pmc = PROCESS_MEMORY_COUNTERS::default(); - let pmc_size = mem::size_of_val(&pmc); - unsafe { - K32GetProcessMemoryInfo( - GetCurrentProcess(), - &mut pmc, - pmc_size as u32, - ) - } - .ok() - .ok()?; - - Some(pmc.WorkingSetSize) - } - } - cfg(target_os = "macos") => { - pub fn get_resident_set_size() -> Option { - use libc::{c_int, c_void, getpid, proc_pidinfo, proc_taskinfo, PROC_PIDTASKINFO}; - use std::mem; - const PROC_TASKINFO_SIZE: c_int = mem::size_of::() as c_int; - - unsafe { - let mut info: proc_taskinfo = mem::zeroed(); - let info_ptr = &mut info as *mut proc_taskinfo as *mut c_void; - let pid = getpid() as c_int; - let ret = proc_pidinfo(pid, PROC_PIDTASKINFO, 0, info_ptr, PROC_TASKINFO_SIZE); - if ret == PROC_TASKINFO_SIZE { - Some(info.pti_resident_size as usize) - } else { - None - } - } - } - } - cfg(unix) => { - pub fn get_resident_set_size() -> Option { - let field = 1; - let contents = fs::read("/proc/self/statm").ok()?; - let contents = String::from_utf8(contents).ok()?; - let s = contents.split_whitespace().nth(field)?; - let npages = s.parse::().ok()?; - Some(npages * 4096) - } - } - _ => { - pub fn get_resident_set_size() -> Option { - None - } - } -} - -#[cfg(test)] -mod tests; +);((),());}builder.from_label_and_args(event_label,&recorder.args)}else{builder. +from_label(event_label)};let _=();let _=();TimingGuard::start(profiler,profiler. +generic_activity_event_kind,event_id)})}#[ inline(always)]pub fn artifact_size(&self,artifact_kind:&str,artifact_name:A,size:u64)where A:Borrow+Into,{drop(self.exec(EventFilter::ARTIFACT_SIZES,|profiler|{({});let builder= +EventIdBuilder::new(&profiler.profiler);((),());*&*&();let event_label=profiler. +get_or_alloc_cached_string(artifact_kind);((),());*&*&();let event_arg=profiler. +get_or_alloc_cached_string(artifact_name);let _=();((),());let event_id=builder. +from_label_and_arg(event_label,event_arg);3;3;let thread_id=get_thread_id();3;3; +profiler.profiler.record_integer_event(profiler.artifact_size_event_kind,//({}); +event_id,thread_id,size,);((),());TimingGuard::none()}))}#[inline(always)]pub fn +generic_activity_with_args(&self,event_label:&'static str,event_args:&[String], +)->TimingGuard<'_>{self.exec(EventFilter::GENERIC_ACTIVITIES,|profiler|{({});let +builder=EventIdBuilder::new(&profiler.profiler);{;};();let event_label=profiler. +get_or_alloc_cached_string(event_label);((),());*&*&();let event_id=if profiler. +event_filter_mask.contains(EventFilter::FUNCTION_ARGS){();let event_args:Vec<_>= +event_args.iter().map(|s|profiler.get_or_alloc_cached_string( &s[..])).collect() +;3;builder.from_label_and_args(event_label,&event_args)}else{builder.from_label( +event_label)};;TimingGuard::start(profiler,profiler.generic_activity_event_kind, +event_id)})}#[inline(always)]pub fn query_provider(&self)->TimingGuard<'_>{self +.exec(EventFilter::QUERY_PROVIDERS,|profiler|{TimingGuard::start(profiler,//{;}; +profiler.query_event_kind,EventId::INVALID)})}#[inline(always)]pub fn//let _=(); +query_cache_hit(&self,query_invocation_id:QueryInvocationId){;#[inline(never)]#[ +cold]fn cold_call(profiler_ref:&SelfProfilerRef,query_invocation_id://if true{}; +QueryInvocationId){let _=();profiler_ref.instant_query_event(|profiler|profiler. +query_cache_hit_event_kind,query_invocation_id,);*&*&();}{();};if unlikely(self. +event_filter_mask.contains(EventFilter::QUERY_CACHE_HITS)){{();};cold_call(self, +query_invocation_id);let _=||();}}#[inline(always)]pub fn query_blocked(&self)-> +TimingGuard<'_>{self.exec(EventFilter::QUERY_BLOCKED,|profiler|{TimingGuard:://; +start(profiler,profiler.query_blocked_event_kind,EventId::INVALID)})}#[inline(// +always)]pub fn incr_cache_loading(&self) ->TimingGuard<'_>{self.exec(EventFilter +::INCR_CACHE_LOADS,|profiler|{TimingGuard::start(profiler,profiler.//let _=||(); +incremental_load_result_event_kind,EventId::INVALID,)}) }#[inline(always)]pub fn +incr_result_hashing(&self)->TimingGuard<'_>{self.exec(EventFilter:://let _=||(); +INCR_RESULT_HASHING,|profiler|{TimingGuard::start(profiler,profiler.//if true{}; +incremental_result_hashing_event_kind,EventId::INVALID,)})}#[inline(always)]fn// +instant_query_event(&self,event_kind:fn(&SelfProfiler)->StringId,//loop{break;}; +query_invocation_id:QueryInvocationId,){({});let event_id=StringId::new_virtual( +query_invocation_id.0);;let thread_id=get_thread_id();let profiler=self.profiler +.as_ref().unwrap();;profiler.profiler.record_instant_event(event_kind(profiler), +EventId::from_virtual(event_id),thread_id,);3;}pub fn with_profiler(&self,f:impl +FnOnce(&SelfProfiler)){if let Some(profiler)= &self.profiler{f(profiler)}}pub fn +get_or_alloc_cached_string(&self,s:&str)->Option{self.profiler.//({}); +as_ref().map(|p|p.get_or_alloc_cached_string(s) )}#[inline]pub fn enabled(&self) +->bool{(self.profiler.is_some())}#[inline]pub fn llvm_recording_enabled(&self)-> +bool{((((self.event_filter_mask.contains(EventFilter:: LLVM)))))}#[inline]pub fn +get_self_profiler(&self)->Option>{(self.profiler.clone())}}pub +struct EventArgRecorder<'p>{profiler:&'p SelfProfiler,args:SmallVec<[StringId;2 +]>,}impl EventArgRecorder<'_>{pub fn record_arg(&mut self,event_arg:A)where// +A:Borrow+Into,{loop{break};loop{break};let event_arg=self.profiler. +get_or_alloc_cached_string(event_arg);3;;self.args.push(event_arg);;}}pub struct +SelfProfiler{profiler:Profiler,event_filter_mask:EventFilter,string_cache://{;}; +RwLock>,query_event_kind:StringId,//((),());let _=(); +generic_activity_event_kind:StringId,incremental_load_result_event_kind://{();}; +StringId,incremental_result_hashing_event_kind:StringId,//let _=||();let _=||(); +query_blocked_event_kind:StringId,query_cache_hit_event_kind:StringId,//((),()); +artifact_size_event_kind:StringId,}impl SelfProfiler{pub fn new(//if let _=(){}; +output_directory:&Path,crate_name:Option<&str >,event_filters:Option<&[String]>, +counter_name:&str,)->Result>{let _=();fs:: +create_dir_all(output_directory)?;({});({});let crate_name=crate_name.unwrap_or( +"unknown-crate");{;};{;};let pid:u32=process::id();{;};{;};let filename=format!( +"{crate_name}-{pid:07}.rustc_profile");;let path=output_directory.join(&filename +);();();let profiler=Profiler::with_counter(&path,measureme::counters::Counter:: +by_name(counter_name)?)?;;;let query_event_kind=profiler.alloc_string("Query");; +let generic_activity_event_kind=profiler.alloc_string("GenericActivity");3;3;let +incremental_load_result_event_kind=profiler.alloc_string(//if true{};let _=||(); +"IncrementalLoadResult");3;3;let incremental_result_hashing_event_kind=profiler. +alloc_string("IncrementalResultHashing");;let query_blocked_event_kind=profiler. +alloc_string("QueryBlocked");{();};({});let query_cache_hit_event_kind=profiler. +alloc_string("QueryCacheHit");{();};{();};let artifact_size_event_kind=profiler. +alloc_string("ArtifactSize");;;let mut event_filter_mask=EventFilter::empty();if +let Some(event_filters)=event_filters{;let mut unknown_events=vec![];for item in +event_filters{if let Some(&(_,mask))=(EVENT_FILTERS_BY_NAME.iter()).find(|&(name +,_)|name==item){;event_filter_mask|=mask;}else{unknown_events.push(item.clone()) +;;}}if!unknown_events.is_empty(){;unknown_events.sort();;unknown_events.dedup(); +warn! ("Unknown self-profiler events specified: {}. Available options are: {}.", +unknown_events.join(", "),EVENT_FILTERS_BY_NAME.iter().map(|&(name,_)|name.//(); +to_string()).collect::>().join(", "));({});}}else{({});event_filter_mask= +EventFilter::DEFAULT;3;}Ok(SelfProfiler{profiler,event_filter_mask,string_cache: +RwLock::new(FxHashMap::default( )),query_event_kind,generic_activity_event_kind, +incremental_load_result_event_kind,incremental_result_hashing_event_kind,//({}); +query_blocked_event_kind,query_cache_hit_event_kind,artifact_size_event_kind ,}) +}pub fn alloc_string(&self,s:&STR)->StringId{//3; +self.profiler.alloc_string(s)}pub fn get_or_alloc_cached_string(&self,s:A)-> +StringId where A:Borrow+Into,{{;let string_cache=self.string_cache. +read();3;if let Some(&id)=string_cache.get(s.borrow()){3;return id;3;}}3;let mut +string_cache=self.string_cache.write();;match string_cache.entry(s.into()){Entry +::Occupied(e)=>*e.get(),Entry::Vacant(e)=>{let _=();let string_id=self.profiler. +alloc_string(&e.key()[..]);loop{break};loop{break};*e.insert(string_id)}}}pub fn +map_query_invocation_id_to_string(&self,from:QueryInvocationId,to:StringId){;let +from=StringId::new_virtual(from.0);((),());((),());*&*&();((),());self.profiler. +map_virtual_to_concrete_string(from,to);((),());((),());((),());let _=();}pub fn +bulk_map_query_invocation_id_to_single_string(&self, from:I,to:StringId)where +I:Iterator+ExactSizeIterator,{();let from=from.map(|qid| +StringId::new_virtual(qid.0));let _=();let _=();let _=();let _=();self.profiler. +bulk_map_virtual_to_single_concrete_string(from,to);if true{};let _=||();}pub fn +query_key_recording_enabled(&self)->bool{self.event_filter_mask.contains(//({}); +EventFilter::QUERY_KEYS)}pub fn event_id_builder(&self)->EventIdBuilder<'_>{//3; +EventIdBuilder::new(((&self.profiler)))} }#[must_use]pub struct TimingGuard<'a>( +Option>);impl<'a>TimingGuard<'a>{#[inline]pub fn//(); +start(profiler:&'a SelfProfiler,event_kind:StringId,event_id:EventId,)->//{();}; +TimingGuard<'a>{();let thread_id=get_thread_id();3;3;let raw_profiler=&profiler. +profiler;({});({});let timing_guard=raw_profiler.start_recording_interval_event( +event_kind,event_id,thread_id);3;TimingGuard(Some(timing_guard))}#[inline]pub fn +finish_with_query_invocation_id(self,query_invocation_id:QueryInvocationId){if// +let Some(guard)=self.0{{();};outline(||{({});let event_id=StringId::new_virtual( +query_invocation_id.0);3;3;let event_id=EventId::from_virtual(event_id);;;guard. +finish_with_override_event_id(event_id);{();};});({});}}#[inline]pub fn none()-> +TimingGuard<'a>{((TimingGuard(None)))}#[inline(always)]pub fn run(self,f:impl +FnOnce()->R)->R{();let _timer=self;3;f()}}struct VerboseInfo{start_time:Instant, +start_rss:Option,message:String,format:TimePassesFormat,}#[must_use]pub// +struct VerboseTimingGuard<'a>{info:Option< VerboseInfo>,_guard:TimingGuard<'a>,} +impl<'a>VerboseTimingGuard<'a>{pub fn start(message_and_format:Option<(String,// +TimePassesFormat)>,_guard:TimingGuard<'a>,)->Self{VerboseTimingGuard{_guard,//3; +info:message_and_format.map(|(message,format)|VerboseInfo{start_time:Instant::// +now(),start_rss:(get_resident_set_size()),message,format ,}),}}#[inline(always)] +pub fn run(self,f:impl FnOnce()->R)->R{3;let _timer=self;3;f()}}impl Drop for +VerboseTimingGuard<'_>{fn drop(&mut self){if let Some(info)=&self.info{{();};let +end_rss=get_resident_set_size();{;};{;};let dur=info.start_time.elapsed();();(); +print_time_passes_entry(&info.message,dur,info.start_rss,end_rss,info.format);;} +}}struct JsonTimePassesEntry<'a>{pass:&'a str,time:f64,start_rss:Option, +end_rss:Option,}impl Display for JsonTimePassesEntry<'_>{fn fmt(&self,f: +&mut std::fmt::Formatter<'_>)->std::fmt::Result{((),());let Self{pass:what,time, +start_rss,end_rss}=self;loop{break};loop{break};let _=||();loop{break};write!(f, +r#"{{"pass":"{what}","time":{time},"rss_start":"#).unwrap();{;};match start_rss{ +Some(rss)=>write!(f,"{rss}")?,None=>write!(f,"null")?,}((),());((),());write!(f, +r#","rss_end":"#)?;3;match end_rss{Some(rss)=>write!(f,"{rss}")?,None=>write!(f, +"null")?,};write!(f,"}}")?;Ok(())}}pub fn print_time_passes_entry(what:&str,dur: +Duration,start_rss:Option,end_rss :Option,format:TimePassesFormat, +){match format{TimePassesFormat::Json=>{;let entry=JsonTimePassesEntry{pass:what +,time:dur.as_secs_f64(),start_rss,end_rss};;eprintln!(r#"time: {entry}"#);return +;3;}TimePassesFormat::Text=>(),};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( +){3;return;3;};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;3;;let mem_string= +match(start_rss,end_rss){(Some(start_rss),Some(end_rss))=>{{();};let change_rss= +end_rss as i128-start_rss as i128;let _=();if true{};let _=();if true{};format!( +"; rss: {:>4}MB -> {:>4}MB ({:>+5}MB)",rss_to_mb(start_rss) ,rss_to_mb(end_rss), +rss_change_to_mb(change_rss),)}(Some(start_rss),None)=>format!(//*&*&();((),()); +"; rss start: {:>4}MB",rss_to_mb(start_rss)),(None,Some(end_rss))=>format!(//(); +"; rss end: {:>4}MB",rss_to_mb(end_rss)),(None,None)=>String::new(),};;eprintln! +("time: {:>7}{}\t{}",duration_to_secs_str(dur),mem_string,what);let _=();}pub fn +duration_to_secs_str(dur:std::time::Duration)->String{format!("{:.3}",dur.//{;}; +as_secs_f64())}fn get_thread_id()->u32{ std::thread::current().id().as_u64().get +()as u32}cfg_match!{cfg(windows )=>{pub fn get_resident_set_size()->Option{use std::mem;use windows::{Win32::System::ProcessStatus::{//let _=();let _=(); +K32GetProcessMemoryInfo,PROCESS_MEMORY_COUNTERS},Win32::System::Threading:://(); +GetCurrentProcess,};let mut pmc =PROCESS_MEMORY_COUNTERS::default();let pmc_size +=mem::size_of_val(&pmc); unsafe{K32GetProcessMemoryInfo(GetCurrentProcess(),&mut +pmc,pmc_size as u32,)}.ok().ok()?;Some(pmc.WorkingSetSize)}}cfg(target_os=//{;}; +"macos")=>{pub fn get_resident_set_size()->Option{use libc::{c_int,//{;}; +c_void,getpid,proc_pidinfo,proc_taskinfo,PROC_PIDTASKINFO};use std::mem;const//; +PROC_TASKINFO_SIZE:c_int=mem::size_of:: ()as c_int;unsafe{let mut +info:proc_taskinfo=mem::zeroed();let info_ptr=&mut info as*mut proc_taskinfo//3; +as*mut c_void;let pid=getpid()as c_int;let ret=proc_pidinfo(pid,//if let _=(){}; +PROC_PIDTASKINFO,0,info_ptr,PROC_TASKINFO_SIZE) ;if ret==PROC_TASKINFO_SIZE{Some +(info.pti_resident_size as usize)}else{None}}}}cfg(unix)=>{pub fn//loop{break;}; +get_resident_set_size()->Option{let field=1;let contents=fs::read(//({}); +"/proc/self/statm").ok()?;let contents=String:: from_utf8(contents).ok()?;let s= +contents.split_whitespace().nth(field)?;let npages=s.parse::().ok()?;//3; +Some(npages*4096)}}_=>{pub fn get_resident_set_size()->Option{None}}}#[// +cfg(test)]mod tests;//if let _=(){};*&*&();((),());if let _=(){};*&*&();((),()); diff --git a/compiler/rustc_data_structures/src/profiling/tests.rs b/compiler/rustc_data_structures/src/profiling/tests.rs index 2b09de085da06..e626ec9f4b1c6 100644 --- a/compiler/rustc_data_structures/src/profiling/tests.rs +++ b/compiler/rustc_data_structures/src/profiling/tests.rs @@ -1,19 +1,7 @@ -use super::JsonTimePassesEntry; - -#[test] -fn with_rss() { - let entry = - JsonTimePassesEntry { pass: "typeck", time: 56.1, start_rss: Some(10), end_rss: Some(20) }; - - assert_eq!(entry.to_string(), r#"{"pass":"typeck","time":56.1,"rss_start":10,"rss_end":20}"#) -} - -#[test] -fn no_rss() { - let entry = JsonTimePassesEntry { pass: "typeck", time: 56.1, start_rss: None, end_rss: None }; - - assert_eq!( - entry.to_string(), - r#"{"pass":"typeck","time":56.1,"rss_start":null,"rss_end":null}"# - ) -} +use super::JsonTimePassesEntry;#[test]fn with_rss(){let _=();let _=();let entry= +JsonTimePassesEntry{pass:"typeck",time:56.1,start_rss: Some(10),end_rss:Some(20) +};loop{break};loop{break};loop{break};loop{break;};assert_eq!(entry.to_string(), +r#"{"pass":"typeck","time":56.1,"rss_start":10,"rss_end":20}"#)}#[test]fn//({}); +no_rss(){3;let entry=JsonTimePassesEntry{pass:"typeck",time:56.1,start_rss:None, +end_rss:None};let _=();let _=();let _=();if true{};assert_eq!(entry.to_string(), +r#"{"pass":"typeck","time":56.1,"rss_start":null,"rss_end":null}"#)}//if true{}; diff --git a/compiler/rustc_data_structures/src/sharded.rs b/compiler/rustc_data_structures/src/sharded.rs index 4b02b18346069..f43566d650461 100644 --- a/compiler/rustc_data_structures/src/sharded.rs +++ b/compiler/rustc_data_structures/src/sharded.rs @@ -1,243 +1,58 @@ -use crate::fx::{FxHashMap, FxHasher}; -#[cfg(parallel_compiler)] -use crate::sync::{is_dyn_thread_safe, CacheAligned}; -use crate::sync::{Lock, LockGuard, Mode}; -#[cfg(parallel_compiler)] -use either::Either; -use std::borrow::Borrow; -use std::collections::hash_map::RawEntryMut; -use std::hash::{Hash, Hasher}; -use std::iter; -use std::mem; - -// 32 shards is sufficient to reduce contention on an 8-core Ryzen 7 1700, -// but this should be tested on higher core count CPUs. How the `Sharded` type gets used -// may also affect the ideal number of shards. -const SHARD_BITS: usize = 5; - -#[cfg(parallel_compiler)] -const SHARDS: usize = 1 << SHARD_BITS; - -/// An array of cache-line aligned inner locked structures with convenience methods. -/// A single field is used when the compiler uses only one thread. -pub enum Sharded { - Single(Lock), - #[cfg(parallel_compiler)] - Shards(Box<[CacheAligned>; SHARDS]>), -} - -impl Default for Sharded { - #[inline] - fn default() -> Self { - Self::new(T::default) - } -} - -impl Sharded { - #[inline] - pub fn new(mut value: impl FnMut() -> T) -> Self { - #[cfg(parallel_compiler)] - if is_dyn_thread_safe() { - return Sharded::Shards(Box::new( - [(); SHARDS].map(|()| CacheAligned(Lock::new(value()))), - )); - } - - Sharded::Single(Lock::new(value())) - } - - /// The shard is selected by hashing `val` with `FxHasher`. - #[inline] - pub fn get_shard_by_value(&self, _val: &K) -> &Lock { - match self { - Self::Single(single) => single, - #[cfg(parallel_compiler)] - Self::Shards(..) => self.get_shard_by_hash(make_hash(_val)), - } - } - - #[inline] - pub fn get_shard_by_hash(&self, hash: u64) -> &Lock { - self.get_shard_by_index(get_shard_hash(hash)) - } - - #[inline] - pub fn get_shard_by_index(&self, _i: usize) -> &Lock { - match self { - Self::Single(single) => single, - #[cfg(parallel_compiler)] - Self::Shards(shards) => { - // SAFETY: The index gets ANDed with the shard mask, ensuring it is always inbounds. - unsafe { &shards.get_unchecked(_i & (SHARDS - 1)).0 } - } - } - } - - /// The shard is selected by hashing `val` with `FxHasher`. - #[inline] - #[track_caller] - pub fn lock_shard_by_value(&self, _val: &K) -> LockGuard<'_, T> { - match self { - Self::Single(single) => { - // Synchronization is disabled so use the `lock_assume_no_sync` method optimized - // for that case. - - // SAFETY: We know `is_dyn_thread_safe` was false when creating the lock thus - // `might_be_dyn_thread_safe` was also false. - unsafe { single.lock_assume(Mode::NoSync) } - } - #[cfg(parallel_compiler)] - Self::Shards(..) => self.lock_shard_by_hash(make_hash(_val)), - } - } - - #[inline] - #[track_caller] - pub fn lock_shard_by_hash(&self, hash: u64) -> LockGuard<'_, T> { - self.lock_shard_by_index(get_shard_hash(hash)) - } - - #[inline] - #[track_caller] - pub fn lock_shard_by_index(&self, _i: usize) -> LockGuard<'_, T> { - match self { - Self::Single(single) => { - // Synchronization is disabled so use the `lock_assume_no_sync` method optimized - // for that case. - - // SAFETY: We know `is_dyn_thread_safe` was false when creating the lock thus - // `might_be_dyn_thread_safe` was also false. - unsafe { single.lock_assume(Mode::NoSync) } - } - #[cfg(parallel_compiler)] - Self::Shards(shards) => { - // Synchronization is enabled so use the `lock_assume_sync` method optimized - // for that case. - - // SAFETY (get_unchecked): The index gets ANDed with the shard mask, ensuring it is - // always inbounds. - // SAFETY (lock_assume_sync): We know `is_dyn_thread_safe` was true when creating - // the lock thus `might_be_dyn_thread_safe` was also true. - unsafe { shards.get_unchecked(_i & (SHARDS - 1)).0.lock_assume(Mode::Sync) } - } - } - } - - #[inline] - pub fn lock_shards(&self) -> impl Iterator> { - match self { - #[cfg(not(parallel_compiler))] - Self::Single(single) => iter::once(single.lock()), - #[cfg(parallel_compiler)] - Self::Single(single) => Either::Left(iter::once(single.lock())), - #[cfg(parallel_compiler)] - Self::Shards(shards) => Either::Right(shards.iter().map(|shard| shard.0.lock())), - } - } - - #[inline] - pub fn try_lock_shards(&self) -> impl Iterator>> { - match self { - #[cfg(not(parallel_compiler))] - Self::Single(single) => iter::once(single.try_lock()), - #[cfg(parallel_compiler)] - Self::Single(single) => Either::Left(iter::once(single.try_lock())), - #[cfg(parallel_compiler)] - Self::Shards(shards) => Either::Right(shards.iter().map(|shard| shard.0.try_lock())), - } - } -} - -#[inline] -pub fn shards() -> usize { - #[cfg(parallel_compiler)] - if is_dyn_thread_safe() { - return SHARDS; - } - - 1 -} - -pub type ShardedHashMap = Sharded>; - -impl ShardedHashMap { - pub fn len(&self) -> usize { - self.lock_shards().map(|shard| shard.len()).sum() - } -} - -impl ShardedHashMap { - #[inline] - pub fn intern_ref(&self, value: &Q, make: impl FnOnce() -> K) -> K - where - K: Borrow, - Q: Hash + Eq, - { - let hash = make_hash(value); - let mut shard = self.lock_shard_by_hash(hash); - let entry = shard.raw_entry_mut().from_key_hashed_nocheck(hash, value); - - match entry { - RawEntryMut::Occupied(e) => *e.key(), - RawEntryMut::Vacant(e) => { - let v = make(); - e.insert_hashed_nocheck(hash, v, ()); - v - } - } - } - - #[inline] - pub fn intern(&self, value: Q, make: impl FnOnce(Q) -> K) -> K - where - K: Borrow, - Q: Hash + Eq, - { - let hash = make_hash(&value); - let mut shard = self.lock_shard_by_hash(hash); - let entry = shard.raw_entry_mut().from_key_hashed_nocheck(hash, &value); - - match entry { - RawEntryMut::Occupied(e) => *e.key(), - RawEntryMut::Vacant(e) => { - let v = make(value); - e.insert_hashed_nocheck(hash, v, ()); - v - } - } - } -} - -pub trait IntoPointer { - /// Returns a pointer which outlives `self`. - fn into_pointer(&self) -> *const (); -} - -impl ShardedHashMap { - pub fn contains_pointer_to(&self, value: &T) -> bool { - let hash = make_hash(&value); - let shard = self.lock_shard_by_hash(hash); - let value = value.into_pointer(); - shard.raw_entry().from_hash(hash, |entry| entry.into_pointer() == value).is_some() - } -} - -#[inline] -pub fn make_hash(val: &K) -> u64 { - let mut state = FxHasher::default(); - val.hash(&mut state); - state.finish() -} - -/// Get a shard with a pre-computed hash value. If `get_shard_by_value` is -/// ever used in combination with `get_shard_by_hash` on a single `Sharded` -/// instance, then `hash` must be computed with `FxHasher`. Otherwise, -/// `hash` can be computed with any hasher, so long as that hasher is used -/// consistently for each `Sharded` instance. -#[inline] -fn get_shard_hash(hash: u64) -> usize { - let hash_len = mem::size_of::(); - // Ignore the top 7 bits as hashbrown uses these and get the next SHARD_BITS highest bits. - // hashbrown also uses the lowest bits, so we can't use those - (hash >> (hash_len * 8 - 7 - SHARD_BITS)) as usize -} +use crate::fx::{FxHashMap,FxHasher};# [cfg(parallel_compiler)]use crate::sync::{ +is_dyn_thread_safe,CacheAligned};use crate::sync::{Lock,LockGuard,Mode};#[cfg(// +parallel_compiler)]use either::Either;use std::borrow::Borrow;use std:://*&*&(); +collections::hash_map::RawEntryMut;use std::hash::{Hash,Hasher};use std::iter;// +use std::mem;const SHARD_BITS:usize=((5));#[cfg(parallel_compiler)]const SHARDS: +usize=1<{Single(Lock),#[cfg(parallel_compiler +)]Shards(Box<[CacheAligned>;SHARDS]>),}implDefault for//({}); +Sharded{#[inline]fn default()->Self{ Self::new(T::default)}}implSharded +{#[inline]pub fn new(mut value:impl FnMut()->T)->Self{#[cfg(parallel_compiler)] +if is_dyn_thread_safe(){{;};return Sharded::Shards(Box::new([();SHARDS].map(|()| +CacheAligned(Lock::new(value()))),));{;};}Sharded::Single(Lock::new(value()))}#[ +inline]pub fn get_shard_by_value(&self,_val:&K)->&Lock{match// +self{Self::Single(single)=>single,#[cfg(parallel_compiler)]Self::Shards(..)=>//; +self.get_shard_by_hash((make_hash(_val))), }}#[inline]pub fn get_shard_by_hash(& +self,hash:u64)->&Lock{self .get_shard_by_index(get_shard_hash(hash))}#[inline +]pub fn get_shard_by_index(&self,_i:usize)->&Lock{match self{Self::Single(//; +single)=>single,#[cfg(parallel_compiler)]Self ::Shards(shards)=>{unsafe{&shards. +get_unchecked(((_i&(((((SHARDS-((1)))))))))).0}}}}#[inline]#[track_caller]pub fn +lock_shard_by_value(&self,_val:&K)->LockGuard<'_,T>{match self{// +Self::Single(single)=>{unsafe{(((((single.lock_assume(Mode::NoSync))))))}}#[cfg( +parallel_compiler)]Self::Shards(..)=>self .lock_shard_by_hash(make_hash(_val)),} +}#[inline]#[track_caller]pub fn lock_shard_by_hash(&self,hash:u64)->LockGuard{(self.lock_shard_by_index(get_shard_hash( hash)))}#[inline]#[track_caller] +pub fn lock_shard_by_index(&self,_i:usize)->LockGuard<'_,T>{match self{Self:://; +Single(single)=>{unsafe{((((((((single.lock_assume(Mode::NoSync)))))))))}}#[cfg( +parallel_compiler)]Self::Shards(shards)=>{unsafe{shards.get_unchecked(_i&(//{;}; +SHARDS-((1)))).0.lock_assume(Mode::Sync)}}}}#[inline]pub fn lock_shards(&self)-> +impl Iterator>{match self{#[cfg(not(parallel_compiler))]//; +Self::Single(single)=>iter::once(single. lock()),#[cfg(parallel_compiler)]Self:: +Single(single)=>Either::Left(iter::once( single.lock())),#[cfg(parallel_compiler +)]Self::Shards(shards)=>Either::Right(shards.iter() .map(|shard|shard.0.lock())) +,}}#[inline]pub fn try_lock_shards( &self)->impl Iterator>>{match self{#[cfg(not(parallel_compiler))]Self::Single(single)=>iter:://; +once(single.try_lock()),#[ cfg(parallel_compiler)]Self::Single(single)=>Either:: +Left(((iter::once((single.try_lock()))))),#[cfg(parallel_compiler)]Self::Shards( +shards)=>(Either::Right(((shards.iter()).map(|shard|shard.0.try_lock())))),}}}#[ +inline]pub fn shards()->usize{#[cfg(parallel_compiler)]if is_dyn_thread_safe(){; +return SHARDS;;}1}pub type ShardedHashMap=Sharded>;implShardedHashMap{pub fn len(&self)->usize{(self.lock_shards()).map(|shard| +shard.len()).sum()}}implShardedHashMap{#[inline]pub fn//3; +intern_ref(&self,value:&Q,make: impl FnOnce()->K)->K where K:Borrow +,Q:Hash+Eq,{3;let hash=make_hash(value);;;let mut shard=self.lock_shard_by_hash( +hash);;let entry=shard.raw_entry_mut().from_key_hashed_nocheck(hash,value);match +entry{RawEntryMut::Occupied(e)=>*e.key(),RawEntryMut::Vacant(e)=>{3;let v=make() +;;e.insert_hashed_nocheck(hash,v,());v}}}#[inline]pub fn intern(&self,value:Q +,make:impl FnOnce(Q)->K)->K where K:Borrow,Q:Hash+Eq,{();let hash=make_hash(& +value);{;};();let mut shard=self.lock_shard_by_hash(hash);();();let entry=shard. +raw_entry_mut().from_key_hashed_nocheck(hash,&value);3;match entry{RawEntryMut:: +Occupied(e)=>*e.key(),RawEntryMut::Vacant(e)=>{({});let v=make(value);{;};{;};e. +insert_hashed_nocheck(hash,v,());();v}}}}pub trait IntoPointer{fn into_pointer(& +self)->*const();}implShardedHashMap{pub fn//3; +contains_pointer_to(&self,value:&T)->bool{let _=();let hash= +make_hash(&value);3;3;let shard=self.lock_shard_by_hash(hash);;;let value=value. +into_pointer();();shard.raw_entry().from_hash(hash,|entry|entry.into_pointer()== +value).is_some()}}#[inline]pub fn make_hash(val:&K)->u64{;let mut +state=FxHasher::default();();3;val.hash(&mut state);3;state.finish()}#[inline]fn +get_shard_hash(hash:u64)->usize{3;let hash_len=mem::size_of::();;(hash>>( +hash_len*((((((((((((8))))))))))))-(((((((((((7)))))))))))-SHARD_BITS))as usize} diff --git a/compiler/rustc_data_structures/src/sip128.rs b/compiler/rustc_data_structures/src/sip128.rs index 4a0ed87f77c84..52af3d8e2d6b4 100644 --- a/compiler/rustc_data_structures/src/sip128.rs +++ b/compiler/rustc_data_structures/src/sip128.rs @@ -1,500 +1,87 @@ -//! This is a copy of `core::hash::sip` adapted to providing 128 bit hashes. - -use std::hash::Hasher; -use std::mem::{self, MaybeUninit}; -use std::ptr; - -#[cfg(test)] -mod tests; - -// The SipHash algorithm operates on 8-byte chunks. -const ELEM_SIZE: usize = mem::size_of::(); - -// Size of the buffer in number of elements, not including the spill. -// -// The selection of this size was guided by rustc-perf benchmark comparisons of -// different buffer sizes. It should be periodically reevaluated as the compiler -// implementation and input characteristics change. -// -// Using the same-sized buffer for everything we hash is a performance versus -// complexity tradeoff. The ideal buffer size, and whether buffering should even -// be used, depends on what is being hashed. It may be worth it to size the -// buffer appropriately (perhaps by making SipHasher128 generic over the buffer -// size) or disable buffering depending on what is being hashed. But at this -// time, we use the same buffer size for everything. -const BUFFER_CAPACITY: usize = 8; - -// Size of the buffer in bytes, not including the spill. -const BUFFER_SIZE: usize = BUFFER_CAPACITY * ELEM_SIZE; - -// Size of the buffer in number of elements, including the spill. -const BUFFER_WITH_SPILL_CAPACITY: usize = BUFFER_CAPACITY + 1; - -// Size of the buffer in bytes, including the spill. -const BUFFER_WITH_SPILL_SIZE: usize = BUFFER_WITH_SPILL_CAPACITY * ELEM_SIZE; - -// Index of the spill element in the buffer. -const BUFFER_SPILL_INDEX: usize = BUFFER_WITH_SPILL_CAPACITY - 1; - -#[derive(Debug, Clone)] -#[repr(C)] -pub struct SipHasher128 { - // The access pattern during hashing consists of accesses to `nbuf` and - // `buf` until the buffer is full, followed by accesses to `state` and - // `processed`, and then repetition of that pattern until hashing is done. - // This is the basis for the ordering of fields below. However, in practice - // the cache miss-rate for data access is extremely low regardless of order. - nbuf: usize, // how many bytes in buf are valid - buf: [MaybeUninit; BUFFER_WITH_SPILL_CAPACITY], // unprocessed bytes le - state: State, // hash State - processed: usize, // how many bytes we've processed -} - -#[derive(Debug, Clone, Copy)] -#[repr(C)] -struct State { - // v0, v2 and v1, v3 show up in pairs in the algorithm, - // and simd implementations of SipHash will use vectors - // of v02 and v13. By placing them in this order in the struct, - // the compiler can pick up on just a few simd optimizations by itself. - v0: u64, - v2: u64, - v1: u64, - v3: u64, -} - -macro_rules! compress { - ($state:expr) => {{ compress!($state.v0, $state.v1, $state.v2, $state.v3) }}; - ($v0:expr, $v1:expr, $v2:expr, $v3:expr) => {{ - $v0 = $v0.wrapping_add($v1); - $v1 = $v1.rotate_left(13); - $v1 ^= $v0; - $v0 = $v0.rotate_left(32); - $v2 = $v2.wrapping_add($v3); - $v3 = $v3.rotate_left(16); - $v3 ^= $v2; - $v0 = $v0.wrapping_add($v3); - $v3 = $v3.rotate_left(21); - $v3 ^= $v0; - $v2 = $v2.wrapping_add($v1); - $v1 = $v1.rotate_left(17); - $v1 ^= $v2; - $v2 = $v2.rotate_left(32); - }}; -} - -// Copies up to 8 bytes from source to destination. This performs better than -// `ptr::copy_nonoverlapping` on microbenchmarks and may perform better on real -// workloads since all of the copies have fixed sizes and avoid calling memcpy. -// -// This is specifically designed for copies of up to 8 bytes, because that's the -// maximum of number bytes needed to fill an 8-byte-sized element on which -// SipHash operates. Note that for variable-sized copies which are known to be -// less than 8 bytes, this function will perform more work than necessary unless -// the compiler is able to optimize the extra work away. -#[inline] -unsafe fn copy_nonoverlapping_small(src: *const u8, dst: *mut u8, count: usize) { - debug_assert!(count <= 8); - - unsafe { - if count == 8 { - ptr::copy_nonoverlapping(src, dst, 8); - return; - } - - let mut i = 0; - if i + 3 < count { - ptr::copy_nonoverlapping(src.add(i), dst.add(i), 4); - i += 4; - } - - if i + 1 < count { - ptr::copy_nonoverlapping(src.add(i), dst.add(i), 2); - i += 2 - } - - if i < count { - *dst.add(i) = *src.add(i); - i += 1; - } - - debug_assert_eq!(i, count); - } -} - -// # Implementation -// -// This implementation uses buffering to reduce the hashing cost for inputs -// consisting of many small integers. Buffering simplifies the integration of -// integer input--the integer write function typically just appends to the -// buffer with a statically sized write, updates metadata, and returns. -// -// Buffering also prevents alternating between writes that do and do not trigger -// the hashing process. Only when the entire buffer is full do we transition -// into hashing. This allows us to keep the hash state in registers for longer, -// instead of loading and storing it before and after processing each element. -// -// When a write fills the buffer, a buffer processing function is invoked to -// hash all of the buffered input. The buffer processing functions are marked -// `#[inline(never)]` so that they aren't inlined into the append functions, -// which ensures the more frequently called append functions remain inlineable -// and don't include register pushing/popping that would only be made necessary -// by inclusion of the complex buffer processing path which uses those -// registers. -// -// The buffer includes a "spill"--an extra element at the end--which simplifies -// the integer write buffer processing path. The value that fills the buffer can -// be written with a statically sized write that may spill over into the spill. -// After the buffer is processed, the part of the value that spilled over can be -// written from the spill to the beginning of the buffer with another statically -// sized write. This write may copy more bytes than actually spilled over, but -// we maintain the metadata such that any extra copied bytes will be ignored by -// subsequent processing. Due to the static sizes, this scheme performs better -// than copying the exact number of bytes needed into the end and beginning of -// the buffer. -// -// The buffer is uninitialized, which improves performance, but may preclude -// efficient implementation of alternative approaches. The improvement is not so -// large that an alternative approach should be disregarded because it cannot be -// efficiently implemented with an uninitialized buffer. On the other hand, an -// uninitialized buffer may become more important should a larger one be used. -// -// # Platform Dependence -// -// The SipHash algorithm operates on byte sequences. It parses the input stream -// as 8-byte little-endian integers. Therefore, given the same byte sequence, it -// produces the same result on big- and little-endian hardware. -// -// However, the Hasher trait has methods which operate on multi-byte integers. -// How they are converted into byte sequences can be endian-dependent (by using -// native byte order) or independent (by consistently using either LE or BE byte -// order). It can also be `isize` and `usize` size dependent (by using the -// native size), or independent (by converting to a common size), supposing the -// values can be represented in 32 bits. -// -// In order to make `SipHasher128` consistent with `SipHasher` in libstd, we -// choose to do the integer to byte sequence conversion in the platform- -// dependent way. Clients can achieve platform-independent hashing by widening -// `isize` and `usize` integers to 64 bits on 32-bit systems and byte-swapping -// integers on big-endian systems before passing them to the writing functions. -// This causes the input byte sequence to look identical on big- and little- -// endian systems (supposing `isize` and `usize` values can be represented in 32 -// bits), which ensures platform-independent results. -impl SipHasher128 { - #[inline] - pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher128 { - let mut hasher = SipHasher128 { - nbuf: 0, - buf: MaybeUninit::uninit_array(), - state: State { - v0: key0 ^ 0x736f6d6570736575, - // The XOR with 0xee is only done on 128-bit algorithm version. - v1: key1 ^ (0x646f72616e646f6d ^ 0xee), - v2: key0 ^ 0x6c7967656e657261, - v3: key1 ^ 0x7465646279746573, - }, - processed: 0, - }; - - unsafe { - // Initialize spill because we read from it in `short_write_process_buffer`. - *hasher.buf.get_unchecked_mut(BUFFER_SPILL_INDEX) = MaybeUninit::zeroed(); - } - - hasher - } - - #[inline] - pub fn short_write(&mut self, bytes: [u8; LEN]) { - let nbuf = self.nbuf; - debug_assert!(LEN <= 8); - debug_assert!(nbuf < BUFFER_SIZE); - debug_assert!(nbuf + LEN < BUFFER_WITH_SPILL_SIZE); - - if nbuf + LEN < BUFFER_SIZE { - unsafe { - // The memcpy call is optimized away because the size is known. - let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf); - ptr::copy_nonoverlapping(bytes.as_ptr(), dst, LEN); - } - - self.nbuf = nbuf + LEN; - - return; - } - - unsafe { self.short_write_process_buffer(bytes) } - } - - // A specialized write function for values with size <= 8 that should only - // be called when the write would cause the buffer to fill. - // - // SAFETY: the write of `x` into `self.buf` starting at byte offset - // `self.nbuf` must cause `self.buf` to become fully initialized (and not - // overflow) if it wasn't already. - #[inline(never)] - unsafe fn short_write_process_buffer(&mut self, bytes: [u8; LEN]) { - unsafe { - let nbuf = self.nbuf; - debug_assert!(LEN <= 8); - debug_assert!(nbuf < BUFFER_SIZE); - debug_assert!(nbuf + LEN >= BUFFER_SIZE); - debug_assert!(nbuf + LEN < BUFFER_WITH_SPILL_SIZE); - - // Copy first part of input into end of buffer, possibly into spill - // element. The memcpy call is optimized away because the size is known. - let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf); - ptr::copy_nonoverlapping(bytes.as_ptr(), dst, LEN); - - // Process buffer. - for i in 0..BUFFER_CAPACITY { - let elem = self.buf.get_unchecked(i).assume_init().to_le(); - self.state.v3 ^= elem; - Sip13Rounds::c_rounds(&mut self.state); - self.state.v0 ^= elem; - } - - // Copy remaining input into start of buffer by copying LEN - 1 - // elements from spill (at most LEN - 1 bytes could have overflowed - // into the spill). The memcpy call is optimized away because the size - // is known. And the whole copy is optimized away for LEN == 1. - let dst = self.buf.as_mut_ptr() as *mut u8; - let src = self.buf.get_unchecked(BUFFER_SPILL_INDEX) as *const _ as *const u8; - ptr::copy_nonoverlapping(src, dst, LEN - 1); - - // This function should only be called when the write fills the buffer. - // Therefore, when LEN == 1, the new `self.nbuf` must be zero. - // LEN is statically known, so the branch is optimized away. - self.nbuf = if LEN == 1 { 0 } else { nbuf + LEN - BUFFER_SIZE }; - self.processed += BUFFER_SIZE; - } - } - - // A write function for byte slices. - #[inline] - fn slice_write(&mut self, msg: &[u8]) { - let length = msg.len(); - let nbuf = self.nbuf; - debug_assert!(nbuf < BUFFER_SIZE); - - if nbuf + length < BUFFER_SIZE { - unsafe { - let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf); - - if length <= 8 { - copy_nonoverlapping_small(msg.as_ptr(), dst, length); - } else { - // This memcpy is *not* optimized away. - ptr::copy_nonoverlapping(msg.as_ptr(), dst, length); - } - } - - self.nbuf = nbuf + length; - - return; - } - - unsafe { self.slice_write_process_buffer(msg) } - } - - // A write function for byte slices that should only be called when the - // write would cause the buffer to fill. - // - // SAFETY: `self.buf` must be initialized up to the byte offset `self.nbuf`, - // and `msg` must contain enough bytes to initialize the rest of the element - // containing the byte offset `self.nbuf`. - #[inline(never)] - unsafe fn slice_write_process_buffer(&mut self, msg: &[u8]) { - unsafe { - let length = msg.len(); - let nbuf = self.nbuf; - debug_assert!(nbuf < BUFFER_SIZE); - debug_assert!(nbuf + length >= BUFFER_SIZE); - - // Always copy first part of input into current element of buffer. - // This function should only be called when the write fills the buffer, - // so we know that there is enough input to fill the current element. - let valid_in_elem = nbuf % ELEM_SIZE; - let needed_in_elem = ELEM_SIZE - valid_in_elem; - - let src = msg.as_ptr(); - let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf); - copy_nonoverlapping_small(src, dst, needed_in_elem); - - // Process buffer. - - // Using `nbuf / ELEM_SIZE + 1` rather than `(nbuf + needed_in_elem) / - // ELEM_SIZE` to show the compiler that this loop's upper bound is > 0. - // We know that is true, because last step ensured we have a full - // element in the buffer. - let last = nbuf / ELEM_SIZE + 1; - - for i in 0..last { - let elem = self.buf.get_unchecked(i).assume_init().to_le(); - self.state.v3 ^= elem; - Sip13Rounds::c_rounds(&mut self.state); - self.state.v0 ^= elem; - } - - // Process the remaining element-sized chunks of input. - let mut processed = needed_in_elem; - let input_left = length - processed; - let elems_left = input_left / ELEM_SIZE; - let extra_bytes_left = input_left % ELEM_SIZE; - - for _ in 0..elems_left { - let elem = (msg.as_ptr().add(processed) as *const u64).read_unaligned().to_le(); - self.state.v3 ^= elem; - Sip13Rounds::c_rounds(&mut self.state); - self.state.v0 ^= elem; - processed += ELEM_SIZE; - } - - // Copy remaining input into start of buffer. - let src = msg.as_ptr().add(processed); - let dst = self.buf.as_mut_ptr() as *mut u8; - copy_nonoverlapping_small(src, dst, extra_bytes_left); - - self.nbuf = extra_bytes_left; - self.processed += nbuf + processed; - } - } - - #[inline] - pub fn finish128(mut self) -> (u64, u64) { - debug_assert!(self.nbuf < BUFFER_SIZE); - - // Process full elements in buffer. - let last = self.nbuf / ELEM_SIZE; - - // Since we're consuming self, avoid updating members for a potential - // performance gain. - let mut state = self.state; - - for i in 0..last { - let elem = unsafe { self.buf.get_unchecked(i).assume_init().to_le() }; - state.v3 ^= elem; - Sip13Rounds::c_rounds(&mut state); - state.v0 ^= elem; - } - - // Get remaining partial element. - let elem = if self.nbuf % ELEM_SIZE != 0 { - unsafe { - // Ensure element is initialized by writing zero bytes. At most - // `ELEM_SIZE - 1` are required given the above check. It's safe - // to write this many because we have the spill and we maintain - // `self.nbuf` such that this write will start before the spill. - let dst = (self.buf.as_mut_ptr() as *mut u8).add(self.nbuf); - ptr::write_bytes(dst, 0, ELEM_SIZE - 1); - self.buf.get_unchecked(last).assume_init().to_le() - } - } else { - 0 - }; - - // Finalize the hash. - let length = self.processed + self.nbuf; - let b: u64 = ((length as u64 & 0xff) << 56) | elem; - - state.v3 ^= b; - Sip13Rounds::c_rounds(&mut state); - state.v0 ^= b; - - state.v2 ^= 0xee; - Sip13Rounds::d_rounds(&mut state); - let _0 = state.v0 ^ state.v1 ^ state.v2 ^ state.v3; - - state.v1 ^= 0xdd; - Sip13Rounds::d_rounds(&mut state); - let _1 = state.v0 ^ state.v1 ^ state.v2 ^ state.v3; - - (_0, _1) - } -} - -impl Hasher for SipHasher128 { - #[inline] - fn write_u8(&mut self, i: u8) { - self.short_write(i.to_ne_bytes()); - } - - #[inline] - fn write_u16(&mut self, i: u16) { - self.short_write(i.to_ne_bytes()); - } - - #[inline] - fn write_u32(&mut self, i: u32) { - self.short_write(i.to_ne_bytes()); - } - - #[inline] - fn write_u64(&mut self, i: u64) { - self.short_write(i.to_ne_bytes()); - } - - #[inline] - fn write_usize(&mut self, i: usize) { - self.short_write(i.to_ne_bytes()); - } - - #[inline] - fn write_i8(&mut self, i: i8) { - self.short_write((i as u8).to_ne_bytes()); - } - - #[inline] - fn write_i16(&mut self, i: i16) { - self.short_write((i as u16).to_ne_bytes()); - } - - #[inline] - fn write_i32(&mut self, i: i32) { - self.short_write((i as u32).to_ne_bytes()); - } - - #[inline] - fn write_i64(&mut self, i: i64) { - self.short_write((i as u64).to_ne_bytes()); - } - - #[inline] - fn write_isize(&mut self, i: isize) { - self.short_write((i as usize).to_ne_bytes()); - } - - #[inline] - fn write(&mut self, msg: &[u8]) { - self.slice_write(msg); - } - - #[inline] - fn write_str(&mut self, s: &str) { - // This hasher works byte-wise, and `0xFF` cannot show up in a `str`, - // so just hashing the one extra byte is enough to be prefix-free. - self.write(s.as_bytes()); - self.write_u8(0xFF); - } - - fn finish(&self) -> u64 { - panic!("SipHasher128 cannot provide valid 64 bit hashes") - } -} - -#[derive(Debug, Clone, Default)] -struct Sip13Rounds; - -impl Sip13Rounds { - #[inline] - fn c_rounds(state: &mut State) { - compress!(state); - } - - #[inline] - fn d_rounds(state: &mut State) { - compress!(state); - compress!(state); - compress!(state); - } -} +use std::hash::Hasher;use std::mem::{self ,MaybeUninit};use std::ptr;#[cfg(test) +]mod tests;const ELEM_SIZE:usize=(mem ::size_of::());const BUFFER_CAPACITY: +usize=((((8))));const BUFFER_SIZE :usize=((((BUFFER_CAPACITY*ELEM_SIZE))));const +BUFFER_WITH_SPILL_CAPACITY:usize=BUFFER_CAPACITY+ 1;const BUFFER_WITH_SPILL_SIZE +:usize=((BUFFER_WITH_SPILL_CAPACITY*ELEM_SIZE)) ;const BUFFER_SPILL_INDEX:usize= +BUFFER_WITH_SPILL_CAPACITY-((((1))));#[derive(Debug, Clone)]#[repr(C)]pub struct +SipHasher128{nbuf:usize,buf:[ MaybeUninit;BUFFER_WITH_SPILL_CAPACITY],state +:State,processed:usize,}#[derive(Debug,Clone,Copy)]#[repr(C)]struct State{v0://; +u64,v2:u64,v1:u64,v3:u64,}macro_rules!compress{($state:expr)=>{{compress!($//(); +state.v0,$state.v1,$state.v2,$state.v3)}} ;($v0:expr,$v1:expr,$v2:expr,$v3:expr) +=>{{$v0=$v0.wrapping_add($v1);$v1=$v1.rotate_left(13);$v1^=$v0;$v0=$v0.//*&*&(); +rotate_left(32);$v2=$v2.wrapping_add($v3);$ v3=$v3.rotate_left(16);$v3^=$v2;$v0= +$v0.wrapping_add($v3);$v3=$v3.rotate_left(21 );$v3^=$v0;$v2=$v2.wrapping_add($v1 +);$v1=$v1.rotate_left(17);$v1^=$v2;$v2=$v2.rotate_left(32);}};}#[inline]unsafe// +fn copy_nonoverlapping_small(src:*const u8,dst:*mut u8,count:usize){loop{break}; +debug_assert!(count<=8);;unsafe{if count==8{ptr::copy_nonoverlapping(src,dst,8); +return;;}let mut i=0;if i+3SipHasher128{;let +mut hasher=SipHasher128{nbuf:(0),buf:MaybeUninit::uninit_array(),state:State{v0: +key0^((0x736f6d6570736575)),v1:(key1^((((0x646f72616e646f6d)^(0xee))))),v2:key0^ +0x6c7967656e657261,v3:key1^0x7465646279746573,},processed:0,};3;unsafe{;*hasher. +buf.get_unchecked_mut(BUFFER_SPILL_INDEX)=MaybeUninit::zeroed();{();};}hasher}#[ +inline]pub fn short_write(&mut self,bytes:[u8;LEN]){3;let nbuf= +self.nbuf;;;debug_assert!(LEN<=8);debug_assert!(nbuf(& +mut self,bytes:[u8;LEN]){unsafe{3;let nbuf=self.nbuf;3;;debug_assert!(LEN<=8);;; +debug_assert!(nbuf=BUFFER_SIZE);();3; +debug_assert!(nbuf+LEN= +BUFFER_SIZE);3;;let valid_in_elem=nbuf%ELEM_SIZE;;;let needed_in_elem=ELEM_SIZE- +valid_in_elem;;let src=msg.as_ptr();let dst=(self.buf.as_mut_ptr()as*mut u8).add +(nbuf);();3;copy_nonoverlapping_small(src,dst,needed_in_elem);3;3;let last=nbuf/ +ELEM_SIZE+1;;for i in 0..last{;let elem=self.buf.get_unchecked(i).assume_init(). +to_le();;;self.state.v3^=elem;Sip13Rounds::c_rounds(&mut self.state);self.state. +v0^=elem;;};let mut processed=needed_in_elem;let input_left=length-processed;let +elems_left=input_left/ELEM_SIZE;;let extra_bytes_left=input_left%ELEM_SIZE;for _ +in 0..elems_left{loop{break};let elem=(msg.as_ptr().add(processed)as*const u64). +read_unaligned().to_le();;;self.state.v3^=elem;;Sip13Rounds::c_rounds(&mut self. +state);;;self.state.v0^=elem;;;processed+=ELEM_SIZE;;};let src=msg.as_ptr().add( +processed);;let dst=self.buf.as_mut_ptr()as*mut u8;copy_nonoverlapping_small(src +,dst,extra_bytes_left);();3;self.nbuf=extra_bytes_left;3;3;self.processed+=nbuf+ +processed;;}}#[inline]pub fn finish128(mut self)->(u64,u64){;debug_assert!(self. +nbufu64{panic!( +"SipHasher128 cannot provide valid 64 bit hashes")}}#[derive(Debug,Clone,//({}); +Default)]struct Sip13Rounds;impl Sip13Rounds{#[inline]fn c_rounds(state:&mut//3; +State){;compress!(state);}#[inline]fn d_rounds(state:&mut State){compress!(state +);let _=();let _=();compress!(state);((),());((),());compress!(state);((),());}} diff --git a/compiler/rustc_data_structures/src/sip128/tests.rs b/compiler/rustc_data_structures/src/sip128/tests.rs index e9dd0f1176b91..92afeb31ecdb2 100644 --- a/compiler/rustc_data_structures/src/sip128/tests.rs +++ b/compiler/rustc_data_structures/src/sip128/tests.rs @@ -1,304 +1,139 @@ -use super::*; - -use std::hash::Hash; - -// Hash just the bytes of the slice, without length prefix -struct Bytes<'a>(&'a [u8]); - -impl<'a> Hash for Bytes<'a> { - #[allow(unused_must_use)] - fn hash(&self, state: &mut H) { - for byte in self.0 { - state.write_u8(*byte); - } - } -} - -fn hash_with(mut st: SipHasher128, x: &T) -> (u64, u64) { - x.hash(&mut st); - st.finish128() -} - -fn hash(x: &T) -> (u64, u64) { - hash_with(SipHasher128::new_with_keys(0, 0), x) -} -#[rustfmt::skip] -const TEST_VECTOR: [[u8; 16]; 64] = [ - [0xe7, 0x7e, 0xbc, 0xb2, 0x27, 0x88, 0xa5, 0xbe, 0xfd, 0x62, 0xdb, 0x6a, 0xdd, 0x30, 0x30, 0x01], - [0xfc, 0x6f, 0x37, 0x04, 0x60, 0xd3, 0xed, 0xa8, 0x5e, 0x05, 0x73, 0xcc, 0x2b, 0x2f, 0xf0, 0x63], - [0x75, 0x78, 0x7f, 0x09, 0x05, 0x69, 0x83, 0x9b, 0x85, 0x5b, 0xc9, 0x54, 0x8c, 0x6a, 0xea, 0x95], - [0x6b, 0xc5, 0xcc, 0xfa, 0x1e, 0xdc, 0xf7, 0x9f, 0x48, 0x23, 0x18, 0x77, 0x12, 0xeb, 0xd7, 0x43], - [0x0c, 0x78, 0x4e, 0x71, 0xac, 0x2b, 0x28, 0x5a, 0x9f, 0x8e, 0x92, 0xe7, 0x8f, 0xbf, 0x2c, 0x25], - [0xf3, 0x28, 0xdb, 0x89, 0x34, 0x5b, 0x62, 0x0c, 0x79, 0x52, 0x29, 0xa4, 0x26, 0x95, 0x84, 0x3e], - [0xdc, 0xd0, 0x3d, 0x29, 0xf7, 0x43, 0xe7, 0x10, 0x09, 0x51, 0xb0, 0xe8, 0x39, 0x85, 0xa6, 0xf8], - [0x10, 0x84, 0xb9, 0x23, 0xf2, 0xaa, 0xe0, 0xc3, 0xa6, 0x2f, 0x2e, 0xc8, 0x08, 0x48, 0xab, 0x77], - [0xaa, 0x12, 0xfe, 0xe1, 0xd5, 0xe3, 0xda, 0xb4, 0x72, 0x4f, 0x16, 0xab, 0x35, 0xf9, 0xc7, 0x99], - [0x81, 0xdd, 0xb8, 0x04, 0x2c, 0xf3, 0x39, 0x94, 0xf4, 0x72, 0x0e, 0x00, 0x94, 0x13, 0x7c, 0x42], - [0x4f, 0xaa, 0x54, 0x1d, 0x5d, 0x49, 0x8e, 0x89, 0xba, 0x0e, 0xa4, 0xc3, 0x87, 0xb2, 0x2f, 0xb4], - [0x72, 0x3b, 0x9a, 0xf3, 0x55, 0x44, 0x91, 0xdb, 0xb1, 0xd6, 0x63, 0x3d, 0xfc, 0x6e, 0x0c, 0x4e], - [0xe5, 0x3f, 0x92, 0x85, 0x9e, 0x48, 0x19, 0xa8, 0xdc, 0x06, 0x95, 0x73, 0x9f, 0xea, 0x8c, 0x65], - [0xb2, 0xf8, 0x58, 0xc7, 0xc9, 0xea, 0x80, 0x1d, 0x53, 0xd6, 0x03, 0x59, 0x6d, 0x65, 0x78, 0x44], - [0x87, 0xe7, 0x62, 0x68, 0xdb, 0xc9, 0x22, 0x72, 0x26, 0xb0, 0xca, 0x66, 0x5f, 0x64, 0xe3, 0x78], - [0xc1, 0x7e, 0x55, 0x05, 0xb2, 0xbd, 0x52, 0x6c, 0x29, 0x21, 0xcd, 0xec, 0x1e, 0x7e, 0x01, 0x09], - [0xd0, 0xa8, 0xd9, 0x57, 0x15, 0x51, 0x8e, 0xeb, 0xb5, 0x13, 0xb0, 0xf8, 0x3d, 0x9e, 0x17, 0x93], - [0x23, 0x41, 0x26, 0xf9, 0x3f, 0xbb, 0x66, 0x8d, 0x97, 0x51, 0x12, 0xe8, 0xfe, 0xbd, 0xf7, 0xec], - [0xef, 0x42, 0xf0, 0x3d, 0xb7, 0x8f, 0x70, 0x4d, 0x02, 0x3c, 0x44, 0x9f, 0x16, 0xb7, 0x09, 0x2b], - [0xab, 0xf7, 0x62, 0x38, 0xc2, 0x0a, 0xf1, 0x61, 0xb2, 0x31, 0x4b, 0x4d, 0x55, 0x26, 0xbc, 0xe9], - [0x3c, 0x2c, 0x2f, 0x11, 0xbb, 0x90, 0xcf, 0x0b, 0xe3, 0x35, 0xca, 0x9b, 0x2e, 0x91, 0xe9, 0xb7], - [0x2a, 0x7a, 0x68, 0x0f, 0x22, 0xa0, 0x2a, 0x92, 0xf4, 0x51, 0x49, 0xd2, 0x0f, 0xec, 0xe0, 0xef], - [0xc9, 0xa8, 0xd1, 0x30, 0x23, 0x1d, 0xd4, 0x3e, 0x42, 0xe6, 0x45, 0x69, 0x57, 0xf8, 0x37, 0x79], - [0x1d, 0x12, 0x7b, 0x84, 0x40, 0x5c, 0xea, 0xb9, 0x9f, 0xd8, 0x77, 0x5a, 0x9b, 0xe6, 0xc5, 0x59], - [0x9e, 0x4b, 0xf8, 0x37, 0xbc, 0xfd, 0x92, 0xca, 0xce, 0x09, 0xd2, 0x06, 0x1a, 0x84, 0xd0, 0x4a], - [0x39, 0x03, 0x1a, 0x96, 0x5d, 0x73, 0xb4, 0xaf, 0x5a, 0x27, 0x4d, 0x18, 0xf9, 0x73, 0xb1, 0xd2], - [0x7f, 0x4d, 0x0a, 0x12, 0x09, 0xd6, 0x7e, 0x4e, 0xd0, 0x6f, 0x75, 0x38, 0xe1, 0xcf, 0xad, 0x64], - [0xe6, 0x1e, 0xe2, 0x40, 0xfb, 0xdc, 0xce, 0x38, 0x96, 0x9f, 0x4c, 0xd2, 0x49, 0x27, 0xdd, 0x93], - [0x4c, 0x3b, 0xa2, 0xb3, 0x7b, 0x0f, 0xdd, 0x8c, 0xfa, 0x5e, 0x95, 0xc1, 0x89, 0xb2, 0x94, 0x14], - [0xe0, 0x6f, 0xd4, 0xca, 0x06, 0x6f, 0xec, 0xdd, 0x54, 0x06, 0x8a, 0x5a, 0xd8, 0x89, 0x6f, 0x86], - [0x5c, 0xa8, 0x4c, 0x34, 0x13, 0x9c, 0x65, 0x80, 0xa8, 0x8a, 0xf2, 0x49, 0x90, 0x72, 0x07, 0x06], - [0x42, 0xea, 0x96, 0x1c, 0x5b, 0x3c, 0x85, 0x8b, 0x17, 0xc3, 0xe5, 0x50, 0xdf, 0xa7, 0x90, 0x10], - [0x40, 0x6c, 0x44, 0xde, 0xe6, 0x78, 0x57, 0xb2, 0x94, 0x31, 0x60, 0xf3, 0x0c, 0x74, 0x17, 0xd3], - [0xc5, 0xf5, 0x7b, 0xae, 0x13, 0x20, 0xfc, 0xf4, 0xb4, 0xe8, 0x68, 0xe7, 0x1d, 0x56, 0xc6, 0x6b], - [0x04, 0xbf, 0x73, 0x7a, 0x5b, 0x67, 0x6b, 0xe7, 0xc3, 0xde, 0x05, 0x01, 0x7d, 0xf4, 0xbf, 0xf9], - [0x51, 0x63, 0xc9, 0xc0, 0x3f, 0x19, 0x07, 0xea, 0x10, 0x44, 0xed, 0x5c, 0x30, 0x72, 0x7b, 0x4f], - [0x37, 0xa1, 0x10, 0xf0, 0x02, 0x71, 0x8e, 0xda, 0xd2, 0x4b, 0x3f, 0x9e, 0xe4, 0x53, 0xf1, 0x40], - [0xb9, 0x87, 0x7e, 0x38, 0x1a, 0xed, 0xd3, 0xda, 0x08, 0xc3, 0x3e, 0x75, 0xff, 0x23, 0xac, 0x10], - [0x7c, 0x50, 0x04, 0x00, 0x5e, 0xc5, 0xda, 0x4c, 0x5a, 0xc9, 0x44, 0x0e, 0x5c, 0x72, 0x31, 0x93], - [0x81, 0xb8, 0x24, 0x37, 0x83, 0xdb, 0xc6, 0x46, 0xca, 0x9d, 0x0c, 0xd8, 0x2a, 0xbd, 0xb4, 0x6c], - [0x50, 0x57, 0x20, 0x54, 0x3e, 0xb9, 0xb4, 0x13, 0xd5, 0x0b, 0x3c, 0xfa, 0xd9, 0xee, 0xf9, 0x38], - [0x94, 0x5f, 0x59, 0x4d, 0xe7, 0x24, 0x11, 0xe4, 0xd3, 0x35, 0xbe, 0x87, 0x44, 0x56, 0xd8, 0xf3], - [0x37, 0x92, 0x3b, 0x3e, 0x37, 0x17, 0x77, 0xb2, 0x11, 0x70, 0xbf, 0x9d, 0x7e, 0x62, 0xf6, 0x02], - [0x3a, 0xd4, 0xe7, 0xc8, 0x57, 0x64, 0x96, 0x46, 0x11, 0xeb, 0x0a, 0x6c, 0x4d, 0x62, 0xde, 0x56], - [0xcd, 0x91, 0x39, 0x6c, 0x44, 0xaf, 0x4f, 0x51, 0x85, 0x57, 0x8d, 0x9d, 0xd9, 0x80, 0x3f, 0x0a], - [0xfe, 0x28, 0x15, 0x8e, 0x72, 0x7b, 0x86, 0x8f, 0x39, 0x03, 0xc9, 0xac, 0xda, 0x64, 0xa2, 0x58], - [0x40, 0xcc, 0x10, 0xb8, 0x28, 0x8c, 0xe5, 0xf0, 0xbc, 0x3a, 0xc0, 0xb6, 0x8a, 0x0e, 0xeb, 0xc8], - [0x6f, 0x14, 0x90, 0xf5, 0x40, 0x69, 0x9a, 0x3c, 0xd4, 0x97, 0x44, 0x20, 0xec, 0xc9, 0x27, 0x37], - [0xd5, 0x05, 0xf1, 0xb7, 0x5e, 0x1a, 0x84, 0xa6, 0x03, 0xc4, 0x35, 0x83, 0xb2, 0xed, 0x03, 0x08], - [0x49, 0x15, 0x73, 0xcf, 0xd7, 0x2b, 0xb4, 0x68, 0x2b, 0x7c, 0xa5, 0x88, 0x0e, 0x1c, 0x8d, 0x6f], - [0x3e, 0xd6, 0x9c, 0xfe, 0x45, 0xab, 0x40, 0x3f, 0x2f, 0xd2, 0xad, 0x95, 0x9b, 0xa2, 0x76, 0x66], - [0x8b, 0xe8, 0x39, 0xef, 0x1b, 0x20, 0xb5, 0x7c, 0x83, 0xba, 0x7e, 0xb6, 0xa8, 0xc2, 0x2b, 0x6a], - [0x14, 0x09, 0x18, 0x6a, 0xb4, 0x22, 0x31, 0xfe, 0xde, 0xe1, 0x81, 0x62, 0xcf, 0x1c, 0xb4, 0xca], - [0x2b, 0xf3, 0xcc, 0xc2, 0x4a, 0xb6, 0x72, 0xcf, 0x15, 0x1f, 0xb8, 0xd2, 0xf3, 0xf3, 0x06, 0x9b], - [0xb9, 0xb9, 0x3a, 0x28, 0x82, 0xd6, 0x02, 0x5c, 0xdb, 0x8c, 0x56, 0xfa, 0x13, 0xf7, 0x53, 0x7b], - [0xd9, 0x7c, 0xca, 0x36, 0x94, 0xfb, 0x20, 0x6d, 0xb8, 0xbd, 0x1f, 0x36, 0x50, 0xc3, 0x33, 0x22], - [0x94, 0xec, 0x2e, 0x19, 0xa4, 0x0b, 0xe4, 0x1a, 0xf3, 0x94, 0x0d, 0x6b, 0x30, 0xc4, 0x93, 0x84], - [0x4b, 0x41, 0x60, 0x3f, 0x20, 0x9a, 0x04, 0x5b, 0xe1, 0x40, 0xa3, 0x41, 0xa3, 0xdf, 0xfe, 0x10], - [0x23, 0xfb, 0xcb, 0x30, 0x9f, 0x1c, 0xf0, 0x94, 0x89, 0x07, 0x55, 0xab, 0x1b, 0x42, 0x65, 0x69], - [0xe7, 0xd9, 0xb6, 0x56, 0x90, 0x91, 0x8a, 0x2b, 0x23, 0x2f, 0x2f, 0x5c, 0x12, 0xc8, 0x30, 0x0e], - [0xad, 0xe8, 0x3c, 0xf7, 0xe7, 0xf3, 0x84, 0x7b, 0x36, 0xfa, 0x4b, 0x54, 0xb0, 0x0d, 0xce, 0x61], - [0x06, 0x10, 0xc5, 0xf2, 0xee, 0x57, 0x1c, 0x8a, 0xc8, 0x0c, 0xbf, 0xe5, 0x38, 0xbd, 0xf1, 0xc7], - [0x27, 0x1d, 0x5d, 0x00, 0xfb, 0xdb, 0x5d, 0x15, 0x5d, 0x9d, 0xce, 0xa9, 0x7c, 0xb4, 0x02, 0x18], - [0x4c, 0x58, 0x00, 0xe3, 0x4e, 0xfe, 0x42, 0x6f, 0x07, 0x9f, 0x6b, 0x0a, 0xa7, 0x52, 0x60, 0xad], -]; - -#[test] -fn test_siphash_1_3_test_vector() { - let k0 = 0x_07_06_05_04_03_02_01_00; - let k1 = 0x_0f_0e_0d_0c_0b_0a_09_08; - - let mut input: Vec = Vec::new(); - - for i in 0..64 { - let out = hash_with(SipHasher128::new_with_keys(k0, k1), &Bytes(&input[..])); - let expected = ( - ((TEST_VECTOR[i][0] as u64) << 0) - | ((TEST_VECTOR[i][1] as u64) << 8) - | ((TEST_VECTOR[i][2] as u64) << 16) - | ((TEST_VECTOR[i][3] as u64) << 24) - | ((TEST_VECTOR[i][4] as u64) << 32) - | ((TEST_VECTOR[i][5] as u64) << 40) - | ((TEST_VECTOR[i][6] as u64) << 48) - | ((TEST_VECTOR[i][7] as u64) << 56), - ((TEST_VECTOR[i][8] as u64) << 0) - | ((TEST_VECTOR[i][9] as u64) << 8) - | ((TEST_VECTOR[i][10] as u64) << 16) - | ((TEST_VECTOR[i][11] as u64) << 24) - | ((TEST_VECTOR[i][12] as u64) << 32) - | ((TEST_VECTOR[i][13] as u64) << 40) - | ((TEST_VECTOR[i][14] as u64) << 48) - | ((TEST_VECTOR[i][15] as u64) << 56), - ); - - assert_eq!(out, expected); - input.push(i as u8); - } -} - -#[test] -#[cfg(target_arch = "arm")] -fn test_hash_usize() { - let val = 0xdeadbeef_deadbeef_u64; - assert!(hash(&(val as u64)) != hash(&(val as usize))); - assert_eq!(hash(&(val as u32)), hash(&(val as usize))); -} -#[test] -#[cfg(target_arch = "x86_64")] -fn test_hash_usize() { - let val = 0xdeadbeef_deadbeef_u64; - assert_eq!(hash(&(val as u64)), hash(&(val as usize))); - assert!(hash(&(val as u32)) != hash(&(val as usize))); -} -#[test] -#[cfg(target_arch = "x86")] -fn test_hash_usize() { - let val = 0xdeadbeef_deadbeef_u64; - assert!(hash(&(val as u64)) != hash(&(val as usize))); - assert_eq!(hash(&(val as u32)), hash(&(val as usize))); -} - -#[test] -fn test_hash_idempotent() { - let val64 = 0xdeadbeef_deadbeef_u64; - assert_eq!(hash(&val64), hash(&val64)); - let val32 = 0xdeadbeef_u32; - assert_eq!(hash(&val32), hash(&val32)); -} - -#[test] -fn test_hash_no_bytes_dropped_64() { - let val = 0xdeadbeef_deadbeef_u64; - - assert!(hash(&val) != hash(&zero_byte(val, 0))); - assert!(hash(&val) != hash(&zero_byte(val, 1))); - assert!(hash(&val) != hash(&zero_byte(val, 2))); - assert!(hash(&val) != hash(&zero_byte(val, 3))); - assert!(hash(&val) != hash(&zero_byte(val, 4))); - assert!(hash(&val) != hash(&zero_byte(val, 5))); - assert!(hash(&val) != hash(&zero_byte(val, 6))); - assert!(hash(&val) != hash(&zero_byte(val, 7))); - - fn zero_byte(val: u64, byte: usize) -> u64 { - assert!(byte < 8); - val & !(0xff << (byte * 8)) - } -} - -#[test] -fn test_hash_no_bytes_dropped_32() { - let val = 0xdeadbeef_u32; - - assert!(hash(&val) != hash(&zero_byte(val, 0))); - assert!(hash(&val) != hash(&zero_byte(val, 1))); - assert!(hash(&val) != hash(&zero_byte(val, 2))); - assert!(hash(&val) != hash(&zero_byte(val, 3))); - - fn zero_byte(val: u32, byte: usize) -> u32 { - assert!(byte < 4); - val & !(0xff << (byte * 8)) - } -} - -#[test] -fn test_hash_no_concat_alias() { - let s = ("aa", "bb"); - let t = ("aabb", ""); - let u = ("a", "abb"); - - assert!(s != t && t != u); - assert!(hash(&s) != hash(&t) && hash(&s) != hash(&u)); - - let u = [1, 0, 0, 0]; - let v = (&u[..1], &u[1..3], &u[3..]); - let w = (&u[..], &u[4..4], &u[4..4]); - - assert!(v != w); - assert!(hash(&v) != hash(&w)); -} - -#[test] -fn test_short_write_works() { - let test_u8 = 0xFF_u8; - let test_u16 = 0x1122_u16; - let test_u32 = 0x22334455_u32; - let test_u64 = 0x33445566_778899AA_u64; - let test_u128 = 0x11223344_55667788_99AABBCC_DDEEFF77_u128; - let test_usize = 0xD0C0B0A0_usize; - - let test_i8 = -1_i8; - let test_i16 = -2_i16; - let test_i32 = -3_i32; - let test_i64 = -4_i64; - let test_i128 = -5_i128; - let test_isize = -6_isize; - - let mut h1 = SipHasher128::new_with_keys(0, 0); - h1.write(b"bytes"); - h1.write(b"string"); - h1.write_u8(test_u8); - h1.write_u16(test_u16); - h1.write_u32(test_u32); - h1.write_u64(test_u64); - h1.write_u128(test_u128); - h1.write_usize(test_usize); - h1.write_i8(test_i8); - h1.write_i16(test_i16); - h1.write_i32(test_i32); - h1.write_i64(test_i64); - h1.write_i128(test_i128); - h1.write_isize(test_isize); - - let mut h2 = SipHasher128::new_with_keys(0, 0); - h2.write(b"bytes"); - h2.write(b"string"); - h2.write(&test_u8.to_ne_bytes()); - h2.write(&test_u16.to_ne_bytes()); - h2.write(&test_u32.to_ne_bytes()); - h2.write(&test_u64.to_ne_bytes()); - h2.write(&test_u128.to_ne_bytes()); - h2.write(&test_usize.to_ne_bytes()); - h2.write(&test_i8.to_ne_bytes()); - h2.write(&test_i16.to_ne_bytes()); - h2.write(&test_i32.to_ne_bytes()); - h2.write(&test_i64.to_ne_bytes()); - h2.write(&test_i128.to_ne_bytes()); - h2.write(&test_isize.to_ne_bytes()); - - let h1_hash = h1.finish128(); - let h2_hash = h2.finish128(); - - assert_eq!(h1_hash, h2_hash); -} - -macro_rules! test_fill_buffer { - ($type:ty, $write_method:ident) => {{ - // Test filling and overfilling the buffer from all possible offsets - // for a given integer type and its corresponding write method. - const SIZE: usize = std::mem::size_of::<$type>(); - let input = [42; BUFFER_SIZE]; - let x = 0x01234567_89ABCDEF_76543210_FEDCBA98_u128 as $type; - let x_bytes = &x.to_ne_bytes(); - - for i in 1..=SIZE { - let s = &input[..BUFFER_SIZE - i]; - - let mut h1 = SipHasher128::new_with_keys(7, 13); - h1.write(s); - h1.$write_method(x); - - let mut h2 = SipHasher128::new_with_keys(7, 13); - h2.write(s); - h2.write(x_bytes); - - let h1_hash = h1.finish128(); - let h2_hash = h2.finish128(); - - assert_eq!(h1_hash, h2_hash); - } - }}; -} - -#[test] -fn test_fill_buffer() { - test_fill_buffer!(u8, write_u8); - test_fill_buffer!(u16, write_u16); - test_fill_buffer!(u32, write_u32); - test_fill_buffer!(u64, write_u64); - test_fill_buffer!(u128, write_u128); - test_fill_buffer!(usize, write_usize); - - test_fill_buffer!(i8, write_i8); - test_fill_buffer!(i16, write_i16); - test_fill_buffer!(i32, write_i32); - test_fill_buffer!(i64, write_i64); - test_fill_buffer!(i128, write_i128); - test_fill_buffer!(isize, write_isize); -} +use super::*;use std::hash::Hash;struct Bytes<'a>(&'a[u8]);impl<'a>Hash for//(); +Bytes<'a>{#[allow(unused_must_use)]fn hash(&self,state:&mut H){for//3; +byte in self.0{{();};state.write_u8(*byte);{();};}}}fn hash_with(mut st: +SipHasher128,x:&T)->(u64,u64){;x.hash(&mut st);st.finish128()}fn hash(x: +&T)->(u64,u64){(hash_with(SipHasher128::new_with_keys( 0,0),x))}#[rustfmt::skip] +const TEST_VECTOR:[[u8;(16)];64]=[[0xe7,0x7e,0xbc,0xb2,0x27,0x88,0xa5,0xbe,0xfd, +0x62,(0xdb),0x6a,0xdd,0x30,0x30,0x01],[ 0xfc,0x6f,0x37,0x04,0x60,0xd3,0xed,0xa8, +0x5e,(0x05),0x73,0xcc,0x2b,0x2f,0xf0,0x63] ,[0x75,0x78,0x7f,0x09,0x05,0x69,0x83, +0x9b,(0x85),0x5b,0xc9,0x54,0x8c,0x6a,0xea, 0x95],[0x6b,0xc5,0xcc,0xfa,0x1e,0xdc, +0xf7,(0x9f),0x48,0x23,0x18,0x77,0x12,0xeb, 0xd7,0x43],[0x0c,0x78,0x4e,0x71,0xac, +0x2b,(0x28),0x5a,0x9f,0x8e,0x92,0xe7,0x8f, 0xbf,0x2c,0x25],[0xf3,0x28,0xdb,0x89, +0x34,(0x5b),0x62,0x0c,0x79,0x52,0x29,0xa4, 0x26,0x95,0x84,0x3e],[0xdc,0xd0,0x3d, +0x29,(0xf7),0x43,0xe7,0x10,0x09,0x51,0xb0, 0xe8,0x39,0x85,0xa6,0xf8],[0x10,0x84, +0xb9,(0x23),0xf2,0xaa,0xe0,0xc3,0xa6,0x2f, 0x2e,0xc8,0x08,0x48,0xab,0x77],[0xaa, +0x12,(0xfe),0xe1,0xd5,0xe3,0xda,0xb4,0x72, 0x4f,0x16,0xab,0x35,0xf9,0xc7,0x99],[ +0x81,0xdd,0xb8,0x04,0x2c,0xf3,0x39,0x94, 0xf4,0x72,0x0e,0x00,0x94,0x13,0x7c,0x42 +],[(0x4f),0xaa,0x54,0x1d,0x5d,0x49,0x8e,0x89,0xba,0x0e,0xa4,0xc3,0x87,0xb2,0x2f, +0xb4],[(0x72),0x3b,0x9a,0xf3,0x55,0x44, 0x91,0xdb,0xb1,0xd6,0x63,0x3d,0xfc,0x6e, +0x0c,(0x4e)],[0xe5,0x3f,0x92,0x85,0x9e, 0x48,0x19,0xa8,0xdc,0x06,0x95,0x73,0x9f, +0xea,(0x8c),0x65],[0xb2,0xf8,0x58,0xc7, 0xc9,0xea,0x80,0x1d,0x53,0xd6,0x03,0x59, +0x6d,(0x65),0x78,0x44],[0x87,0xe7,0x62, 0x68,0xdb,0xc9,0x22,0x72,0x26,0xb0,0xca, +0x66,(0x5f),0x64,0xe3,0x78],[0xc1,0x7e, 0x55,0x05,0xb2,0xbd,0x52,0x6c,0x29,0x21, +0xcd,(0xec),0x1e,0x7e,0x01,0x09],[0xd0, 0xa8,0xd9,0x57,0x15,0x51,0x8e,0xeb,0xb5, +0x13,(0xb0),0xf8,0x3d,0x9e,0x17,0x93],[ 0x23,0x41,0x26,0xf9,0x3f,0xbb,0x66,0x8d, +0x97,(0x51),0x12,0xe8,0xfe,0xbd,0xf7,0xec] ,[0xef,0x42,0xf0,0x3d,0xb7,0x8f,0x70, +0x4d,(0x02),0x3c,0x44,0x9f,0x16,0xb7,0x09, 0x2b],[0xab,0xf7,0x62,0x38,0xc2,0x0a, +0xf1,(0x61),0xb2,0x31,0x4b,0x4d,0x55,0x26, 0xbc,0xe9],[0x3c,0x2c,0x2f,0x11,0xbb, +0x90,(0xcf),0x0b,0xe3,0x35,0xca,0x9b,0x2e, 0x91,0xe9,0xb7],[0x2a,0x7a,0x68,0x0f, +0x22,(0xa0),0x2a,0x92,0xf4,0x51,0x49,0xd2, 0x0f,0xec,0xe0,0xef],[0xc9,0xa8,0xd1, +0x30,(0x23),0x1d,0xd4,0x3e,0x42,0xe6,0x45, 0x69,0x57,0xf8,0x37,0x79],[0x1d,0x12, +0x7b,(0x84),0x40,0x5c,0xea,0xb9,0x9f,0xd8, 0x77,0x5a,0x9b,0xe6,0xc5,0x59],[0x9e, +0x4b,(0xf8),0x37,0xbc,0xfd,0x92,0xca,0xce, 0x09,0xd2,0x06,0x1a,0x84,0xd0,0x4a],[ +0x39,0x03,0x1a,0x96,0x5d,0x73,0xb4,0xaf, 0x5a,0x27,0x4d,0x18,0xf9,0x73,0xb1,0xd2 +],[(0x7f),0x4d,0x0a,0x12,0x09,0xd6,0x7e,0x4e,0xd0,0x6f,0x75,0x38,0xe1,0xcf,0xad, +0x64],[(0xe6),0x1e,0xe2,0x40,0xfb,0xdc, 0xce,0x38,0x96,0x9f,0x4c,0xd2,0x49,0x27, +0xdd,(0x93)],[0x4c,0x3b,0xa2,0xb3,0x7b, 0x0f,0xdd,0x8c,0xfa,0x5e,0x95,0xc1,0x89, +0xb2,(0x94),0x14],[0xe0,0x6f,0xd4,0xca, 0x06,0x6f,0xec,0xdd,0x54,0x06,0x8a,0x5a, +0xd8,(0x89),0x6f,0x86],[0x5c,0xa8,0x4c, 0x34,0x13,0x9c,0x65,0x80,0xa8,0x8a,0xf2, +0x49,(0x90),0x72,0x07,0x06],[0x42,0xea, 0x96,0x1c,0x5b,0x3c,0x85,0x8b,0x17,0xc3, +0xe5,(0x50),0xdf,0xa7,0x90,0x10],[0x40, 0x6c,0x44,0xde,0xe6,0x78,0x57,0xb2,0x94, +0x31,(0x60),0xf3,0x0c,0x74,0x17,0xd3],[ 0xc5,0xf5,0x7b,0xae,0x13,0x20,0xfc,0xf4, +0xb4,(0xe8),0x68,0xe7,0x1d,0x56,0xc6,0x6b] ,[0x04,0xbf,0x73,0x7a,0x5b,0x67,0x6b, +0xe7,(0xc3),0xde,0x05,0x01,0x7d,0xf4,0xbf, 0xf9],[0x51,0x63,0xc9,0xc0,0x3f,0x19, +0x07,(0xea),0x10,0x44,0xed,0x5c,0x30,0x72, 0x7b,0x4f],[0x37,0xa1,0x10,0xf0,0x02, +0x71,(0x8e),0xda,0xd2,0x4b,0x3f,0x9e,0xe4, 0x53,0xf1,0x40],[0xb9,0x87,0x7e,0x38, +0x1a,(0xed),0xd3,0xda,0x08,0xc3,0x3e,0x75, 0xff,0x23,0xac,0x10],[0x7c,0x50,0x04, +0x00,(0x5e),0xc5,0xda,0x4c,0x5a,0xc9,0x44, 0x0e,0x5c,0x72,0x31,0x93],[0x81,0xb8, +0x24,(0x37),0x83,0xdb,0xc6,0x46,0xca,0x9d, 0x0c,0xd8,0x2a,0xbd,0xb4,0x6c],[0x50, +0x57,(0x20),0x54,0x3e,0xb9,0xb4,0x13,0xd5, 0x0b,0x3c,0xfa,0xd9,0xee,0xf9,0x38],[ +0x94,0x5f,0x59,0x4d,0xe7,0x24,0x11,0xe4, 0xd3,0x35,0xbe,0x87,0x44,0x56,0xd8,0xf3 +],[(0x37),0x92,0x3b,0x3e,0x37,0x17,0x77,0xb2,0x11,0x70,0xbf,0x9d,0x7e,0x62,0xf6, +0x02],[(0x3a),0xd4,0xe7,0xc8,0x57,0x64, 0x96,0x46,0x11,0xeb,0x0a,0x6c,0x4d,0x62, +0xde,(0x56)],[0xcd,0x91,0x39,0x6c,0x44, 0xaf,0x4f,0x51,0x85,0x57,0x8d,0x9d,0xd9, +0x80,(0x3f),0x0a],[0xfe,0x28,0x15,0x8e, 0x72,0x7b,0x86,0x8f,0x39,0x03,0xc9,0xac, +0xda,(0x64),0xa2,0x58],[0x40,0xcc,0x10, 0xb8,0x28,0x8c,0xe5,0xf0,0xbc,0x3a,0xc0, +0xb6,(0x8a),0x0e,0xeb,0xc8],[0x6f,0x14, 0x90,0xf5,0x40,0x69,0x9a,0x3c,0xd4,0x97, +0x44,(0x20),0xec,0xc9,0x27,0x37],[0xd5, 0x05,0xf1,0xb7,0x5e,0x1a,0x84,0xa6,0x03, +0xc4,(0x35),0x83,0xb2,0xed,0x03,0x08],[ 0x49,0x15,0x73,0xcf,0xd7,0x2b,0xb4,0x68, +0x2b,(0x7c),0xa5,0x88,0x0e,0x1c,0x8d,0x6f] ,[0x3e,0xd6,0x9c,0xfe,0x45,0xab,0x40, +0x3f,(0x2f),0xd2,0xad,0x95,0x9b,0xa2,0x76, 0x66],[0x8b,0xe8,0x39,0xef,0x1b,0x20, +0xb5,(0x7c),0x83,0xba,0x7e,0xb6,0xa8,0xc2, 0x2b,0x6a],[0x14,0x09,0x18,0x6a,0xb4, +0x22,(0x31),0xfe,0xde,0xe1,0x81,0x62,0xcf, 0x1c,0xb4,0xca],[0x2b,0xf3,0xcc,0xc2, +0x4a,(0xb6),0x72,0xcf,0x15,0x1f,0xb8,0xd2, 0xf3,0xf3,0x06,0x9b],[0xb9,0xb9,0x3a, +0x28,(0x82),0xd6,0x02,0x5c,0xdb,0x8c,0x56, 0xfa,0x13,0xf7,0x53,0x7b],[0xd9,0x7c, +0xca,(0x36),0x94,0xfb,0x20,0x6d,0xb8,0xbd, 0x1f,0x36,0x50,0xc3,0x33,0x22],[0x94, +0xec,(0x2e),0x19,0xa4,0x0b,0xe4,0x1a,0xf3, 0x94,0x0d,0x6b,0x30,0xc4,0x93,0x84],[ +0x4b,0x41,0x60,0x3f,0x20,0x9a,0x04,0x5b, 0xe1,0x40,0xa3,0x41,0xa3,0xdf,0xfe,0x10 +],[(0x23),0xfb,0xcb,0x30,0x9f,0x1c,0xf0,0x94,0x89,0x07,0x55,0xab,0x1b,0x42,0x65, +0x69],[(0xe7),0xd9,0xb6,0x56,0x90,0x91, 0x8a,0x2b,0x23,0x2f,0x2f,0x5c,0x12,0xc8, +0x30,(0x0e)],[0xad,0xe8,0x3c,0xf7,0xe7, 0xf3,0x84,0x7b,0x36,0xfa,0x4b,0x54,0xb0, +0x0d,(0xce),0x61],[0x06,0x10,0xc5,0xf2, 0xee,0x57,0x1c,0x8a,0xc8,0x0c,0xbf,0xe5, +0x38,(0xbd),0xf1,0xc7],[0x27,0x1d,0x5d, 0x00,0xfb,0xdb,0x5d,0x15,0x5d,0x9d,0xce, +0xa9,(0x7c),0xb4,0x02,0x18],[0x4c,0x58, 0x00,0xe3,0x4e,0xfe,0x42,0x6f,0x07,0x9f, +0x6b,0x0a,0xa7,0x52,0x60,0xad],];#[test]fn test_siphash_1_3_test_vector(){();let +k0=0x_07_06_05_04_03_02_01_00;;;let k1=0x_0f_0e_0d_0c_0b_0a_09_08;let mut input: +Vec=Vec::new();;for i in 0..64{let out=hash_with(SipHasher128::new_with_keys +(k0,k1),&Bytes(&input[..]));();3;let expected=(((TEST_VECTOR[i][0]as u64)<<0)|(( +TEST_VECTOR[i][1]as u64)<<8)|((TEST_VECTOR[i] [2]as u64)<<16)|((TEST_VECTOR[i][3 +]as u64)<<24)|((TEST_VECTOR[i][4]as u64)<< 32)|((TEST_VECTOR[i][5]as u64)<<40)|( +(TEST_VECTOR[i][6]as u64)<<48)|((TEST_VECTOR[i] [7]as u64)<<56),((TEST_VECTOR[i] +[8]as u64)<<0)|((TEST_VECTOR[i][9]as u64) <<8)|((TEST_VECTOR[i][10]as u64)<<16)| +((TEST_VECTOR[i][11]as u64)<<24)|(( TEST_VECTOR[i][12]as u64)<<32)|((TEST_VECTOR +[i][13]as u64)<<40)|((TEST_VECTOR[i][14 ]as u64)<<48)|((TEST_VECTOR[i][15]as u64 +)<<56),);();3;assert_eq!(out,expected);3;3;input.push(i as u8);3;}}#[test]#[cfg( +target_arch="arm")]fn test_hash_usize(){;let val=0xdeadbeef_deadbeef_u64;assert! +(hash(&(val as u64))!=hash(&(val as usize)));3;3;assert_eq!(hash(&(val as u32)), +hash(&(val as usize)));;}#[test]#[cfg(target_arch="x86_64")]fn test_hash_usize() +{;let val=0xdeadbeef_deadbeef_u64;;;assert_eq!(hash(&(val as u64)),hash(&(val as +usize)));3;3;assert!(hash(&(val as u32))!=hash(&(val as usize)));;}#[test]#[cfg( +target_arch="x86")]fn test_hash_usize(){;let val=0xdeadbeef_deadbeef_u64;assert! +(hash(&(val as u64))!=hash(&(val as usize)));3;3;assert_eq!(hash(&(val as u32)), +hash(&(val as usize)));*&*&();}#[test]fn test_hash_idempotent(){{();};let val64= +0xdeadbeef_deadbeef_u64;3;3;assert_eq!(hash(&val64),hash(&val64));3;3;let val32= +0xdeadbeef_u32;{();};{();};assert_eq!(hash(&val32),hash(&val32));({});}#[test]fn +test_hash_no_bytes_dropped_64(){;let val=0xdeadbeef_deadbeef_u64;;assert!(hash(& +val)!=hash(&zero_byte(val,0)));;;assert!(hash(&val)!=hash(&zero_byte(val,1)));;; +assert!(hash(&val)!=hash(&zero_byte(val,2)));({});{;};assert!(hash(&val)!=hash(& +zero_byte(val,3)));;;assert!(hash(&val)!=hash(&zero_byte(val,4)));assert!(hash(& +val)!=hash(&zero_byte(val,5)));;;assert!(hash(&val)!=hash(&zero_byte(val,6)));;; +assert!(hash(&val)!=hash(&zero_byte(val,7)));;fn zero_byte(val:u64,byte:usize)-> +u64{if true{};assert!(byte<8);let _=();val&!(0xff<<(byte*8))}let _=();}#[test]fn +test_hash_no_bytes_dropped_32(){;let val=0xdeadbeef_u32;assert!(hash(&val)!=hash +(&zero_byte(val,0)));;assert!(hash(&val)!=hash(&zero_byte(val,1)));assert!(hash( +&val)!=hash(&zero_byte(val,2)));;assert!(hash(&val)!=hash(&zero_byte(val,3)));fn +zero_byte(val:u32,byte:usize)->u32{3;assert!(byte<4);;val&!(0xff<<(byte*8))};}#[ +test]fn test_hash_no_concat_alias(){;let s=("aa","bb");let t=("aabb","");let u=( +"a","abb");;assert!(s!=t&&t!=u);assert!(hash(&s)!=hash(&t)&&hash(&s)!=hash(&u)); +let u=[1,0,0,0];;let v=(&u[..1],&u[1..3],&u[3..]);let w=(&u[..],&u[4..4],&u[4..4 +]);;assert!(v!=w);assert!(hash(&v)!=hash(&w));}#[test]fn test_short_write_works( +){;let test_u8=0xFF_u8;;;let test_u16=0x1122_u16;let test_u32=0x22334455_u32;let +test_u64=0x33445566_778899AA_u64;((),());let _=();((),());((),());let test_u128= +0x11223344_55667788_99AABBCC_DDEEFF77_u128;;;let test_usize=0xD0C0B0A0_usize;let +test_i8=-1_i8;;;let test_i16=-2_i16;;let test_i32=-3_i32;let test_i64=-4_i64;let +test_i128=-5_i128;{;};();let test_isize=-6_isize;();();let mut h1=SipHasher128:: +new_with_keys(0,0);;h1.write(b"bytes");h1.write(b"string");h1.write_u8(test_u8); +h1.write_u16(test_u16);3;3;h1.write_u32(test_u32);;;h1.write_u64(test_u64);;;h1. +write_u128(test_u128);3;;h1.write_usize(test_usize);;;h1.write_i8(test_i8);;;h1. +write_i16(test_i16);;h1.write_i32(test_i32);h1.write_i64(test_i64);h1.write_i128 +(test_i128);;h1.write_isize(test_isize);let mut h2=SipHasher128::new_with_keys(0 +,0);;h2.write(b"bytes");h2.write(b"string");h2.write(&test_u8.to_ne_bytes());h2. +write(&test_u16.to_ne_bytes());3;;h2.write(&test_u32.to_ne_bytes());;;h2.write(& +test_u64.to_ne_bytes());;h2.write(&test_u128.to_ne_bytes());h2.write(&test_usize +.to_ne_bytes());;h2.write(&test_i8.to_ne_bytes());h2.write(&test_i16.to_ne_bytes +());;;h2.write(&test_i32.to_ne_bytes());;;h2.write(&test_i64.to_ne_bytes());;h2. +write(&test_i128.to_ne_bytes());;h2.write(&test_isize.to_ne_bytes());let h1_hash +=h1.finish128();3;3;let h2_hash=h2.finish128();3;;assert_eq!(h1_hash,h2_hash);;} +macro_rules!test_fill_buffer{($type:ty,$ write_method:ident)=>{{const SIZE:usize +=std::mem::size_of::<$type>();let input=[42;BUFFER_SIZE];let x=//*&*&();((),()); +0x01234567_89ABCDEF_76543210_FEDCBA98_u128 as$type;let x_bytes=&x.to_ne_bytes() +;for i in 1..=SIZE{let s=&input[..BUFFER_SIZE-i];let mut h1=SipHasher128:://{;}; +new_with_keys(7,13);h1.write(s);h1.$write_method(x);let mut h2=SipHasher128:://; +new_with_keys(7,13);h2.write(s);h2.write(x_bytes);let h1_hash=h1.finish128();//; +let h2_hash=h2.finish128();assert_eq!(h1_hash,h2_hash);}}};}#[test]fn//let _=(); +test_fill_buffer(){();test_fill_buffer!(u8,write_u8);();3;test_fill_buffer!(u16, +write_u16);;;test_fill_buffer!(u32,write_u32);;test_fill_buffer!(u64,write_u64); +test_fill_buffer!(u128,write_u128);3;3;test_fill_buffer!(usize,write_usize);3;3; +test_fill_buffer!(i8,write_i8);{;};{;};test_fill_buffer!(i16,write_i16);{;};{;}; +test_fill_buffer!(i32,write_i32);{;};{;};test_fill_buffer!(i64,write_i64);();(); +test_fill_buffer!(i128,write_i128);();3;test_fill_buffer!(isize,write_isize);3;} diff --git a/compiler/rustc_data_structures/src/small_c_str.rs b/compiler/rustc_data_structures/src/small_c_str.rs index 809ce3d44832e..81dad73ba5b38 100644 --- a/compiler/rustc_data_structures/src/small_c_str.rs +++ b/compiler/rustc_data_structures/src/small_c_str.rs @@ -1,87 +1,22 @@ -use std::ffi; -use std::ops::Deref; - -use smallvec::SmallVec; - -#[cfg(test)] -mod tests; - -const SIZE: usize = 36; - -/// Like SmallVec but for C strings. -#[derive(Clone)] -pub struct SmallCStr { - data: SmallVec<[u8; SIZE]>, -} - -impl SmallCStr { - #[inline] - pub fn new(s: &str) -> SmallCStr { - let len = s.len(); - let len1 = len + 1; - let data = if len < SIZE { - let mut buf = [0; SIZE]; - buf[..len].copy_from_slice(s.as_bytes()); - SmallVec::from_buf_and_len(buf, len1) - } else { - let mut data = Vec::with_capacity(len1); - data.extend_from_slice(s.as_bytes()); - data.push(0); - SmallVec::from_vec(data) - }; - if let Err(e) = ffi::CStr::from_bytes_with_nul(&data) { - panic!("The string \"{s}\" cannot be converted into a CStr: {e}"); - } - SmallCStr { data } - } - - #[inline] - pub fn new_with_nul(s: &str) -> SmallCStr { - let b = s.as_bytes(); - if let Err(e) = ffi::CStr::from_bytes_with_nul(b) { - panic!("The string \"{s}\" cannot be converted into a CStr: {e}"); - } - SmallCStr { data: SmallVec::from_slice(s.as_bytes()) } - } - - #[inline] - pub fn as_c_str(&self) -> &ffi::CStr { - unsafe { ffi::CStr::from_bytes_with_nul_unchecked(&self.data) } - } - - #[inline] - pub fn len_with_nul(&self) -> usize { - self.data.len() - } - - pub fn spilled(&self) -> bool { - self.data.spilled() - } -} - -impl Deref for SmallCStr { - type Target = ffi::CStr; - - #[inline] - fn deref(&self) -> &ffi::CStr { - self.as_c_str() - } -} - -impl<'a> FromIterator<&'a str> for SmallCStr { - fn from_iter>(iter: T) -> Self { - let mut data = - iter.into_iter().flat_map(|s| s.as_bytes()).copied().collect::>(); - data.push(0); - if let Err(e) = ffi::CStr::from_bytes_with_nul(&data) { - panic!("The iterator {data:?} cannot be converted into a CStr: {e}"); - } - Self { data } - } -} - -impl From<&ffi::CStr> for SmallCStr { - fn from(s: &ffi::CStr) -> Self { - Self { data: SmallVec::from_slice(s.to_bytes_with_nul()) } - } -} +use std::ffi;use std::ops::Deref;use smallvec::SmallVec;#[cfg(test)]mod tests;// +const SIZE:usize=36;#[derive(Clone )]pub struct SmallCStr{data:SmallVec<[u8;SIZE +]>,}impl SmallCStr{#[inline]pub fn new(s:&str)->SmallCStr{;let len=s.len();;;let +len1=len+1;;let data=if lenSmallCStr{;let b=s.as_bytes();if let Err(e)= +ffi::CStr::from_bytes_with_nul(b){let _=();if true{};if true{};if true{};panic!( +"The string \"{s}\" cannot be converted into a CStr: {e}");({});}SmallCStr{data: +SmallVec::from_slice(s.as_bytes())}}# [inline]pub fn as_c_str(&self)->&ffi::CStr +{unsafe{(ffi::CStr::from_bytes_with_nul_unchecked(&self .data))}}#[inline]pub fn +len_with_nul(&self)->usize{((self.data.len()))}pub fn spilled(&self)->bool{self. +data.spilled()}}impl Deref for SmallCStr{type Target=ffi::CStr;#[inline]fn//{;}; +deref(&self)->&ffi::CStr{(((self.as_c_str())))}}impl<'a>FromIterator<&'a str>for +SmallCStr{fn from_iter>(iter:T)->Self{;let mut data +=iter.into_iter().flat_map(|s|s.as_bytes()).copied().collect::>();;; +data.push(0);{;};if let Err(e)=ffi::CStr::from_bytes_with_nul(&data){{;};panic!( +"The iterator {data:?} cannot be converted into a CStr: {e}");;}Self{data}}}impl +From<&ffi::CStr>for SmallCStr{fn from(s:&ffi::CStr)->Self{Self{data:SmallVec::// +from_slice(((((((((((((((((((((((s.to_bytes_with_nul())))))))))))))))))))))))}}} diff --git a/compiler/rustc_data_structures/src/snapshot_map/mod.rs b/compiler/rustc_data_structures/src/snapshot_map/mod.rs index 8a50179cd3b64..821f60898c817 100644 --- a/compiler/rustc_data_structures/src/snapshot_map/mod.rs +++ b/compiler/rustc_data_structures/src/snapshot_map/mod.rs @@ -1,143 +1,33 @@ -use crate::fx::FxHashMap; -use crate::undo_log::{Rollback, Snapshots, UndoLogs, VecLog}; -use std::borrow::{Borrow, BorrowMut}; -use std::hash::Hash; -use std::marker::PhantomData; -use std::ops; - -pub use crate::undo_log::Snapshot; - -#[cfg(test)] -mod tests; - -pub type SnapshotMapStorage = SnapshotMap, ()>; -pub type SnapshotMapRef<'a, K, V, L> = SnapshotMap, &'a mut L>; - -#[derive(Clone)] -pub struct SnapshotMap, L = VecLog>> { - map: M, - undo_log: L, - _marker: PhantomData<(K, V)>, -} - -// HACK(eddyb) manual impl avoids `Default` bounds on `K` and `V`. -impl Default for SnapshotMap -where - M: Default, - L: Default, -{ - fn default() -> Self { - SnapshotMap { map: Default::default(), undo_log: Default::default(), _marker: PhantomData } - } -} - -#[derive(Clone)] -pub enum UndoLog { - Inserted(K), - Overwrite(K, V), - Purged, -} - -impl SnapshotMap { - #[inline] - pub fn with_log(&mut self, undo_log: L2) -> SnapshotMap { - SnapshotMap { map: &mut self.map, undo_log, _marker: PhantomData } - } -} - -impl SnapshotMap -where - K: Hash + Clone + Eq, - M: BorrowMut> + Borrow>, - L: UndoLogs>, -{ - pub fn clear(&mut self) { - self.map.borrow_mut().clear(); - self.undo_log.clear(); - } - - pub fn insert(&mut self, key: K, value: V) -> bool { - match self.map.borrow_mut().insert(key.clone(), value) { - None => { - self.undo_log.push(UndoLog::Inserted(key)); - true - } - Some(old_value) => { - self.undo_log.push(UndoLog::Overwrite(key, old_value)); - false - } - } - } - - pub fn remove(&mut self, key: K) -> bool { - match self.map.borrow_mut().remove(&key) { - Some(old_value) => { - self.undo_log.push(UndoLog::Overwrite(key, old_value)); - true - } - None => false, - } - } - - pub fn get(&self, key: &K) -> Option<&V> { - self.map.borrow().get(key) - } -} - -impl SnapshotMap -where - K: Hash + Clone + Eq, -{ - pub fn snapshot(&mut self) -> Snapshot { - self.undo_log.start_snapshot() - } - - pub fn commit(&mut self, snapshot: Snapshot) { - self.undo_log.commit(snapshot) - } - - pub fn rollback_to(&mut self, snapshot: Snapshot) { - let map = &mut self.map; - self.undo_log.rollback_to(|| map, snapshot) - } -} - -impl<'k, K, V, M, L> ops::Index<&'k K> for SnapshotMap -where - K: Hash + Clone + Eq, - M: Borrow>, -{ - type Output = V; - fn index(&self, key: &'k K) -> &V { - &self.map.borrow()[key] - } -} - -impl Rollback> for SnapshotMap -where - K: Eq + Hash, - M: Rollback>, -{ - fn reverse(&mut self, undo: UndoLog) { - self.map.reverse(undo) - } -} - -impl Rollback> for FxHashMap -where - K: Eq + Hash, -{ - fn reverse(&mut self, undo: UndoLog) { - match undo { - UndoLog::Inserted(key) => { - self.remove(&key); - } - - UndoLog::Overwrite(key, old_value) => { - self.insert(key, old_value); - } - - UndoLog::Purged => {} - } - } -} +use crate::fx::FxHashMap;use crate::undo_log::{Rollback,Snapshots,UndoLogs,//(); +VecLog};use std::borrow::{Borrow,BorrowMut} ;use std::hash::Hash;use std::marker +::PhantomData;use std::ops;pub use crate::undo_log::Snapshot;#[cfg(test)]mod//3; +tests;pub type SnapshotMapStorage=SnapshotMap,()>;pub//; +type SnapshotMapRef<'a,K,V,L>=SnapshotMap,&'a mut L> +;#[derive(Clone)]pub struct SnapshotMap,L=VecLog>>{map:M,undo_log:L,_marker:PhantomData<(K,V)>,}implDefault for//(); +SnapshotMapwhere M:Default,L:Default,{fn default()->Self{SnapshotMap{// +map:(Default::default()),undo_log:(Default ::default()),_marker:PhantomData}}}#[ +derive(Clone)]pub enum UndoLog{Inserted( K),Overwrite(K,V),Purged,}implSnapshotMap{#[inline ]pub fn with_log(&mut self,undo_log:L2)-> +SnapshotMap{SnapshotMap{map:(((&mut self.map))),undo_log,_marker: +PhantomData}}}implSnapshotMapwhere K:Hash+Clone+Eq,M://*&*&(); +BorrowMut>+Borrow>,L:UndoLogs>,{pub// +fn clear(&mut self){;self.map.borrow_mut().clear();self.undo_log.clear();}pub fn +insert(&mut self,key:K,value:V)->bool{ match (self.map.borrow_mut()).insert(key. +clone(),value){None=>{();self.undo_log.push(UndoLog::Inserted(key));3;true}Some( +old_value)=>{;self.undo_log.push(UndoLog::Overwrite(key,old_value));;false}}}pub +fn remove(&mut self,key:K)->bool{match self.map.borrow_mut().remove(&key){Some( +old_value)=>{;self.undo_log.push(UndoLog::Overwrite(key,old_value));;true}None=> +false,}}pub fn get(&self,key:&K)->Option<& V>{self.map.borrow().get(key)}}implSnapshotMapwhere K:Hash+Clone+ Eq,{pub fn snapshot(&mut self)->Snapshot{ +self.undo_log.start_snapshot()}pub fn commit (&mut self,snapshot:Snapshot){self. +undo_log.commit(snapshot)}pub fn rollback_to(&mut self,snapshot:Snapshot){();let +map=&mut self.map;();self.undo_log.rollback_to(||map,snapshot)}}impl<'k,K,V,M,L> +ops::Index<&'k K>for SnapshotMapwhere K:Hash+Clone+Eq,M:Borrow>,{type Output=V;fn index(&self,key :&'k K)->&V{&self.map.borrow() +[key]}}implRollback>for SnapshotMapwhere K:Eq+//; +Hash,M:Rollback>,{fn reverse( &mut self,undo:UndoLog){self.map +.reverse(undo)}}implRollback>for FxHashMapwhere K:Eq+//3; +Hash,{fn reverse(&mut self,undo:UndoLog< K,V>){match undo{UndoLog::Inserted(key) +=>{3;self.remove(&key);3;}UndoLog::Overwrite(key,old_value)=>{3;self.insert(key, +old_value);let _=||();loop{break};let _=||();loop{break};}UndoLog::Purged=>{}}}} diff --git a/compiler/rustc_data_structures/src/snapshot_map/tests.rs b/compiler/rustc_data_structures/src/snapshot_map/tests.rs index 72ca53c2be9ed..8c62bbc93d066 100644 --- a/compiler/rustc_data_structures/src/snapshot_map/tests.rs +++ b/compiler/rustc_data_structures/src/snapshot_map/tests.rs @@ -1,43 +1,13 @@ -use super::SnapshotMap; - -#[test] -fn basic() { - let mut map = SnapshotMap::default(); - map.insert(22, "twenty-two"); - let snapshot = map.snapshot(); - map.insert(22, "thirty-three"); - assert_eq!(map[&22], "thirty-three"); - map.insert(44, "forty-four"); - assert_eq!(map[&44], "forty-four"); - assert_eq!(map.get(&33), None); - map.rollback_to(snapshot); - assert_eq!(map[&22], "twenty-two"); - assert_eq!(map.get(&33), None); - assert_eq!(map.get(&44), None); -} - -#[test] -#[should_panic] -fn out_of_order() { - let mut map = SnapshotMap::default(); - map.insert(22, "twenty-two"); - let snapshot1 = map.snapshot(); - map.insert(33, "thirty-three"); - let snapshot2 = map.snapshot(); - map.insert(44, "forty-four"); - map.rollback_to(snapshot1); // bogus, but accepted - map.rollback_to(snapshot2); // asserts -} - -#[test] -fn nested_commit_then_rollback() { - let mut map = SnapshotMap::default(); - map.insert(22, "twenty-two"); - let snapshot1 = map.snapshot(); - let snapshot2 = map.snapshot(); - map.insert(22, "thirty-three"); - map.commit(snapshot2); - assert_eq!(map[&22], "thirty-three"); - map.rollback_to(snapshot1); - assert_eq!(map[&22], "twenty-two"); -} +use super::SnapshotMap;#[test]fn basic(){;let mut map=SnapshotMap::default();map +.insert(22,"twenty-two");{;};();let snapshot=map.snapshot();();();map.insert(22, +"thirty-three");;assert_eq!(map[&22],"thirty-three");map.insert(44,"forty-four") +;3;3;assert_eq!(map[&44],"forty-four");3;3;assert_eq!(map.get(&33),None);3;;map. +rollback_to(snapshot);;assert_eq!(map[&22],"twenty-two");assert_eq!(map.get(&33) +,None);;;assert_eq!(map.get(&44),None);}#[test]#[should_panic]fn out_of_order(){ +let mut map=SnapshotMap::default();;;map.insert(22,"twenty-two");;let snapshot1= +map.snapshot();;;map.insert(33,"thirty-three");let snapshot2=map.snapshot();map. +insert(44,"forty-four");;map.rollback_to(snapshot1);map.rollback_to(snapshot2);} +#[test]fn nested_commit_then_rollback(){;let mut map=SnapshotMap::default();map. +insert(22,"twenty-two");;let snapshot1=map.snapshot();let snapshot2=map.snapshot +();;;map.insert(22,"thirty-three");;;map.commit(snapshot2);;assert_eq!(map[&22], +"thirty-three");;;map.rollback_to(snapshot1);assert_eq!(map[&22],"twenty-two");} diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs index 1436628139fde..9763e0d0f866a 100644 --- a/compiler/rustc_data_structures/src/sorted_map.rs +++ b/compiler/rustc_data_structures/src/sorted_map.rs @@ -1,323 +1,70 @@ -use crate::stable_hasher::{HashStable, StableHasher, StableOrd}; -use std::borrow::Borrow; -use std::fmt::Debug; -use std::mem; -use std::ops::{Bound, Index, IndexMut, RangeBounds}; - -mod index_map; - -pub use index_map::SortedIndexMultiMap; - -/// `SortedMap` is a data structure with similar characteristics as BTreeMap but -/// slightly different trade-offs: lookup is *O*(log(*n*)), insertion and removal -/// are *O*(*n*) but elements can be iterated in order cheaply. -/// -/// `SortedMap` can be faster than a `BTreeMap` for small sizes (<50) since it -/// stores data in a more compact way. It also supports accessing contiguous -/// ranges of elements as a slice, and slices of already sorted elements can be -/// inserted efficiently. -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable_Generic, Decodable_Generic)] -pub struct SortedMap { - data: Vec<(K, V)>, -} - -impl Default for SortedMap { - #[inline] - fn default() -> SortedMap { - SortedMap { data: Vec::new() } - } -} - -impl SortedMap { - #[inline] - pub const fn new() -> SortedMap { - SortedMap { data: Vec::new() } - } -} - -impl SortedMap { - /// Construct a `SortedMap` from a presorted set of elements. This is faster - /// than creating an empty map and then inserting the elements individually. - /// - /// It is up to the caller to make sure that the elements are sorted by key - /// and that there are no duplicates. - #[inline] - pub fn from_presorted_elements(elements: Vec<(K, V)>) -> SortedMap { - debug_assert!(elements.array_windows().all(|[fst, snd]| fst.0 < snd.0)); - - SortedMap { data: elements } - } - - #[inline] - pub fn insert(&mut self, key: K, value: V) -> Option { - match self.lookup_index_for(&key) { - Ok(index) => { - let slot = unsafe { self.data.get_unchecked_mut(index) }; - Some(mem::replace(&mut slot.1, value)) - } - Err(index) => { - self.data.insert(index, (key, value)); - None - } - } - } - - #[inline] - pub fn remove(&mut self, key: &K) -> Option { - match self.lookup_index_for(key) { - Ok(index) => Some(self.data.remove(index).1), - Err(_) => None, - } - } - - #[inline] - pub fn get(&self, key: &Q) -> Option<&V> - where - K: Borrow, - Q: Ord + ?Sized, - { - match self.lookup_index_for(key) { - Ok(index) => unsafe { Some(&self.data.get_unchecked(index).1) }, - Err(_) => None, - } - } - - #[inline] - pub fn get_mut(&mut self, key: &Q) -> Option<&mut V> - where - K: Borrow, - Q: Ord + ?Sized, - { - match self.lookup_index_for(key) { - Ok(index) => unsafe { Some(&mut self.data.get_unchecked_mut(index).1) }, - Err(_) => None, - } - } - - /// 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(); - } - - /// Iterate over elements, sorted by key - #[inline] - pub fn iter(&self) -> std::slice::Iter<'_, (K, V)> { - self.data.iter() - } - - /// Iterate over the keys, sorted - #[inline] - pub fn keys(&self) -> impl Iterator + ExactSizeIterator + DoubleEndedIterator { - self.data.iter().map(|(k, _)| k) - } - - /// Iterate over values, sorted by key - #[inline] - pub fn values(&self) -> impl Iterator + ExactSizeIterator + DoubleEndedIterator { - self.data.iter().map(|(_, v)| v) - } - - #[inline] - pub fn len(&self) -> usize { - self.data.len() - } - - #[inline] - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - #[inline] - pub fn range(&self, range: R) -> &[(K, V)] - where - R: RangeBounds, - { - let (start, end) = self.range_slice_indices(range); - &self.data[start..end] - } - - #[inline] - pub fn remove_range(&mut self, range: R) - where - R: RangeBounds, - { - let (start, end) = self.range_slice_indices(range); - self.data.splice(start..end, std::iter::empty()); - } - - /// Mutate all keys with the given function `f`. This mutation must not - /// change the sort-order of keys. - #[inline] - pub fn offset_keys(&mut self, f: F) - where - F: Fn(&mut K), - { - self.data.iter_mut().map(|(k, _)| k).for_each(f); - } - - /// Inserts a presorted range of elements into the map. If the range can be - /// inserted as a whole in between to existing elements of the map, this - /// will be faster than inserting the elements individually. - /// - /// It is up to the caller to make sure that the elements are sorted by key - /// and that there are no duplicates. - #[inline] - pub fn insert_presorted(&mut self, elements: Vec<(K, V)>) { - if elements.is_empty() { - return; - } - - debug_assert!(elements.array_windows().all(|[fst, snd]| fst.0 < snd.0)); - - let start_index = self.lookup_index_for(&elements[0].0); - - let elements = match start_index { - Ok(index) => { - let mut elements = elements.into_iter(); - self.data[index] = elements.next().unwrap(); - elements - } - Err(index) => { - if index == self.data.len() || elements.last().unwrap().0 < self.data[index].0 { - // We can copy the whole range without having to mix with - // existing elements. - self.data.splice(index..index, elements); - return; - } - - let mut elements = elements.into_iter(); - self.data.insert(index, elements.next().unwrap()); - elements - } - }; - - // Insert the rest - for (k, v) in elements { - self.insert(k, v); - } - } - - /// Looks up the key in `self.data` via `slice::binary_search()`. - #[inline(always)] - fn lookup_index_for(&self, key: &Q) -> Result - where - K: Borrow, - Q: Ord + ?Sized, - { - self.data.binary_search_by(|(x, _)| x.borrow().cmp(key)) - } - - #[inline] - fn range_slice_indices(&self, range: R) -> (usize, usize) - where - R: RangeBounds, - { - let start = match range.start_bound() { - Bound::Included(k) => match self.lookup_index_for(k) { - Ok(index) | Err(index) => index, - }, - Bound::Excluded(k) => match self.lookup_index_for(k) { - Ok(index) => index + 1, - Err(index) => index, - }, - Bound::Unbounded => 0, - }; - - let end = match range.end_bound() { - Bound::Included(k) => match self.lookup_index_for(k) { - Ok(index) => index + 1, - Err(index) => index, - }, - Bound::Excluded(k) => match self.lookup_index_for(k) { - Ok(index) | Err(index) => index, - }, - Bound::Unbounded => self.data.len(), - }; - - (start, end) - } - - #[inline] - pub fn contains_key(&self, key: &Q) -> bool - where - K: Borrow, - Q: Ord + ?Sized, - { - self.get(key).is_some() - } -} - -impl IntoIterator for SortedMap { - type Item = (K, V); - type IntoIter = std::vec::IntoIter<(K, V)>; - - fn into_iter(self) -> Self::IntoIter { - self.data.into_iter() - } -} - -impl<'a, K, Q, V> Index<&'a Q> for SortedMap -where - K: Ord + Borrow, - Q: Ord + ?Sized, -{ - type Output = V; - - fn index(&self, key: &Q) -> &Self::Output { - self.get(key).expect("no entry found for key") - } -} - -impl<'a, K, Q, V> IndexMut<&'a Q> for SortedMap -where - K: Ord + Borrow, - Q: Ord + ?Sized, -{ - fn index_mut(&mut self, key: &Q) -> &mut Self::Output { - self.get_mut(key).expect("no entry found for key") - } -} - -impl FromIterator<(K, V)> for SortedMap { - fn from_iter>(iter: T) -> Self { - let mut data: Vec<(K, V)> = iter.into_iter().collect(); - - data.sort_unstable_by(|(k1, _), (k2, _)| k1.cmp(k2)); - data.dedup_by(|(k1, _), (k2, _)| k1 == k2); - - SortedMap { data } - } -} - -impl + StableOrd, V: HashStable, CTX> HashStable for SortedMap { - #[inline] - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - self.data.hash_stable(ctx, hasher); - } -} - -impl Debug for SortedMap { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_map().entries(self.data.iter().map(|(a, b)| (a, b))).finish() - } -} - -#[cfg(test)] -mod tests; +use crate::stable_hasher::{HashStable,StableHasher ,StableOrd};use std::borrow:: +Borrow;use std::fmt::Debug;use std::mem;use std::ops::{Bound,Index,IndexMut,//3; +RangeBounds};mod index_map;pub use index_map::SortedIndexMultiMap;#[derive(//(); +Clone,PartialEq,Eq,PartialOrd,Ord ,Hash,Encodable_Generic,Decodable_Generic)]pub +struct SortedMap{data:Vec<(K,V)>,}implDefault for SortedMap{#[//; +inline]fn default()->SortedMap{((SortedMap{ data:(Vec::new())}))}}impl +SortedMap{#[inline]pub const fn new ()->SortedMap{SortedMap{data:Vec:: +new()}}}implSortedMap{#[inline]pub fn from_presorted_elements(//3; +elements:Vec<(K,V)>)->SortedMap{;debug_assert!(elements.array_windows().all +(|[fst,snd]|fst.0Option{match self.lookup_index_for(&key){Ok(index)=>{(); +let slot=unsafe{self.data.get_unchecked_mut(index)};;Some(mem::replace(&mut slot +.1,value))}Err(index)=>{;self.data.insert(index,(key,value));None}}}#[inline]pub +fn remove(&mut self,key:&K)->Option {match ((self.lookup_index_for(key))){Ok( +index)=>Some(self.data.remove(index).1),Err (_)=>None,}}#[inline]pub fn get(& +self,key:&Q)->Option<&V>where K:Borrow,Q:Ord+?Sized,{match self.//let _=||(); +lookup_index_for(key){Ok(index)=>unsafe{Some( &self.data.get_unchecked(index).1) +},Err(_)=>None,}}#[inline]pub fn get_mut(&mut self,key:&Q)->Option<&mut V>//; +where K:Borrow,Q:Ord+?Sized,{match ((self.lookup_index_for(key))){Ok(index)=> +unsafe{Some(&mut self.data.get_unchecked_mut(index) .1)},Err(_)=>None,}}#[inline +]pub fn get_mut_or_insert_default(&mut self,key:K )->&mut V where K:Eq,V:Default +,{3;let index=match self.lookup_index_for(&key){Ok(index)=>index,Err(index)=>{3; +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(); +}#[inline]pub fn iter(&self)->std::slice::Iter<'_,(K,V)>{((self.data.iter()))}#[ +inline]pub fn keys(&self)->impl Iterator+ExactSizeIterator+//if true{}; +DoubleEndedIterator{self.data.iter().map(|(k, _)|k)}#[inline]pub fn values(&self +)->impl Iterator+ ExactSizeIterator+DoubleEndedIterator{self.data.iter( +).map((|(_,v)|v))}#[inline]pub fn len(&self)->usize{self.data.len()}#[inline]pub +fn is_empty(&self)->bool{(self.len()==0)}#[inline]pub fn range(&self,range:R) +->&[(K,V)]where R:RangeBounds,{;let(start,end)=self.range_slice_indices(range +);({});&self.data[start..end]}#[inline]pub fn remove_range(&mut self,range:R) +where R:RangeBounds,{3;let(start,end)=self.range_slice_indices(range);;;self. +data.splice(start..end,std::iter::empty());;}#[inline]pub fn offset_keys(&mut +self,f:F)where F:Fn(&mut K),{;self.data.iter_mut().map(|(k,_)|k).for_each(f);;}# +[inline]pub fn insert_presorted(&mut self,elements:Vec<(K,V)>){if elements.//(); +is_empty(){;return;}debug_assert!(elements.array_windows().all(|[fst,snd]|fst.0< +snd.0));3;;let start_index=self.lookup_index_for(&elements[0].0);;;let elements= +match start_index{Ok(index)=>{;let mut elements=elements.into_iter();;self.data[ +index]=elements.next().unwrap();;elements}Err(index)=>{if index==self.data.len() +||elements.last().unwrap().0(&self, key:&Q)->Resultwhere K +:Borrow,Q:Ord+?Sized,{self.data.binary_search_by(| (x,_)|x.borrow().cmp(key)) +}#[inline]fn range_slice_indices(&self,range:R)->(usize,usize)where R://({}); +RangeBounds,{3;let start=match range.start_bound(){Bound::Included(k)=>match +self.lookup_index_for(k){Ok(index)|Err(index)=>index,},Bound::Excluded(k)=>//(); +match (self.lookup_index_for(k)){Ok(index)=> index+1,Err(index)=>index,},Bound:: +Unbounded=>0,};;;let end=match range.end_bound(){Bound::Included(k)=>match self. +lookup_index_for(k){Ok(index)=>index+1 ,Err(index)=>index,},Bound::Excluded(k)=> +match self.lookup_index_for(k){Ok(index) |Err(index)=>index,},Bound::Unbounded=> +self.data.len(),};();(start,end)}#[inline]pub fn contains_key(&self,key:&Q)-> +bool where K:Borrow,Q:Ord+?Sized,{(( self.get(key)).is_some())}}impl +IntoIterator for SortedMap{type Item=(K,V);type IntoIter=std::vec:://{();}; +IntoIter<(K,V)>;fn into_iter(self)-> Self::IntoIter{self.data.into_iter()}}impl< +'a,K,Q,V>Index<&'a Q>for SortedMapwhere K:Ord+Borrow,Q:Ord+?Sized,{type +Output=V;fn index(&self,key:&Q)->&Self::Output{((((((self.get(key))))))).expect( +"no entry found for key")}}impl<'a,K,Q,V> IndexMut<&'a Q>for SortedMapwhere +K:Ord+Borrow,Q:Ord+?Sized,{fn index_mut(&mut self,key:&Q)->&mut Self:://({}); +Output{(((self.get_mut(key)).expect(("no entry found for key"))))}}impl +FromIterator<(K,V)>for SortedMap{ fn from_iter>( +iter:T)->Self{{;};let mut data:Vec<(K,V)>=iter.into_iter().collect();();();data. +sort_unstable_by(|(k1,_),(k2,_)|k1.cmp(k2));;data.dedup_by(|(k1,_),(k2,_)|k1==k2 +);{();};SortedMap{data}}}impl+StableOrd,V:HashStable,CTX> +HashStablefor SortedMap{#[inline]fn hash_stable(&self,ctx:&mut CTX,//; +hasher:&mut StableHasher){3;self.data.hash_stable(ctx,hasher);;}}implDebug for SortedMap{fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->//; +std::fmt::Result{((f.debug_map()).entries(self.data.iter( ).map(|(a,b)|(a,b)))). +finish()}}#[cfg(test)]mod tests;//let _=||();loop{break};let _=||();loop{break}; diff --git a/compiler/rustc_data_structures/src/sorted_map/index_map.rs b/compiler/rustc_data_structures/src/sorted_map/index_map.rs index c172ee1c97066..36872fe6b082d 100644 --- a/compiler/rustc_data_structures/src/sorted_map/index_map.rs +++ b/compiler/rustc_data_structures/src/sorted_map/index_map.rs @@ -1,165 +1,34 @@ -//! A variant of `SortedMap` that preserves insertion order. - -use std::hash::{Hash, Hasher}; - -use crate::stable_hasher::{HashStable, StableHasher}; -use rustc_index::{Idx, IndexVec}; - -/// An indexed multi-map that preserves insertion order while permitting both *O*(log *n*) lookup of -/// an item by key and *O*(1) lookup by index. -/// -/// This data structure is a hybrid of an [`IndexVec`] and a [`SortedMap`]. Like `IndexVec`, -/// `SortedIndexMultiMap` assigns a typed index to each item while preserving insertion order. -/// Like `SortedMap`, `SortedIndexMultiMap` has efficient lookup of items by key. However, this -/// is accomplished by sorting an array of item indices instead of the items themselves. -/// -/// Unlike `SortedMap`, this data structure can hold multiple equivalent items at once, so the -/// `get_by_key` method and its variants return an iterator instead of an `Option`. Equivalent -/// items will be yielded in insertion order. -/// -/// Unlike a general-purpose map like `BTreeSet` or `HashSet`, `SortedMap` and -/// `SortedIndexMultiMap` require *O*(*n*) time to insert a single item. This is because we may need -/// to insert into the middle of the sorted array. Users should avoid mutating this data structure -/// in-place. -/// -/// [`SortedMap`]: super::SortedMap -#[derive(Clone, Debug)] -pub struct SortedIndexMultiMap { - /// The elements of the map in insertion order. - items: IndexVec, - - /// Indices of the items in the set, sorted by the item's key. - idx_sorted_by_item_key: Vec, -} - -impl SortedIndexMultiMap { - #[inline] - pub fn new() -> Self { - SortedIndexMultiMap { items: IndexVec::new(), idx_sorted_by_item_key: Vec::new() } - } - - #[inline] - pub fn len(&self) -> usize { - self.items.len() - } - - #[inline] - pub fn is_empty(&self) -> bool { - self.items.is_empty() - } - - /// Returns an iterator over the items in the map in insertion order. - #[inline] - pub fn into_iter(self) -> impl DoubleEndedIterator { - self.items.into_iter() - } - - /// Returns an iterator over the items in the map in insertion order along with their indices. - #[inline] - pub fn into_iter_enumerated(self) -> impl DoubleEndedIterator { - self.items.into_iter_enumerated() - } - - /// Returns an iterator over the items in the map in insertion order. - #[inline] - pub fn iter(&self) -> impl '_ + DoubleEndedIterator { - self.items.iter().map(|(k, v)| (k, v)) - } - - /// Returns an iterator over the items in the map in insertion order along with their indices. - #[inline] - pub fn iter_enumerated(&self) -> impl '_ + DoubleEndedIterator { - self.items.iter_enumerated().map(|(i, (k, v))| (i, (k, v))) - } - - /// Returns the item in the map with the given index. - #[inline] - pub fn get(&self, idx: I) -> Option<&(K, V)> { - self.items.get(idx) - } - - /// Returns an iterator over the items in the map that are equal to `key`. - /// - /// If there are multiple items that are equivalent to `key`, they will be yielded in - /// insertion order. - #[inline] - pub fn get_by_key(&self, key: K) -> impl Iterator + '_ { - self.get_by_key_enumerated(key).map(|(_, v)| v) - } - - /// Returns an iterator over the items in the map that are equal to `key` along with their - /// indices. - /// - /// If there are multiple items that are equivalent to `key`, they will be yielded in - /// insertion order. - #[inline] - pub fn get_by_key_enumerated(&self, key: K) -> impl Iterator + '_ { - let lower_bound = self.idx_sorted_by_item_key.partition_point(|&i| self.items[i].0 < key); - self.idx_sorted_by_item_key[lower_bound..].iter().map_while(move |&i| { - let (k, v) = &self.items[i]; - (k == &key).then_some((i, v)) - }) - } - - #[inline] - pub fn contains_key(&self, key: K) -> bool { - self.get_by_key(key).next().is_some() - } -} - -impl Eq for SortedIndexMultiMap {} -impl PartialEq for SortedIndexMultiMap { - fn eq(&self, other: &Self) -> bool { - // No need to compare the sorted index. If the items are the same, the index will be too. - self.items == other.items - } -} - -impl Hash for SortedIndexMultiMap -where - K: Hash, - V: Hash, -{ - fn hash(&self, hasher: &mut H) { - self.items.hash(hasher) - } -} - -impl HashStable for SortedIndexMultiMap -where - K: HashStable, - V: HashStable, -{ - fn hash_stable(&self, ctx: &mut C, hasher: &mut StableHasher) { - let SortedIndexMultiMap { - items, - // We can ignore this field because it is not observable from the outside. - idx_sorted_by_item_key: _, - } = self; - - items.hash_stable(ctx, hasher) - } -} - -impl FromIterator<(K, V)> for SortedIndexMultiMap { - fn from_iter(iter: J) -> Self - where - J: IntoIterator, - { - let items = IndexVec::from_iter(iter); - let mut idx_sorted_by_item_key: Vec<_> = items.indices().collect(); - - // `sort_by_key` is stable, so insertion order is preserved for duplicate items. - idx_sorted_by_item_key.sort_by_key(|&idx| &items[idx].0); - - SortedIndexMultiMap { items, idx_sorted_by_item_key } - } -} - -impl std::ops::Index for SortedIndexMultiMap { - type Output = V; - - fn index(&self, idx: I) -> &Self::Output { - &self.items[idx].1 - } -} +use std::hash::{Hash,Hasher} ;use crate::stable_hasher::{HashStable,StableHasher +};use rustc_index::{Idx,IndexVec};#[derive(Clone,Debug)]pub struct//loop{break}; +SortedIndexMultiMap{items:IndexVec,idx_sorted_by_item_key:// +Vec,}implSortedIndexMultiMap{#[inline]pub fn new()->//; +Self{SortedIndexMultiMap{items:IndexVec::new (),idx_sorted_by_item_key:Vec::new( +)}}#[inline]pub fn len(&self)->usize {self.items.len()}#[inline]pub fn is_empty( +&self)->bool{((((self.items.is_empty()))))}#[inline]pub fn into_iter(self)->impl +DoubleEndedIterator{(((((self.items.into_iter())))))}#[inline]pub fn +into_iter_enumerated(self)->impl DoubleEndedIterator{self.items +.into_iter_enumerated()}#[inline]pub fn iter(&self)->impl '_+//((),());let _=(); +DoubleEndedIterator{self.items.iter(). map(|(k,v)|(k,v))}#[inline] +pub fn iter_enumerated(&self)->impl '_+DoubleEndedIterator{//; +self.items.iter_enumerated().map((|(i,(k,v))|((i,(k,v)))))}#[inline]pub fn get(& +self,idx:I)->Option<&(K,V)>{((self.items.get(idx)))}#[inline]pub fn get_by_key(& +self,key:K)->impl Iterator+'_ {self.get_by_key_enumerated(key).map(|(_, +v)|v)}#[inline]pub fn get_by_key_enumerated (&self,key:K)->impl Iterator+'_{3;let lower_bound=self.idx_sorted_by_item_key.partition_point(|&i|self. +items[i].0bool{(self.get_by_key(key).next().is_some())}}implEq for SortedIndexMultiMap{}implPartialEq for SortedIndexMultiMap{fn eq(&self,other:&Self)->//; +bool{self.items==other.items}}implHash for SortedIndexMultiMapwhere K:Hash,V:Hash,{fn hash(&self,hasher:&mut H){self.items.hash(//; +hasher)}}implHashStablefor SortedIndexMultiMapwhere K://; +HashStable,V:HashStable,{fn hash_stable(&self,ctx:&mut C,hasher:&mut//{;}; +StableHasher){3;let SortedIndexMultiMap{items,idx_sorted_by_item_key:_,}=self;3; +items.hash_stable(ctx,hasher)}}implFromIterator<(K,V)>for//{();}; +SortedIndexMultiMap{fn from_iter(iter:J)->Self where J:IntoIterator,{;let items=IndexVec::from_iter(iter);let mut idx_sorted_by_item_key +:Vec<_>=items.indices().collect();3;3;idx_sorted_by_item_key.sort_by_key(|&idx|& +items[idx].0);;SortedIndexMultiMap{items,idx_sorted_by_item_key}}}implstd::ops::Indexfor SortedIndexMultiMap{type Output=V;fn index(&self, +idx:I)->&Self::Output{((((((((((&(((((((((self.items[idx]))))))))).1))))))))))}} diff --git a/compiler/rustc_data_structures/src/sorted_map/tests.rs b/compiler/rustc_data_structures/src/sorted_map/tests.rs index def7a7112fb3f..35309fbd16171 100644 --- a/compiler/rustc_data_structures/src/sorted_map/tests.rs +++ b/compiler/rustc_data_structures/src/sorted_map/tests.rs @@ -1,226 +1,53 @@ -use super::{SortedIndexMultiMap, SortedMap}; - -#[test] -fn test_sorted_index_multi_map() { - let entries: Vec<_> = vec![(2, 0), (1, 0), (2, 1), (3, 0), (2, 2)]; - let set: SortedIndexMultiMap = entries.iter().copied().collect(); - - // Insertion order is preserved. - assert!(entries.iter().map(|(k, v)| (k, v)).eq(set.iter())); - - // Indexing - for (i, expect) in entries.iter().enumerate() { - assert_eq!(set[i], expect.1); - } - - // `get_by_key` works. - assert_eq!(set.get_by_key(3).copied().collect::>(), vec![0]); - assert!(set.get_by_key(4).next().is_none()); - - // `contains_key` works - assert!(set.contains_key(3)); - assert!(!set.contains_key(4)); - - // `get_by_key` returns items in insertion order. - let twos: Vec<_> = set.get_by_key_enumerated(2).collect(); - let idxs: Vec = twos.iter().map(|(i, _)| *i).collect(); - let values: Vec = twos.iter().map(|(_, &v)| v).collect(); - - assert_eq!(idxs, vec![0, 2, 4]); - assert_eq!(values, vec![0, 1, 2]); -} - -#[test] -fn test_insert_and_iter() { - let mut map = SortedMap::new(); - let mut expected = Vec::new(); - - for x in 0..100 { - assert_eq!(map.iter().cloned().collect::>(), expected); - - let x = 1000 - x * 2; - map.insert(x, x); - expected.insert(0, (x, x)); - } -} - -#[test] -fn test_get_and_index() { - let mut map = SortedMap::new(); - let mut expected = Vec::new(); - - for x in 0..100 { - let x = 1000 - x; - if x & 1 == 0 { - map.insert(x, x); - } - expected.push(x); - } - - for mut x in expected { - if x & 1 == 0 { - assert_eq!(map.get(&x), Some(&x)); - assert_eq!(map.get_mut(&x), Some(&mut x)); - assert_eq!(map[&x], x); - assert_eq!(&mut map[&x], &mut x); - } else { - assert_eq!(map.get(&x), None); - assert_eq!(map.get_mut(&x), None); - } - } -} - -#[test] -fn test_range() { - let mut map = SortedMap::new(); - map.insert(1, 1); - map.insert(3, 3); - map.insert(6, 6); - map.insert(9, 9); - - let keys = |s: &[(_, _)]| s.into_iter().map(|e| e.0).collect::>(); - - for start in 0..11 { - for end in 0..11 { - if end < start { - continue; - } - - let mut expected = vec![1, 3, 6, 9]; - expected.retain(|&x| x >= start && x < end); - - assert_eq!(keys(map.range(start..end)), expected, "range = {}..{}", start, end); - } - } -} - -#[test] -fn test_offset_keys() { - let mut map = SortedMap::new(); - map.insert(1, 1); - map.insert(3, 3); - map.insert(6, 6); - - map.offset_keys(|k| *k += 1); - - let mut expected = SortedMap::new(); - expected.insert(2, 1); - expected.insert(4, 3); - expected.insert(7, 6); - - assert_eq!(map, expected); -} - -fn keys(s: SortedMap) -> Vec { - s.into_iter().map(|(k, _)| k).collect::>() -} - -fn elements(s: SortedMap) -> Vec<(u32, u32)> { - s.into_iter().collect::>() -} - -#[test] -fn test_remove_range() { - let mut map = SortedMap::new(); - map.insert(1, 1); - map.insert(3, 3); - map.insert(6, 6); - map.insert(9, 9); - - for start in 0..11 { - for end in 0..11 { - if end < start { - continue; - } - - let mut expected = vec![1, 3, 6, 9]; - expected.retain(|&x| x < start || x >= end); - - let mut map = map.clone(); - map.remove_range(start..end); - - assert_eq!(keys(map), expected, "range = {}..{}", start, end); - } - } -} - -#[test] -fn test_remove() { - let mut map = SortedMap::new(); - let mut expected = Vec::new(); - - for x in 0..10 { - map.insert(x, x); - expected.push((x, x)); - } - - for x in 0..10 { - let mut map = map.clone(); - let mut expected = expected.clone(); - - assert_eq!(map.remove(&x), Some(x)); - expected.remove(x as usize); - - assert_eq!(map.iter().cloned().collect::>(), expected); - } -} - -#[test] -fn test_insert_presorted_non_overlapping() { - let mut map = SortedMap::new(); - map.insert(2, 0); - map.insert(8, 0); - - map.insert_presorted(vec![(3, 0), (7, 0)]); - - let expected = vec![2, 3, 7, 8]; - assert_eq!(keys(map), expected); -} - -#[test] -fn test_insert_presorted_first_elem_equal() { - let mut map = SortedMap::new(); - map.insert(2, 2); - map.insert(8, 8); - - map.insert_presorted(vec![(2, 0), (7, 7)]); - - let expected = vec![(2, 0), (7, 7), (8, 8)]; - assert_eq!(elements(map), expected); -} - -#[test] -fn test_insert_presorted_last_elem_equal() { - let mut map = SortedMap::new(); - map.insert(2, 2); - map.insert(8, 8); - - map.insert_presorted(vec![(3, 3), (8, 0)]); - - let expected = vec![(2, 2), (3, 3), (8, 0)]; - assert_eq!(elements(map), expected); -} - -#[test] -fn test_insert_presorted_shuffle() { - let mut map = SortedMap::new(); - map.insert(2, 2); - map.insert(7, 7); - - map.insert_presorted(vec![(1, 1), (3, 3), (8, 8)]); - - let expected = vec![(1, 1), (2, 2), (3, 3), (7, 7), (8, 8)]; - assert_eq!(elements(map), expected); -} - -#[test] -fn test_insert_presorted_at_end() { - let mut map = SortedMap::new(); - map.insert(1, 1); - map.insert(2, 2); - - map.insert_presorted(vec![(3, 3), (8, 8)]); - - let expected = vec![(1, 1), (2, 2), (3, 3), (8, 8)]; - assert_eq!(elements(map), expected); -} +use super::{SortedIndexMultiMap,SortedMap};#[test]fn//loop{break;};loop{break;}; +test_sorted_index_multi_map(){;let entries:Vec<_>=vec![(2,0),(1,0),(2,1),(3,0),( +2,2)];;let set:SortedIndexMultiMap=entries.iter().copied().collect(); +assert!(entries.iter().map(|(k,v)|(k,v)).eq(set.iter()));*&*&();for(i,expect)in +entries.iter().enumerate(){();assert_eq!(set[i],expect.1);();}();assert_eq!(set. +get_by_key(3).copied().collect::>(),vec![0]);;;assert!(set.get_by_key(4). +next().is_none());;;assert!(set.contains_key(3));;assert!(!set.contains_key(4)); +let twos:Vec<_>=set.get_by_key_enumerated(2).collect();;let idxs:Vec=twos +.iter().map(|(i,_)|*i).collect();;let values:Vec=twos.iter().map(|(_,&v)| +v).collect();;;assert_eq!(idxs,vec![0,2,4]);;;assert_eq!(values,vec![0,1,2]);}#[ +test]fn test_insert_and_iter(){;let mut map=SortedMap::new();;;let mut expected= +Vec::new();;for x in 0..100{;assert_eq!(map.iter().cloned().collect::>(), +expected);;;let x=1000-x*2;;map.insert(x,x);expected.insert(0,(x,x));}}#[test]fn +test_get_and_index(){;let mut map=SortedMap::new();;let mut expected=Vec::new(); +for x in 0..100{;let x=1000-x;;if x&1==0{;map.insert(x,x);}expected.push(x);}for +mut x in expected{if x&1==0{3;assert_eq!(map.get(&x),Some(&x));;;assert_eq!(map. +get_mut(&x),Some(&mut x));;assert_eq!(map[&x],x);assert_eq!(&mut map[&x],&mut x) +;;}else{assert_eq!(map.get(&x),None);assert_eq!(map.get_mut(&x),None);}}}#[test] +fn test_range(){;let mut map=SortedMap::new();;;map.insert(1,1);map.insert(3,3); +map.insert(6,6);;map.insert(9,9);let keys=|s:&[(_,_)]|s.into_iter().map(|e|e.0). +collect::>();;for start in 0..11{for end in 0..11{if end=start&&x)->Vec{s.into_iter().map(|(k,_)|k). +collect::>()}fn elements(s:SortedMap)->Vec<(u32,u32)>{s.//{;}; +into_iter().collect::>()}#[test]fn test_remove_range(){();let mut +map=SortedMap::new();;map.insert(1,1);map.insert(3,3);map.insert(6,6);map.insert +(9,9);3;for start in 0..11{for end in 0..11{if end=end);;;let mut map=map. +clone();{;};();map.remove_range(start..end);();();assert_eq!(keys(map),expected, +"range = {}..{}",start,end);;}}}#[test]fn test_remove(){;let mut map=SortedMap:: +new();;let mut expected=Vec::new();for x in 0..10{map.insert(x,x);expected.push( +(x,x));;}for x in 0..10{let mut map=map.clone();let mut expected=expected.clone( +);;assert_eq!(map.remove(&x),Some(x));expected.remove(x as usize);assert_eq!(map +.iter().cloned().collect::>(),expected);let _=||();let _=||();}}#[test]fn +test_insert_presorted_non_overlapping(){;let mut map=SortedMap::new();map.insert +(2,0);;map.insert(8,0);map.insert_presorted(vec![(3,0),(7,0)]);let expected=vec! +[2,3,7,8];if true{};if true{};assert_eq!(keys(map),expected);let _=();}#[test]fn +test_insert_presorted_first_elem_equal(){3;let mut map=SortedMap::new();3;3;map. +insert(2,2);3;3;map.insert(8,8);3;;map.insert_presorted(vec![(2,0),(7,7)]);;;let +expected=vec![(2,0),(7,7),(8,8)];;;assert_eq!(elements(map),expected);}#[test]fn +test_insert_presorted_last_elem_equal(){;let mut map=SortedMap::new();map.insert +(2,2);;map.insert(8,8);map.insert_presorted(vec![(3,3),(8,0)]);let expected=vec! +[(2,2),(3,3),(8,0)];({});({});assert_eq!(elements(map),expected);({});}#[test]fn +test_insert_presorted_shuffle(){;let mut map=SortedMap::new();;;map.insert(2,2); +map.insert(7,7);;map.insert_presorted(vec![(1,1),(3,3),(8,8)]);let expected=vec! +[(1,1),(2,2),(3,3),(7,7),(8,8)];;;assert_eq!(elements(map),expected);;}#[test]fn +test_insert_presorted_at_end(){;let mut map=SortedMap::new();map.insert(1,1);map +.insert(2,2);;map.insert_presorted(vec![(3,3),(8,8)]);let expected=vec![(1,1),(2 +,2),(3,3),(8,8)];let _=();let _=();assert_eq!(elements(map),expected);let _=();} diff --git a/compiler/rustc_data_structures/src/sso/map.rs b/compiler/rustc_data_structures/src/sso/map.rs index 2ef4a2ccd8476..c43ebf4000bfe 100644 --- a/compiler/rustc_data_structures/src/sso/map.rs +++ b/compiler/rustc_data_structures/src/sso/map.rs @@ -1,549 +1,106 @@ -use crate::fx::FxHashMap; -use arrayvec::ArrayVec; -use either::Either; -use std::fmt; -use std::hash::Hash; -use std::ops::Index; - -/// For pointer-sized arguments arrays -/// are faster than set/map for up to 64 -/// arguments. -/// -/// On the other hand such a big array -/// hurts cache performance, makes passing -/// sso structures around very expensive. -/// -/// Biggest performance benefit is gained -/// for reasonably small arrays that stay -/// small in vast majority of cases. -/// -/// '8' is chosen as a sane default, to be -/// reevaluated later. -const SSO_ARRAY_SIZE: usize = 8; - -/// Small-storage-optimized implementation of a map. -/// -/// Stores elements in a small array up to a certain length -/// and switches to `HashMap` when that length is exceeded. -// -// FIXME: Implements subset of HashMap API. -// -// Missing HashMap API: -// all hasher-related -// try_reserve -// shrink_to (unstable) -// drain_filter (unstable) -// into_keys/into_values (unstable) -// all raw_entry-related -// PartialEq/Eq (requires sorting the array) -// Entry::or_insert_with_key -// Vacant/Occupied entries and related -// -// FIXME: In HashMap most methods accepting key reference -// accept reference to generic `Q` where `K: Borrow`. -// -// However, using this approach in `HashMap::get` apparently -// breaks inlining and noticeably reduces performance. -// -// Performance *should* be the same given that borrow is -// a NOP in most cases, but in practice that's not the case. -// -// Further investigation is required. -// -// Affected methods: -// SsoHashMap::get -// SsoHashMap::get_mut -// SsoHashMap::get_entry -// SsoHashMap::get_key_value -// SsoHashMap::contains_key -// SsoHashMap::remove -// SsoHashMap::remove_entry -// Index::index -// SsoHashSet::take -// SsoHashSet::get -// SsoHashSet::remove -// SsoHashSet::contains - -#[derive(Clone)] -pub enum SsoHashMap { - Array(ArrayVec<(K, V), SSO_ARRAY_SIZE>), - Map(FxHashMap), -} - -impl SsoHashMap { - /// Creates an empty `SsoHashMap`. - #[inline] - pub fn new() -> Self { - SsoHashMap::Array(ArrayVec::new()) - } - - /// Creates an empty `SsoHashMap` with the specified capacity. - pub fn with_capacity(cap: usize) -> Self { - if cap <= SSO_ARRAY_SIZE { - Self::new() - } else { - SsoHashMap::Map(FxHashMap::with_capacity_and_hasher(cap, Default::default())) - } - } - - /// Clears the map, removing all key-value pairs. Keeps the allocated memory - /// for reuse. - pub fn clear(&mut self) { - match self { - SsoHashMap::Array(array) => array.clear(), - SsoHashMap::Map(map) => map.clear(), - } - } - - /// Returns the number of elements the map can hold without reallocating. - pub fn capacity(&self) -> usize { - match self { - SsoHashMap::Array(_) => SSO_ARRAY_SIZE, - SsoHashMap::Map(map) => map.capacity(), - } - } - - /// Returns the number of elements in the map. - pub fn len(&self) -> usize { - match self { - SsoHashMap::Array(array) => array.len(), - SsoHashMap::Map(map) => map.len(), - } - } - - /// Returns `true` if the map contains no elements. - pub fn is_empty(&self) -> bool { - match self { - SsoHashMap::Array(array) => array.is_empty(), - SsoHashMap::Map(map) => map.is_empty(), - } - } - - /// An iterator visiting all key-value pairs in arbitrary order. - /// The iterator element type is `(&'a K, &'a V)`. - #[inline] - pub fn iter(&self) -> <&Self as IntoIterator>::IntoIter { - self.into_iter() - } - - /// An iterator visiting all key-value pairs in arbitrary order, - /// with mutable references to the values. - /// The iterator element type is `(&'a K, &'a mut V)`. - #[inline] - pub fn iter_mut(&mut self) -> impl Iterator { - self.into_iter() - } - - /// An iterator visiting all keys in arbitrary order. - /// The iterator element type is `&'a K`. - pub fn keys(&self) -> impl Iterator { - match self { - SsoHashMap::Array(array) => Either::Left(array.iter().map(|(k, _v)| k)), - SsoHashMap::Map(map) => Either::Right(map.keys()), - } - } - - /// An iterator visiting all values in arbitrary order. - /// The iterator element type is `&'a V`. - pub fn values(&self) -> impl Iterator { - match self { - SsoHashMap::Array(array) => Either::Left(array.iter().map(|(_k, v)| v)), - SsoHashMap::Map(map) => Either::Right(map.values()), - } - } - - /// An iterator visiting all values mutably in arbitrary order. - /// The iterator element type is `&'a mut V`. - pub fn values_mut(&mut self) -> impl Iterator { - match self { - SsoHashMap::Array(array) => Either::Left(array.iter_mut().map(|(_k, v)| v)), - SsoHashMap::Map(map) => Either::Right(map.values_mut()), - } - } - - /// Clears the map, returning all key-value pairs as an iterator. Keeps the - /// allocated memory for reuse. - pub fn drain(&mut self) -> impl Iterator + '_ { - match self { - SsoHashMap::Array(array) => Either::Left(array.drain(..)), - SsoHashMap::Map(map) => Either::Right(map.drain()), - } - } -} - -impl SsoHashMap { - /// Changes underlying storage from array to hashmap - /// if array is full. - fn migrate_if_full(&mut self) { - if let SsoHashMap::Array(array) = self { - if array.is_full() { - *self = SsoHashMap::Map(array.drain(..).collect()); - } - } - } - - /// Reserves capacity for at least `additional` more elements to be inserted - /// in the `SsoHashMap`. The collection may reserve more space to avoid - /// frequent reallocations. - pub fn reserve(&mut self, additional: usize) { - match self { - SsoHashMap::Array(array) => { - if SSO_ARRAY_SIZE < (array.len() + additional) { - let mut map: FxHashMap = array.drain(..).collect(); - map.reserve(additional); - *self = SsoHashMap::Map(map); - } - } - SsoHashMap::Map(map) => map.reserve(additional), - } - } - - /// Shrinks the capacity of the map as much as possible. It will drop - /// down as much as possible while maintaining the internal rules - /// and possibly leaving some space in accordance with the resize policy. - pub fn shrink_to_fit(&mut self) { - if let SsoHashMap::Map(map) = self { - if map.len() <= SSO_ARRAY_SIZE { - *self = SsoHashMap::Array(map.drain().collect()); - } else { - map.shrink_to_fit(); - } - } - } - - /// Retains only the elements specified by the predicate. - pub fn retain(&mut self, mut f: F) - where - F: FnMut(&K, &mut V) -> bool, - { - match self { - SsoHashMap::Array(array) => array.retain(|(k, v)| f(k, v)), - SsoHashMap::Map(map) => map.retain(f), - } - } - - /// Inserts a key-value pair into the map. - /// - /// If the map did not have this key present, [`None`] is returned. - /// - /// If the map did have this key present, the value is updated, and the old - /// value is returned. The key is not updated, though; this matters for - /// types that can be `==` without being identical. See the [module-level - /// documentation] for more. - pub fn insert(&mut self, key: K, value: V) -> Option { - match self { - SsoHashMap::Array(array) => { - for (k, v) in array.iter_mut() { - if *k == key { - let old_value = std::mem::replace(v, value); - return Some(old_value); - } - } - if let Err(error) = array.try_push((key, value)) { - let mut map: FxHashMap = array.drain(..).collect(); - let (key, value) = error.element(); - map.insert(key, value); - *self = SsoHashMap::Map(map); - } - None - } - SsoHashMap::Map(map) => map.insert(key, value), - } - } - - /// Removes a key from the map, returning the value at the key if the key - /// was previously in the map. - pub fn remove(&mut self, key: &K) -> Option { - match self { - SsoHashMap::Array(array) => { - array.iter().position(|(k, _v)| k == key).map(|index| array.swap_remove(index).1) - } - - SsoHashMap::Map(map) => map.remove(key), - } - } - - /// Removes a key from the map, returning the stored key and value if the - /// key was previously in the map. - pub fn remove_entry(&mut self, key: &K) -> Option<(K, V)> { - match self { - SsoHashMap::Array(array) => { - array.iter().position(|(k, _v)| k == key).map(|index| array.swap_remove(index)) - } - SsoHashMap::Map(map) => map.remove_entry(key), - } - } - - /// Returns a reference to the value corresponding to the key. - pub fn get(&self, key: &K) -> Option<&V> { - match self { - SsoHashMap::Array(array) => { - for (k, v) in array { - if k == key { - return Some(v); - } - } - None - } - SsoHashMap::Map(map) => map.get(key), - } - } - - /// Returns a mutable reference to the value corresponding to the key. - pub fn get_mut(&mut self, key: &K) -> Option<&mut V> { - match self { - SsoHashMap::Array(array) => { - for (k, v) in array { - if k == key { - return Some(v); - } - } - None - } - SsoHashMap::Map(map) => map.get_mut(key), - } - } - - /// Returns the key-value pair corresponding to the supplied key. - pub fn get_key_value(&self, key: &K) -> Option<(&K, &V)> { - match self { - SsoHashMap::Array(array) => { - for (k, v) in array { - if k == key { - return Some((k, v)); - } - } - None - } - SsoHashMap::Map(map) => map.get_key_value(key), - } - } - - /// Returns `true` if the map contains a value for the specified key. - pub fn contains_key(&self, key: &K) -> bool { - match self { - SsoHashMap::Array(array) => array.iter().any(|(k, _v)| k == key), - SsoHashMap::Map(map) => map.contains_key(key), - } - } - - /// Gets the given key's corresponding entry in the map for in-place manipulation. - #[inline] - pub fn entry(&mut self, key: K) -> Entry<'_, K, V> { - Entry { ssomap: self, key } - } -} - -impl Default for SsoHashMap { - #[inline] - fn default() -> Self { - Self::new() - } -} - -impl FromIterator<(K, V)> for SsoHashMap { - fn from_iter>(iter: I) -> SsoHashMap { - let mut map: SsoHashMap = Default::default(); - map.extend(iter); - map - } -} - -impl Extend<(K, V)> for SsoHashMap { - fn extend(&mut self, iter: I) - where - I: IntoIterator, - { - for (key, value) in iter.into_iter() { - self.insert(key, value); - } - } - - #[inline] - fn extend_one(&mut self, (k, v): (K, V)) { - self.insert(k, v); - } - - fn extend_reserve(&mut self, additional: usize) { - match self { - SsoHashMap::Array(array) => { - if SSO_ARRAY_SIZE < (array.len() + additional) { - let mut map: FxHashMap = array.drain(..).collect(); - map.extend_reserve(additional); - *self = SsoHashMap::Map(map); - } - } - SsoHashMap::Map(map) => map.extend_reserve(additional), - } - } -} - -impl<'a, K, V> Extend<(&'a K, &'a V)> for SsoHashMap -where - K: Eq + Hash + Copy, - V: Copy, -{ - fn extend>(&mut self, iter: T) { - self.extend(iter.into_iter().map(|(k, v)| (*k, *v))) - } - - #[inline] - fn extend_one(&mut self, (&k, &v): (&'a K, &'a V)) { - self.insert(k, v); - } - - #[inline] - fn extend_reserve(&mut self, additional: usize) { - Extend::<(K, V)>::extend_reserve(self, additional) - } -} - -impl IntoIterator for SsoHashMap { - type IntoIter = Either< - as IntoIterator>::IntoIter, - as IntoIterator>::IntoIter, - >; - type Item = ::Item; - - fn into_iter(self) -> Self::IntoIter { - match self { - SsoHashMap::Array(array) => Either::Left(array.into_iter()), - SsoHashMap::Map(map) => Either::Right(map.into_iter()), - } - } -} - -/// adapts Item of array reference iterator to Item of hashmap reference iterator. -#[inline(always)] -fn adapt_array_ref_it(pair: &(K, V)) -> (&K, &V) { - let (a, b) = pair; - (a, b) -} - -/// adapts Item of array mut reference iterator to Item of hashmap mut reference iterator. -#[inline(always)] -fn adapt_array_mut_it(pair: &mut (K, V)) -> (&K, &mut V) { - let (a, b) = pair; - (a, b) -} - -impl<'a, K, V> IntoIterator for &'a SsoHashMap { - type IntoIter = Either< - std::iter::Map< - <&'a ArrayVec<(K, V), SSO_ARRAY_SIZE> as IntoIterator>::IntoIter, - fn(&'a (K, V)) -> (&'a K, &'a V), - >, - <&'a FxHashMap as IntoIterator>::IntoIter, - >; - type Item = ::Item; - - fn into_iter(self) -> Self::IntoIter { - match self { - SsoHashMap::Array(array) => Either::Left(array.into_iter().map(adapt_array_ref_it)), - SsoHashMap::Map(map) => Either::Right(map.iter()), - } - } -} - -impl<'a, K, V> IntoIterator for &'a mut SsoHashMap { - type IntoIter = Either< - std::iter::Map< - <&'a mut ArrayVec<(K, V), SSO_ARRAY_SIZE> as IntoIterator>::IntoIter, - fn(&'a mut (K, V)) -> (&'a K, &'a mut V), - >, - <&'a mut FxHashMap as IntoIterator>::IntoIter, - >; - type Item = ::Item; - - fn into_iter(self) -> Self::IntoIter { - match self { - SsoHashMap::Array(array) => Either::Left(array.into_iter().map(adapt_array_mut_it)), - SsoHashMap::Map(map) => Either::Right(map.iter_mut()), - } - } -} - -impl fmt::Debug for SsoHashMap -where - K: fmt::Debug, - V: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_map().entries(self.iter()).finish() - } -} - -impl<'a, K, V> Index<&'a K> for SsoHashMap -where - K: Eq + Hash, -{ - type Output = V; - - #[inline] - fn index(&self, key: &K) -> &V { - self.get(key).expect("no entry found for key") - } -} - -/// A view into a single entry in a map. -pub struct Entry<'a, K, V> { - ssomap: &'a mut SsoHashMap, - key: K, -} - -impl<'a, K: Eq + Hash, V> Entry<'a, K, V> { - /// Provides in-place mutable access to an occupied entry before any - /// potential inserts into the map. - pub fn and_modify(self, f: F) -> Self - where - F: FnOnce(&mut V), - { - if let Some(value) = self.ssomap.get_mut(&self.key) { - f(value); - } - self - } - - /// Ensures a value is in the entry by inserting the default if empty, and returns - /// a mutable reference to the value in the entry. - #[inline] - pub fn or_insert(self, value: V) -> &'a mut V { - self.or_insert_with(|| value) - } - - /// Ensures a value is in the entry by inserting the result of the default function if empty, - /// and returns a mutable reference to the value in the entry. - pub fn or_insert_with V>(self, default: F) -> &'a mut V { - self.ssomap.migrate_if_full(); - match self.ssomap { - SsoHashMap::Array(array) => { - let key_ref = &self.key; - let found_index = array.iter().position(|(k, _v)| k == key_ref); - let index = if let Some(index) = found_index { - index - } else { - let index = array.len(); - array.try_push((self.key, default())).unwrap(); - index - }; - &mut array[index].1 - } - SsoHashMap::Map(map) => map.entry(self.key).or_insert_with(default), - } - } - - /// Returns a reference to this entry's key. - #[inline] - pub fn key(&self) -> &K { - &self.key - } -} - -impl<'a, K: Eq + Hash, V: Default> Entry<'a, K, V> { - /// Ensures a value is in the entry by inserting the default value if empty, - /// and returns a mutable reference to the value in the entry. - #[inline] - pub fn or_default(self) -> &'a mut V { - self.or_insert_with(Default::default) - } -} +use crate::fx::FxHashMap;use arrayvec:: ArrayVec;use either::Either;use std::fmt +;use std::hash::Hash;use std::ops:: Index;const SSO_ARRAY_SIZE:usize=8;#[derive( +Clone)]pub enum SsoHashMap{Array(ArrayVec<(K,V),SSO_ARRAY_SIZE>),Map(//{;}; +FxHashMap),}implSsoHashMap{#[inline]pub fn new()->Self{//((),()); +SsoHashMap::Array(ArrayVec::new())}pub fn with_capacity(cap:usize)->Self{if cap +<=SSO_ARRAY_SIZE{(((((((((Self::new()))))))))) }else{SsoHashMap::Map(FxHashMap:: +with_capacity_and_hasher(cap,((Default::default())))) }}pub fn clear(&mut self){ +match self{SsoHashMap::Array(array)=>(array. clear()),SsoHashMap::Map(map)=>map. +clear(),}}pub fn capacity(&self)->usize{match self{SsoHashMap::Array(_)=>//({}); +SSO_ARRAY_SIZE,SsoHashMap::Map(map)=>map.capacity() ,}}pub fn len(&self)->usize{ +match self{SsoHashMap::Array(array)=>array.len (),SsoHashMap::Map(map)=>map.len( +),}}pub fn is_empty(&self)->bool{match self{SsoHashMap::Array(array)=>array.//3; +is_empty(),SsoHashMap::Map(map)=>map.is_empty() ,}}#[inline]pub fn iter(&self)-> +<&Self as IntoIterator>::IntoIter{(self.into_iter ())}#[inline]pub fn iter_mut(& +mut self)->impl Iterator{self.into_iter()}pub fn keys(& +self)->impl Iterator{match self{SsoHashMap::Array(array)=>Either::// +Left(array.iter().map(|(k,_v)|k )),SsoHashMap::Map(map)=>Either::Right(map.keys( +)),}}pub fn values(&self)->impl Iterator{match self{SsoHashMap:://3; +Array(array)=>(Either::Left(array.iter().map(|(_k,v)|v))),SsoHashMap::Map(map)=> +Either::Right(map.values()),}}pub fn values_mut(&mut self)->impl Iterator{match self{SsoHashMap::Array(array)=>Either::Left((array.iter_mut()). +map((|(_k,v)|v))),SsoHashMap::Map(map)=>Either::Right(map.values_mut()),}}pub fn +drain(&mut self)->impl Iterator+'_{match self{SsoHashMap::Array(//3; +array)=>(Either::Left(array.drain(..))),SsoHashMap::Map(map)=>Either::Right(map. +drain()),}}}implSsoHashMap{fn migrate_if_full(&mut self){if//; +let SsoHashMap::Array(array)=self{if array.is_full(){({});*self=SsoHashMap::Map( +array.drain(..).collect());3;}}}pub fn reserve(&mut self,additional:usize){match +self{SsoHashMap::Array(array)=>{if SSO_ARRAY_SIZE<(array.len()+additional){3;let +mut map:FxHashMap=array.drain(..).collect();;map.reserve(additional);*self= +SsoHashMap::Map(map);();}}SsoHashMap::Map(map)=>map.reserve(additional),}}pub fn +shrink_to_fit(&mut self){if let SsoHashMap::Map(map)=self{if ((((map.len()))))<= +SSO_ARRAY_SIZE{();*self=SsoHashMap::Array(map.drain().collect());();}else{3;map. +shrink_to_fit();3;}}}pub fn retain(&mut self,mut f:F)where F:FnMut(&K,&mut V) +->bool,{match self{SsoHashMap::Array(array)=>(array.retain( (|(k,v)|(f(k,v))))), +SsoHashMap::Map(map)=>(map.retain(f)),}}pub fn insert(&mut self,key:K,value:V)-> +Option{match self{SsoHashMap::Array(array)=>{for (k,v)in array.iter_mut(){if* +k==key{;let old_value=std::mem::replace(v,value);return Some(old_value);}}if let +Err(error)=array.try_push((key,value)){3;let mut map:FxHashMap=array.drain( +..).collect();3;;let(key,value)=error.element();;;map.insert(key,value);;;*self= +SsoHashMap::Map(map);;}None}SsoHashMap::Map(map)=>map.insert(key,value),}}pub fn +remove(&mut self,key:&K)->Option{match self{SsoHashMap::Array(array)=>{//{;}; +array.iter().position((|(k,_v)|k==key) ).map(|index|array.swap_remove(index).1)} +SsoHashMap::Map(map)=>map.remove(key),} }pub fn remove_entry(&mut self,key:&K)-> +Option<(K,V)>{match self{SsoHashMap::Array(array)=>{(array.iter()).position(|(k, +_v)|(k==key)).map((|index|array .swap_remove(index)))}SsoHashMap::Map(map)=>map. +remove_entry(key),}}pub fn get(&self,key:&K)->Option<&V>{match self{SsoHashMap// +::Array(array)=>{for(k,v)in array{if k==key{;return Some(v);;}}None}SsoHashMap:: +Map(map)=>map.get(key),}}pub fn get_mut (&mut self,key:&K)->Option<&mut V>{match +self{SsoHashMap::Array(array)=>{for(k,v)in array{if k==key{3;return Some(v);3;}} +None}SsoHashMap::Map(map)=>map.get_mut(key) ,}}pub fn get_key_value(&self,key:&K +)->Option<(&K,&V)>{match self{SsoHashMap::Array(array)=>{for(k,v)in array{if k// +==key{;return Some((k,v));}}None}SsoHashMap::Map(map)=>map.get_key_value(key),}} +pub fn contains_key(&self,key:&K)->bool{match self{SsoHashMap::Array(array)=>//; +array.iter().any(|(k,_v)|k==key ),SsoHashMap::Map(map)=>map.contains_key(key),}} +#[inline]pub fn entry(&mut self,key:K)->Entry<'_,K,V>{(Entry{ssomap:self,key})}} +implDefault for SsoHashMap{#[inline]fn default()->Self{(Self::new())}} +implFromIterator<(K,V)>for SsoHashMap{fn from_iter>(iter:I)->SsoHashMap{;let mut map:SsoHashMap= +Default::default();3;3;map.extend(iter);3;map}}implExtend<(K,V)>for +SsoHashMap{fn extend(&mut self, iter:I)where I:IntoIterator, +{for(key,value)in iter.into_iter(){({});self.insert(key,value);{;};}}#[inline]fn +extend_one(&mut self,(k,v):(K,V)){;self.insert(k,v);}fn extend_reserve(&mut self +,additional:usize){match self{SsoHashMap::Array(array)=>{if SSO_ARRAY_SIZE<(//3; +array.len()+additional){;let mut map:FxHashMap=array.drain(..).collect();;; +map.extend_reserve(additional);;*self=SsoHashMap::Map(map);}}SsoHashMap::Map(map +)=>(((map.extend_reserve(additional)))),}}}impl<'a, K,V>Extend<(&'a K,&'a V)>for +SsoHashMapwhere K:Eq+Hash+Copy,V:Copy,{fn extend>(&mut self,iter:T){self.extend(iter.into_iter() .map(|(k,v)|(*k,*v)))} +#[inline]fn extend_one(&mut self,(&k,&v):(&'a K,&'a V)){3;self.insert(k,v);3;}#[ +inline]fn extend_reserve(&mut self,additional:usize){Extend::<(K,V)>:://((),()); +extend_reserve(self,additional)}}implIntoIterator for SsoHashMap{type +IntoIter=Either< as IntoIterator>::IntoIter,as IntoIterator>::IntoIter,>;type Item=::Item;fn into_iter(self) ->Self::IntoIter{match self{SsoHashMap::Array +(array)=>(Either::Left(array.into_iter() )),SsoHashMap::Map(map)=>Either::Right( +map.into_iter()),}}}#[inline(always)] fn adapt_array_ref_it(pair:&(K,V))->( +&K,&V){3;let(a,b)=pair;;(a,b)}#[inline(always)]fn adapt_array_mut_it(pair:& +mut(K,V))->(&K,&mut V){();let(a,b)=pair;();(a,b)}impl<'a,K,V>IntoIterator for&'a +SsoHashMap{type IntoIter=Eitheras IntoIterator>::IntoIter,fn(&'a(K,V))->(&'a K,&'a V),>,<&'a//3; +FxHashMapas IntoIterator>::IntoIter,>;type Item=::Item;fn into_iter(self) ->Self::IntoIter{match self{SsoHashMap::Array +(array)=>(Either::Left(array.into_iter ().map(adapt_array_ref_it))),SsoHashMap:: +Map(map)=>((Either::Right((map.iter())))),}}}impl<'a,K,V>IntoIterator for&'a mut +SsoHashMap{type IntoIter=Eitheras IntoIterator>::IntoIter,fn(&'a mut(K, V))->(&'a K,&'a mut V),> +,<&'a mut FxHashMapas IntoIterator>::IntoIter,>;type Item=::Item;fn into_iter(self)->Self::IntoIter{match self{SsoHashMap:://; +Array(array)=>((Either::Left((((array.into_iter()).map(adapt_array_mut_it)))))), +SsoHashMap::Map(map)=>(Either::Right(map.iter_mut())),}}}implfmt::Debug for +SsoHashMapwhere K:fmt::Debug,V:fmt::Debug,{fn fmt(&self,f:&mut fmt:://({}); +Formatter<'_>)->fmt::Result{(f.debug_map().entries(self.iter()).finish())}}impl< +'a,K,V>Index<&'a K>for SsoHashMapwhere K:Eq+Hash,{type Output=V;#[inline]// +fn index(&self,key:&K)->&V{(self.get(key).expect("no entry found for key"))}}pub +struct Entry<'a,K,V>{ssomap:&'a mut SsoHashMap,key:K,}impl<'a,K:Eq+Hash,V> +Entry<'a,K,V>{pub fn and_modify(self,f:F)->Self where F:FnOnce(&mut V),{if//; +let Some(value)=self.ssomap.get_mut(&self.key){3;f(value);;}self}#[inline]pub fn +or_insert(self,value:V)->&'a mut V{(((self.or_insert_with(((||value))))))}pub fn +or_insert_withV>(self,default:F)->&'a mut V{let _=||();self.ssomap. +migrate_if_full();3;match self.ssomap{SsoHashMap::Array(array)=>{3;let key_ref=& +self.key;;let found_index=array.iter().position(|(k,_v)|k==key_ref);let index=if +let Some(index)=found_index{index}else{;let index=array.len();;;array.try_push(( +self.key,default())).unwrap();;index};&mut array[index].1}SsoHashMap::Map(map)=> +map.entry(self.key).or_insert_with(default),}}#[inline]pub fn key(&self)->&K{&// +self.key}}impl<'a,K:Eq+Hash,V:Default >Entry<'a,K,V>{#[inline]pub fn or_default( +self)->&'a mut V{((((((((((((self.or_insert_with(Default::default)))))))))))))}} diff --git a/compiler/rustc_data_structures/src/sso/mod.rs b/compiler/rustc_data_structures/src/sso/mod.rs index ef634b9adcec3..62e4f26d43c37 100644 --- a/compiler/rustc_data_structures/src/sso/mod.rs +++ b/compiler/rustc_data_structures/src/sso/mod.rs @@ -1,5 +1 @@ -mod map; -mod set; - -pub use map::SsoHashMap; -pub use set::SsoHashSet; +mod map;mod set;pub use map::SsoHashMap;pub use set::SsoHashSet;//if let _=(){}; diff --git a/compiler/rustc_data_structures/src/sso/set.rs b/compiler/rustc_data_structures/src/sso/set.rs index a4b40138933de..7fc893ce0eab5 100644 --- a/compiler/rustc_data_structures/src/sso/set.rs +++ b/compiler/rustc_data_structures/src/sso/set.rs @@ -1,237 +1,39 @@ -use std::fmt; -use std::hash::Hash; - -use super::map::SsoHashMap; - -/// Small-storage-optimized implementation of a set. -/// -/// Stores elements in a small array up to a certain length -/// and switches to `HashSet` when that length is exceeded. -// -// FIXME: Implements subset of HashSet API. -// -// Missing HashSet API: -// all hasher-related -// try_reserve -// shrink_to (unstable) -// drain_filter (unstable) -// replace -// get_or_insert/get_or_insert_owned/get_or_insert_with (unstable) -// difference/symmetric_difference/intersection/union -// is_disjoint/is_subset/is_superset -// PartialEq/Eq (requires SsoHashMap implementation) -// BitOr/BitAnd/BitXor/Sub -#[derive(Clone)] -pub struct SsoHashSet { - map: SsoHashMap, -} - -/// Adapter function used to return -/// result if SsoHashMap functions into -/// result SsoHashSet should return. -#[inline(always)] -fn entry_to_key((k, _v): (K, V)) -> K { - k -} - -impl SsoHashSet { - /// Creates an empty `SsoHashSet`. - #[inline] - pub fn new() -> Self { - Self { map: SsoHashMap::new() } - } - - /// Creates an empty `SsoHashSet` with the specified capacity. - #[inline] - pub fn with_capacity(cap: usize) -> Self { - Self { map: SsoHashMap::with_capacity(cap) } - } - - /// Clears the set, removing all values. - #[inline] - pub fn clear(&mut self) { - self.map.clear() - } - - /// Returns the number of elements the set can hold without reallocating. - #[inline] - pub fn capacity(&self) -> usize { - self.map.capacity() - } - - /// Returns the number of elements in the set. - #[inline] - pub fn len(&self) -> usize { - self.map.len() - } - - /// Returns `true` if the set contains no elements. - #[inline] - pub fn is_empty(&self) -> bool { - self.map.is_empty() - } - - /// An iterator visiting all elements in arbitrary order. - /// The iterator element type is `&'a T`. - #[inline] - pub fn iter(&self) -> impl Iterator { - self.into_iter() - } - - /// Clears the set, returning all elements in an iterator. - #[inline] - pub fn drain(&mut self) -> impl Iterator + '_ { - self.map.drain().map(entry_to_key) - } -} - -impl SsoHashSet { - /// Reserves capacity for at least `additional` more elements to be inserted - /// in the `SsoHashSet`. The collection may reserve more space to avoid - /// frequent reallocations. - #[inline] - pub fn reserve(&mut self, additional: usize) { - self.map.reserve(additional) - } - - /// Shrinks the capacity of the set as much as possible. It will drop - /// down as much as possible while maintaining the internal rules - /// and possibly leaving some space in accordance with the resize policy. - #[inline] - pub fn shrink_to_fit(&mut self) { - self.map.shrink_to_fit() - } - - /// Retains only the elements specified by the predicate. - #[inline] - pub fn retain(&mut self, mut f: F) - where - F: FnMut(&T) -> bool, - { - self.map.retain(|k, _v| f(k)) - } - - /// Removes and returns the value in the set, if any, that is equal to the given one. - #[inline] - pub fn take(&mut self, value: &T) -> Option { - self.map.remove_entry(value).map(entry_to_key) - } - - /// Returns a reference to the value in the set, if any, that is equal to the given value. - #[inline] - pub fn get(&self, value: &T) -> Option<&T> { - self.map.get_key_value(value).map(entry_to_key) - } - - /// Adds a value to the set. - /// - /// Returns whether the value was newly inserted. That is: - /// - /// - If the set did not previously contain this value, `true` is returned. - /// - If the set already contained this value, `false` is returned. - #[inline] - pub fn insert(&mut self, elem: T) -> bool { - self.map.insert(elem, ()).is_none() - } - - /// Removes a value from the set. Returns whether the value was - /// present in the set. - #[inline] - pub fn remove(&mut self, value: &T) -> bool { - self.map.remove(value).is_some() - } - - /// Returns `true` if the set contains a value. - #[inline] - pub fn contains(&self, value: &T) -> bool { - self.map.contains_key(value) - } -} - -impl FromIterator for SsoHashSet { - fn from_iter>(iter: I) -> SsoHashSet { - let mut set: SsoHashSet = Default::default(); - set.extend(iter); - set - } -} - -impl Default for SsoHashSet { - #[inline] - fn default() -> Self { - Self::new() - } -} - -impl Extend for SsoHashSet { - fn extend(&mut self, iter: I) - where - I: IntoIterator, - { - for val in iter.into_iter() { - self.insert(val); - } - } - - #[inline] - fn extend_one(&mut self, item: T) { - self.insert(item); - } - - #[inline] - fn extend_reserve(&mut self, additional: usize) { - self.map.extend_reserve(additional) - } -} - -impl<'a, T> Extend<&'a T> for SsoHashSet -where - T: 'a + Eq + Hash + Copy, -{ - #[inline] - fn extend>(&mut self, iter: I) { - self.extend(iter.into_iter().cloned()); - } - - #[inline] - fn extend_one(&mut self, &item: &'a T) { - self.insert(item); - } - - #[inline] - fn extend_reserve(&mut self, additional: usize) { - Extend::::extend_reserve(self, additional) - } -} - -impl IntoIterator for SsoHashSet { - type IntoIter = std::iter::Map< as IntoIterator>::IntoIter, fn((T, ())) -> T>; - type Item = ::Item; - - #[inline] - fn into_iter(self) -> Self::IntoIter { - self.map.into_iter().map(entry_to_key) - } -} - -impl<'a, T> IntoIterator for &'a SsoHashSet { - type IntoIter = std::iter::Map< - <&'a SsoHashMap as IntoIterator>::IntoIter, - fn((&'a T, &'a ())) -> &'a T, - >; - type Item = ::Item; - - #[inline] - fn into_iter(self) -> Self::IntoIter { - self.map.iter().map(entry_to_key) - } -} - -impl fmt::Debug for SsoHashSet -where - T: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_set().entries(self.iter()).finish() - } -} +use std::fmt;use std::hash::Hash;use super::map::SsoHashMap;#[derive(Clone)]pub +struct SsoHashSet{map:SsoHashMap,}#[inline(always)]fn entry_to_key((k,_v):(K,V))->K{k}implSsoHashSet{#[inline]pub fn new()->Self{Self{map +:((SsoHashMap::new()))}}#[inline]pub fn with_capacity(cap:usize)->Self{Self{map: +SsoHashMap::with_capacity(cap)}}#[inline]pub fn clear(&mut self){self.map.clear +()}#[inline]pub fn capacity(&self)-> usize{(self.map.capacity())}#[inline]pub fn +len(&self)->usize{self.map.len()}# [inline]pub fn is_empty(&self)->bool{self.map +.is_empty()}#[inline]pub fn iter(& self)->impl Iterator{self.into_iter( +)}#[inline]pub fn drain(&mut self)->impl Iterator+'_{(self.map.drain()). +map(entry_to_key)}}implSsoHashSet{#[inline]pub fn reserve(&mut//3; +self,additional:usize){((((((self.map. reserve(additional)))))))}#[inline]pub fn +shrink_to_fit(&mut self){(self.map.shrink_to_fit() )}#[inline]pub fn retain(& +mut self,mut f:F)where F:FnMut(&T)->bool,{self .map.retain(|k,_v|f(k))}#[inline] +pub fn take(&mut self,value:&T)->Option{((self.map.remove_entry(value))).map( +entry_to_key)}#[inline]pub fn get(&self,value:&T)->Option<&T>{self.map.//*&*&(); +get_key_value(value).map(entry_to_key)}#[inline ]pub fn insert(&mut self,elem:T) +->bool{((self.map.insert(elem,())). is_none())}#[inline]pub fn remove(&mut self, +value:&T)->bool{self.map.remove(value) .is_some()}#[inline]pub fn contains(&self +,value:&T)->bool{(self.map.contains_key( value))}}implFromIterator +for SsoHashSet{fn from_iter>(iter:I)->SsoHashSet{3; +let mut set:SsoHashSet=Default::default();3;3;set.extend(iter);3;set}}impl +Default for SsoHashSet{#[inline]fn default() ->Self{(Self::new())}}implExtendfor SsoHashSet{fn extend(&mut self,iter:I)where I://((),()); +IntoIterator,{for val in iter.into_iter(){;self.insert(val);;}}#[inline] +fn extend_one(&mut self,item:T){;self.insert(item);}#[inline]fn extend_reserve(& +mut self,additional:usize){(((self.map.extend_reserve(additional))))}}impl<'a,T> +Extend<&'a T>for SsoHashSetwhere T:'a+Eq+Hash+Copy,{#[inline]fn extend>(&mut self,iter:I){;self.extend(iter.into_iter().cloned +());;}#[inline]fn extend_one(&mut self,&item:&'a T){self.insert(item);}#[inline] +fn extend_reserve(&mut self,additional:usize ){Extend::::extend_reserve(self, +additional)}}implIntoIterator for SsoHashSet{type IntoIter=std::iter::Map +<as IntoIterator>::IntoIter,fn((T,()))->T>;type Item=::Item;#[inline]fn into_iter(self)->Self::IntoIter{self.//; +map.into_iter().map(entry_to_key)}}impl <'a,T>IntoIterator for&'a SsoHashSet{ +type IntoIter=std::iter::Map< <&'a SsoHashMapas IntoIterator>::IntoIter,// +fn((&'a T,&'a()))->&'a T,>;type Item=::Item;#[//{;}; +inline]fn into_iter(self)->Self::IntoIter{( self.map.iter().map(entry_to_key))}} +implfmt::Debug for SsoHashSetwhere T:fmt::Debug,{fn fmt(&self,f:&mut fmt// +::Formatter<'_>)->fmt::Result{((f.debug_set() .entries(self.iter())).finish())}} diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs index 8418b4bbd4702..5d6766f3014bb 100644 --- a/compiler/rustc_data_structures/src/stable_hasher.rs +++ b/compiler/rustc_data_structures/src/stable_hasher.rs @@ -1,728 +1,166 @@ -use crate::sip128::SipHasher128; -use rustc_index::bit_set::{self, BitSet}; -use rustc_index::{Idx, IndexSlice, IndexVec}; -use smallvec::SmallVec; -use std::fmt; -use std::hash::{BuildHasher, Hash, Hasher}; -use std::marker::PhantomData; -use std::mem; -use std::num::NonZero; - -#[cfg(test)] -mod tests; - -pub use crate::hashes::{Hash128, Hash64}; - -/// When hashing something that ends up affecting properties like symbol names, -/// we want these symbol names to be calculated independently of other factors -/// like what architecture you're compiling *from*. -/// -/// To that end we always convert integers to little-endian format before -/// hashing and the architecture dependent `isize` and `usize` types are -/// extended to 64 bits if needed. -pub struct StableHasher { - state: SipHasher128, -} - -impl fmt::Debug for StableHasher { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self.state) - } -} - -pub trait StableHasherResult: Sized { - fn finish(hasher: StableHasher) -> Self; -} - -impl StableHasher { - #[inline] - pub fn new() -> Self { - StableHasher { state: SipHasher128::new_with_keys(0, 0) } - } - - #[inline] - pub fn finish(self) -> W { - W::finish(self) - } -} - -impl StableHasher { - #[inline] - pub fn finalize(self) -> (u64, u64) { - self.state.finish128() - } -} - -impl Hasher for StableHasher { - fn finish(&self) -> u64 { - panic!("use StableHasher::finalize instead"); - } - - #[inline] - fn write(&mut self, bytes: &[u8]) { - self.state.write(bytes); - } - - #[inline] - fn write_str(&mut self, s: &str) { - self.state.write_str(s); - } - - #[inline] - fn write_length_prefix(&mut self, len: usize) { - // Our impl for `usize` will extend it if needed. - self.write_usize(len); - } - - #[inline] - fn write_u8(&mut self, i: u8) { - self.state.write_u8(i); - } - - #[inline] - fn write_u16(&mut self, i: u16) { - self.state.short_write(i.to_le_bytes()); - } - - #[inline] - fn write_u32(&mut self, i: u32) { - self.state.short_write(i.to_le_bytes()); - } - - #[inline] - fn write_u64(&mut self, i: u64) { - self.state.short_write(i.to_le_bytes()); - } - - #[inline] - fn write_u128(&mut self, i: u128) { - self.write_u64(i as u64); - self.write_u64((i >> 64) as u64); - } - - #[inline] - fn write_usize(&mut self, i: usize) { - // Always treat usize as u64 so we get the same results on 32 and 64 bit - // platforms. This is important for symbol hashes when cross compiling, - // for example. - self.state.short_write((i as u64).to_le_bytes()); - } - - #[inline] - fn write_i8(&mut self, i: i8) { - self.state.write_i8(i); - } - - #[inline] - fn write_i16(&mut self, i: i16) { - self.state.short_write((i as u16).to_le_bytes()); - } - - #[inline] - fn write_i32(&mut self, i: i32) { - self.state.short_write((i as u32).to_le_bytes()); - } - - #[inline] - fn write_i64(&mut self, i: i64) { - self.state.short_write((i as u64).to_le_bytes()); - } - - #[inline] - fn write_i128(&mut self, i: i128) { - self.state.write(&(i as u128).to_le_bytes()); - } - - #[inline] - fn write_isize(&mut self, i: isize) { - // Always treat isize as a 64-bit number so we get the same results on 32 and 64 bit - // platforms. This is important for symbol hashes when cross compiling, - // for example. Sign extending here is preferable as it means that the - // same negative number hashes the same on both 32 and 64 bit platforms. - let value = i as u64; - - // Cold path - #[cold] - #[inline(never)] - fn hash_value(state: &mut SipHasher128, value: u64) { - state.write_u8(0xFF); - state.short_write(value.to_le_bytes()); - } - - // `isize` values often seem to have a small (positive) numeric value in practice. - // To exploit this, if the value is small, we will hash a smaller amount of bytes. - // However, we cannot just skip the leading zero bytes, as that would produce the same hash - // e.g. if you hash two values that have the same bit pattern when they are swapped. - // See https://github.com/rust-lang/rust/pull/93014 for context. - // - // Therefore, we employ the following strategy: - // 1) When we encounter a value that fits within a single byte (the most common case), we - // hash just that byte. This is the most common case that is being optimized. However, we do - // not do this for the value 0xFF, as that is a reserved prefix (a bit like in UTF-8). - // 2) When we encounter a larger value, we hash a "marker" 0xFF and then the corresponding - // 8 bytes. Since this prefix cannot occur when we hash a single byte, when we hash two - // `isize`s that fit within a different amount of bytes, they should always produce a different - // byte stream for the hasher. - if value < 0xFF { - self.state.write_u8(value as u8); - } else { - hash_value(&mut self.state, value); - } - } -} - -/// Something that implements `HashStable` can be hashed in a way that is -/// stable across multiple compilation sessions. -/// -/// Note that `HashStable` imposes rather more strict requirements than usual -/// hash functions: -/// -/// - Stable hashes are sometimes used as identifiers. Therefore they must -/// conform to the corresponding `PartialEq` implementations: -/// -/// - `x == y` implies `hash_stable(x) == hash_stable(y)`, and -/// - `x != y` implies `hash_stable(x) != hash_stable(y)`. -/// -/// That second condition is usually not required for hash functions -/// (e.g. `Hash`). In practice this means that `hash_stable` must feed any -/// information into the hasher that a `PartialEq` comparison takes into -/// account. See [#49300](https://github.com/rust-lang/rust/issues/49300) -/// for an example where violating this invariant has caused trouble in the -/// past. -/// -/// - `hash_stable()` must be independent of the current -/// compilation session. E.g. they must not hash memory addresses or other -/// things that are "randomly" assigned per compilation session. -/// -/// - `hash_stable()` must be independent of the host architecture. The -/// `StableHasher` takes care of endianness and `isize`/`usize` platform -/// differences. -pub trait HashStable { - fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher); -} - -/// Implement this for types that can be turned into stable keys like, for -/// example, for DefId that can be converted to a DefPathHash. This is used for -/// bringing maps into a predictable order before hashing them. -pub trait ToStableHashKey { - type KeyType: Ord + Sized + HashStable; - fn to_stable_hash_key(&self, hcx: &HCX) -> Self::KeyType; -} - -/// Trait for marking a type as having a sort order that is -/// stable across compilation session boundaries. More formally: -/// -/// ```txt -/// Ord::cmp(a1, b1) == Ord::cmp(a2, b2) -/// where a2 = decode(encode(a1, context1), context2) -/// b2 = decode(encode(b1, context1), context2) -/// ``` -/// -/// i.e. the result of `Ord::cmp` is not influenced by encoding -/// the values in one session and then decoding them in another -/// session. -/// -/// This is trivially true for types where encoding and decoding -/// don't change the bytes of the values that are used during -/// comparison and comparison only depends on these bytes (as -/// opposed to some non-local state). Examples are u32, String, -/// Path, etc. -/// -/// But it is not true for: -/// - `*const T` and `*mut T` because the values of these pointers -/// will change between sessions. -/// - `DefIndex`, `CrateNum`, `LocalDefId`, because their concrete -/// values depend on state that might be different between -/// compilation sessions. -/// -/// The associated constant `CAN_USE_UNSTABLE_SORT` denotes whether -/// unstable sorting can be used for this type. Set to true if and -/// only if `a == b` implies `a` and `b` are fully indistinguishable. -pub unsafe trait StableOrd: Ord { - const CAN_USE_UNSTABLE_SORT: bool; -} - -unsafe impl StableOrd for &T { - const CAN_USE_UNSTABLE_SORT: bool = T::CAN_USE_UNSTABLE_SORT; -} - -/// This is a companion trait to `StableOrd`. Some types like `Symbol` can be -/// compared in a cross-session stable way, but their `Ord` implementation is -/// not stable. In such cases, a `StableOrd` implementation can be provided -/// to offer a lightweight way for stable sorting. (The more heavyweight option -/// is to sort via `ToStableHashKey`, but then sorting needs to have access to -/// a stable hashing context and `ToStableHashKey` can also be expensive as in -/// the case of `Symbol` where it has to allocate a `String`.) -/// -/// See the documentation of [StableOrd] for how stable sort order is defined. -/// The same definition applies here. Be careful when implementing this trait. -pub trait StableCompare { - const CAN_USE_UNSTABLE_SORT: bool; - - fn stable_cmp(&self, other: &Self) -> std::cmp::Ordering; -} - -/// `StableOrd` denotes that the type's `Ord` implementation is stable, so -/// we can implement `StableCompare` by just delegating to `Ord`. -impl StableCompare for T { - const CAN_USE_UNSTABLE_SORT: bool = T::CAN_USE_UNSTABLE_SORT; - - fn stable_cmp(&self, other: &Self) -> std::cmp::Ordering { - self.cmp(other) - } -} - -/// Implement HashStable by just calling `Hash::hash()`. Also implement `StableOrd` for the type since -/// that has the same requirements. -/// -/// **WARNING** This is only valid for types that *really* don't need any context for fingerprinting. -/// But it is easy to misuse this macro (see [#96013](https://github.com/rust-lang/rust/issues/96013) -/// for examples). Therefore this macro is not exported and should only be used in the limited cases -/// here in this module. -/// -/// Use `#[derive(HashStable_Generic)]` instead. -macro_rules! impl_stable_traits_for_trivial_type { - ($t:ty) => { - impl $crate::stable_hasher::HashStable for $t { - #[inline] - fn hash_stable(&self, _: &mut CTX, hasher: &mut $crate::stable_hasher::StableHasher) { - ::std::hash::Hash::hash(self, hasher); - } - } - - unsafe impl $crate::stable_hasher::StableOrd for $t { - const CAN_USE_UNSTABLE_SORT: bool = true; - } - }; -} - -impl_stable_traits_for_trivial_type!(i8); -impl_stable_traits_for_trivial_type!(i16); -impl_stable_traits_for_trivial_type!(i32); -impl_stable_traits_for_trivial_type!(i64); -impl_stable_traits_for_trivial_type!(isize); - -impl_stable_traits_for_trivial_type!(u8); -impl_stable_traits_for_trivial_type!(u16); -impl_stable_traits_for_trivial_type!(u32); -impl_stable_traits_for_trivial_type!(u64); -impl_stable_traits_for_trivial_type!(usize); - -impl_stable_traits_for_trivial_type!(u128); -impl_stable_traits_for_trivial_type!(i128); - -impl_stable_traits_for_trivial_type!(char); -impl_stable_traits_for_trivial_type!(()); - -impl_stable_traits_for_trivial_type!(Hash64); - -// We need a custom impl as the default hash function will only hash half the bits. For stable -// hashing we want to hash the full 128-bit hash. -impl HashStable for Hash128 { - #[inline] - fn hash_stable(&self, _: &mut CTX, hasher: &mut StableHasher) { - self.as_u128().hash(hasher); - } -} - -unsafe impl StableOrd for Hash128 { - const CAN_USE_UNSTABLE_SORT: bool = true; -} - -impl HashStable for ! { - fn hash_stable(&self, _ctx: &mut CTX, _hasher: &mut StableHasher) { - unreachable!() - } -} - -impl HashStable for PhantomData { - fn hash_stable(&self, _ctx: &mut CTX, _hasher: &mut StableHasher) {} -} - -impl HashStable for NonZero { - #[inline] - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - self.get().hash_stable(ctx, hasher) - } -} - -impl HashStable for NonZero { - #[inline] - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - self.get().hash_stable(ctx, hasher) - } -} - -impl HashStable for f32 { - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - let val: u32 = self.to_bits(); - val.hash_stable(ctx, hasher); - } -} - -impl HashStable for f64 { - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - let val: u64 = self.to_bits(); - val.hash_stable(ctx, hasher); - } -} - -impl HashStable for ::std::cmp::Ordering { - #[inline] - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - (*self as i8).hash_stable(ctx, hasher); - } -} - -impl, CTX> HashStable for (T1,) { - #[inline] - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - let (ref _0,) = *self; - _0.hash_stable(ctx, hasher); - } -} - -impl, T2: HashStable, CTX> HashStable for (T1, T2) { - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - let (ref _0, ref _1) = *self; - _0.hash_stable(ctx, hasher); - _1.hash_stable(ctx, hasher); - } -} - -unsafe impl StableOrd for (T1, T2) { - const CAN_USE_UNSTABLE_SORT: bool = T1::CAN_USE_UNSTABLE_SORT && T2::CAN_USE_UNSTABLE_SORT; -} - -impl HashStable for (T1, T2, T3) -where - T1: HashStable, - T2: HashStable, - T3: HashStable, -{ - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - let (ref _0, ref _1, ref _2) = *self; - _0.hash_stable(ctx, hasher); - _1.hash_stable(ctx, hasher); - _2.hash_stable(ctx, hasher); - } -} - -unsafe impl StableOrd for (T1, T2, T3) { - const CAN_USE_UNSTABLE_SORT: bool = - T1::CAN_USE_UNSTABLE_SORT && T2::CAN_USE_UNSTABLE_SORT && T3::CAN_USE_UNSTABLE_SORT; -} - -impl HashStable for (T1, T2, T3, T4) -where - T1: HashStable, - T2: HashStable, - T3: HashStable, - T4: HashStable, -{ - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - let (ref _0, ref _1, ref _2, ref _3) = *self; - _0.hash_stable(ctx, hasher); - _1.hash_stable(ctx, hasher); - _2.hash_stable(ctx, hasher); - _3.hash_stable(ctx, hasher); - } -} - -unsafe impl StableOrd - for (T1, T2, T3, T4) -{ - const CAN_USE_UNSTABLE_SORT: bool = T1::CAN_USE_UNSTABLE_SORT - && T2::CAN_USE_UNSTABLE_SORT - && T3::CAN_USE_UNSTABLE_SORT - && T4::CAN_USE_UNSTABLE_SORT; -} - -impl, CTX> HashStable for [T] { - default fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - self.len().hash_stable(ctx, hasher); - for item in self { - item.hash_stable(ctx, hasher); - } - } -} - -impl HashStable for [u8] { - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - self.len().hash_stable(ctx, hasher); - hasher.write(self); - } -} - -impl, CTX> HashStable for Vec { - #[inline] - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - self[..].hash_stable(ctx, hasher); - } -} - -impl HashStable for indexmap::IndexMap -where - K: HashStable + Eq + Hash, - V: HashStable, - R: BuildHasher, -{ - #[inline] - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - self.len().hash_stable(ctx, hasher); - for kv in self { - kv.hash_stable(ctx, hasher); - } - } -} - -impl HashStable for indexmap::IndexSet -where - K: HashStable + Eq + Hash, - R: BuildHasher, -{ - #[inline] - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - self.len().hash_stable(ctx, hasher); - for key in self { - key.hash_stable(ctx, hasher); - } - } -} - -impl HashStable for SmallVec<[A; N]> -where - A: HashStable, -{ - #[inline] - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - self[..].hash_stable(ctx, hasher); - } -} - -impl, CTX> HashStable for Box { - #[inline] - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - (**self).hash_stable(ctx, hasher); - } -} - -impl, CTX> HashStable for ::std::rc::Rc { - #[inline] - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - (**self).hash_stable(ctx, hasher); - } -} - -impl, CTX> HashStable for ::std::sync::Arc { - #[inline] - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - (**self).hash_stable(ctx, hasher); - } -} - -impl HashStable for str { - #[inline] - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - self.as_bytes().hash_stable(ctx, hasher); - } -} - -unsafe impl StableOrd for &str { - const CAN_USE_UNSTABLE_SORT: bool = true; -} - -impl HashStable for String { - #[inline] - fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { - self[..].hash_stable(hcx, hasher); - } -} - -// Safety: String comparison only depends on their contents and the -// contents are not changed by (de-)serialization. -unsafe impl StableOrd for String { - const CAN_USE_UNSTABLE_SORT: bool = true; -} - -impl ToStableHashKey for String { - type KeyType = String; - #[inline] - fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType { - self.clone() - } -} - -impl, T2: ToStableHashKey> ToStableHashKey for (T1, T2) { - type KeyType = (T1::KeyType, T2::KeyType); - #[inline] - fn to_stable_hash_key(&self, hcx: &HCX) -> Self::KeyType { - (self.0.to_stable_hash_key(hcx), self.1.to_stable_hash_key(hcx)) - } -} - -impl HashStable for bool { - #[inline] - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - (if *self { 1u8 } else { 0u8 }).hash_stable(ctx, hasher); - } -} - -// Safety: sort order of bools is not changed by (de-)serialization. -unsafe impl StableOrd for bool { - const CAN_USE_UNSTABLE_SORT: bool = true; -} - -impl HashStable for Option -where - T: HashStable, -{ - #[inline] - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - if let Some(ref value) = *self { - 1u8.hash_stable(ctx, hasher); - value.hash_stable(ctx, hasher); - } else { - 0u8.hash_stable(ctx, hasher); - } - } -} - -// Safety: the Option wrapper does not add instability to comparison. -unsafe impl StableOrd for Option { - const CAN_USE_UNSTABLE_SORT: bool = T::CAN_USE_UNSTABLE_SORT; -} - -impl HashStable for Result -where - T1: HashStable, - T2: HashStable, -{ - #[inline] - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - mem::discriminant(self).hash_stable(ctx, hasher); - match *self { - Ok(ref x) => x.hash_stable(ctx, hasher), - Err(ref x) => x.hash_stable(ctx, hasher), - } - } -} - -impl<'a, T, CTX> HashStable for &'a T -where - T: HashStable + ?Sized, -{ - #[inline] - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - (**self).hash_stable(ctx, hasher); - } -} - -impl HashStable for ::std::mem::Discriminant { - #[inline] - fn hash_stable(&self, _: &mut CTX, hasher: &mut StableHasher) { - ::std::hash::Hash::hash(self, hasher); - } -} - -impl HashStable for ::std::ops::RangeInclusive -where - T: HashStable, -{ - #[inline] - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - self.start().hash_stable(ctx, hasher); - self.end().hash_stable(ctx, hasher); - } -} - -impl HashStable for IndexSlice -where - T: HashStable, -{ - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - self.len().hash_stable(ctx, hasher); - for v in &self.raw { - v.hash_stable(ctx, hasher); - } - } -} - -impl HashStable for IndexVec -where - T: HashStable, -{ - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - self.len().hash_stable(ctx, hasher); - for v in &self.raw { - v.hash_stable(ctx, hasher); - } - } -} - -impl HashStable for BitSet { - fn hash_stable(&self, _ctx: &mut CTX, hasher: &mut StableHasher) { - ::std::hash::Hash::hash(self, hasher); - } -} - -impl HashStable for bit_set::BitMatrix { - fn hash_stable(&self, _ctx: &mut CTX, hasher: &mut StableHasher) { - ::std::hash::Hash::hash(self, hasher); - } -} - -impl HashStable for bit_set::FiniteBitSet -where - T: HashStable + bit_set::FiniteBitSetTy, -{ - fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { - self.0.hash_stable(hcx, hasher); - } -} - -impl_stable_traits_for_trivial_type!(::std::path::Path); -impl_stable_traits_for_trivial_type!(::std::path::PathBuf); - -// It is not safe to implement HashStable for HashSet, HashMap or any other collection type -// with unstable but observable iteration order. -// See https://github.com/rust-lang/compiler-team/issues/533 for further information. -impl !HashStable for std::collections::HashSet {} -impl !HashStable for std::collections::HashMap {} - -impl HashStable for ::std::collections::BTreeMap -where - K: HashStable + StableOrd, - V: HashStable, -{ - fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) { - self.len().hash_stable(hcx, hasher); - for entry in self.iter() { - entry.hash_stable(hcx, hasher); - } - } -} - -impl HashStable for ::std::collections::BTreeSet -where - K: HashStable + StableOrd, -{ - fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) { - self.len().hash_stable(hcx, hasher); - for entry in self.iter() { - entry.hash_stable(hcx, hasher); - } - } -} - -/// Controls what data we do or do not hash. -/// Whenever a `HashStable` implementation caches its -/// result, it needs to include `HashingControls` as part -/// of the key, to ensure that it does not produce an incorrect -/// result (for example, using a `Fingerprint` produced while -/// hashing `Span`s when a `Fingerprint` without `Span`s is -/// being requested) -#[derive(Clone, Hash, Eq, PartialEq, Debug)] -pub struct HashingControls { - pub hash_spans: bool, -} +use crate::sip128::SipHasher128;use rustc_index::bit_set::{self,BitSet};use//(); +rustc_index::{Idx,IndexSlice,IndexVec};use smallvec::SmallVec;use std::fmt;use// +std::hash::{BuildHasher,Hash,Hasher};use std::marker::PhantomData;use std::mem; +use std::num::NonZero;#[cfg(test)]mod tests;pub use crate::hashes::{Hash128,//3; +Hash64};pub struct StableHasher{state:SipHasher128,}impl fmt::Debug for//*&*&(); +StableHasher{fn fmt(&self,f:&mut fmt::Formatter<'_>)->fmt::Result{write!(f,//(); +"{:?}",self.state)}}pub trait StableHasherResult:Sized{fn finish(hasher://{();}; +StableHasher)->Self;}impl StableHasher{#[inline ]pub fn new()->Self{StableHasher +{state:(((SipHasher128::new_with_keys(((0)),((0))))))}}#[inline]pub fn finish(self)->W{W::finish(self )}}impl StableHasher{#[inline]pub fn +finalize(self)->(u64,u64){(self.state.finish128())}}impl Hasher for StableHasher +{fn finish(&self)->u64{;panic!("use StableHasher::finalize instead");;}#[inline] +fn write(&mut self,bytes:&[u8]){;self.state.write(bytes);}#[inline]fn write_str( +&mut self,s:&str){;self.state.write_str(s);}#[inline]fn write_length_prefix(&mut +self,len:usize){3;self.write_usize(len);;}#[inline]fn write_u8(&mut self,i:u8){; +self.state.write_u8(i);();}#[inline]fn write_u16(&mut self,i:u16){();self.state. +short_write(i.to_le_bytes());;}#[inline]fn write_u32(&mut self,i:u32){self.state +.short_write(i.to_le_bytes());();}#[inline]fn write_u64(&mut self,i:u64){3;self. +state.short_write(i.to_le_bytes());3;}#[inline]fn write_u128(&mut self,i:u128){; +self.write_u64(i as u64);;self.write_u64((i>>64)as u64);}#[inline]fn write_usize +(&mut self,i:usize){;self.state.short_write((i as u64).to_le_bytes());}#[inline] +fn write_i8(&mut self,i:i8){;self.state.write_i8(i);;}#[inline]fn write_i16(&mut +self,i:i16){{;};self.state.short_write((i as u16).to_le_bytes());();}#[inline]fn +write_i32(&mut self,i:i32){;self.state.short_write((i as u32).to_le_bytes());}#[ +inline]fn write_i64(&mut self,i:i64){let _=();self.state.short_write((i as u64). +to_le_bytes());3;}#[inline]fn write_i128(&mut self,i:i128){;self.state.write(&(i +as u128).to_le_bytes());;}#[inline]fn write_isize(&mut self,i:isize){let value=i +as u64;;;#[cold]#[inline(never)]fn hash_value(state:&mut SipHasher128,value:u64) +{;state.write_u8(0xFF);;;state.short_write(value.to_le_bytes());;}if value<0xFF{ +self.state.write_u8(value as u8);;}else{hash_value(&mut self.state,value);}}}pub +trait HashStable{fn hash_stable(&self,hcx:&mut CTX,hasher:&mut//let _=||(); +StableHasher);}pub trait ToStableHashKey{type KeyType:Ord+Sized+HashStable +;fn to_stable_hash_key(&self,hcx:&HCX)->Self::KeyType;}pub unsafe trait//3; +StableOrd:Ord{const CAN_USE_UNSTABLE_SORT:bool;}unsafe impl//{();}; +StableOrd for&T{const CAN_USE_UNSTABLE_SORT:bool=T::CAN_USE_UNSTABLE_SORT;}pub// +trait StableCompare{const CAN_USE_UNSTABLE_SORT:bool ;fn stable_cmp(&self,other: +&Self)->std::cmp::Ordering;}implStableCompare for T{const//((),()); +CAN_USE_UNSTABLE_SORT:bool=T::CAN_USE_UNSTABLE_SORT;fn stable_cmp(&self,other:& +Self)->std::cmp::Ordering{(((((((((((( self.cmp(other)))))))))))))}}macro_rules! +impl_stable_traits_for_trivial_type{($t:ty)=>{impl$crate::stable_hasher::// +HashStablefor$t{#[inline]fn hash_stable( &self,_:&mut CTX,hasher:&mut$crate +::stable_hasher::StableHasher){::std::hash::Hash::hash(self,hasher);}}unsafe//3; +impl$crate::stable_hasher::StableOrd for$t{const CAN_USE_UNSTABLE_SORT:bool=//3; +true;}};}impl_stable_traits_for_trivial_type!(i8);//if let _=(){};if let _=(){}; +impl_stable_traits_for_trivial_type!(i16 );impl_stable_traits_for_trivial_type!( +i32);impl_stable_traits_for_trivial_type!(i64);//*&*&();((),());((),());((),()); +impl_stable_traits_for_trivial_type!( isize);impl_stable_traits_for_trivial_type +!(u8);impl_stable_traits_for_trivial_type!(u16);//*&*&();((),());*&*&();((),()); +impl_stable_traits_for_trivial_type!(u32 );impl_stable_traits_for_trivial_type!( +u64);impl_stable_traits_for_trivial_type!(usize);//if let _=(){};*&*&();((),()); +impl_stable_traits_for_trivial_type!(u128 );impl_stable_traits_for_trivial_type! +(i128);impl_stable_traits_for_trivial_type!(char);//if let _=(){};if let _=(){}; +impl_stable_traits_for_trivial_type!(());impl_stable_traits_for_trivial_type!(// +Hash64);implHashStablefor Hash128{#[inline]fn hash_stable(&self,_:&//; +mut CTX,hasher:&mut StableHasher){();self.as_u128().hash(hasher);3;}}unsafe impl +StableOrd for Hash128{const CAN_USE_UNSTABLE_SORT:bool=(((((true)))));}impl +HashStablefor!{fn hash_stable(&self,_ctx:&mut CTX,_hasher:&mut//let _=||(); +StableHasher){(unreachable!())}}implHashStablefor PhantomData{fn +hash_stable(&self,_ctx:&mut CTX,_hasher:&mut StableHasher){}}impl//((),()); +HashStablefor NonZero{#[inline]fn hash_stable(&self,ctx:&mut CTX,//(); +hasher:&mut StableHasher){((((self.get() )).hash_stable(ctx,hasher)))}}impl +HashStablefor NonZero{#[inline]fn hash_stable(&self,ctx:&mut CTX,//; +hasher:&mut StableHasher){((((self.get() )).hash_stable(ctx,hasher)))}}impl +HashStablefor f32{fn hash_stable(&self,ctx:&mut CTX,hasher:&mut//if true{}; +StableHasher){;let val:u32=self.to_bits();val.hash_stable(ctx,hasher);}}implHashStablefor f64{fn hash_stable(&self,ctx:&mut CTX,hasher:&mut//let _=(); +StableHasher){;let val:u64=self.to_bits();val.hash_stable(ctx,hasher);}}implHashStablefor::std::cmp::Ordering{#[inline]fn hash_stable(&self,ctx:&mut// +CTX,hasher:&mut StableHasher){;(*self as i8).hash_stable(ctx,hasher);;}}impl,CTX>HashStablefor(T1, ){#[inline]fn hash_stable(&self,ctx:& +mut CTX,hasher:&mut StableHasher){;let(ref _0,)=*self;_0.hash_stable(ctx,hasher) +;3;}}impl,T2:HashStable,CTX>HashStablefor(T1,T2){fn +hash_stable(&self,ctx:&mut CTX,hasher:&mut StableHasher){();let(ref _0,ref _1)=* +self;;;_0.hash_stable(ctx,hasher);;;_1.hash_stable(ctx,hasher);}}unsafe implStableOrd for(T1 ,T2){const CAN_USE_UNSTABLE_SORT:bool=T1 +::CAN_USE_UNSTABLE_SORT&&T2::CAN_USE_UNSTABLE_SORT;}impl//((),()); +HashStablefor(T1,T2,T3)where T1:HashStable,T2:HashStable,T3://(); +HashStable,{fn hash_stable(&self,ctx:&mut CTX,hasher:&mut StableHasher){(); +let(ref _0,ref _1,ref _2)=*self;;;_0.hash_stable(ctx,hasher);_1.hash_stable(ctx, +hasher);;;_2.hash_stable(ctx,hasher);}}unsafe implStableOrd for(T1,T2,T3){const CAN_USE_UNSTABLE_SORT:bool=T1:://*&*&(); +CAN_USE_UNSTABLE_SORT&&T2::CAN_USE_UNSTABLE_SORT&&T3::CAN_USE_UNSTABLE_SORT;}//; +implHashStablefor( T1,T2,T3,T4)where T1:HashStable,T2 +:HashStable,T3:HashStable,T4:HashStable,{fn hash_stable(&self,//; +ctx:&mut CTX,hasher:&mut StableHasher){;let(ref _0,ref _1,ref _2,ref _3)=*self;; +_0.hash_stable(ctx,hasher);;_1.hash_stable(ctx,hasher);_2.hash_stable(ctx,hasher +);();();_3.hash_stable(ctx,hasher);3;}}unsafe implStableOrd for(T1,T2,T3,T4){const CAN_USE_UNSTABLE_SORT:// +bool=((((((((T1::CAN_USE_UNSTABLE_SORT &&T2::CAN_USE_UNSTABLE_SORT))))))))&&T3:: +CAN_USE_UNSTABLE_SORT&&T4::CAN_USE_UNSTABLE_SORT;}impl,CTX>//; +HashStablefor[T]{default fn hash_stable(&self,ctx:&mut CTX,hasher:&mut//(); +StableHasher){();self.len().hash_stable(ctx,hasher);();for item in self{();item. +hash_stable(ctx,hasher);;}}}implHashStablefor[u8]{fn hash_stable(&self +,ctx:&mut CTX,hasher:&mut StableHasher){3;self.len().hash_stable(ctx,hasher);3;; +hasher.write(self);{;};}}impl,CTX>HashStablefor Vec{#[ +inline]fn hash_stable(&self,ctx:&mut CTX,hasher:&mut StableHasher){{;};self[..]. +hash_stable(ctx,hasher);;}}implHashStablefor indexmap::IndexMap< +K,V,R>where K:HashStable+Eq+ Hash,V:HashStable,R:BuildHasher,{#[inline +]fn hash_stable(&self,ctx:&mut CTX,hasher:&mut StableHasher){((),());self.len(). +hash_stable(ctx,hasher);;for kv in self{;kv.hash_stable(ctx,hasher);}}}implHashStablefor indexmap::IndexSetwhere K:HashStable+Eq+Hash,R +:BuildHasher,{#[inline]fn hash_stable(&self,ctx:&mut CTX,hasher:&mut//if true{}; +StableHasher){{;};self.len().hash_stable(ctx,hasher);{;};for key in self{();key. +hash_stable(ctx,hasher);;}}}implHashStablefor SmallVec +<[A;N]>where A:HashStable,{#[inline]fn hash_stable(&self,ctx:&mut CTX,//(); +hasher:&mut StableHasher){();self[..].hash_stable(ctx,hasher);3;}}impl,CTX>HashStablefor Box< T>{#[inline]fn hash_stable(&self,ctx +:&mut CTX,hasher:&mut StableHasher){;(**self).hash_stable(ctx,hasher);}}impl,CTX>HashStablefor::std::rc::Rc{#[inline]fn//{();}; +hash_stable(&self,ctx:&mut CTX,hasher:&mut StableHasher){3;(**self).hash_stable( +ctx,hasher);;}}impl,CTX>HashStablefor::std::sync:: +Arc{#[inline]fn hash_stable(&self,ctx:&mut CTX,hasher:&mut StableHasher){;(** +self).hash_stable(ctx,hasher);({});}}implHashStablefor str{#[inline]fn +hash_stable(&self,ctx:&mut CTX,hasher:&mut StableHasher){*&*&();self.as_bytes(). +hash_stable(ctx,hasher);let _=();if true{};}}unsafe impl StableOrd for&str{const +CAN_USE_UNSTABLE_SORT:bool=true;}impl HashStablefor String{#[inline]fn +hash_stable(&self,hcx:&mut CTX,hasher:&mut StableHasher){3;self[..].hash_stable( +hcx,hasher);;}}unsafe impl StableOrd for String{const CAN_USE_UNSTABLE_SORT:bool +=(true);}implToStableHashKeyfor String{type KeyType=String;#[inline]fn +to_stable_hash_key(&self,_:&HCX)->Self::KeyType{(((self.clone())))}}impl,T2:ToStableHashKey>ToStableHashKeyfor(T1,T2){//3; +type KeyType=(T1::KeyType,T2::KeyType) ;#[inline]fn to_stable_hash_key(&self,hcx +:&HCX)->Self::KeyType{(self. 0.to_stable_hash_key(hcx),self.1.to_stable_hash_key +(hcx))}}implHashStablefor bool{#[inline]fn hash_stable(&self,ctx:&mut +CTX,hasher:&mut StableHasher){;(if*self{1u8}else{0u8}).hash_stable(ctx,hasher);; +}}unsafe impl StableOrd for bool{const CAN_USE_UNSTABLE_SORT:bool=true;}implHashStablefor Optionwhere T:HashStable,{#[inline]fn//if true{}; +hash_stable(&self,ctx:&mut CTX,hasher:& mut StableHasher){if let Some(ref value) +=*self{;1u8.hash_stable(ctx,hasher);;;value.hash_stable(ctx,hasher);;}else{;0u8. +hash_stable(ctx,hasher);({});}}}unsafe implStableOrd for Option{ +const CAN_USE_UNSTABLE_SORT:bool=T::CAN_USE_UNSTABLE_SORT;}impl//{;}; +HashStablefor Resultwhere T1 :HashStable,T2:HashStable,{#[ +inline]fn hash_stable(&self,ctx:&mut CTX,hasher:&mut StableHasher){((),());mem:: +discriminant(self).hash_stable(ctx,hasher);;match*self{Ok(ref x)=>x.hash_stable( +ctx,hasher),Err(ref x)=>(x.hash_stable(ctx,hasher)),}}}impl<'a,T,CTX>HashStable< +CTX>for&'a T where T:HashStable+ ?Sized,{#[inline]fn hash_stable(&self,ctx: +&mut CTX,hasher:&mut StableHasher){3;(**self).hash_stable(ctx,hasher);;}}implHashStablefor::std::mem::Discriminant {#[inline]fn hash_stable(&self +,_:&mut CTX,hasher:&mut StableHasher){3;::std::hash::Hash::hash(self,hasher);;}} +implHashStablefor::std::ops::RangeInclusivewhere T:HashStable,{#[inline]fn hash_stable(&self,ctx:&mut CTX,hasher:&mut StableHasher){;self +.start().hash_stable(ctx,hasher);;;self.end().hash_stable(ctx,hasher);;}}implHashStablefor IndexSlicewhere T:HashStable,{fn//*&*&(); +hash_stable(&self,ctx:&mut CTX,hasher:&mut StableHasher){;self.len().hash_stable +(ctx,hasher);;for v in&self.raw{;v.hash_stable(ctx,hasher);;}}}impl +HashStablefor IndexVecwhere T:HashStable,{fn hash_stable(&self,// +ctx:&mut CTX,hasher:&mut StableHasher){;self.len().hash_stable(ctx,hasher);for v +in&self.raw{();v.hash_stable(ctx,hasher);();}}}implHashStablefor +BitSet{fn hash_stable(&self,_ctx:&mut CTX,hasher:&mut StableHasher){3;::std:: +hash::Hash::hash(self,hasher);;}}implHashStablefor bit_set +::BitMatrix{fn hash_stable(&self,_ctx:&mut CTX,hasher:&mut StableHasher){3; +::std::hash::Hash::hash(self,hasher);3;}}implHashStablefor bit_set:: +FiniteBitSetwhere T:HashStable+bit_set::FiniteBitSetTy,{fn hash_stable( +&self,hcx:&mut CTX,hasher:&mut StableHasher){;self.0.hash_stable(hcx,hasher);;}} +impl_stable_traits_for_trivial_type!(::std::path::Path);//let _=||();let _=||(); +impl_stable_traits_for_trivial_type!(::std::path::PathBuf);impl!//*&*&(); +HashStablefor std::collections::HashSet{}impl!HashStable// +for std::collections::HashMap{}implHashStablefor::std:://{;}; +collections::BTreeMapwhere K:HashStable +StableOrd,V:HashStable,{ +fn hash_stable(&self,hcx:&mut HCX,hasher:&mut StableHasher){let _=();self.len(). +hash_stable(hcx,hasher);;for entry in self.iter(){entry.hash_stable(hcx,hasher); +}}}implHashStablefor::std::collections::BTreeSetwhere K://*&*&(); +HashStable+StableOrd,{fn hash_stable(&self,hcx:&mut HCX,hasher:&mut//{();}; +StableHasher){;self.len().hash_stable(hcx,hasher);for entry in self.iter(){entry +.hash_stable(hcx,hasher);3;}}}#[derive(Clone,Hash,Eq,PartialEq,Debug)]pub struct +HashingControls{pub hash_spans:bool,}//if true{};if true{};if true{};let _=||(); diff --git a/compiler/rustc_data_structures/src/stable_hasher/tests.rs b/compiler/rustc_data_structures/src/stable_hasher/tests.rs index c8921f6a7784f..ebd6c0253f847 100644 --- a/compiler/rustc_data_structures/src/stable_hasher/tests.rs +++ b/compiler/rustc_data_structures/src/stable_hasher/tests.rs @@ -1,163 +1,37 @@ -use super::*; - -// The tests below compare the computed hashes to particular expected values -// in order to test that we produce the same results on different platforms, -// regardless of endianness and `usize` and `isize` size differences (this -// of course assumes we run these tests on platforms that differ in those -// ways). The expected values depend on the hashing algorithm used, so they -// need to be updated whenever StableHasher changes its hashing algorithm. - -#[test] -fn test_hash_integers() { - // Test that integers are handled consistently across platforms. - let test_u8 = 0xAB_u8; - let test_u16 = 0xFFEE_u16; - let test_u32 = 0x445577AA_u32; - let test_u64 = 0x01234567_13243546_u64; - let test_u128 = 0x22114433_66557788_99AACCBB_EEDDFF77_u128; - let test_usize = 0xD0C0B0A0_usize; - - let test_i8 = -100_i8; - let test_i16 = -200_i16; - let test_i32 = -300_i32; - let test_i64 = -400_i64; - let test_i128 = -500_i128; - let test_isize = -600_isize; - - let mut h = StableHasher::new(); - test_u8.hash(&mut h); - test_u16.hash(&mut h); - test_u32.hash(&mut h); - test_u64.hash(&mut h); - test_u128.hash(&mut h); - test_usize.hash(&mut h); - test_i8.hash(&mut h); - test_i16.hash(&mut h); - test_i32.hash(&mut h); - test_i64.hash(&mut h); - test_i128.hash(&mut h); - test_isize.hash(&mut h); - - // This depends on the hashing algorithm. See note at top of file. - let expected = (13997337031081104755, 6178945012502239489); - - assert_eq!(h.finalize(), expected); -} - -#[test] -fn test_hash_usize() { - // Test that usize specifically is handled consistently across platforms. - let test_usize = 0xABCDEF01_usize; - - let mut h = StableHasher::new(); - test_usize.hash(&mut h); - - // This depends on the hashing algorithm. See note at top of file. - let expected = (12037165114281468837, 3094087741167521712); - - assert_eq!(h.finalize(), expected); -} - -#[test] -fn test_hash_isize() { - // Test that isize specifically is handled consistently across platforms. - let test_isize = -7_isize; - - let mut h = StableHasher::new(); - test_isize.hash(&mut h); - - // This depends on the hashing algorithm. See note at top of file. - let expected = (3979067582695659080, 2322428596355037273); - - assert_eq!(h.finalize(), expected); -} - -fn hash>(t: &T) -> Hash128 { - let mut h = StableHasher::new(); - let ctx = &mut (); - t.hash_stable(ctx, &mut h); - h.finish() -} - -// Check that bit set hash includes the domain size. -#[test] -fn test_hash_bit_set() { - use rustc_index::bit_set::BitSet; - let a: BitSet = BitSet::new_empty(1); - let b: BitSet = BitSet::new_empty(2); - assert_ne!(a, b); - assert_ne!(hash(&a), hash(&b)); -} - -// Check that bit matrix hash includes the matrix dimensions. -#[test] -fn test_hash_bit_matrix() { - use rustc_index::bit_set::BitMatrix; - let a: BitMatrix = BitMatrix::new(1, 1); - let b: BitMatrix = BitMatrix::new(1, 2); - assert_ne!(a, b); - assert_ne!(hash(&a), hash(&b)); -} - -// Check that exchanging the value of two adjacent fields changes the hash. -#[test] -fn test_attribute_permutation() { - macro_rules! test_type { - ($ty: ty) => {{ - struct Foo { - a: $ty, - b: $ty, - } - - impl HashStable for Foo { - fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { - self.a.hash_stable(hcx, hasher); - self.b.hash_stable(hcx, hasher); - } - } - - #[allow(overflowing_literals)] - let mut item = Foo { a: 0xFF, b: 0xFF_FF }; - let hash_a = hash(&item); - std::mem::swap(&mut item.a, &mut item.b); - let hash_b = hash(&item); - assert_ne!( - hash_a, - hash_b, - "The hash stayed the same after values were swapped for type `{}`!", - stringify!($ty) - ); - }}; - } - - test_type!(u16); - test_type!(u32); - test_type!(u64); - test_type!(u128); - - test_type!(i16); - test_type!(i32); - test_type!(i64); - test_type!(i128); -} - -// Check that the `isize` hashing optimization does not produce the same hash when permuting two -// values. -#[test] -fn test_isize_compression() { - fn check_hash(a: u64, b: u64) { - let hash_a = hash(&(a as isize, b as isize)); - let hash_b = hash(&(b as isize, a as isize)); - assert_ne!( - hash_a, hash_b, - "The hash stayed the same when permuting values `{a}` and `{b}`!", - ); - } - - check_hash(0xAA, 0xAAAA); - check_hash(0xFF, 0xFFFF); - check_hash(0xAAAA, 0xAAAAAA); - check_hash(0xAAAAAA, 0xAAAAAAAA); - check_hash(0xFF, 0xFFFFFFFFFFFFFFFF); - check_hash(u64::MAX /* -1 */, 1); -} +use super::*;#[test]fn test_hash_integers(){;let test_u8=0xAB_u8;;;let test_u16= +0xFFEE_u16;;let test_u32=0x445577AA_u32;let test_u64=0x01234567_13243546_u64;let +test_u128=0x22114433_66557788_99AACCBB_EEDDFF77_u128;{();};{();};let test_usize= +0xD0C0B0A0_usize;3;;let test_i8=-100_i8;;;let test_i16=-200_i16;;;let test_i32=- +300_i32;;let test_i64=-400_i64;let test_i128=-500_i128;let test_isize=-600_isize +;;;let mut h=StableHasher::new();;;test_u8.hash(&mut h);;;test_u16.hash(&mut h); +test_u32.hash(&mut h);;;test_u64.hash(&mut h);test_u128.hash(&mut h);test_usize. +hash(&mut h);;;test_i8.hash(&mut h);test_i16.hash(&mut h);test_i32.hash(&mut h); +test_i64.hash(&mut h);3;3;test_i128.hash(&mut h);;;test_isize.hash(&mut h);;;let +expected=(13997337031081104755,6178945012502239489);3;3;assert_eq!(h.finalize(), +expected);;}#[test]fn test_hash_usize(){;let test_usize=0xABCDEF01_usize;let mut +h=StableHasher::new();({});({});test_usize.hash(&mut h);({});({});let expected=( +12037165114281468837,3094087741167521712);;assert_eq!(h.finalize(),expected);}#[ +test]fn test_hash_isize(){;let test_isize=-7_isize;let mut h=StableHasher::new() +;;test_isize.hash(&mut h);let expected=(3979067582695659080,2322428596355037273) +;;;assert_eq!(h.finalize(),expected);;}fn hash>(t:&T)->Hash128{ +let mut h=StableHasher::new();;let ctx=&mut();t.hash_stable(ctx,&mut h);h.finish +()}#[test]fn test_hash_bit_set(){;use rustc_index::bit_set::BitSet;let a:BitSet< +usize>=BitSet::new_empty(1);;let b:BitSet=BitSet::new_empty(2);assert_ne! +(a,b);3;3;assert_ne!(hash(&a),hash(&b));3;}#[test]fn test_hash_bit_matrix(){;use +rustc_index::bit_set::BitMatrix;;let a:BitMatrix=BitMatrix::new(1,1 +);;;let b:BitMatrix=BitMatrix::new(1,2);assert_ne!(a,b);assert_ne!( +hash(&a),hash(&b));({});}#[test]fn test_attribute_permutation(){{;};macro_rules! +test_type{($ty:ty)=>{{struct Foo{a:$ty,b:$ty,}implHashStablefor Foo{// +fn hash_stable(&self,hcx:&mut CTX, hasher:&mut StableHasher){self.a.hash_stable( +hcx,hasher);self.b.hash_stable(hcx,hasher);}}#[allow(overflowing_literals)]let// +mut item=Foo{a:0xFF,b:0xFF_FF};let hash_a =hash(&item);std::mem::swap(&mut item. +a,&mut item.b);let hash_b=hash(&item);assert_ne!(hash_a,hash_b,//*&*&();((),()); +"The hash stayed the same after values were swapped for type `{}`!", stringify!( +$ty));}};};;test_type!(u16);;;test_type!(u32);;test_type!(u64);test_type!(u128); +test_type!(i16);;;test_type!(i32);;;test_type!(i64);;test_type!(i128);}#[test]fn +test_isize_compression(){();fn check_hash(a:u64,b:u64){();let hash_a=hash(&(a as +isize,b as isize));;let hash_b=hash(&(b as isize,a as isize));assert_ne!(hash_a, +hash_b,"The hash stayed the same when permuting values `{a}` and `{b}`!",);3;};; +check_hash(0xAA,0xAAAA);;;check_hash(0xFF,0xFFFF);;;check_hash(0xAAAA,0xAAAAAA); +check_hash(0xAAAAAA,0xAAAAAAAA);;check_hash(0xFF,0xFFFFFFFFFFFFFFFF);check_hash( +u64::MAX,1);((),());((),());((),());let _=();((),());let _=();((),());let _=();} diff --git a/compiler/rustc_data_structures/src/stack.rs b/compiler/rustc_data_structures/src/stack.rs index 7ff1339c5ab34..ad8b5832bc985 100644 --- a/compiler/rustc_data_structures/src/stack.rs +++ b/compiler/rustc_data_structures/src/stack.rs @@ -1,18 +1,3 @@ -// This is the amount of bytes that need to be left on the stack before increasing the size. -// It must be at least as large as the stack required by any code that does not call -// `ensure_sufficient_stack`. -const RED_ZONE: usize = 100 * 1024; // 100k - -// Only the first stack that is pushed, grows exponentially (2^n * STACK_PER_RECURSION) from then -// on. This flag has performance relevant characteristics. Don't set it too high. -const STACK_PER_RECURSION: usize = 1024 * 1024; // 1MB - -/// Grows the stack on demand to prevent stack overflow. Call this in strategic locations -/// to "break up" recursive calls. E.g. almost any call to `visit_expr` or equivalent can benefit -/// from this. -/// -/// Should not be sprinkled around carelessly, as it causes a little bit of overhead. -#[inline] -pub fn ensure_sufficient_stack(f: impl FnOnce() -> R) -> R { - stacker::maybe_grow(RED_ZONE, STACK_PER_RECURSION, f) -} +const RED_ZONE:usize=((100)*(1024));const STACK_PER_RECURSION:usize=1024*1024;#[ +inline]pub fn ensure_sufficient_stack(f:impl FnOnce()->R)->R{stacker:://({}); +maybe_grow(RED_ZONE,STACK_PER_RECURSION,f)}//((),());let _=();let _=();let _=(); diff --git a/compiler/rustc_data_structures/src/steal.rs b/compiler/rustc_data_structures/src/steal.rs index 9a0fd52677d13..c769e844f139c 100644 --- a/compiler/rustc_data_structures/src/steal.rs +++ b/compiler/rustc_data_structures/src/steal.rs @@ -1,60 +1,13 @@ -use crate::stable_hasher::{HashStable, StableHasher}; -use crate::sync::{MappedReadGuard, ReadGuard, RwLock}; - -/// The `Steal` struct is intended to used as the value for a query. -/// Specifically, we sometimes have queries (*cough* MIR *cough*) -/// where we create a large, complex value that we want to iteratively -/// update (e.g., optimize). We could clone the value for each -/// optimization, but that'd be expensive. And yet we don't just want -/// to mutate it in place, because that would spoil the idea that -/// queries are these pure functions that produce an immutable value -/// (since if you did the query twice, you could observe the mutations). -/// So instead we have the query produce a `&'tcx Steal>` -/// (to be very specific). Now we can read from this -/// as much as we want (using `borrow()`), but you can also -/// `steal()`. Once you steal, any further attempt to read will panic. -/// Therefore, we know that -- assuming no ICE -- nobody is observing -/// the fact that the MIR was updated. -/// -/// Obviously, whenever you have a query that yields a `Steal` value, -/// you must treat it with caution, and make sure that you know that -/// -- once the value is stolen -- it will never be read from again. -// -// FIXME(#41710): what is the best way to model linear queries? -#[derive(Debug)] -pub struct Steal { - value: RwLock>, -} - -impl Steal { - pub fn new(value: T) -> Self { - Steal { value: RwLock::new(Some(value)) } - } - - #[track_caller] - pub fn borrow(&self) -> MappedReadGuard<'_, T> { - let borrow = self.value.borrow(); - if borrow.is_none() { - panic!("attempted to read from stolen value: {}", std::any::type_name::()); - } - ReadGuard::map(borrow, |opt| opt.as_ref().unwrap()) - } - - #[track_caller] - pub fn get_mut(&mut self) -> &mut T { - self.value.get_mut().as_mut().expect("attempt to read from stolen value") - } - - #[track_caller] - pub fn steal(&self) -> T { - let value_ref = &mut *self.value.try_write().expect("stealing value which is locked"); - let value = value_ref.take(); - value.expect("attempt to steal from stolen value") - } -} - -impl> HashStable for Steal { - fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { - self.borrow().hash_stable(hcx, hasher); - } -} +use crate::stable_hasher::{HashStable,StableHasher};use crate::sync::{//((),()); +MappedReadGuard,ReadGuard,RwLock};#[derive(Debug)]pub struct Steal{value://3; +RwLock>,}implSteal{pub fn new(value:T)->Self{Steal{value:RwLock +::new(Some(value))}}#[track_caller]pub fn borrow(&self)->MappedReadGuard<'_,T>{; +let borrow=self.value.borrow();let _=||();if borrow.is_none(){let _=||();panic!( +"attempted to read from stolen value: {}",std::any::type_name::());let _=();} +ReadGuard::map(borrow,|opt|opt.as_ref() .unwrap())}#[track_caller]pub fn get_mut +(&mut self)->&mut T{(((((((((((self .value.get_mut()))))).as_mut())))))).expect( +"attempt to read from stolen value")}#[track_caller]pub fn steal(&self)->T{3;let +value_ref=&mut*self.value.try_write().expect("stealing value which is locked");; +let value=value_ref.take();;value.expect("attempt to steal from stolen value")}} +impl>HashStable for Steal{fn hash_stable(&self,hcx +:&mut CTX,hasher:&mut StableHasher){3;self.borrow().hash_stable(hcx,hasher);3;}} diff --git a/compiler/rustc_data_structures/src/svh.rs b/compiler/rustc_data_structures/src/svh.rs index 1cfc9fecd47d7..098eab45ce378 100644 --- a/compiler/rustc_data_structures/src/svh.rs +++ b/compiler/rustc_data_structures/src/svh.rs @@ -1,47 +1,9 @@ -//! Calculation and management of a Strict Version Hash for crates -//! -//! The SVH is used for incremental compilation to track when HIR -//! nodes have changed between compilations, and also to detect -//! mismatches where we have two versions of the same crate that were -//! compiled from distinct sources. - -use crate::fingerprint::Fingerprint; -use std::fmt; - -use crate::stable_hasher; - -#[derive(Copy, Clone, PartialEq, Eq, Debug, Encodable_Generic, Decodable_Generic, Hash)] -pub struct Svh { - hash: Fingerprint, -} - -impl Svh { - /// Creates a new `Svh` given the hash. If you actually want to - /// compute the SVH from some HIR, you want the `calculate_svh` - /// function found in `rustc_incremental`. - pub fn new(hash: Fingerprint) -> Svh { - Svh { hash } - } - - pub fn as_u128(self) -> u128 { - self.hash.as_u128() - } - - pub fn to_hex(self) -> String { - format!("{:032x}", self.hash.as_u128()) - } -} - -impl fmt::Display for Svh { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad(&self.to_hex()) - } -} - -impl stable_hasher::HashStable for Svh { - #[inline] - fn hash_stable(&self, ctx: &mut T, hasher: &mut stable_hasher::StableHasher) { - let Svh { hash } = *self; - hash.hash_stable(ctx, hasher); - } -} +use crate::fingerprint::Fingerprint;use std::fmt;use crate::stable_hasher;#[//3; +derive(Copy,Clone,PartialEq,Eq ,Debug,Encodable_Generic,Decodable_Generic,Hash)] +pub struct Svh{hash:Fingerprint,}impl Svh{ pub fn new(hash:Fingerprint)->Svh{Svh +{hash}}pub fn as_u128(self)->u128{(( self.hash.as_u128()))}pub fn to_hex(self)-> +String{format!("{:032x}",self.hash.as_u128()) }}impl fmt::Display for Svh{fn fmt +(&self,f:&mut fmt::Formatter<'_>)->fmt::Result{( f.pad(&self.to_hex()))}}impl +stable_hasher::HashStablefor Svh{#[inline]fn hash_stable(&self,ctx:&mut T,//; +hasher:&mut stable_hasher::StableHasher){;let Svh{hash}=*self;;hash.hash_stable( +ctx,hasher);((),());((),());((),());let _=();((),());((),());((),());let _=();}} diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index eab6d8168ca8e..1a89b16d9fab5 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -1,447 +1,90 @@ -//! This module defines various operations and types that are implemented in -//! one way for the serial compiler, and another way the parallel compiler. -//! -//! Operations -//! ---------- -//! The parallel versions of operations use Rayon to execute code in parallel, -//! while the serial versions degenerate straightforwardly to serial execution. -//! The operations include `join`, `parallel`, `par_iter`, and `par_for_each`. -//! -//! Types -//! ----- -//! The parallel versions of types provide various kinds of synchronization, -//! while the serial compiler versions do not. -//! -//! The following table shows how the types are implemented internally. Except -//! where noted otherwise, the type in column one is defined as a -//! newtype around the type from column two or three. -//! -//! | Type | Serial version | Parallel version | -//! | ----------------------- | ------------------- | ------------------------------- | -//! | `Lrc` | `rc::Rc` | `sync::Arc` | -//! |` Weak` | `rc::Weak` | `sync::Weak` | -//! | `LRef<'a, T>` [^2] | `&'a mut T` | `&'a T` | -//! | | | | -//! | `AtomicBool` | `Cell` | `atomic::AtomicBool` | -//! | `AtomicU32` | `Cell` | `atomic::AtomicU32` | -//! | `AtomicU64` | `Cell` | `atomic::AtomicU64` | -//! | `AtomicUsize` | `Cell` | `atomic::AtomicUsize` | -//! | | | | -//! | `Lock` | `RefCell` | `RefCell` or | -//! | | | `parking_lot::Mutex` | -//! | `RwLock` | `RefCell` | `parking_lot::RwLock` | -//! | `MTLock` [^1] | `T` | `Lock` | -//! | `MTLockRef<'a, T>` [^2] | `&'a mut MTLock` | `&'a MTLock` | -//! | | | | -//! | `ParallelIterator` | `Iterator` | `rayon::iter::ParallelIterator` | -//! -//! [^1] `MTLock` is similar to `Lock`, but the serial version avoids the cost -//! of a `RefCell`. This is appropriate when interior mutability is not -//! required. -//! -//! [^2] `MTRef`, `MTLockRef` are type aliases. - -pub use crate::marker::*; -use std::collections::HashMap; -use std::hash::{BuildHasher, Hash}; - -mod lock; -pub use lock::{Lock, LockGuard, Mode}; - -mod worker_local; -pub use worker_local::{Registry, WorkerLocal}; - -mod parallel; -#[cfg(parallel_compiler)] -pub use parallel::scope; -pub use parallel::{join, par_for_each_in, par_map, parallel_guard, try_par_for_each_in}; - -pub use vec::{AppendOnlyIndexVec, AppendOnlyVec}; - -mod vec; - -mod freeze; -pub use freeze::{FreezeLock, FreezeReadGuard, FreezeWriteGuard}; - -mod mode { - use std::sync::atomic::{AtomicU8, Ordering}; - - const UNINITIALIZED: u8 = 0; - const DYN_NOT_THREAD_SAFE: u8 = 1; - const DYN_THREAD_SAFE: u8 = 2; - - static DYN_THREAD_SAFE_MODE: AtomicU8 = AtomicU8::new(UNINITIALIZED); - - // Whether thread safety is enabled (due to running under multiple threads). - #[inline] - pub fn is_dyn_thread_safe() -> bool { - match DYN_THREAD_SAFE_MODE.load(Ordering::Relaxed) { - DYN_NOT_THREAD_SAFE => false, - DYN_THREAD_SAFE => true, - _ => panic!("uninitialized dyn_thread_safe mode!"), - } - } - - // Whether thread safety might be enabled. - #[inline] - pub fn might_be_dyn_thread_safe() -> bool { - DYN_THREAD_SAFE_MODE.load(Ordering::Relaxed) != DYN_NOT_THREAD_SAFE - } - - // Only set by the `-Z threads` compile option - pub fn set_dyn_thread_safe_mode(mode: bool) { - let set: u8 = if mode { DYN_THREAD_SAFE } else { DYN_NOT_THREAD_SAFE }; - let previous = DYN_THREAD_SAFE_MODE.compare_exchange( - UNINITIALIZED, - set, - Ordering::Relaxed, - Ordering::Relaxed, - ); - - // Check that the mode was either uninitialized or was already set to the requested mode. - assert!(previous.is_ok() || previous == Err(set)); - } -} - -pub use mode::{is_dyn_thread_safe, set_dyn_thread_safe_mode}; - -cfg_match! { - cfg(not(parallel_compiler)) => { - use std::ops::Add; - use std::cell::Cell; - use std::sync::atomic::Ordering; - - pub unsafe auto trait Send {} - pub unsafe auto trait Sync {} - - unsafe impl Send for T {} - unsafe impl Sync for T {} - - /// This is a single threaded variant of `AtomicU64`, `AtomicUsize`, etc. - /// It has explicit ordering arguments and is only intended for use with - /// the native atomic types. - /// You should use this type through the `AtomicU64`, `AtomicUsize`, etc, type aliases - /// as it's not intended to be used separately. - #[derive(Debug, Default)] - pub struct Atomic(Cell); - - impl Atomic { - #[inline] - pub fn new(v: T) -> Self { - Atomic(Cell::new(v)) - } - - #[inline] - pub fn into_inner(self) -> T { - self.0.into_inner() - } - - #[inline] - pub fn load(&self, _: Ordering) -> T { - self.0.get() - } - - #[inline] - pub fn store(&self, val: T, _: Ordering) { - self.0.set(val) - } - - #[inline] - pub fn swap(&self, val: T, _: Ordering) -> T { - self.0.replace(val) - } - } - - impl Atomic { - pub fn fetch_or(&self, val: bool, _: Ordering) -> bool { - let old = self.0.get(); - self.0.set(val | old); - old - } - pub fn fetch_and(&self, val: bool, _: Ordering) -> bool { - let old = self.0.get(); - self.0.set(val & old); - old - } - } - - impl Atomic { - #[inline] - pub fn compare_exchange(&self, - current: T, - new: T, - _: Ordering, - _: Ordering) - -> Result { - let read = self.0.get(); - if read == current { - self.0.set(new); - Ok(read) - } else { - Err(read) - } - } - } - - impl + Copy> Atomic { - #[inline] - pub fn fetch_add(&self, val: T, _: Ordering) -> T { - let old = self.0.get(); - self.0.set(old + val); - old - } - } - - pub type AtomicUsize = Atomic; - pub type AtomicBool = Atomic; - pub type AtomicU32 = Atomic; - pub type AtomicU64 = Atomic; - - pub use std::rc::Rc as Lrc; - pub use std::rc::Weak as Weak; - pub use std::cell::Ref as ReadGuard; - pub use std::cell::Ref as MappedReadGuard; - pub use std::cell::RefMut as WriteGuard; - pub use std::cell::RefMut as MappedWriteGuard; - pub use std::cell::RefMut as MappedLockGuard; - - pub use std::cell::OnceCell as OnceLock; - - use std::cell::RefCell as InnerRwLock; - - pub type LRef<'a, T> = &'a mut T; - - #[derive(Debug, Default)] - pub struct MTLock(T); - - impl MTLock { - #[inline(always)] - pub fn new(inner: T) -> Self { - MTLock(inner) - } - - #[inline(always)] - pub fn into_inner(self) -> T { - self.0 - } - - #[inline(always)] - pub fn get_mut(&mut self) -> &mut T { - &mut self.0 - } - - #[inline(always)] - pub fn lock(&self) -> &T { - &self.0 - } - - #[inline(always)] - pub fn lock_mut(&mut self) -> &mut T { - &mut self.0 - } - } - - // FIXME: Probably a bad idea (in the threaded case) - impl Clone for MTLock { - #[inline] - fn clone(&self) -> Self { - MTLock(self.0.clone()) - } - } - } - _ => { - pub use std::marker::Send as Send; - pub use std::marker::Sync as Sync; - - pub use parking_lot::RwLockReadGuard as ReadGuard; - pub use parking_lot::MappedRwLockReadGuard as MappedReadGuard; - pub use parking_lot::RwLockWriteGuard as WriteGuard; - pub use parking_lot::MappedRwLockWriteGuard as MappedWriteGuard; - - pub use parking_lot::MappedMutexGuard as MappedLockGuard; - - pub use std::sync::OnceLock; - - pub use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicU32}; - - // PowerPC and MIPS platforms with 32-bit pointers do not - // have AtomicU64 type. - #[cfg(not(any(target_arch = "powerpc", target_arch = "mips")))] - pub use std::sync::atomic::AtomicU64; - - #[cfg(any(target_arch = "powerpc", target_arch = "mips"))] - pub use portable_atomic::AtomicU64; - - pub use std::sync::Arc as Lrc; - pub use std::sync::Weak as Weak; - - pub type LRef<'a, T> = &'a T; - - #[derive(Debug, Default)] - pub struct MTLock(Lock); - - impl MTLock { - #[inline(always)] - pub fn new(inner: T) -> Self { - MTLock(Lock::new(inner)) - } - - #[inline(always)] - pub fn into_inner(self) -> T { - self.0.into_inner() - } - - #[inline(always)] - pub fn get_mut(&mut self) -> &mut T { - self.0.get_mut() - } - - #[inline(always)] - pub fn lock(&self) -> LockGuard<'_, T> { - self.0.lock() - } - - #[inline(always)] - pub fn lock_mut(&self) -> LockGuard<'_, T> { - self.lock() - } - } - - use parking_lot::RwLock as InnerRwLock; - - /// This makes locks panic if they are already held. - /// It is only useful when you are running in a single thread - const ERROR_CHECKING: bool = false; - } -} - -pub type MTLockRef<'a, T> = LRef<'a, MTLock>; - -#[derive(Default)] -#[cfg_attr(parallel_compiler, repr(align(64)))] -pub struct CacheAligned(pub T); - -pub trait HashMapExt { - /// Same as HashMap::insert, but it may panic if there's already an - /// entry for `key` with a value not equal to `value` - fn insert_same(&mut self, key: K, value: V); -} - -impl HashMapExt for HashMap { - fn insert_same(&mut self, key: K, value: V) { - self.entry(key).and_modify(|old| assert!(*old == value)).or_insert(value); - } -} - -#[derive(Debug, Default)] -pub struct RwLock(InnerRwLock); - -impl RwLock { - #[inline(always)] - pub fn new(inner: T) -> Self { - RwLock(InnerRwLock::new(inner)) - } - - #[inline(always)] - pub fn into_inner(self) -> T { - self.0.into_inner() - } - - #[inline(always)] - pub fn get_mut(&mut self) -> &mut T { - self.0.get_mut() - } - - #[cfg(not(parallel_compiler))] - #[inline(always)] - #[track_caller] - pub fn read(&self) -> ReadGuard<'_, T> { - self.0.borrow() - } - - #[cfg(parallel_compiler)] - #[inline(always)] - pub fn read(&self) -> ReadGuard<'_, T> { - if ERROR_CHECKING { - self.0.try_read().expect("lock was already held") - } else { - self.0.read() - } - } - - #[inline(always)] - #[track_caller] - pub fn with_read_lock R, R>(&self, f: F) -> R { - f(&*self.read()) - } - - #[cfg(not(parallel_compiler))] - #[inline(always)] - pub fn try_write(&self) -> Result, ()> { - self.0.try_borrow_mut().map_err(|_| ()) - } - - #[cfg(parallel_compiler)] - #[inline(always)] - pub fn try_write(&self) -> Result, ()> { - self.0.try_write().ok_or(()) - } - - #[cfg(not(parallel_compiler))] - #[inline(always)] - #[track_caller] - pub fn write(&self) -> WriteGuard<'_, T> { - self.0.borrow_mut() - } - - #[cfg(parallel_compiler)] - #[inline(always)] - pub fn write(&self) -> WriteGuard<'_, T> { - if ERROR_CHECKING { - self.0.try_write().expect("lock was already held") - } else { - self.0.write() - } - } - - #[inline(always)] - #[track_caller] - pub fn with_write_lock R, R>(&self, f: F) -> R { - f(&mut *self.write()) - } - - #[inline(always)] - #[track_caller] - pub fn borrow(&self) -> ReadGuard<'_, T> { - self.read() - } - - #[inline(always)] - #[track_caller] - pub fn borrow_mut(&self) -> WriteGuard<'_, T> { - self.write() - } - - #[cfg(not(parallel_compiler))] - #[inline(always)] - pub fn leak(&self) -> &T { - ReadGuard::leak(self.read()) - } - - #[cfg(parallel_compiler)] - #[inline(always)] - pub fn leak(&self) -> &T { - let guard = self.read(); - let ret = unsafe { &*std::ptr::addr_of!(*guard) }; - std::mem::forget(guard); - ret - } -} - -// FIXME: Probably a bad idea -impl Clone for RwLock { - #[inline] - fn clone(&self) -> Self { - RwLock::new(self.borrow().clone()) - } -} +pub use crate::marker::*;use std::collections::HashMap;use std::hash::{//*&*&(); +BuildHasher,Hash};mod lock;pub use lock::{Lock,LockGuard,Mode};mod worker_local +;pub use worker_local::{Registry,WorkerLocal};mod parallel;#[cfg(//loop{break;}; +parallel_compiler)]pub use parallel::scope;pub use parallel::{join,//let _=||(); +par_for_each_in,par_map,parallel_guard,try_par_for_each_in};pub use vec::{//{;}; +AppendOnlyIndexVec,AppendOnlyVec};mod vec;mod freeze;pub use freeze::{//((),()); +FreezeLock,FreezeReadGuard,FreezeWriteGuard};mod mode{use std::sync::atomic::{// +AtomicU8,Ordering};const UNINITIALIZED:u8=( 0);const DYN_NOT_THREAD_SAFE:u8=(1); +const DYN_THREAD_SAFE:u8=(2);static DYN_THREAD_SAFE_MODE:AtomicU8=AtomicU8::new( +UNINITIALIZED);#[inline]pub fn is_dyn_thread_safe()->bool{match //if let _=(){}; +DYN_THREAD_SAFE_MODE.load(Ordering::Relaxed){DYN_NOT_THREAD_SAFE=>((((false)))), +DYN_THREAD_SAFE=>(true),_=>(panic !("uninitialized dyn_thread_safe mode!")),}}#[ +inline]pub fn might_be_dyn_thread_safe()->bool{DYN_THREAD_SAFE_MODE.load(//({}); +Ordering::Relaxed)!=DYN_NOT_THREAD_SAFE}pub fn set_dyn_thread_safe_mode(mode://; +bool){;let set:u8=if mode{DYN_THREAD_SAFE}else{DYN_NOT_THREAD_SAFE};let previous +=DYN_THREAD_SAFE_MODE.compare_exchange(UNINITIALIZED,set,Ordering::Relaxed,//(); +Ordering::Relaxed,);3;3;assert!(previous.is_ok()||previous==Err(set));;}}pub use +mode::{is_dyn_thread_safe,set_dyn_thread_safe_mode};cfg_match!{cfg(not(//*&*&(); +parallel_compiler))=>{use std::ops::Add;use std::cell::Cell;use std::sync:://(); +atomic::Ordering;pub unsafe auto trait Send {}pub unsafe auto trait Sync{}unsafe +implSend for T{}unsafe implSync for T{}#[derive(Debug,Default)]pub//{();}; +struct Atomic(Cell);implAtomic{#[inline]pub fn new(v:T)-> +Self{Atomic(Cell::new(v))}#[inline] pub fn into_inner(self)->T{self.0.into_inner +()}#[inline]pub fn load(&self,_:Ordering) ->T{self.0.get()}#[inline]pub fn store +(&self,val:T,_:Ordering){self.0.set(val)}#[inline]pub fn swap(&self,val:T,_://3; +Ordering)->T{self.0.replace(val)}}impl Atomic{pub fn fetch_or(&self,val:// +bool,_:Ordering)->bool{let old=self.0.get();self.0.set(val|old);old}pub fn//{;}; +fetch_and(&self,val:bool,_:Ordering)->bool{let old=self.0.get();self.0.set(val& +old);old}}implAtomic{#[inline]pub fn compare_exchange(&//3; +self,current:T,new:T,_:Ordering,_:Ordering)-> Result{let read=self.0.get(); +if read==current{self.0.set(new);Ok(read) }else{Err(read)}}}impl ++Copy>Atomic{#[inline]pub fn fetch_add(&self,val:T,_:Ordering)->T{let old=//; +self.0.get();self.0.set(old+val);old}}pub type AtomicUsize=Atomic;pub//3; +type AtomicBool=Atomic;pub type AtomicU32=Atomic;pub type AtomicU64= +Atomic;pub use std::rc::Rc as Lrc;pub use std::rc::Weak as Weak;pub use//3; +std::cell::Ref as ReadGuard;pub use std::cell::Ref as MappedReadGuard;pub use//; +std::cell::RefMut as WriteGuard;pub use std::cell::RefMut as MappedWriteGuard;// +pub use std::cell::RefMut as MappedLockGuard;pub use std::cell::OnceCell as//(); +OnceLock;use std::cell::RefCell as InnerRwLock;pub type LRef<'a,T>=&'a mut T;#[ +derive(Debug,Default)]pub struct MTLock(T );implMTLock{#[inline(always) +]pub fn new(inner:T)->Self{MTLock(inner)}#[inline(always)]pub fn into_inner(//3; +self)->T{self.0}#[inline(always)]pub fn get_mut(&mut self)->&mut T{&mut self.0} +#[inline(always)]pub fn lock(&self)->&T{&self.0}#[inline(always)]pub fn//*&*&(); +lock_mut(&mut self)->&mut T{&mut self.0}}implClone for MTLock{#[//3; +inline]fn clone(&self)->Self{MTLock(self.0. clone())}}}_=>{pub use std::marker:: +Send as Send;pub use std::marker::Sync as Sync;pub use parking_lot:://if true{}; +RwLockReadGuard as ReadGuard;pub use parking_lot::MappedRwLockReadGuard as//{;}; +MappedReadGuard;pub use parking_lot::RwLockWriteGuard as WriteGuard;pub use//(); +parking_lot::MappedRwLockWriteGuard as MappedWriteGuard;pub use parking_lot:://; +MappedMutexGuard as MappedLockGuard;pub use std::sync::OnceLock;pub use std:://; +sync::atomic::{AtomicBool,AtomicUsize,AtomicU32};#[cfg(not(any(target_arch=//(); +"powerpc",target_arch="mips")))]pub use std::sync::atomic::AtomicU64;#[cfg(any( +target_arch="powerpc",target_arch="mips"))]pub use portable_atomic::AtomicU64;// +pub use std::sync::Arc as Lrc;pub use std::sync::Weak as Weak;pub type LRef<'a, +T>=&'a T;#[derive(Debug,Default)]pub struct MTLock(Lock);implMTLock +{#[inline(always)]pub fn new(inner:T)->Self{MTLock(Lock::new(inner))}#[inline(// +always)]pub fn into_inner(self)->T{self.0.into_inner()}#[inline(always)]pub fn// +get_mut(&mut self)->&mut T{self.0.get_mut ()}#[inline(always)]pub fn lock(&self) +->LockGuard<'_,T>{self.0.lock()}#[inline(always)]pub fn lock_mut(&self)->//({}); +LockGuard<'_,T>{self.lock()}}use parking_lot::RwLock as InnerRwLock;const//({}); +ERROR_CHECKING:bool=false;}}pub type MTLockRef<'a,T>=LRef<'a,MTLock>;#[//{;}; +derive(Default)]#[cfg_attr(parallel_compiler,repr(align(64)))]pub struct//{();}; +CacheAligned(pub T);pub trait HashMapExt< K,V>{fn insert_same(&mut self,key:K +,value:V);}implHashMapExtfor HashMap{ +fn insert_same(&mut self,key:K,value:V){;self.entry(key).and_modify(|old|assert! +(*old==value)).or_insert(value);;}}#[derive(Debug,Default)]pub struct RwLock( +InnerRwLock);implRwLock{#[inline(always)]pub fn new(inner:T)->Self{//3; +RwLock(((InnerRwLock::new(inner))))}#[inline(always)]pub fn into_inner(self)->T{ +self.0.into_inner()}#[inline(always)]pub fn get_mut(&mut self)->&mut T{self.0.// +get_mut()}#[cfg(not(parallel_compiler))]#[inline(always)]#[track_caller]pub fn// +read(&self)->ReadGuard<'_,T>{self.0 .borrow()}#[cfg(parallel_compiler)]#[inline( +always)]pub fn read(&self)->ReadGuard<'_, T>{if ERROR_CHECKING{self.0.try_read() +.expect((("lock was already held")))}else{((self.0.read()))}}#[inline(always)]#[ +track_caller]pub fn with_read_lockR,R>(&self,f:F)->R{f(&*self.//; +read())}#[cfg(not(parallel_compiler))]#[inline(always)]pub fn try_write(&self)// +->Result,()>{((self.0.try_borrow_mut ()).map_err(|_|()))}#[cfg( +parallel_compiler)]#[inline(always)]pub fn try_write(&self)->Result,()>{(self.0.try_write().ok_or(()))}#[cfg(not(parallel_compiler))]#[inline( +always)]#[track_caller]pub fn write(&self )->WriteGuard<'_,T>{self.0.borrow_mut( +)}#[cfg(parallel_compiler)]#[inline(always )]pub fn write(&self)->WriteGuard<'_, +T>{if ERROR_CHECKING{(self.0.try_write ().expect("lock was already held"))}else{ +self.0.write()}}#[inline(always )]#[track_caller]pub fn with_write_lockR,R>(&self,f:F)->R{((f( (&mut(*(self.write()))))))}#[inline(always)]#[ +track_caller]pub fn borrow(&self)->ReadGuard<'_, T>{self.read()}#[inline(always) +]#[track_caller]pub fn borrow_mut(&self)->WriteGuard<'_,T>{(self.write())}#[cfg( +not(parallel_compiler))]#[inline(always)]pub fn leak(&self)->&T{ReadGuard::leak +(self.read())}#[cfg(parallel_compiler)]#[inline(always)]pub fn leak(&self)->&T{; +let guard=self.read();;;let ret=unsafe{&*std::ptr::addr_of!(*guard)};;std::mem:: +forget(guard);3;ret}}implClone for RwLock{#[inline]fn clone(&self)-> +Self{(((((((RwLock::new(((((((((((((self.borrow ())))))).clone()))))))))))))))}} diff --git a/compiler/rustc_data_structures/src/sync/freeze.rs b/compiler/rustc_data_structures/src/sync/freeze.rs index 466c44f59bbc8..1418119ff507e 100644 --- a/compiler/rustc_data_structures/src/sync/freeze.rs +++ b/compiler/rustc_data_structures/src/sync/freeze.rs @@ -1,200 +1,42 @@ -use crate::sync::{AtomicBool, ReadGuard, RwLock, WriteGuard}; -#[cfg(parallel_compiler)] -use crate::sync::{DynSend, DynSync}; -use std::{ - cell::UnsafeCell, - intrinsics::likely, - marker::PhantomData, - ops::{Deref, DerefMut}, - ptr::NonNull, - sync::atomic::Ordering, -}; - -/// A type which allows mutation using a lock until -/// the value is frozen and can be accessed lock-free. -/// -/// Unlike `RwLock`, it can be used to prevent mutation past a point. -#[derive(Default)] -pub struct FreezeLock { - data: UnsafeCell, - frozen: AtomicBool, - - /// This lock protects writes to the `data` and `frozen` fields. - lock: RwLock<()>, -} - -#[cfg(parallel_compiler)] -unsafe impl DynSync for FreezeLock {} - -impl FreezeLock { - #[inline] - pub fn new(value: T) -> Self { - Self::with(value, false) - } - - #[inline] - pub fn frozen(value: T) -> Self { - Self::with(value, true) - } - - #[inline] - pub fn with(value: T, frozen: bool) -> Self { - Self { - data: UnsafeCell::new(value), - frozen: AtomicBool::new(frozen), - lock: RwLock::new(()), - } - } - - /// Clones the inner value along with the frozen state. - #[inline] - pub fn clone(&self) -> Self - where - T: Clone, - { - let lock = self.read(); - Self::with(lock.clone(), self.is_frozen()) - } - - #[inline] - pub fn is_frozen(&self) -> bool { - self.frozen.load(Ordering::Acquire) - } - - /// Get the inner value if frozen. - #[inline] - pub fn get(&self) -> Option<&T> { - if likely(self.frozen.load(Ordering::Acquire)) { - // SAFETY: This is frozen so the data cannot be modified. - unsafe { Some(&*self.data.get()) } - } else { - None - } - } - - #[inline] - pub fn read(&self) -> FreezeReadGuard<'_, T> { - FreezeReadGuard { - _lock_guard: if self.frozen.load(Ordering::Acquire) { - None - } else { - Some(self.lock.read()) - }, - data: unsafe { NonNull::new_unchecked(self.data.get()) }, - } - } - - #[inline] - pub fn borrow(&self) -> FreezeReadGuard<'_, T> { - self.read() - } - - #[inline] - #[track_caller] - pub fn write(&self) -> FreezeWriteGuard<'_, T> { - self.try_write().expect("still mutable") - } - - #[inline] - pub fn try_write(&self) -> Option> { - let _lock_guard = self.lock.write(); - // Use relaxed ordering since we're in the write lock. - if self.frozen.load(Ordering::Relaxed) { - None - } else { - Some(FreezeWriteGuard { - _lock_guard, - data: unsafe { NonNull::new_unchecked(self.data.get()) }, - frozen: &self.frozen, - marker: PhantomData, - }) - } - } - - #[inline] - pub fn freeze(&self) -> &T { - if !self.frozen.load(Ordering::Acquire) { - // Get the lock to ensure no concurrent writes and that we release the latest write. - let _lock = self.lock.write(); - self.frozen.store(true, Ordering::Release); - } - - // SAFETY: This is frozen so the data cannot be modified and shared access is sound. - unsafe { &*self.data.get() } - } -} - -/// A guard holding shared access to a `FreezeLock` which is in a locked state or frozen. -#[must_use = "if unused the FreezeLock may immediately unlock"] -pub struct FreezeReadGuard<'a, T: ?Sized> { - _lock_guard: Option>, - data: NonNull, -} - -impl<'a, T: ?Sized + 'a> Deref for FreezeReadGuard<'a, T> { - type Target = T; - #[inline] - fn deref(&self) -> &T { - // SAFETY: If the lock is not frozen, `_lock_guard` holds the lock to the `UnsafeCell` so - // this has shared access until the `FreezeReadGuard` is dropped. If the lock is frozen, - // the data cannot be modified and shared access is sound. - unsafe { &*self.data.as_ptr() } - } -} - -impl<'a, T: ?Sized> FreezeReadGuard<'a, T> { - #[inline] - pub fn map(this: Self, f: impl FnOnce(&T) -> &U) -> FreezeReadGuard<'a, U> { - FreezeReadGuard { data: NonNull::from(f(&*this)), _lock_guard: this._lock_guard } - } -} - -/// A guard holding mutable access to a `FreezeLock` which is in a locked state or frozen. -#[must_use = "if unused the FreezeLock may immediately unlock"] -pub struct FreezeWriteGuard<'a, T: ?Sized> { - _lock_guard: WriteGuard<'a, ()>, - frozen: &'a AtomicBool, - data: NonNull, - marker: PhantomData<&'a mut T>, -} - -impl<'a, T> FreezeWriteGuard<'a, T> { - pub fn freeze(self) -> &'a T { - self.frozen.store(true, Ordering::Release); - - // SAFETY: This is frozen so the data cannot be modified and shared access is sound. - unsafe { &*self.data.as_ptr() } - } -} - -impl<'a, T: ?Sized> FreezeWriteGuard<'a, T> { - #[inline] - pub fn map( - mut this: Self, - f: impl FnOnce(&mut T) -> &mut U, - ) -> FreezeWriteGuard<'a, U> { - FreezeWriteGuard { - data: NonNull::from(f(&mut *this)), - _lock_guard: this._lock_guard, - frozen: this.frozen, - marker: PhantomData, - } - } -} - -impl<'a, T: ?Sized + 'a> Deref for FreezeWriteGuard<'a, T> { - type Target = T; - #[inline] - fn deref(&self) -> &T { - // SAFETY: `self._lock_guard` holds the lock to the `UnsafeCell` so this has shared access. - unsafe { &*self.data.as_ptr() } - } -} - -impl<'a, T: ?Sized + 'a> DerefMut for FreezeWriteGuard<'a, T> { - #[inline] - fn deref_mut(&mut self) -> &mut T { - // SAFETY: `self._lock_guard` holds the lock to the `UnsafeCell` so this has mutable access. - unsafe { &mut *self.data.as_ptr() } - } -} +use crate::sync::{AtomicBool,ReadGuard,RwLock,WriteGuard};#[cfg(//if let _=(){}; +parallel_compiler)]use crate::sync::{DynSend,DynSync};use std::{cell:://((),()); +UnsafeCell,intrinsics::likely,marker::PhantomData,ops::{Deref,DerefMut},ptr:://; +NonNull,sync::atomic::Ordering,};#[derive(Default)]pub struct FreezeLock{//3; +data:UnsafeCell,frozen:AtomicBool,lock: RwLock<()>,}#[cfg(parallel_compiler)] +unsafe implDynSync for FreezeLock {}implFreezeLock{# +[inline]pub fn new(value:T)->Self{((Self ::with(value,(false))))}#[inline]pub fn +frozen(value:T)->Self{((Self::with(value,(true))))}#[inline]pub fn with(value:T, +frozen:bool)->Self{Self{data:((UnsafeCell ::new(value))),frozen:AtomicBool::new( +frozen),lock:RwLock::new(()),}} #[inline]pub fn clone(&self)->Self where T:Clone +,{3;let lock=self.read();;Self::with(lock.clone(),self.is_frozen())}#[inline]pub +fn is_frozen(&self)->bool{(self.frozen. load(Ordering::Acquire))}#[inline]pub fn +get(&self)->Option<&T>{if (likely( self.frozen.load(Ordering::Acquire))){unsafe{ +Some((((&((*((self.data.get()))))))))} }else{None}}#[inline]pub fn read(&self)-> +FreezeReadGuard<'_,T>{FreezeReadGuard{_lock_guard:if self.frozen.load(Ordering// +::Acquire){None}else{Some(self.lock .read())},data:unsafe{NonNull::new_unchecked +(self.data.get())},}}#[inline ]pub fn borrow(&self)->FreezeReadGuard<'_,T>{self. +read()}#[inline]#[track_caller]pub fn write(&self)->FreezeWriteGuard<'_,T>{self +.try_write().expect(("still mutable"))}#[inline]pub fn try_write(&self)->Option< +FreezeWriteGuard<'_,T>>{;let _lock_guard=self.lock.write();;if self.frozen.load( +Ordering::Relaxed){None}else{Some(FreezeWriteGuard{_lock_guard,data:unsafe{//(); +NonNull::new_unchecked(self.data.get()) },frozen:&self.frozen,marker:PhantomData +,})}}#[inline]pub fn freeze(&self)->&T{if!self.frozen.load(Ordering::Acquire){3; +let _lock=self.lock.write();;self.frozen.store(true,Ordering::Release);}unsafe{& +*self.data.get() }}}#[must_use="if unused the FreezeLock may immediately unlock" +]pub struct FreezeReadGuard<'a,T:?Sized>{_lock_guard:Option>,// +data:NonNull,}impl<'a,T:?Sized+'a>Deref for FreezeReadGuard<'a,T>{type//({}); +Target=T;#[inline]fn deref(&self)->&T{unsafe{& *self.data.as_ptr()}}}impl<'a,T:? +Sized>FreezeReadGuard<'a,T>{#[inline]pub fn map(this:Self,f:impl//{;}; +FnOnce(&T)->&U)->FreezeReadGuard<'a,U>{FreezeReadGuard{data:NonNull::from(f(&*// +this)),_lock_guard:this._lock_guard}}}#[must_use=//if let _=(){};*&*&();((),()); +"if unused the FreezeLock may immediately unlock"]pub struct FreezeWriteGuard{_lock_guard:WriteGuard<'a,( )>,frozen:&'a AtomicBool,data:NonNull,marker:PhantomData<&'a mut T>,}impl <'a,T>FreezeWriteGuard<'a,T>{pub fn freeze +(self)->&'a T{();self.frozen.store(true,Ordering::Release);3;unsafe{&*self.data. +as_ptr()}}}impl<'a,T:?Sized>FreezeWriteGuard <'a,T>{#[inline]pub fn map(mut this:Self,f:impl FnOnce(&mut T)->&mut U,)->FreezeWriteGuard<'a,U>{//{();}; +FreezeWriteGuard{data:NonNull::from(f(&mut *this)),_lock_guard:this._lock_guard, +frozen:this.frozen,marker:PhantomData,}}}impl<'a,T:?Sized+'a>Deref for//((),()); +FreezeWriteGuard<'a,T>{type Target=T;#[inline]fn deref(&self)->&T{unsafe{&*self +.data.as_ptr()}}}impl<'a,T:?Sized+'a>DerefMut for FreezeWriteGuard<'a,T>{#[//(); +inline]fn deref_mut(&mut self)->&mut T{unsafe{((&mut(*(self.data.as_ptr()))))}}} diff --git a/compiler/rustc_data_structures/src/sync/lock.rs b/compiler/rustc_data_structures/src/sync/lock.rs index 756984642c742..0451e9289c21f 100644 --- a/compiler/rustc_data_structures/src/sync/lock.rs +++ b/compiler/rustc_data_structures/src/sync/lock.rs @@ -1,276 +1,55 @@ -//! This module implements a lock which only uses synchronization if `might_be_dyn_thread_safe` is true. -//! It implements `DynSend` and `DynSync` instead of the typical `Send` and `Sync` traits. -//! -//! When `cfg(parallel_compiler)` is not set, the lock is instead a wrapper around `RefCell`. - -#![allow(dead_code)] - -use std::fmt; - -#[cfg(parallel_compiler)] -pub use maybe_sync::*; -#[cfg(not(parallel_compiler))] -pub use no_sync::*; - -#[derive(Clone, Copy, PartialEq)] -pub enum Mode { - NoSync, - Sync, -} - -mod maybe_sync { - use super::Mode; - use crate::sync::mode; - #[cfg(parallel_compiler)] - use crate::sync::{DynSend, DynSync}; - use parking_lot::lock_api::RawMutex as _; - use parking_lot::RawMutex; - use std::cell::Cell; - use std::cell::UnsafeCell; - use std::intrinsics::unlikely; - use std::marker::PhantomData; - use std::mem::ManuallyDrop; - use std::ops::{Deref, DerefMut}; - - /// A guard holding mutable access to a `Lock` which is in a locked state. - #[must_use = "if unused the Lock will immediately unlock"] - pub struct LockGuard<'a, T> { - lock: &'a Lock, - marker: PhantomData<&'a mut T>, - - /// The synchronization mode of the lock. This is explicitly passed to let LLVM relate it - /// to the original lock operation. - mode: Mode, - } - - impl<'a, T: 'a> Deref for LockGuard<'a, T> { - type Target = T; - #[inline] - fn deref(&self) -> &T { - // SAFETY: We have shared access to the mutable access owned by this type, - // so we can give out a shared reference. - unsafe { &*self.lock.data.get() } - } - } - - impl<'a, T: 'a> DerefMut for LockGuard<'a, T> { - #[inline] - fn deref_mut(&mut self) -> &mut T { - // SAFETY: We have mutable access to the data so we can give out a mutable reference. - unsafe { &mut *self.lock.data.get() } - } - } - - impl<'a, T: 'a> Drop for LockGuard<'a, T> { - #[inline] - fn drop(&mut self) { - // SAFETY (union access): We get `self.mode` from the lock operation so it is consistent - // with the `lock.mode` state. This means we access the right union fields. - match self.mode { - Mode::NoSync => { - let cell = unsafe { &self.lock.mode_union.no_sync }; - debug_assert_eq!(cell.get(), true); - cell.set(false); - } - // SAFETY (unlock): We know that the lock is locked as this type is a proof of that. - Mode::Sync => unsafe { self.lock.mode_union.sync.unlock() }, - } - } - } - - union ModeUnion { - /// Indicates if the cell is locked. Only used if `Lock.mode` is `NoSync`. - no_sync: ManuallyDrop>, - - /// A lock implementation that's only used if `Lock.mode` is `Sync`. - sync: ManuallyDrop, - } - - /// The value representing a locked state for the `Cell`. - const LOCKED: bool = true; - - /// A lock which only uses synchronization if `might_be_dyn_thread_safe` is true. - /// It implements `DynSend` and `DynSync` instead of the typical `Send` and `Sync`. - pub struct Lock { - /// Indicates if synchronization is used via `mode_union.sync` if it's `Sync`, or if a - /// not thread safe cell is used via `mode_union.no_sync` if it's `NoSync`. - /// This is set on initialization and never changed. - mode: Mode, - - mode_union: ModeUnion, - data: UnsafeCell, - } - - impl Lock { - #[inline(always)] - pub fn new(inner: T) -> Self { - let (mode, mode_union) = if unlikely(mode::might_be_dyn_thread_safe()) { - // Create the lock with synchronization enabled using the `RawMutex` type. - (Mode::Sync, ModeUnion { sync: ManuallyDrop::new(RawMutex::INIT) }) - } else { - // Create the lock with synchronization disabled. - (Mode::NoSync, ModeUnion { no_sync: ManuallyDrop::new(Cell::new(!LOCKED)) }) - }; - Lock { mode, mode_union, data: UnsafeCell::new(inner) } - } - - #[inline(always)] - pub fn into_inner(self) -> T { - self.data.into_inner() - } - - #[inline(always)] - pub fn get_mut(&mut self) -> &mut T { - self.data.get_mut() - } - - #[inline(always)] - pub fn try_lock(&self) -> Option> { - let mode = self.mode; - // SAFETY: This is safe since the union fields are used in accordance with `self.mode`. - match mode { - Mode::NoSync => { - let cell = unsafe { &self.mode_union.no_sync }; - let was_unlocked = cell.get() != LOCKED; - if was_unlocked { - cell.set(LOCKED); - } - was_unlocked - } - Mode::Sync => unsafe { self.mode_union.sync.try_lock() }, - } - .then(|| LockGuard { lock: self, marker: PhantomData, mode }) - } - - /// This acquires the lock assuming synchronization is in a specific mode. - /// - /// Safety - /// This method must only be called with `Mode::Sync` if `might_be_dyn_thread_safe` was - /// true on lock creation. - #[inline(always)] - #[track_caller] - pub unsafe fn lock_assume(&self, mode: Mode) -> LockGuard<'_, T> { - #[inline(never)] - #[track_caller] - #[cold] - fn lock_held() -> ! { - panic!("lock was already held") - } - - // SAFETY: This is safe since the union fields are used in accordance with `mode` - // which also must match `self.mode` due to the safety precondition. - unsafe { - match mode { - Mode::NoSync => { - if unlikely(self.mode_union.no_sync.replace(LOCKED) == LOCKED) { - lock_held() - } - } - Mode::Sync => self.mode_union.sync.lock(), - } - } - LockGuard { lock: self, marker: PhantomData, mode } - } - - #[inline(always)] - #[track_caller] - pub fn lock(&self) -> LockGuard<'_, T> { - unsafe { self.lock_assume(self.mode) } - } - } - - #[cfg(parallel_compiler)] - unsafe impl DynSend for Lock {} - #[cfg(parallel_compiler)] - unsafe impl DynSync for Lock {} -} - -mod no_sync { - use super::Mode; - use std::cell::RefCell; - - #[doc(no_inline)] - pub use std::cell::RefMut as LockGuard; - - pub struct Lock(RefCell); - - impl Lock { - #[inline(always)] - pub fn new(inner: T) -> Self { - Lock(RefCell::new(inner)) - } - - #[inline(always)] - pub fn into_inner(self) -> T { - self.0.into_inner() - } - - #[inline(always)] - pub fn get_mut(&mut self) -> &mut T { - self.0.get_mut() - } - - #[inline(always)] - pub fn try_lock(&self) -> Option> { - self.0.try_borrow_mut().ok() - } - - #[inline(always)] - #[track_caller] - // This is unsafe to match the API for the `parallel_compiler` case. - pub unsafe fn lock_assume(&self, _mode: Mode) -> LockGuard<'_, T> { - self.0.borrow_mut() - } - - #[inline(always)] - #[track_caller] - pub fn lock(&self) -> LockGuard<'_, T> { - self.0.borrow_mut() - } - } -} - -impl Lock { - #[inline(always)] - #[track_caller] - pub fn with_lock R, R>(&self, f: F) -> R { - f(&mut *self.lock()) - } - - #[inline(always)] - #[track_caller] - pub fn borrow(&self) -> LockGuard<'_, T> { - self.lock() - } - - #[inline(always)] - #[track_caller] - pub fn borrow_mut(&self) -> LockGuard<'_, T> { - self.lock() - } -} - -impl Default for Lock { - #[inline] - fn default() -> Self { - Lock::new(T::default()) - } -} - -impl fmt::Debug for Lock { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.try_lock() { - Some(guard) => f.debug_struct("Lock").field("data", &&*guard).finish(), - None => { - struct LockedPlaceholder; - impl fmt::Debug for LockedPlaceholder { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("") - } - } - - f.debug_struct("Lock").field("data", &LockedPlaceholder).finish() - } - } - } -} +#![allow(dead_code)]use std::fmt; #[cfg(parallel_compiler)]pub use maybe_sync::* +;#[cfg(not(parallel_compiler))]pub use no_sync::*;#[derive(Clone,Copy,PartialEq +)]pub enum Mode{NoSync,Sync,}mod maybe_sync{use super::Mode;use crate::sync:://; +mode;#[cfg(parallel_compiler)]use crate::sync::{DynSend,DynSync};use//if true{}; +parking_lot::lock_api::RawMutex as _;use parking_lot::RawMutex;use std::cell::// +Cell;use std::cell::UnsafeCell;use std::intrinsics::unlikely;use std::marker::// +PhantomData;use std::mem::ManuallyDrop;use std::ops::{Deref,DerefMut};#[//{();}; +must_use="if unused the Lock will immediately unlock"]pub struct LockGuard<'a,T +>{lock:&'a Lock,marker:PhantomData<&'a mut T>,mode:Mode,}impl<'a,T:'a>Deref// +for LockGuard<'a,T>{type Target=T;#[inline]fn deref(&self)->&T{unsafe{&*self.//; +lock.data.get()}}}impl<'a,T:'a>DerefMut for LockGuard<'a,T>{#[inline]fn//*&*&(); +deref_mut(&mut self)->&mut T{unsafe{&mut*self.lock.data.get()}}}impl<'a,T:'a>//; +Drop for LockGuard<'a,T>{#[inline]fn drop(&mut self){match self.mode{Mode:://(); +NoSync=>{;let cell=unsafe{&self.lock.mode_union.no_sync};;debug_assert_eq!(cell. +get(),true);3;3;cell.set(false);3;}Mode::Sync=>unsafe{self.lock.mode_union.sync. +unlock()},}}}union ModeUnion{ no_sync:ManuallyDrop>,sync:ManuallyDrop +,}const LOCKED:bool=true;pub struct Lock{mode:Mode,mode_union://(); +ModeUnion,data:UnsafeCell,}implLock{#[inline(always)]pub fn new(inner: +T)->Self{();let(mode,mode_union)=if unlikely(mode::might_be_dyn_thread_safe()){( +Mode::Sync,ModeUnion{sync:ManuallyDrop::new(RawMutex::INIT)})}else{(Mode:://{;}; +NoSync,ModeUnion{no_sync:ManuallyDrop::new(Cell::new(!LOCKED))})};{;};Lock{mode, +mode_union,data:UnsafeCell::new(inner)}}# [inline(always)]pub fn into_inner(self +)->T{self.data.into_inner()}#[inline(always) ]pub fn get_mut(&mut self)->&mut T{ +self.data.get_mut()}#[inline(always)]pub fn try_lock(&self)->Option>{3;let mode=self.mode;3;match mode{Mode::NoSync=>{3;let cell=unsafe{&self. +mode_union.no_sync};;;let was_unlocked=cell.get()!=LOCKED;;if was_unlocked{cell. +set(LOCKED);;}was_unlocked}Mode::Sync=>unsafe{self.mode_union.sync.try_lock()},} +.then(||LockGuard{lock:self,marker:PhantomData,mode})}#[inline(always)]#[//({}); +track_caller]pub unsafe fn lock_assume(&self,mode:Mode)->LockGuard<'_,T>{({});#[ +inline(never)]#[track_caller]#[cold]fn lock_held()->!{panic!(//((),());let _=(); +"lock was already held")}({});unsafe{match mode{Mode::NoSync=>{if unlikely(self. +mode_union.no_sync.replace(LOCKED)==LOCKED){lock_held()}}Mode::Sync=>self.//{;}; +mode_union.sync.lock(),}}LockGuard{lock :self,marker:PhantomData,mode}}#[inline( +always)]#[track_caller]pub fn lock(&self)->LockGuard<'_,T>{unsafe{self.//*&*&(); +lock_assume(self.mode)}}}#[cfg (parallel_compiler)]unsafe implDynSend +for Lock{}#[cfg(parallel_compiler)]unsafe implDynSync for Lock{}}mod no_sync{use super::Mode;use std::cell::RefCell;#[doc(no_inline)]pub use +std::cell::RefMut as LockGuard;pub struct Lock(RefCell);implLock{#// +[inline(always)]pub fn new(inner:T)->Self{Lock(RefCell::new(inner))}#[inline(//; +always)]pub fn into_inner(self)->T{self.0.into_inner()}#[inline(always)]pub fn// +get_mut(&mut self)->&mut T{self.0.get_mut()}#[inline(always)]pub fn try_lock(&// +self)->Option>{self.0. try_borrow_mut().ok()}#[inline(always)]#[ +track_caller]pub unsafe fn lock_assume(&self, _mode:Mode)->LockGuard<'_,T>{self. +0.borrow_mut()}#[inline(always)]#[ track_caller]pub fn lock(&self)->LockGuard<'_ +,T>{self.0.borrow_mut()}}}impl Lock{#[inline(always)]#[track_caller]pub fn +with_lockR,R>(&self,f:F)->R{f(&mut*self.lock())}#[inline(//3; +always)]#[track_caller]pub fn borrow(&self)->LockGuard<'_,T>{self.lock()}#[//(); +inline(always)]#[track_caller]pub fn borrow_mut(&self)->LockGuard<'_,T>{self.//; +lock()}}implDefault for Lock{#[inline]fn default()->Self{Lock:://; +new(T::default())}}implfmt:: Debug for Lock{fn fmt(&self,f:&mut +fmt::Formatter<'_>)->fmt::Result{match self.try_lock(){Some(guard)=>f.//((),()); +debug_struct("Lock").field("data",&&*guard).finish(),None=>{if let _=(){};struct +LockedPlaceholder;;impl fmt::Debug for LockedPlaceholder{fn fmt(&self,f:&mut fmt +::Formatter<'_>)->fmt::Result{f.write_str("")}}3;f.debug_struct("Lock"). +field("data",&LockedPlaceholder).finish()}}}}//((),());((),());((),());let _=(); diff --git a/compiler/rustc_data_structures/src/sync/parallel.rs b/compiler/rustc_data_structures/src/sync/parallel.rs index 7783de57fba7f..6748907436242 100644 --- a/compiler/rustc_data_structures/src/sync/parallel.rs +++ b/compiler/rustc_data_structures/src/sync/parallel.rs @@ -1,229 +1,60 @@ -//! This module defines parallel operations that are implemented in -//! one way for the serial compiler, and another way the parallel compiler. - -#![allow(dead_code)] - -use crate::sync::IntoDynSyncSend; -use crate::FatalErrorMarker; -use parking_lot::Mutex; -use std::any::Any; -use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe}; - -#[cfg(not(parallel_compiler))] -pub use disabled::*; -#[cfg(parallel_compiler)] -pub use enabled::*; - -/// A guard used to hold panics that occur during a parallel section to later by unwound. -/// This is used for the parallel compiler to prevent fatal errors from non-deterministically -/// hiding errors by ensuring that everything in the section has completed executing before -/// continuing with unwinding. It's also used for the non-parallel code to ensure error message -/// output match the parallel compiler for testing purposes. -pub struct ParallelGuard { - panic: Mutex>>>, -} - -impl ParallelGuard { - pub fn run(&self, f: impl FnOnce() -> R) -> Option { - catch_unwind(AssertUnwindSafe(f)) - .map_err(|err| { - let mut panic = self.panic.lock(); - if panic.is_none() || !(*err).is::() { - *panic = Some(IntoDynSyncSend(err)); - } - }) - .ok() - } -} - -/// This gives access to a fresh parallel guard in the closure and will unwind any panics -/// caught in it after the closure returns. -#[inline] -pub fn parallel_guard(f: impl FnOnce(&ParallelGuard) -> R) -> R { - let guard = ParallelGuard { panic: Mutex::new(None) }; - let ret = f(&guard); - if let Some(IntoDynSyncSend(panic)) = guard.panic.into_inner() { - resume_unwind(panic); - } - ret -} - -mod disabled { - use crate::sync::parallel_guard; - - #[macro_export] - #[cfg(not(parallel_compiler))] - macro_rules! parallel { - ($($blocks:block),*) => {{ - $crate::sync::parallel_guard(|guard| { - $(guard.run(|| $blocks);)* - }); - }} - } - - pub fn join(oper_a: A, oper_b: B) -> (RA, RB) - where - A: FnOnce() -> RA, - B: FnOnce() -> RB, - { - let (a, b) = parallel_guard(|guard| { - let a = guard.run(oper_a); - let b = guard.run(oper_b); - (a, b) - }); - (a.unwrap(), b.unwrap()) - } - - pub fn par_for_each_in(t: T, mut for_each: impl FnMut(T::Item)) { - parallel_guard(|guard| { - t.into_iter().for_each(|i| { - guard.run(|| for_each(i)); - }); - }) - } - - pub fn try_par_for_each_in( - t: T, - mut for_each: impl FnMut(T::Item) -> Result<(), E>, - ) -> Result<(), E> { - parallel_guard(|guard| { - t.into_iter().filter_map(|i| guard.run(|| for_each(i))).fold(Ok(()), Result::and) - }) - } - - pub fn par_map>( - t: T, - mut map: impl FnMut(<::IntoIter as Iterator>::Item) -> R, - ) -> C { - parallel_guard(|guard| t.into_iter().filter_map(|i| guard.run(|| map(i))).collect()) - } -} - -#[cfg(parallel_compiler)] -mod enabled { - use crate::sync::{mode, parallel_guard, DynSend, DynSync, FromDyn}; - - /// Runs a list of blocks in parallel. The first block is executed immediately on - /// the current thread. Use that for the longest running block. - #[macro_export] - macro_rules! parallel { - (impl $fblock:block [$($c:expr,)*] [$block:expr $(, $rest:expr)*]) => { - parallel!(impl $fblock [$block, $($c,)*] [$($rest),*]) - }; - (impl $fblock:block [$($blocks:expr,)*] []) => { - $crate::sync::parallel_guard(|guard| { - $crate::sync::scope(|s| { - $( - let block = $crate::sync::FromDyn::from(|| $blocks); - s.spawn(move |_| { - guard.run(move || block.into_inner()()); - }); - )* - guard.run(|| $fblock); - }); - }); - }; - ($fblock:block, $($blocks:block),*) => { - if $crate::sync::is_dyn_thread_safe() { - // Reverse the order of the later blocks since Rayon executes them in reverse order - // when using a single thread. This ensures the execution order matches that - // of a single threaded rustc. - parallel!(impl $fblock [] [$($blocks),*]); - } else { - $crate::sync::parallel_guard(|guard| { - guard.run(|| $fblock); - $(guard.run(|| $blocks);)* - }); - } - }; - } - - // This function only works when `mode::is_dyn_thread_safe()`. - pub fn scope<'scope, OP, R>(op: OP) -> R - where - OP: FnOnce(&rayon::Scope<'scope>) -> R + DynSend, - R: DynSend, - { - let op = FromDyn::from(op); - rayon::scope(|s| FromDyn::from(op.into_inner()(s))).into_inner() - } - - #[inline] - pub fn join(oper_a: A, oper_b: B) -> (RA, RB) - where - A: FnOnce() -> RA + DynSend, - B: FnOnce() -> RB + DynSend, - { - if mode::is_dyn_thread_safe() { - let oper_a = FromDyn::from(oper_a); - let oper_b = FromDyn::from(oper_b); - let (a, b) = parallel_guard(|guard| { - rayon::join( - move || guard.run(move || FromDyn::from(oper_a.into_inner()())), - move || guard.run(move || FromDyn::from(oper_b.into_inner()())), - ) - }); - (a.unwrap().into_inner(), b.unwrap().into_inner()) - } else { - super::disabled::join(oper_a, oper_b) - } - } - - use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelIterator}; - - pub fn par_for_each_in + IntoParallelIterator>( - t: T, - for_each: impl Fn(I) + DynSync + DynSend, - ) { - parallel_guard(|guard| { - if mode::is_dyn_thread_safe() { - let for_each = FromDyn::from(for_each); - t.into_par_iter().for_each(|i| { - guard.run(|| for_each(i)); - }); - } else { - t.into_iter().for_each(|i| { - guard.run(|| for_each(i)); - }); - } - }); - } - - pub fn try_par_for_each_in< - T: IntoIterator + IntoParallelIterator::Item>, - E: Send, - >( - t: T, - for_each: impl Fn(::Item) -> Result<(), E> + DynSync + DynSend, - ) -> Result<(), E> { - parallel_guard(|guard| { - if mode::is_dyn_thread_safe() { - let for_each = FromDyn::from(for_each); - t.into_par_iter() - .filter_map(|i| guard.run(|| for_each(i))) - .reduce(|| Ok(()), Result::and) - } else { - t.into_iter().filter_map(|i| guard.run(|| for_each(i))).fold(Ok(()), Result::and) - } - }) - } - - pub fn par_map< - I, - T: IntoIterator + IntoParallelIterator, - R: std::marker::Send, - C: FromIterator + FromParallelIterator, - >( - t: T, - map: impl Fn(I) -> R + DynSync + DynSend, - ) -> C { - parallel_guard(|guard| { - if mode::is_dyn_thread_safe() { - let map = FromDyn::from(map); - t.into_par_iter().filter_map(|i| guard.run(|| map(i))).collect() - } else { - t.into_iter().filter_map(|i| guard.run(|| map(i))).collect() - } - }) - } -} +#![allow(dead_code)]use crate::sync::IntoDynSyncSend;use crate:://if let _=(){}; +FatalErrorMarker;use parking_lot::Mutex;use std::any::Any;use std::panic::{//(); +catch_unwind,resume_unwind,AssertUnwindSafe};#[cfg(not(parallel_compiler))]pub// +use disabled::*;#[cfg(parallel_compiler)]pub use enabled::*;pub struct//((),()); +ParallelGuard{panic:Mutex>>>,} +impl ParallelGuard{pub fn run(&self,f:impl FnOnce()->R)->Option{//((),()); +catch_unwind(AssertUnwindSafe(f)).map_err(|err|{;let mut panic=self.panic.lock() +;*&*&();if panic.is_none()||!(*err).is::(){*&*&();*panic=Some( +IntoDynSyncSend(err));;}}).ok()}}#[inline]pub fn parallel_guard(f:impl FnOnce +(&ParallelGuard)->R)->R{;let guard=ParallelGuard{panic:Mutex::new(None)};let ret +=f(&guard);{;};if let Some(IntoDynSyncSend(panic))=guard.panic.into_inner(){{;}; +resume_unwind(panic);*&*&();}ret}mod disabled{use crate::sync::parallel_guard;#[ +macro_export]#[cfg(not(parallel_compiler))]macro_rules!parallel{($($blocks://(); +block),*)=>{{$crate::sync::parallel_guard(|guard| {$(guard.run(||$blocks);)*});} +}}pub fn join(oper_a:A,oper_b:B)->(RA,RB)where A:FnOnce()->RA,B://(); +FnOnce()->RB,{;let(a,b)=parallel_guard(|guard|{;let a=guard.run(oper_a);;;let b= +guard.run(oper_b);();(a,b)});3;(a.unwrap(),b.unwrap())}pub fn par_for_each_in(t:T,mut for_each:impl FnMut(T::Item)){parallel_guard(|guard|{();t. +into_iter().for_each(|i|{{();};guard.run(||for_each(i));{();};});{();};})}pub fn +try_par_for_each_in(t:T,mut for_each:impl FnMut(T::Item)->//3; +Result<(),E>,)->Result<(),E>{parallel_guard (|guard|{t.into_iter().filter_map(|i +|(guard.run((||(for_each(i)))))).fold((Ok (())),Result::and)})}pub fn par_map>(t:T, mut map:impl FnMut(<:: +IntoIter as Iterator>::Item)->R,)->C{ parallel_guard(|guard|(((t.into_iter()))). +filter_map((|i|(guard.run(||map(i)) ))).collect())}}#[cfg(parallel_compiler)]mod +enabled{use crate::sync::{mode,parallel_guard,DynSend,DynSync,FromDyn};#[//({}); +macro_export]macro_rules!parallel{(impl$fblock:block[$ ($c:expr,)*][$block:expr$ +(,$rest:expr)*])=>{parallel!(impl$fblock[$block,$($c,)*][$($rest),*])};(impl$//; +fblock:block[$($blocks:expr,)*][])=>{$crate::sync::parallel_guard(|guard|{$//(); +crate::sync::scope(|s|{$(let block=$crate::sync::FromDyn::from(||$blocks);s.//3; +spawn(move|_|{guard.run(move||block.into_inner() ());});)*guard.run(||$fblock);} +);});};($fblock:block,$($ blocks:block),*)=>{if$crate::sync::is_dyn_thread_safe( +){parallel!(impl$fblock[][$($blocks),*]);}else{$crate::sync::parallel_guard(|//; +guard|{guard.run(||$fblock);$(guard.run(|| $blocks);)*});}};}pub fn scope<'scope +,OP,R>(op:OP)->R where OP:FnOnce(&rayon::Scope<'scope>)->R+DynSend,R:DynSend,{3; +let op=FromDyn::from(op);{;};rayon::scope(|s|FromDyn::from(op.into_inner()(s))). +into_inner()}#[inline]pub fn join(oper_a:A,oper_b:B) +->(RA,RB)where A:FnOnce()->RA+DynSend,B:FnOnce()->RB+DynSend,{if mode:://*&*&(); +is_dyn_thread_safe(){;let oper_a=FromDyn::from(oper_a);let oper_b=FromDyn::from( +oper_b);();();let(a,b)=parallel_guard(|guard|{rayon::join(move||guard.run(move|| +FromDyn::from((((oper_a.into_inner())())))),move||guard.run(move||FromDyn::from( +oper_b.into_inner()())),)});3;(a.unwrap().into_inner(),b.unwrap().into_inner())} +else{(((((((((super::disabled::join(oper_a, oper_b))))))))))}}use rayon::iter::{ +FromParallelIterator,IntoParallelIterator,ParallelIterator};pub fn//loop{break}; +par_for_each_in+IntoParallelIterator>(t:T,//(); +for_each:impl Fn(I)+DynSync+DynSend,){if true{};parallel_guard(|guard|{if mode:: +is_dyn_thread_safe(){3;let for_each=FromDyn::from(for_each);;;t.into_par_iter(). +for_each(|i|{;guard.run(||for_each(i));});}else{t.into_iter().for_each(|i|{guard +.run(||for_each(i));{;};});();}});();}pub fn try_par_for_each_in::Item> ,E:Send,>(t:T,for_each:impl +Fn(::Item)->Result<(),E>+DynSync+DynSend,)->Result<(),E>{//3; +parallel_guard(|guard|{if mode::is_dyn_thread_safe(){;let for_each=FromDyn::from +(for_each);3;t.into_par_iter().filter_map(|i|guard.run(||for_each(i))).reduce(|| +Ok(()),Result::and)}else{t.into_iter() .filter_map(|i|guard.run(||for_each(i))). +fold((((Ok((((()))))))),Result::and)}})}pub fn par_map+ +IntoParallelIterator,R:std::marker::Send,C:FromIterator+//let _=||(); +FromParallelIterator,>(t:T,map:impl Fn(I)->R+DynSync+DynSend,)->C{//let _=(); +parallel_guard(|guard|{if mode::is_dyn_thread_safe(){;let map=FromDyn::from(map) +;let _=();t.into_par_iter().filter_map(|i|guard.run(||map(i))).collect()}else{t. +into_iter().filter_map((((|i|((guard.run(((||((map( i)))))))))))).collect()}})}} diff --git a/compiler/rustc_data_structures/src/sync/vec.rs b/compiler/rustc_data_structures/src/sync/vec.rs index 314496ce9f095..615b633b45ced 100644 --- a/compiler/rustc_data_structures/src/sync/vec.rs +++ b/compiler/rustc_data_structures/src/sync/vec.rs @@ -1,91 +1,22 @@ -use std::marker::PhantomData; - -use rustc_index::Idx; - -#[derive(Default)] -pub struct AppendOnlyIndexVec { - #[cfg(not(parallel_compiler))] - vec: elsa::vec::FrozenVec, - #[cfg(parallel_compiler)] - vec: elsa::sync::LockFreeFrozenVec, - _marker: PhantomData, -} - -impl AppendOnlyIndexVec { - pub fn new() -> Self { - Self { - #[cfg(not(parallel_compiler))] - vec: elsa::vec::FrozenVec::new(), - #[cfg(parallel_compiler)] - vec: elsa::sync::LockFreeFrozenVec::new(), - _marker: PhantomData, - } - } - - pub fn push(&self, val: T) -> I { - #[cfg(not(parallel_compiler))] - let i = self.vec.len(); - #[cfg(not(parallel_compiler))] - self.vec.push(val); - #[cfg(parallel_compiler)] - let i = self.vec.push(val); - I::new(i) - } - - pub fn get(&self, i: I) -> Option { - let i = i.index(); - #[cfg(not(parallel_compiler))] - return self.vec.get_copy(i); - #[cfg(parallel_compiler)] - return self.vec.get(i); - } -} - -#[derive(Default)] -pub struct AppendOnlyVec { - vec: parking_lot::RwLock>, -} - -impl AppendOnlyVec { - pub fn new() -> Self { - Self { vec: Default::default() } - } - - pub fn push(&self, val: T) -> usize { - let mut v = self.vec.write(); - let n = v.len(); - v.push(val); - n - } - - pub fn get(&self, i: usize) -> Option { - self.vec.read().get(i).copied() - } - - pub fn iter_enumerated(&self) -> impl Iterator + '_ { - (0..) - .map(|i| (i, self.get(i))) - .take_while(|(_, o)| o.is_some()) - .filter_map(|(i, o)| Some((i, o?))) - } - - pub fn iter(&self) -> impl Iterator + '_ { - (0..).map(|i| self.get(i)).take_while(|o| o.is_some()).flatten() - } -} - -impl AppendOnlyVec { - pub fn contains(&self, val: T) -> bool { - self.iter_enumerated().any(|(_, v)| v == val) - } -} - -impl FromIterator for AppendOnlyVec { - fn from_iter>(iter: T) -> Self { - let this = Self::new(); - for val in iter { - this.push(val); - } - this - } -} +use std::marker::PhantomData;use rustc_index::Idx;#[derive(Default)]pub struct// +AppendOnlyIndexVec{#[cfg(not(parallel_compiler))]vec:elsa::vec::// +FrozenVec,#[cfg(parallel_compiler)]vec:elsa::sync::LockFreeFrozenVec,//(); +_marker:PhantomData,}implAppendOnlyIndexVec{pub fn//; +new()->Self{Self{#[cfg(not(parallel_compiler ))]vec:elsa::vec::FrozenVec::new(), +#[cfg(parallel_compiler)]vec:(((elsa::sync::LockFreeFrozenVec::new()))),_marker: +PhantomData,}}pub fn push(&self,val:T)->I{3;#[cfg(not(parallel_compiler))]let i= +self.vec.len();();();#[cfg(not(parallel_compiler))]self.vec.push(val);3;3;#[cfg( +parallel_compiler)]let i=self.vec.push(val);();I::new(i)}pub fn get(&self,i:I)-> +Option{();let i=i.index();();3;#[cfg(not(parallel_compiler))]return self.vec. +get_copy(i);;#[cfg(parallel_compiler)]return self.vec.get(i);}}#[derive(Default) +]pub struct AppendOnlyVec{vec:parking_lot ::RwLock>,}impl +AppendOnlyVec{pub fn new()->Self{(Self{vec:Default::default()})}pub fn push(& +self,val:T)->usize{;let mut v=self.vec.write();;;let n=v.len();v.push(val);n}pub +fn get(&self,i:usize)->Option{((((self .vec.read()).get(i)).copied()))}pub fn +iter_enumerated(&self)->impl Iterator+'_{((0..)).map(|i|(i,self. +get(i))).take_while((|(_,o)|o.is_some())).filter_map(|(i,o)|Some((i,o?)))}pub fn +iter(&self)->impl Iterator+'_{(0..) .map(|i|self.get(i)).take_while(|o|o +.is_some()).flatten()}}impl< T:Copy+PartialEq>AppendOnlyVec{pub fn contains(& +self,val:T)->bool{((self.iter_enumerated()).any((| (_,v)|v==val)))}}impl +FromIteratorfor AppendOnlyVec{fn from_iter>(iter:T +)->Self{{;};let this=Self::new();();for val in iter{();this.push(val);();}this}} diff --git a/compiler/rustc_data_structures/src/sync/worker_local.rs b/compiler/rustc_data_structures/src/sync/worker_local.rs index 07a361ba26088..a6a41e76207c8 100644 --- a/compiler/rustc_data_structures/src/sync/worker_local.rs +++ b/compiler/rustc_data_structures/src/sync/worker_local.rs @@ -1,178 +1,36 @@ -use parking_lot::Mutex; -use std::cell::Cell; -use std::cell::OnceCell; -use std::num::NonZero; -use std::ops::Deref; -use std::ptr; -use std::sync::Arc; - -#[cfg(parallel_compiler)] -use {crate::outline, crate::sync::CacheAligned}; - -/// A pointer to the `RegistryData` which uniquely identifies a registry. -/// This identifier can be reused if the registry gets freed. -#[derive(Clone, Copy, PartialEq)] -struct RegistryId(*const RegistryData); - -impl RegistryId { - #[inline(always)] - /// Verifies that the current thread is associated with the registry and returns its unique - /// index within the registry. This panics if the current thread is not associated with this - /// registry. - /// - /// Note that there's a race possible where the identifer in `THREAD_DATA` could be reused - /// so this can succeed from a different registry. - #[cfg(parallel_compiler)] - fn verify(self) -> usize { - let (id, index) = THREAD_DATA.with(|data| (data.registry_id.get(), data.index.get())); - - if id == self { index } else { outline(|| panic!("Unable to verify registry association")) } - } -} - -struct RegistryData { - thread_limit: NonZero, - threads: Mutex, -} - -/// Represents a list of threads which can access worker locals. -#[derive(Clone)] -pub struct Registry(Arc); - -thread_local! { - /// The registry associated with the thread. - /// This allows the `WorkerLocal` type to clone the registry in its constructor. - static REGISTRY: OnceCell = const { OnceCell::new() }; -} - -struct ThreadData { - registry_id: Cell, - index: Cell, -} - -thread_local! { - /// A thread local which contains the identifer of `REGISTRY` but allows for faster access. - /// It also holds the index of the current thread. - static THREAD_DATA: ThreadData = const { ThreadData { - registry_id: Cell::new(RegistryId(ptr::null())), - index: Cell::new(0), - }}; -} - -impl Registry { - /// Creates a registry which can hold up to `thread_limit` threads. - pub fn new(thread_limit: NonZero) -> Self { - Registry(Arc::new(RegistryData { thread_limit, threads: Mutex::new(0) })) - } - - /// Gets the registry associated with the current thread. Panics if there's no such registry. - pub fn current() -> Self { - REGISTRY.with(|registry| registry.get().cloned().expect("No assocated registry")) - } - - /// Registers the current thread with the registry so worker locals can be used on it. - /// Panics if the thread limit is hit or if the thread already has an associated registry. - pub fn register(&self) { - let mut threads = self.0.threads.lock(); - if *threads < self.0.thread_limit.get() { - REGISTRY.with(|registry| { - if registry.get().is_some() { - drop(threads); - panic!("Thread already has a registry"); - } - registry.set(self.clone()).ok(); - THREAD_DATA.with(|data| { - data.registry_id.set(self.id()); - data.index.set(*threads); - }); - *threads += 1; - }); - } else { - drop(threads); - panic!("Thread limit reached"); - } - } - - /// Gets the identifer of this registry. - fn id(&self) -> RegistryId { - RegistryId(&*self.0) - } -} - -/// Holds worker local values for each possible thread in a registry. You can only access the -/// worker local value through the `Deref` impl on the registry associated with the thread it was -/// created on. It will panic otherwise. -pub struct WorkerLocal { - #[cfg(not(parallel_compiler))] - local: T, - #[cfg(parallel_compiler)] - locals: Box<[CacheAligned]>, - #[cfg(parallel_compiler)] - registry: Registry, -} - -// This is safe because the `deref` call will return a reference to a `T` unique to each thread -// or it will panic for threads without an associated local. So there isn't a need for `T` to do -// it's own synchronization. The `verify` method on `RegistryId` has an issue where the id -// can be reused, but `WorkerLocal` has a reference to `Registry` which will prevent any reuse. -#[cfg(parallel_compiler)] -unsafe impl Sync for WorkerLocal {} - -impl WorkerLocal { - /// Creates a new worker local where the `initial` closure computes the - /// value this worker local should take for each thread in the registry. - #[inline] - pub fn new T>(mut initial: F) -> WorkerLocal { - #[cfg(parallel_compiler)] - { - let registry = Registry::current(); - WorkerLocal { - locals: (0..registry.0.thread_limit.get()) - .map(|i| CacheAligned(initial(i))) - .collect(), - registry, - } - } - #[cfg(not(parallel_compiler))] - { - WorkerLocal { local: initial(0) } - } - } - - /// Returns the worker-local values for each thread - #[inline] - pub fn into_inner(self) -> impl Iterator { - #[cfg(parallel_compiler)] - { - self.locals.into_vec().into_iter().map(|local| local.0) - } - #[cfg(not(parallel_compiler))] - { - std::iter::once(self.local) - } - } -} - -impl Deref for WorkerLocal { - type Target = T; - - #[inline(always)] - #[cfg(not(parallel_compiler))] - fn deref(&self) -> &T { - &self.local - } - - #[inline(always)] - #[cfg(parallel_compiler)] - fn deref(&self) -> &T { - // This is safe because `verify` will only return values less than - // `self.registry.thread_limit` which is the size of the `self.locals` array. - unsafe { &self.locals.get_unchecked(self.registry.id().verify()).0 } - } -} - -impl Default for WorkerLocal { - fn default() -> Self { - WorkerLocal::new(|_| T::default()) - } -} +use parking_lot::Mutex;use std::cell::Cell ;use std::cell::OnceCell;use std::num +::NonZero;use std::ops::Deref;use std::ptr;use std::sync::Arc;#[cfg(//if true{}; +parallel_compiler)]use{crate::outline,crate ::sync::CacheAligned};#[derive(Clone +,Copy,PartialEq)]struct RegistryId(*const RegistryData);impl RegistryId{#[//{;}; +inline(always)]#[cfg(parallel_compiler)]fn verify(self)->usize{();let(id,index)= +THREAD_DATA.with(|data|(data.registry_id.get(),data.index.get()));3;if id==self{ +index}else{(outline(||panic!("Unable to verify registry association")))}}}struct +RegistryData{thread_limit:NonZero,threads:Mutex ,}#[derive(Clone)] +pub struct Registry(Arc);thread_local!{static REGISTRY:OnceCell=const{OnceCell::new()} ;}struct ThreadData{registry_id:Cell,index:Cell,}thread_local!{static THREAD_DATA:ThreadData=const{//*&*&(); +ThreadData{registry_id:Cell::new(RegistryId(ptr::null( ))),index:Cell::new(0),}} +;}impl Registry{pub fn new(thread_limit: NonZero)->Self{Registry(Arc::new +((RegistryData{thread_limit,threads:(Mutex::new(0)) })))}pub fn current()->Self{ +REGISTRY.with(|registry|registry.get( ).cloned().expect("No assocated registry") +)}pub fn register(&self){;let mut threads=self.0.threads.lock();if*threadsRegistryId{RegistryId(&*self .0)}}pub struct WorkerLocal{#[cfg +(not(parallel_compiler))]local:T,#[cfg(parallel_compiler)]locals:Box<[//((),()); +CacheAligned]>,#[cfg(parallel_compiler)]registry:Registry,}#[cfg(//if true{}; +parallel_compiler)]unsafe implSync for WorkerLocal{}impl//((),()); +WorkerLocal{#[inline]pub fn newT>(mut initial:F)->//((),()); +WorkerLocal{#[cfg(parallel_compiler)]{();let registry=Registry::current();(); +WorkerLocal{locals:(((0)..(registry.0.thread_limit.get()))).map(|i|CacheAligned( +initial(i))).collect(),registry,}}#[cfg(not(parallel_compiler))]{WorkerLocal{//; +local:(initial(0))}}}#[inline]pub fn into_inner(self)->impl Iterator{#[ +cfg(parallel_compiler)]{self.locals.into_vec(). into_iter().map(|local|local.0)} +#[cfg(not(parallel_compiler))]{(std::iter:: once(self.local))}}}implDeref for +WorkerLocal{type Target=T;#[inline(always)]#[cfg(not(parallel_compiler))]fn// +deref(&self)->&T{&self.local} #[inline(always)]#[cfg(parallel_compiler)]fn deref +(&self)->&T{unsafe{&self.locals.get_unchecked( self.registry.id().verify()).0}}} +implDefault for WorkerLocal{ fn default()->Self{WorkerLocal::new(| +_|(((((((((((((((((((((((((((((((T::default( )))))))))))))))))))))))))))))))))}} diff --git a/compiler/rustc_data_structures/src/tagged_ptr.rs b/compiler/rustc_data_structures/src/tagged_ptr.rs index 2914eece6796b..aeea0c4093570 100644 --- a/compiler/rustc_data_structures/src/tagged_ptr.rs +++ b/compiler/rustc_data_structures/src/tagged_ptr.rs @@ -1,283 +1,33 @@ -//! This module implements tagged pointers. -//! -//! In order to utilize the pointer packing, you must have two types: a pointer, -//! and a tag. -//! -//! The pointer must implement the [`Pointer`] trait, with the primary -//! requirement being convertible to and from a raw pointer. Note that the -//! pointer must be dereferenceable, so raw pointers generally cannot implement -//! the [`Pointer`] trait. This implies that the pointer must also be non-null. -//! -//! Many common pointer types already implement the [`Pointer`] trait. -//! -//! The tag must implement the [`Tag`] trait. -//! -//! We assert that the tag and the [`Pointer`] types are compatible at compile -//! time. - -use std::ops::Deref; -use std::ptr::NonNull; -use std::rc::Rc; -use std::sync::Arc; - -use crate::aligned::Aligned; - -mod copy; -mod drop; -mod impl_tag; - -pub use copy::CopyTaggedPtr; -pub use drop::TaggedPtr; - -/// This describes the pointer type encapsulated by [`TaggedPtr`] and -/// [`CopyTaggedPtr`]. -/// -/// # Safety -/// -/// The pointer returned from [`into_ptr`] must be a [valid], pointer to -/// [`::Target`]. -/// -/// Note that if `Self` implements [`DerefMut`] the pointer returned from -/// [`into_ptr`] must be valid for writes (and thus calling [`NonNull::as_mut`] -/// on it must be safe). -/// -/// The [`BITS`] constant must be correct. [`BITS`] least-significant bits, -/// must be zero on all pointers returned from [`into_ptr`]. -/// -/// For example, if the alignment of [`Self::Target`] is 2, then `BITS` should be 1. -/// -/// [`BITS`]: Pointer::BITS -/// [`into_ptr`]: Pointer::into_ptr -/// [valid]: std::ptr#safety -/// [`::Target`]: Deref::Target -/// [`Self::Target`]: Deref::Target -/// [`DerefMut`]: std::ops::DerefMut -pub unsafe trait Pointer: Deref { - /// Number of unused (always zero) **least-significant bits** in this - /// pointer, usually related to the pointees alignment. - /// - /// For example if [`BITS`] = `2`, then given `ptr = Self::into_ptr(..)`, - /// `ptr.addr() & 0b11 == 0` must be true. - /// - /// Most likely the value you want to use here is the following, unless - /// your [`Self::Target`] type is unsized (e.g., `ty::List` in rustc) - /// or your pointer is over/under aligned, in which case you'll need to - /// manually figure out what the right type to pass to [`bits_for`] is, or - /// what the value to set here. - /// - /// ```rust - /// # use std::ops::Deref; - /// # use rustc_data_structures::tagged_ptr::bits_for; - /// # struct T; - /// # impl Deref for T { type Target = u8; fn deref(&self) -> &u8 { &0 } } - /// # impl T { - /// const BITS: u32 = bits_for::<::Target>(); - /// # } - /// ``` - /// - /// [`BITS`]: Pointer::BITS - /// [`Self::Target`]: Deref::Target - const BITS: u32; - - /// Turns this pointer into a raw, non-null pointer. - /// - /// The inverse of this function is [`from_ptr`]. - /// - /// This function guarantees that the least-significant [`Self::BITS`] bits - /// are zero. - /// - /// [`from_ptr`]: Pointer::from_ptr - /// [`Self::BITS`]: Pointer::BITS - fn into_ptr(self) -> NonNull; - - /// Re-creates the original pointer, from a raw pointer returned by [`into_ptr`]. - /// - /// # Safety - /// - /// The passed `ptr` must be returned from [`into_ptr`]. - /// - /// This acts as [`ptr::read::()`] semantically, it should not be called more than - /// once on non-[`Copy`] `Pointer`s. - /// - /// [`into_ptr`]: Pointer::into_ptr - /// [`ptr::read::()`]: std::ptr::read - unsafe fn from_ptr(ptr: NonNull) -> Self; -} - -/// This describes tags that the [`TaggedPtr`] struct can hold. -/// -/// # Safety -/// -/// The [`BITS`] constant must be correct. -/// -/// No more than [`BITS`] least-significant bits may be set in the returned usize. -/// -/// [`BITS`]: Tag::BITS -pub unsafe trait Tag: Copy { - /// Number of least-significant bits in the return value of [`into_usize`] - /// which may be non-zero. In other words this is the bit width of the - /// value. - /// - /// [`into_usize`]: Tag::into_usize - const BITS: u32; - - /// Turns this tag into an integer. - /// - /// The inverse of this function is [`from_usize`]. - /// - /// This function guarantees that only the least-significant [`Self::BITS`] - /// bits can be non-zero. - /// - /// [`from_usize`]: Tag::from_usize - /// [`Self::BITS`]: Tag::BITS - fn into_usize(self) -> usize; - - /// Re-creates the tag from the integer returned by [`into_usize`]. - /// - /// # Safety - /// - /// The passed `tag` must be returned from [`into_usize`]. - /// - /// [`into_usize`]: Tag::into_usize - unsafe fn from_usize(tag: usize) -> Self; -} - -/// Returns the number of bits available for use for tags in a pointer to `T` -/// (this is based on `T`'s alignment). -pub const fn bits_for() -> u32 { - crate::aligned::align_of::().as_nonzero().trailing_zeros() -} - -/// Returns the correct [`Tag::BITS`] constant for a set of tag values. -pub const fn bits_for_tags(mut tags: &[usize]) -> u32 { - let mut bits = 0; - - while let &[tag, ref rest @ ..] = tags { - tags = rest; - - // bits required to represent `tag`, - // position of the most significant 1 - let b = usize::BITS - tag.leading_zeros(); - if b > bits { - bits = b; - } - } - - bits -} - -unsafe impl Pointer for Box { - const BITS: u32 = bits_for::(); - - #[inline] - fn into_ptr(self) -> NonNull { - // Safety: pointers from `Box::into_raw` are valid & non-null - unsafe { NonNull::new_unchecked(Box::into_raw(self)) } - } - - #[inline] - unsafe fn from_ptr(ptr: NonNull) -> Self { - // Safety: `ptr` comes from `into_ptr` which calls `Box::into_raw` - unsafe { Box::from_raw(ptr.as_ptr()) } - } -} - -unsafe impl Pointer for Rc { - const BITS: u32 = bits_for::(); - - #[inline] - fn into_ptr(self) -> NonNull { - // Safety: pointers from `Rc::into_raw` are valid & non-null - unsafe { NonNull::new_unchecked(Rc::into_raw(self).cast_mut()) } - } - - #[inline] - unsafe fn from_ptr(ptr: NonNull) -> Self { - // Safety: `ptr` comes from `into_ptr` which calls `Rc::into_raw` - unsafe { Rc::from_raw(ptr.as_ptr()) } - } -} - -unsafe impl Pointer for Arc { - const BITS: u32 = bits_for::(); - - #[inline] - fn into_ptr(self) -> NonNull { - // Safety: pointers from `Arc::into_raw` are valid & non-null - unsafe { NonNull::new_unchecked(Arc::into_raw(self).cast_mut()) } - } - - #[inline] - unsafe fn from_ptr(ptr: NonNull) -> Self { - // Safety: `ptr` comes from `into_ptr` which calls `Arc::into_raw` - unsafe { Arc::from_raw(ptr.as_ptr()) } - } -} - -unsafe impl<'a, T: 'a + ?Sized + Aligned> Pointer for &'a T { - const BITS: u32 = bits_for::(); - - #[inline] - fn into_ptr(self) -> NonNull { - NonNull::from(self) - } - - #[inline] - unsafe fn from_ptr(ptr: NonNull) -> Self { - // Safety: - // `ptr` comes from `into_ptr` which gets the pointer from a reference - unsafe { ptr.as_ref() } - } -} - -unsafe impl<'a, T: 'a + ?Sized + Aligned> Pointer for &'a mut T { - const BITS: u32 = bits_for::(); - - #[inline] - fn into_ptr(self) -> NonNull { - NonNull::from(self) - } - - #[inline] - unsafe fn from_ptr(mut ptr: NonNull) -> Self { - // Safety: - // `ptr` comes from `into_ptr` which gets the pointer from a reference - unsafe { ptr.as_mut() } - } -} - -/// A tag type used in [`CopyTaggedPtr`] and [`TaggedPtr`] tests. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -#[cfg(test)] -enum Tag2 { - B00 = 0b00, - B01 = 0b01, - B10 = 0b10, - B11 = 0b11, -} - -#[cfg(test)] -unsafe impl Tag for Tag2 { - const BITS: u32 = 2; - - fn into_usize(self) -> usize { - self as _ - } - - unsafe fn from_usize(tag: usize) -> Self { - match tag { - 0b00 => Tag2::B00, - 0b01 => Tag2::B01, - 0b10 => Tag2::B10, - 0b11 => Tag2::B11, - _ => unreachable!(), - } - } -} - -#[cfg(test)] -impl crate::stable_hasher::HashStable for Tag2 { - fn hash_stable(&self, hcx: &mut HCX, hasher: &mut crate::stable_hasher::StableHasher) { - (*self as u8).hash_stable(hcx, hasher); - } -} +use std::ops::Deref;use std::ptr::NonNull;use std::rc::Rc;use std::sync::Arc;//; +use crate::aligned::Aligned;mod copy;mod drop;mod impl_tag;pub use copy:://({}); +CopyTaggedPtr;pub use drop::TaggedPtr;pub unsafe trait Pointer:Deref{const BITS +:u32;fn into_ptr(self)->NonNull;unsafe fn from_ptr(ptr:NonNull)->Self;}pub unsafe trait Tag:Copy{const BITS:u32;fn into_usize(//; +self)->usize;unsafe fn from_usize(tag:usize)->Self;}pub const fn bits_for()->u32{((((((crate::aligned ::align_of::()))).as_nonzero()))). +trailing_zeros()}pub const fn bits_for_tags(mut tags:&[usize])->u32{({});let mut +bits=0;3;while let&[tag,ref rest@..]=tags{3;tags=rest;3;3;let b=usize::BITS-tag. +leading_zeros();3;if b>bits{;bits=b;;}}bits}unsafe implPointer +for Box{const BITS:u32=bits_for::< Self::Target>();#[inline]fn into_ptr(self) +->NonNull{unsafe{((NonNull::new_unchecked((Box::into_raw(self)))))}}#[inline] +unsafe fn from_ptr(ptr:NonNull)->Self{unsafe{(Box::from_raw(ptr.as_ptr()))}}} +unsafe implPointer for Rc {const BITS:u32=bits_for::();#[inline]fn into_ptr(self )->NonNull{unsafe{NonNull::new_unchecked( +Rc::into_raw(self).cast_mut())}}#[inline]unsafe fn from_ptr(ptr:NonNull)->//; +Self{unsafe{(Rc::from_raw(ptr.as_ptr() ))}}}unsafe implPointer +for Arc{const BITS:u32=bits_for::< Self::Target>();#[inline]fn into_ptr(self) +->NonNull{unsafe{(NonNull::new_unchecked(Arc::into_raw(self).cast_mut()))}}#[ +inline]unsafe fn from_ptr(ptr:NonNull )->Self{unsafe{Arc::from_raw(ptr.as_ptr +())}}}unsafe impl<'a,T:'a+?Sized+Aligned>Pointer for&'a T{const BITS:u32=//({}); +bits_for::();#[inline] fn into_ptr(self)->NonNull{NonNull::from +(self)}#[inline]unsafe fn from_ptr(ptr:NonNull )->Self{unsafe{ptr.as_ref()}}} +unsafe impl<'a,T:'a+?Sized+Aligned>Pointer for&'a mut T{const BITS:u32=bits_for +::();#[inline]fn into_ptr( self)->NonNull{NonNull::from(self)}# +[inline]unsafe fn from_ptr(mut ptr:NonNull )->Self{unsafe{(ptr.as_mut())}}}#[ +derive(Copy,Clone,Debug,PartialEq,Eq)]#[cfg(test)]enum Tag2{B00=(0b00),B01=0b01, +B10=(0b10),B11=(0b11),}#[cfg(test)] unsafe impl Tag for Tag2{const BITS:u32=2;fn +into_usize(self)->usize{(self as _) }unsafe fn from_usize(tag:usize)->Self{match +tag{0b00=>Tag2::B00,0b01=>Tag2::B01,0b10=>Tag2::B10,0b11=>Tag2::B11,_=>//*&*&(); +unreachable!(),}}}#[cfg(test )]implcrate::stable_hasher::HashStablefor +Tag2{fn hash_stable(&self,hcx:&mut HCX,hasher:&mut crate::stable_hasher:://({}); +StableHasher){loop{break;};(*self as u8).hash_stable(hcx,hasher);loop{break;};}} diff --git a/compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs b/compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs index f17a0bf26d747..304c4431bbe14 100644 --- a/compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs +++ b/compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs @@ -1,144 +1,10 @@ -/// Implements [`Tag`] for a given type. -/// -/// You can use `impl_tag` on structs and enums. -/// You need to specify the type and all its possible values, -/// which can only be paths with optional fields. -/// -/// [`Tag`]: crate::tagged_ptr::Tag -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// #![feature(macro_metavar_expr)] -/// use rustc_data_structures::{impl_tag, tagged_ptr::Tag}; -/// -/// #[derive(Copy, Clone, PartialEq, Debug)] -/// enum SomeTag { -/// A, -/// B, -/// X { v: bool }, -/// Y(bool, bool), -/// } -/// -/// impl_tag! { -/// // The type for which the `Tag` will be implemented -/// impl Tag for SomeTag; -/// // You need to specify all possible tag values: -/// SomeTag::A, // 0 -/// SomeTag::B, // 1 -/// // For variants with fields, you need to specify the fields: -/// SomeTag::X { v: true }, // 2 -/// SomeTag::X { v: false }, // 3 -/// // For tuple variants use named syntax: -/// SomeTag::Y { 0: true, 1: true }, // 4 -/// SomeTag::Y { 0: false, 1: true }, // 5 -/// SomeTag::Y { 0: true, 1: false }, // 6 -/// SomeTag::Y { 0: false, 1: false }, // 7 -/// } -/// -/// // Tag values are assigned in order: -/// assert_eq!(SomeTag::A.into_usize(), 0); -/// assert_eq!(SomeTag::X { v: false }.into_usize(), 3); -/// assert_eq!(SomeTag::Y(false, true).into_usize(), 5); -/// -/// assert_eq!(unsafe { SomeTag::from_usize(1) }, SomeTag::B); -/// assert_eq!(unsafe { SomeTag::from_usize(2) }, SomeTag::X { v: true }); -/// assert_eq!(unsafe { SomeTag::from_usize(7) }, SomeTag::Y(false, false)); -/// ``` -/// -/// Structs are supported: -/// -/// ``` -/// #![feature(macro_metavar_expr)] -/// # use rustc_data_structures::impl_tag; -/// #[derive(Copy, Clone)] -/// struct Flags { a: bool, b: bool } -/// -/// impl_tag! { -/// impl Tag for Flags; -/// Flags { a: true, b: true }, -/// Flags { a: false, b: true }, -/// Flags { a: true, b: false }, -/// Flags { a: false, b: false }, -/// } -/// ``` -/// -/// Not specifying all values results in a compile error: -/// -/// ```compile_fail,E0004 -/// #![feature(macro_metavar_expr)] -/// # use rustc_data_structures::impl_tag; -/// #[derive(Copy, Clone)] -/// enum E { -/// A, -/// B, -/// } -/// -/// impl_tag! { -/// impl Tag for E; -/// E::A, -/// } -/// ``` -#[macro_export] -macro_rules! impl_tag { - ( - impl Tag for $Self:ty; - $( - $($path:ident)::* $( { $( $fields:tt )* })?, - )* - ) => { - // Safety: - // `bits_for_tags` is called on the same `${index()}`-es as - // `into_usize` returns, thus `BITS` constant is correct. - unsafe impl $crate::tagged_ptr::Tag for $Self { - const BITS: u32 = $crate::tagged_ptr::bits_for_tags(&[ - $( - ${index()}, - $( ${ignore($path)} )* - )* - ]); - - #[inline] - fn into_usize(self) -> usize { - // This forbids use of repeating patterns (`Enum::V`&`Enum::V`, etc) - // (or at least it should, see ) - #[forbid(unreachable_patterns)] - match self { - // `match` is doing heavy lifting here, by requiring exhaustiveness - $( - $($path)::* $( { $( $fields )* } )? => ${index()}, - )* - } - } - - #[inline] - unsafe fn from_usize(tag: usize) -> Self { - match tag { - $( - ${index()} => $($path)::* $( { $( $fields )* } )?, - )* - - // Safety: - // `into_usize` only returns `${index()}` of the same - // repetition as we are filtering above, thus if this is - // reached, the safety contract of this function was - // already breached. - _ => unsafe { - debug_assert!( - false, - "invalid tag: {tag}\ +#[macro_export]macro_rules!impl_tag{(impl Tag for$Self :ty;$($($path:ident)::*$( +{$($fields:tt)*})?,)*)=> {unsafe impl$crate::tagged_ptr::Tag for$Self{const BITS +:u32=$crate::tagged_ptr::bits_for_tags(&[$(${index() },$(${ignore($path)})*)*]); +#[inline]fn into_usize(self)->usize {#[forbid(unreachable_patterns)]match self{$ +($($path)::*$({$($fields)*})? =>${index()},)*}}#[inline]unsafe fn from_usize(//; +tag:usize)->Self{match tag{$(${index()}=>$($path)::*$({$($fields)*})?,)*_=>//(); +unsafe{debug_assert!(false,//loop{break};loop{break;};loop{break;};loop{break;}; +"invalid tag: {tag}\ (this is a bug in the caller of `from_usize`)" - ); - std::hint::unreachable_unchecked() - }, - } - } - - } - }; -} - -#[cfg(test)] -mod tests; +);std::hint::unreachable_unchecked()},}}}};}#[cfg(test)]mod tests;//loop{break}; diff --git a/compiler/rustc_data_structures/src/tagged_ptr/impl_tag/tests.rs b/compiler/rustc_data_structures/src/tagged_ptr/impl_tag/tests.rs index 62c926153e1e9..6fbea8673455d 100644 --- a/compiler/rustc_data_structures/src/tagged_ptr/impl_tag/tests.rs +++ b/compiler/rustc_data_structures/src/tagged_ptr/impl_tag/tests.rs @@ -1,34 +1,8 @@ -#[test] -fn bits_constant() { - use crate::tagged_ptr::Tag; - - #[derive(Copy, Clone)] - struct Unit; - impl_tag! { impl Tag for Unit; Unit, } - assert_eq!(Unit::BITS, 0); - - #[derive(Copy, Clone)] - enum Enum3 { - A, - B, - C, - } - impl_tag! { impl Tag for Enum3; Enum3::A, Enum3::B, Enum3::C, } - assert_eq!(Enum3::BITS, 2); - - #[derive(Copy, Clone)] - struct Eight(bool, bool, bool); - impl_tag! { - impl Tag for Eight; - Eight { 0: true, 1: true, 2: true }, - Eight { 0: true, 1: true, 2: false }, - Eight { 0: true, 1: false, 2: true }, - Eight { 0: true, 1: false, 2: false }, - Eight { 0: false, 1: true, 2: true }, - Eight { 0: false, 1: true, 2: false }, - Eight { 0: false, 1: false, 2: true }, - Eight { 0: false, 1: false, 2: false }, - } - - assert_eq!(Eight::BITS, 3); -} +#[test]fn bits_constant(){3;use crate::tagged_ptr::Tag;3;3;#[derive(Copy,Clone)] +struct Unit;;impl_tag!{impl Tag for Unit;Unit,}assert_eq!(Unit::BITS,0);#[derive +(Copy,Clone)]enum Enum3{A,B,C,}3;impl_tag!{impl Tag for Enum3;Enum3::A,Enum3::B, +Enum3::C,};assert_eq!(Enum3::BITS,2);#[derive(Copy,Clone)]struct Eight(bool,bool +,bool);;impl_tag!{impl Tag for Eight;Eight{0:true,1:true,2:true},Eight{0:true,1: +true,2:false},Eight{0:true,1:false,2: true},Eight{0:true,1:false,2:false},Eight{ +0:false,1:true,2:true},Eight{0:false,1:true,2:false},Eight{0:false,1:false,2://; +true},Eight{0:false,1:false,2:false},}((),());assert_eq!(Eight::BITS,3);*&*&();} diff --git a/compiler/rustc_data_structures/src/temp_dir.rs b/compiler/rustc_data_structures/src/temp_dir.rs index 621d3011a2aa1..5a583f011b0cb 100644 --- a/compiler/rustc_data_structures/src/temp_dir.rs +++ b/compiler/rustc_data_structures/src/temp_dir.rs @@ -1,34 +1,7 @@ -use std::mem::ManuallyDrop; -use std::path::Path; -use tempfile::TempDir; - -/// This is used to avoid TempDir being dropped on error paths unintentionally. -#[derive(Debug)] -pub struct MaybeTempDir { - dir: ManuallyDrop, - // Whether the TempDir should be deleted on drop. - keep: bool, -} - -impl Drop for MaybeTempDir { - fn drop(&mut self) { - // SAFETY: We are in the destructor, and no further access will - // occur. - let dir = unsafe { ManuallyDrop::take(&mut self.dir) }; - if self.keep { - let _ = dir.into_path(); - } - } -} - -impl AsRef for MaybeTempDir { - fn as_ref(&self) -> &Path { - self.dir.path() - } -} - -impl MaybeTempDir { - pub fn new(dir: TempDir, keep_on_drop: bool) -> MaybeTempDir { - MaybeTempDir { dir: ManuallyDrop::new(dir), keep: keep_on_drop } - } -} +use std::mem::ManuallyDrop;use std::path::Path;use tempfile::TempDir;#[derive(// +Debug)]pub struct MaybeTempDir{dir:ManuallyDrop,keep:bool,}impl Drop//; +for MaybeTempDir{fn drop(&mut self){;let dir=unsafe{ManuallyDrop::take(&mut self +.dir)};;if self.keep{;let _=dir.into_path();}}}impl AsReffor MaybeTempDir{ +fn as_ref(&self)->&Path{(((self.dir.path())))}}impl MaybeTempDir{pub fn new(dir: +TempDir,keep_on_drop:bool)->MaybeTempDir{ MaybeTempDir{dir:ManuallyDrop::new(dir +),keep:keep_on_drop}}}//if let _=(){};if let _=(){};if let _=(){};if let _=(){}; diff --git a/compiler/rustc_data_structures/src/tiny_list.rs b/compiler/rustc_data_structures/src/tiny_list.rs index 11a408f216a14..44595e3dfeee5 100644 --- a/compiler/rustc_data_structures/src/tiny_list.rs +++ b/compiler/rustc_data_structures/src/tiny_list.rs @@ -1,80 +1,14 @@ -//! A singly-linked list. -//! -//! Using this data structure only makes sense under very specific -//! circumstances: -//! -//! - If you have a list that rarely stores more than one element, then this -//! data-structure can store the element without allocating and only uses as -//! much space as an `Option<(T, usize)>`. If T can double as the `Option` -//! discriminant, it will even only be as large as `T, usize`. -//! -//! If you expect to store more than 1 element in the common case, steer clear -//! and use a `Vec`, `Box<[T]>`, or a `SmallVec`. - -#[cfg(test)] -mod tests; - -#[derive(Clone)] -pub struct TinyList { - head: Option>, -} - -impl TinyList { - #[inline] - pub fn new() -> TinyList { - TinyList { head: None } - } - - #[inline] - pub fn new_single(data: T) -> TinyList { - TinyList { head: Some(Element { data, next: None }) } - } - - #[inline] - pub fn insert(&mut self, data: T) { - self.head = Some(Element { data, next: self.head.take().map(Box::new) }); - } - - #[inline] - pub fn remove(&mut self, data: &T) -> bool { - self.head = match &mut self.head { - Some(head) if head.data == *data => head.next.take().map(|x| *x), - Some(head) => return head.remove_next(data), - None => return false, - }; - true - } - - #[inline] - pub fn contains(&self, data: &T) -> bool { - let mut elem = self.head.as_ref(); - while let Some(e) = elem { - if &e.data == data { - return true; - } - elem = e.next.as_deref(); - } - false - } -} - -#[derive(Clone)] -struct Element { - data: T, - next: Option>>, -} - -impl Element { - fn remove_next(mut self: &mut Self, data: &T) -> bool { - loop { - match self.next { - Some(ref mut next) if next.data == *data => { - self.next = next.next.take(); - return true; - } - Some(ref mut next) => self = next, - None => return false, - } - } - } -} +#[cfg(test)]mod tests;#[derive(Clone)]pub struct TinyList{head:Option>,}implTinyList{#[inline]pub fn new()->TinyList{//; +TinyList{head:None}}#[inline]pub fn new_single(data:T)->TinyList{TinyList{//; +head:Some(Element{data,next:None})}}#[inline]pub fn insert(&mut self,data:T){(); +self.head=Some(Element{data,next:self.head.take().map(Box::new)});;}#[inline]pub +fn remove(&mut self,data:&T)->bool{3;self.head=match&mut self.head{Some(head)if +head.data==(*data)=>((head.next.take()).map((|x|(*x)))),Some(head)=>return head. +remove_next(data),None=>return false,};;true}#[inline]pub fn contains(&self,data +:&T)->bool{3;let mut elem=self.head.as_ref();;while let Some(e)=elem{if&e.data== +data{;return true;}elem=e.next.as_deref();}false}}#[derive(Clone)]struct Element +{data:T,next:Option>>,}implElement{fn//*&*&(); +remove_next(mut self:&mut Self,data:&T) ->bool{loop{match self.next{Some(ref mut +next)if next.data==*data=>{3;self.next=next.next.take();;;return true;;}Some(ref +mut next)=>((((((self=next)))))),None=>((((((return ((((((false)))))))))))),}}}} diff --git a/compiler/rustc_data_structures/src/tiny_list/tests.rs b/compiler/rustc_data_structures/src/tiny_list/tests.rs index 4b95e62bef02b..4732e0aad1a87 100644 --- a/compiler/rustc_data_structures/src/tiny_list/tests.rs +++ b/compiler/rustc_data_structures/src/tiny_list/tests.rs @@ -1,155 +1,33 @@ -use super::*; - -extern crate test; -use test::{black_box, Bencher}; - -impl TinyList { - fn len(&self) -> usize { - let (mut elem, mut count) = (self.head.as_ref(), 0); - while let Some(e) = elem { - count += 1; - elem = e.next.as_deref(); - } - count - } -} - -#[test] -fn test_contains_and_insert() { - fn do_insert(i: u32) -> bool { - i % 2 == 0 - } - - let mut list = TinyList::new(); - - for i in 0..10 { - for j in 0..i { - if do_insert(j) { - assert!(list.contains(&j)); - } else { - assert!(!list.contains(&j)); - } - } - - assert!(!list.contains(&i)); - - if do_insert(i) { - list.insert(i); - assert!(list.contains(&i)); - } - } -} - -#[test] -fn test_remove_first() { - let mut list = TinyList::new(); - list.insert(1); - list.insert(2); - list.insert(3); - list.insert(4); - assert_eq!(list.len(), 4); - - assert!(list.remove(&4)); - assert!(!list.contains(&4)); - - assert_eq!(list.len(), 3); - assert!(list.contains(&1)); - assert!(list.contains(&2)); - assert!(list.contains(&3)); -} - -#[test] -fn test_remove_last() { - let mut list = TinyList::new(); - list.insert(1); - list.insert(2); - list.insert(3); - list.insert(4); - assert_eq!(list.len(), 4); - - assert!(list.remove(&1)); - assert!(!list.contains(&1)); - - assert_eq!(list.len(), 3); - assert!(list.contains(&2)); - assert!(list.contains(&3)); - assert!(list.contains(&4)); -} - -#[test] -fn test_remove_middle() { - let mut list = TinyList::new(); - list.insert(1); - list.insert(2); - list.insert(3); - list.insert(4); - assert_eq!(list.len(), 4); - - assert!(list.remove(&2)); - assert!(!list.contains(&2)); - - assert_eq!(list.len(), 3); - assert!(list.contains(&1)); - assert!(list.contains(&3)); - assert!(list.contains(&4)); -} - -#[test] -fn test_remove_single() { - let mut list = TinyList::new(); - list.insert(1); - assert_eq!(list.len(), 1); - - assert!(list.remove(&1)); - assert!(!list.contains(&1)); - - assert_eq!(list.len(), 0); -} - -#[bench] -fn bench_insert_empty(b: &mut Bencher) { - b.iter(|| { - let mut list = black_box(TinyList::new()); - list.insert(1); - list - }) -} - -#[bench] -fn bench_insert_one(b: &mut Bencher) { - b.iter(|| { - let mut list = black_box(TinyList::new_single(0)); - list.insert(1); - list - }) -} - -#[bench] -fn bench_contains_empty(b: &mut Bencher) { - b.iter(|| black_box(TinyList::new()).contains(&1)); -} - -#[bench] -fn bench_contains_unknown(b: &mut Bencher) { - b.iter(|| black_box(TinyList::new_single(0)).contains(&1)); -} - -#[bench] -fn bench_contains_one(b: &mut Bencher) { - b.iter(|| black_box(TinyList::new_single(1)).contains(&1)); -} - -#[bench] -fn bench_remove_empty(b: &mut Bencher) { - b.iter(|| black_box(TinyList::new()).remove(&1)); -} - -#[bench] -fn bench_remove_unknown(b: &mut Bencher) { - b.iter(|| black_box(TinyList::new_single(0)).remove(&1)); -} - -#[bench] -fn bench_remove_one(b: &mut Bencher) { - b.iter(|| black_box(TinyList::new_single(1)).remove(&1)); -} +use super::*;extern crate test;use test ::{black_box,Bencher};implTinyList +{fn len(&self)->usize{;let(mut elem,mut count)=(self.head.as_ref(),0);;while let +Some(e)=elem{({});count+=1;({});{;};elem=e.next.as_deref();{;};}count}}#[test]fn +test_contains_and_insert(){();fn do_insert(i:u32)->bool{i%2==0}3;3;let mut list= +TinyList::new();();for i in 0..10{for j in 0..i{if do_insert(j){();assert!(list. +contains(&j));;}else{;assert!(!list.contains(&j));}}assert!(!list.contains(&i)); +if do_insert(i){();list.insert(i);();3;assert!(list.contains(&i));3;}}}#[test]fn +test_remove_first(){;let mut list=TinyList::new();list.insert(1);list.insert(2); +list.insert(3);;list.insert(4);assert_eq!(list.len(),4);assert!(list.remove(&4)) +;;assert!(!list.contains(&4));assert_eq!(list.len(),3);assert!(list.contains(&1) +);();();assert!(list.contains(&2));();();assert!(list.contains(&3));3;}#[test]fn +test_remove_last(){;let mut list=TinyList::new();;list.insert(1);list.insert(2); +list.insert(3);;list.insert(4);assert_eq!(list.len(),4);assert!(list.remove(&1)) +;;assert!(!list.contains(&1));assert_eq!(list.len(),3);assert!(list.contains(&2) +);();();assert!(list.contains(&3));();();assert!(list.contains(&4));3;}#[test]fn +test_remove_middle(){;let mut list=TinyList::new();list.insert(1);list.insert(2) +;;list.insert(3);list.insert(4);assert_eq!(list.len(),4);assert!(list.remove(&2) +);;assert!(!list.contains(&2));assert_eq!(list.len(),3);assert!(list.contains(&1 +));();();assert!(list.contains(&3));();3;assert!(list.contains(&4));3;}#[test]fn +test_remove_single(){;let mut list=TinyList::new();;;list.insert(1);;assert_eq!( +list.len(),1);;;assert!(list.remove(&1));assert!(!list.contains(&1));assert_eq!( +list.len(),0);;}#[bench]fn bench_insert_empty(b:&mut Bencher){b.iter(||{;let mut +list=black_box(TinyList::new());{();};({});list.insert(1);({});list})}#[bench]fn +bench_insert_one(b:&mut Bencher){b.iter(||{{;};let mut list=black_box(TinyList:: +new_single(0));3;3;list.insert(1);;list})}#[bench]fn bench_contains_empty(b:&mut +Bencher){({});b.iter(||black_box(TinyList::new()).contains(&1));({});}#[bench]fn +bench_contains_unknown(b:&mut Bencher){;b.iter(||black_box(TinyList::new_single( +0)).contains(&1));();}#[bench]fn bench_contains_one(b:&mut Bencher){();b.iter(|| +black_box(TinyList::new_single(1)).contains(&1));;}#[bench]fn bench_remove_empty +(b:&mut Bencher){3;b.iter(||black_box(TinyList::new()).remove(&1));3;}#[bench]fn +bench_remove_unknown(b:&mut Bencher){;b.iter(||black_box(TinyList::new_single(0) +).remove(&1));;}#[bench]fn bench_remove_one(b:&mut Bencher){;b.iter(||black_box( +TinyList::new_single(1)).remove(&1));if true{};let _=||();if true{};let _=||();} diff --git a/compiler/rustc_data_structures/src/transitive_relation.rs b/compiler/rustc_data_structures/src/transitive_relation.rs index cd391fe357a6f..6e2f529b163bd 100644 --- a/compiler/rustc_data_structures/src/transitive_relation.rs +++ b/compiler/rustc_data_structures/src/transitive_relation.rs @@ -1,403 +1,61 @@ -use crate::frozen::Frozen; -use crate::fx::{FxHashSet, FxIndexSet}; -use rustc_index::bit_set::BitMatrix; -use std::fmt::Debug; -use std::hash::Hash; -use std::mem; -use std::ops::Deref; - -#[cfg(test)] -mod tests; - -#[derive(Clone, Debug)] -pub struct TransitiveRelationBuilder { - // List of elements. This is used to map from a T to a usize. - elements: FxIndexSet, - - // List of base edges in the graph. Require to compute transitive - // closure. - edges: FxHashSet, -} - -#[derive(Debug)] -pub struct TransitiveRelation { - // Frozen transitive relation elements and edges. - builder: Frozen>, - - // Cached transitive closure derived from the edges. - closure: Frozen>, -} - -impl Deref for TransitiveRelation { - type Target = Frozen>; - - fn deref(&self) -> &Self::Target { - &self.builder - } -} - -impl Clone for TransitiveRelation { - fn clone(&self) -> Self { - TransitiveRelation { - builder: Frozen::freeze(self.builder.deref().clone()), - closure: Frozen::freeze(self.closure.deref().clone()), - } - } -} - -// HACK(eddyb) manual impl avoids `Default` bound on `T`. -impl Default for TransitiveRelationBuilder { - fn default() -> Self { - TransitiveRelationBuilder { elements: Default::default(), edges: Default::default() } - } -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Debug, Hash)] -struct Index(usize); - -#[derive(Clone, PartialEq, Eq, Debug, Hash)] -struct Edge { - source: Index, - target: Index, -} - -impl TransitiveRelationBuilder { - pub fn is_empty(&self) -> bool { - self.edges.is_empty() - } - - pub fn elements(&self) -> impl Iterator { - self.elements.iter() - } - - fn index(&self, a: T) -> Option { - self.elements.get_index_of(&a).map(Index) - } - - fn add_index(&mut self, a: T) -> Index { - let (index, _added) = self.elements.insert_full(a); - Index(index) - } - - /// Applies the (partial) function to each edge and returns a new - /// relation builder. If `f` returns `None` for any end-point, - /// returns `None`. - pub fn maybe_map(&self, mut f: F) -> Option> - where - F: FnMut(T) -> Option, - U: Clone + Debug + Eq + Hash + Copy, - { - let mut result = TransitiveRelationBuilder::default(); - for edge in &self.edges { - result.add(f(self.elements[edge.source.0])?, f(self.elements[edge.target.0])?); - } - Some(result) - } - - /// Indicate that `a < b` (where `<` is this relation) - pub fn add(&mut self, a: T, b: T) { - let a = self.add_index(a); - let b = self.add_index(b); - let edge = Edge { source: a, target: b }; - self.edges.insert(edge); - } - - /// Compute the transitive closure derived from the edges, and converted to - /// the final result. After this, all elements will be immutable to maintain - /// the correctness of the result. - pub fn freeze(self) -> TransitiveRelation { - let mut matrix = BitMatrix::new(self.elements.len(), self.elements.len()); - let mut changed = true; - while changed { - changed = false; - for edge in &self.edges { - // add an edge from S -> T - changed |= matrix.insert(edge.source.0, edge.target.0); - - // add all outgoing edges from T into S - changed |= matrix.union_rows(edge.target.0, edge.source.0); - } - } - TransitiveRelation { builder: Frozen::freeze(self), closure: Frozen::freeze(matrix) } - } -} - -impl TransitiveRelation { - /// Applies the (partial) function to each edge and returns a new - /// relation including transitive closures. - pub fn maybe_map(&self, f: F) -> Option> - where - F: FnMut(T) -> Option, - U: Clone + Debug + Eq + Hash + Copy, - { - Some(self.builder.maybe_map(f)?.freeze()) - } - - /// Checks whether `a < target` (transitively) - pub fn contains(&self, a: T, b: T) -> bool { - match (self.index(a), self.index(b)) { - (Some(a), Some(b)) => self.with_closure(|closure| closure.contains(a.0, b.0)), - (None, _) | (_, None) => false, - } - } - - /// Thinking of `x R y` as an edge `x -> y` in a graph, this - /// returns all things reachable from `a`. - /// - /// Really this probably ought to be `impl Iterator`, but - /// I'm too lazy to make that work, and -- given the caching - /// strategy -- it'd be a touch tricky anyhow. - pub fn reachable_from(&self, a: T) -> Vec { - match self.index(a) { - Some(a) => { - self.with_closure(|closure| closure.iter(a.0).map(|i| self.elements[i]).collect()) - } - None => vec![], - } - } - - /// Picks what I am referring to as the "postdominating" - /// upper-bound for `a` and `b`. This is usually the least upper - /// bound, but in cases where there is no single least upper - /// bound, it is the "mutual immediate postdominator", if you - /// imagine a graph where `a < b` means `a -> b`. - /// - /// This function is needed because region inference currently - /// requires that we produce a single "UB", and there is no best - /// choice for the LUB. Rather than pick arbitrarily, I pick a - /// less good, but predictable choice. This should help ensure - /// that region inference yields predictable results (though it - /// itself is not fully sufficient). - /// - /// Examples are probably clearer than any prose I could write - /// (there are corresponding tests below, btw). In each case, - /// the query is `postdom_upper_bound(a, b)`: - /// - /// ```text - /// // Returns Some(x), which is also LUB. - /// a -> a1 -> x - /// ^ - /// | - /// b -> b1 ---+ - /// - /// // Returns `Some(x)`, which is not LUB (there is none) - /// // diagonal edges run left-to-right. - /// a -> a1 -> x - /// \/ ^ - /// /\ | - /// b -> b1 ---+ - /// - /// // Returns `None`. - /// a -> a1 - /// b -> b1 - /// ``` - pub fn postdom_upper_bound(&self, a: T, b: T) -> Option { - let mubs = self.minimal_upper_bounds(a, b); - self.mutual_immediate_postdominator(mubs) - } - - /// Viewing the relation as a graph, computes the "mutual - /// immediate postdominator" of a set of points (if one - /// exists). See `postdom_upper_bound` for details. - pub fn mutual_immediate_postdominator(&self, mut mubs: Vec) -> Option { - loop { - match mubs.len() { - 0 => return None, - 1 => return Some(mubs[0]), - _ => { - let m = mubs.pop().unwrap(); - let n = mubs.pop().unwrap(); - mubs.extend(self.minimal_upper_bounds(n, m)); - } - } - } - } - - /// Returns the set of bounds `X` such that: - /// - /// - `a < X` and `b < X` - /// - there is no `Y != X` such that `a < Y` and `Y < X` - /// - except for the case where `X < a` (i.e., a strongly connected - /// component in the graph). In that case, the smallest - /// representative of the SCC is returned (as determined by the - /// internal indices). - /// - /// Note that this set can, in principle, have any size. - pub fn minimal_upper_bounds(&self, a: T, b: T) -> Vec { - let (Some(mut a), Some(mut b)) = (self.index(a), self.index(b)) else { - return vec![]; - }; - - // in some cases, there are some arbitrary choices to be made; - // it doesn't really matter what we pick, as long as we pick - // the same thing consistently when queried, so ensure that - // (a, b) are in a consistent relative order - if a > b { - mem::swap(&mut a, &mut b); - } - - let lub_indices = self.with_closure(|closure| { - // Easy case is when either a < b or b < a: - if closure.contains(a.0, b.0) { - return vec![b.0]; - } - if closure.contains(b.0, a.0) { - return vec![a.0]; - } - - // Otherwise, the tricky part is that there may be some c - // where a < c and b < c. In fact, there may be many such - // values. So here is what we do: - // - // 1. Find the vector `[X | a < X && b < X]` of all values - // `X` where `a < X` and `b < X`. In terms of the - // graph, this means all values reachable from both `a` - // and `b`. Note that this vector is also a set, but we - // use the term vector because the order matters - // to the steps below. - // - This vector contains upper bounds, but they are - // not minimal upper bounds. So you may have e.g. - // `[x, y, tcx, z]` where `x < tcx` and `y < tcx` and - // `z < x` and `z < y`: - // - // z --+---> x ----+----> tcx - // | | - // | | - // +---> y ----+ - // - // In this case, we really want to return just `[z]`. - // The following steps below achieve this by gradually - // reducing the list. - // 2. Pare down the vector using `pare_down`. This will - // remove elements from the vector that can be reached - // by an earlier element. - // - In the example above, this would convert `[x, y, - // tcx, z]` to `[x, y, z]`. Note that `x` and `y` are - // still in the vector; this is because while `z < x` - // (and `z < y`) holds, `z` comes after them in the - // vector. - // 3. Reverse the vector and repeat the pare down process. - // - In the example above, we would reverse to - // `[z, y, x]` and then pare down to `[z]`. - // 4. Reverse once more just so that we yield a vector in - // increasing order of index. Not necessary, but why not. - // - // I believe this algorithm yields a minimal set. The - // argument is that, after step 2, we know that no element - // can reach its successors (in the vector, not the graph). - // After step 3, we know that no element can reach any of - // its predecessors (because of step 2) nor successors - // (because we just called `pare_down`) - // - // This same algorithm is used in `parents` below. - - let mut candidates = closure.intersect_rows(a.0, b.0); // (1) - pare_down(&mut candidates, closure); // (2) - candidates.reverse(); // (3a) - pare_down(&mut candidates, closure); // (3b) - candidates - }); - - lub_indices - .into_iter() - .rev() // (4) - .map(|i| self.elements[i]) - .collect() - } - - /// Given an element A, returns the maximal set {B} of elements B - /// such that - /// - /// - A != B - /// - A R B is true - /// - for each i, j: `B[i]` R `B[j]` does not hold - /// - /// The intuition is that this moves "one step up" through a lattice - /// (where the relation is encoding the `<=` relation for the lattice). - /// So e.g., if the relation is `->` and we have - /// - /// ```text - /// a -> b -> d -> f - /// | ^ - /// +--> c -> e ---+ - /// ``` - /// - /// then `parents(a)` returns `[b, c]`. The `postdom_parent` function - /// would further reduce this to just `f`. - pub fn parents(&self, a: T) -> Vec { - let Some(a) = self.index(a) else { - return vec![]; - }; - - // Steal the algorithm for `minimal_upper_bounds` above, but - // with a slight tweak. In the case where `a R a`, we remove - // that from the set of candidates. - let ancestors = self.with_closure(|closure| { - let mut ancestors = closure.intersect_rows(a.0, a.0); - - // Remove anything that can reach `a`. If this is a - // reflexive relation, this will include `a` itself. - ancestors.retain(|&e| !closure.contains(e, a.0)); - - pare_down(&mut ancestors, closure); // (2) - ancestors.reverse(); // (3a) - pare_down(&mut ancestors, closure); // (3b) - ancestors - }); - - ancestors - .into_iter() - .rev() // (4) - .map(|i| self.elements[i]) - .collect() - } - - fn with_closure(&self, op: OP) -> R - where - OP: FnOnce(&BitMatrix) -> R, - { - op(&self.closure) - } - - /// Lists all the base edges in the graph: the initial _non-transitive_ set of element - /// relations, which will be later used as the basis for the transitive closure computation. - pub fn base_edges(&self) -> impl Iterator + '_ { - self.edges - .iter() - .map(move |edge| (self.elements[edge.source.0], self.elements[edge.target.0])) - } -} - -/// Pare down is used as a step in the LUB computation. It edits the -/// candidates array in place by removing any element j for which -/// there exists an earlier element i j. That is, -/// after you run `pare_down`, you know that for all elements that -/// remain in candidates, they cannot reach any of the elements that -/// come after them. -/// -/// Examples follow. Assume that a -> b -> c and x -> y -> z. -/// -/// - Input: `[a, b, x]`. Output: `[a, x]`. -/// - Input: `[b, a, x]`. Output: `[b, a, x]`. -/// - Input: `[a, x, b, y]`. Output: `[a, x]`. -fn pare_down(candidates: &mut Vec, closure: &BitMatrix) { - let mut i = 0; - while let Some(&candidate_i) = candidates.get(i) { - i += 1; - - let mut j = i; - let mut dead = 0; - while let Some(&candidate_j) = candidates.get(j) { - if closure.contains(candidate_i, candidate_j) { - // If `i` can reach `j`, then we can remove `j`. So just - // mark it as dead and move on; subsequent indices will be - // shifted into its place. - dead += 1; - } else { - candidates[j - dead] = candidate_j; - } - j += 1; - } - candidates.truncate(j - dead); - } -} +use crate::frozen::Frozen;use crate ::fx::{FxHashSet,FxIndexSet};use rustc_index +::bit_set::BitMatrix;use std::fmt::Debug;use std::hash::Hash;use std::mem;use//; +std::ops::Deref;#[cfg(test)]mod tests;#[derive(Clone,Debug)]pub struct//((),()); +TransitiveRelationBuilder{elements:FxIndexSet,edges:FxHashSet,}#[//; +derive(Debug)]pub struct TransitiveRelation{builder:Frozen>,closure:Frozen>,}impl//; +Deref for TransitiveRelation{type Target=Frozen>;fn deref(&self)->&Self::Target{(((( &self.builder))))}}implClone for +TransitiveRelation{fn clone(&self )->Self{TransitiveRelation{builder:Frozen:: +freeze(self.builder.deref().clone() ),closure:Frozen::freeze(self.closure.deref( +).clone()),}}}implDefault for TransitiveRelationBuilder{fn//{();}; +default()->Self{TransitiveRelationBuilder{elements:((Default::default())),edges: +Default::default()}}}#[derive(Copy,Clone,PartialEq,Eq,PartialOrd,Debug,Hash)]//; +struct Index(usize);#[derive(Clone,PartialEq ,Eq,Debug,Hash)]struct Edge{source: +Index,target:Index,}implTransitiveRelationBuilder{pub fn//(); +is_empty(&self)->bool{((((self.edges.is_empty()))))}pub fn elements(&self)->impl +Iterator{self.elements.iter()}fn index(&self,a:T)->Option{self. +elements.get_index_of(&a).map(Index)}fn add_index(&mut self,a:T)->Index{{;};let( +index,_added)=self.elements.insert_full(a);;Index(index)}pub fn maybe_map(& +self,mut f:F)->Option>where F:FnMut(T)->Option, +U:Clone+Debug+Eq+Hash+Copy,{;let mut result=TransitiveRelationBuilder::default() +;();for edge in&self.edges{3;result.add(f(self.elements[edge.source.0])?,f(self. +elements[edge.target.0])?);3;}Some(result)}pub fn add(&mut self,a:T,b:T){;let a= +self.add_index(a);;let b=self.add_index(b);let edge=Edge{source:a,target:b};self +.edges.insert(edge);;}pub fn freeze(self)->TransitiveRelation{let mut matrix= +BitMatrix::new(self.elements.len(),self.elements.len());;;let mut changed=true;; +while changed{;changed=false;for edge in&self.edges{changed|=matrix.insert(edge. +source.0,edge.target.0);;changed|=matrix.union_rows(edge.target.0,edge.source.0) +;{();};}}TransitiveRelation{builder:Frozen::freeze(self),closure:Frozen::freeze( +matrix)}}}impl TransitiveRelation{pub fn maybe_map(&self +,f:F)->Option>where F:FnMut(T)->Option,U:Clone+Debug+// +Eq+Hash+Copy,{Some(self.builder.maybe_map(f) ?.freeze())}pub fn contains(&self,a +:T,b:T)->bool{match(((self.index(a)),(self .index(b)))){(Some(a),Some(b))=>self. +with_closure(|closure|closure.contains(a.0,b.0) ),(None,_)|(_,None)=>false,}}pub +fn reachable_from(&self,a:T)->Vec{match ((((self.index(a))))){Some(a)=>{self. +with_closure((|closure|(closure.iter(a.0).map(|i|self.elements[i]).collect())))} +None=>vec![],}}pub fn postdom_upper_bound(&self,a:T,b:T)->Option{();let mubs= +self.minimal_upper_bounds(a,b);;self.mutual_immediate_postdominator(mubs)}pub fn +mutual_immediate_postdominator(&self,mut mubs:Vec)->Option{loop{match //3; +mubs.len(){0=>return None,1=>return Some(mubs[0]),_=>{;let m=mubs.pop().unwrap() +;;;let n=mubs.pop().unwrap();mubs.extend(self.minimal_upper_bounds(n,m));}}}}pub +fn minimal_upper_bounds(&self,a:T,b:T)->Vec{();let(Some(mut a),Some(mut b))=( +self.index(a),self.index(b))else{;return vec![];};if a>b{mem::swap(&mut a,&mut b +);3;};let lub_indices=self.with_closure(|closure|{if closure.contains(a.0,b.0){; +return vec![b.0];3;}if closure.contains(b.0,a.0){3;return vec![a.0];3;}3;let mut +candidates=closure.intersect_rows(a.0,b.0);;;pare_down(&mut candidates,closure); +candidates.reverse();();();pare_down(&mut candidates,closure);();candidates});3; +lub_indices.into_iter().rev().map(|i|self .elements[i]).collect()}pub fn parents +(&self,a:T)->Vec{;let Some(a)=self.index(a)else{return vec![];};let ancestors +=self.with_closure(|closure|{;let mut ancestors=closure.intersect_rows(a.0,a.0); +ancestors.retain(|&e|!closure.contains(e,a.0));;pare_down(&mut ancestors,closure +);;;ancestors.reverse();pare_down(&mut ancestors,closure);ancestors});ancestors. +into_iter().rev().map((|i|(self.elements[i]))).collect()}fn with_closure(& +self,op:OP)->R where OP:FnOnce(&BitMatrix)->R,{(op(&self.closure))} +pub fn base_edges(&self)->impl Iterator+'_{(self.edges.iter()).map( +move|edge|(((self.elements[edge.source.0]),(self.elements[edge.target.0]))))}}fn +pare_down(candidates:&mut Vec,closure:&BitMatrix){;let mut i +=0;;while let Some(&candidate_i)=candidates.get(i){i+=1;let mut j=i;let mut dead +=0;if true{};while let Some(&candidate_j)=candidates.get(j){if closure.contains( +candidate_i,candidate_j){;dead+=1;;}else{;candidates[j-dead]=candidate_j;}j+=1;} +candidates.truncate(j-dead);loop{break};loop{break;};loop{break};loop{break;};}} diff --git a/compiler/rustc_data_structures/src/transitive_relation/tests.rs b/compiler/rustc_data_structures/src/transitive_relation/tests.rs index e756c546e41ba..6f2515ccb4700 100644 --- a/compiler/rustc_data_structures/src/transitive_relation/tests.rs +++ b/compiler/rustc_data_structures/src/transitive_relation/tests.rs @@ -1,378 +1,84 @@ -use super::*; - -impl TransitiveRelation { - /// A "best" parent in some sense. See `parents` and - /// `postdom_upper_bound` for more details. - fn postdom_parent(&self, a: T) -> Option { - self.mutual_immediate_postdominator(self.parents(a)) - } -} - -#[test] -fn test_one_step() { - let mut relation = TransitiveRelationBuilder::default(); - relation.add("a", "b"); - relation.add("a", "c"); - let relation = relation.freeze(); - assert!(relation.contains("a", "c")); - assert!(relation.contains("a", "b")); - assert!(!relation.contains("b", "a")); - assert!(!relation.contains("a", "d")); -} - -#[test] -fn test_many_steps() { - let mut relation = TransitiveRelationBuilder::default(); - relation.add("a", "b"); - relation.add("a", "c"); - relation.add("a", "f"); - - relation.add("b", "c"); - relation.add("b", "d"); - relation.add("b", "e"); - - relation.add("e", "g"); - let relation = relation.freeze(); - - assert!(relation.contains("a", "b")); - assert!(relation.contains("a", "c")); - assert!(relation.contains("a", "d")); - assert!(relation.contains("a", "e")); - assert!(relation.contains("a", "f")); - assert!(relation.contains("a", "g")); - - assert!(relation.contains("b", "g")); - - assert!(!relation.contains("a", "x")); - assert!(!relation.contains("b", "f")); -} - -#[test] -fn mubs_triangle() { - // a -> tcx - // ^ - // | - // b - let mut relation = TransitiveRelationBuilder::default(); - relation.add("a", "tcx"); - relation.add("b", "tcx"); - let relation = relation.freeze(); - assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["tcx"]); - assert_eq!(relation.parents("a"), vec!["tcx"]); - assert_eq!(relation.parents("b"), vec!["tcx"]); -} - -#[test] -fn mubs_best_choice1() { - // 0 -> 1 <- 3 - // | ^ | - // | | | - // +--> 2 <--+ - // - // mubs(0,3) = [1] - - // This tests a particular state in the algorithm, in which we - // need the second pare down call to get the right result (after - // intersection, we have [1, 2], but 2 -> 1). - - let mut relation = TransitiveRelationBuilder::default(); - relation.add("0", "1"); - relation.add("0", "2"); - - relation.add("2", "1"); - - relation.add("3", "1"); - relation.add("3", "2"); - let relation = relation.freeze(); - - assert_eq!(relation.minimal_upper_bounds("0", "3"), vec!["2"]); - assert_eq!(relation.parents("0"), vec!["2"]); - assert_eq!(relation.parents("2"), vec!["1"]); - assert!(relation.parents("1").is_empty()); -} - -#[test] -fn mubs_best_choice2() { - // 0 -> 1 <- 3 - // | | | - // | v | - // +--> 2 <--+ - // - // mubs(0,3) = [2] - - // Like the preceding test, but in this case intersection is [2, - // 1], and hence we rely on the first pare down call. - - let mut relation = TransitiveRelationBuilder::default(); - relation.add("0", "1"); - relation.add("0", "2"); - - relation.add("1", "2"); - - relation.add("3", "1"); - relation.add("3", "2"); - let relation = relation.freeze(); - - assert_eq!(relation.minimal_upper_bounds("0", "3"), vec!["1"]); - assert_eq!(relation.parents("0"), vec!["1"]); - assert_eq!(relation.parents("1"), vec!["2"]); - assert!(relation.parents("2").is_empty()); -} - -#[test] -fn mubs_no_best_choice() { - // in this case, the intersection yields [1, 2], and the "pare - // down" calls find nothing to remove. - let mut relation = TransitiveRelationBuilder::default(); - relation.add("0", "1"); - relation.add("0", "2"); - - relation.add("3", "1"); - relation.add("3", "2"); - let relation = relation.freeze(); - - assert_eq!(relation.minimal_upper_bounds("0", "3"), vec!["1", "2"]); - assert_eq!(relation.parents("0"), vec!["1", "2"]); - assert_eq!(relation.parents("3"), vec!["1", "2"]); -} - -#[test] -fn mubs_best_choice_scc() { - // in this case, 1 and 2 form a cycle; we pick arbitrarily (but - // consistently). - - let mut relation = TransitiveRelationBuilder::default(); - relation.add("0", "1"); - relation.add("0", "2"); - - relation.add("1", "2"); - relation.add("2", "1"); - - relation.add("3", "1"); - relation.add("3", "2"); - let relation = relation.freeze(); - - assert_eq!(relation.minimal_upper_bounds("0", "3"), vec!["1"]); - assert_eq!(relation.parents("0"), vec!["1"]); -} - -#[test] -fn pdub_crisscross() { - // diagonal edges run left-to-right - // a -> a1 -> x - // \/ ^ - // /\ | - // b -> b1 ---+ - - let mut relation = TransitiveRelationBuilder::default(); - relation.add("a", "a1"); - relation.add("a", "b1"); - relation.add("b", "a1"); - relation.add("b", "b1"); - relation.add("a1", "x"); - relation.add("b1", "x"); - let relation = relation.freeze(); - - assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["a1", "b1"]); - assert_eq!(relation.postdom_upper_bound("a", "b"), Some("x")); - assert_eq!(relation.postdom_parent("a"), Some("x")); - assert_eq!(relation.postdom_parent("b"), Some("x")); -} - -#[test] -fn pdub_crisscross_more() { - // diagonal edges run left-to-right - // a -> a1 -> a2 -> a3 -> x - // \/ \/ ^ - // /\ /\ | - // b -> b1 -> b2 ---------+ - - let mut relation = TransitiveRelationBuilder::default(); - relation.add("a", "a1"); - relation.add("a", "b1"); - relation.add("b", "a1"); - relation.add("b", "b1"); - - relation.add("a1", "a2"); - relation.add("a1", "b2"); - relation.add("b1", "a2"); - relation.add("b1", "b2"); - - relation.add("a2", "a3"); - - relation.add("a3", "x"); - relation.add("b2", "x"); - let relation = relation.freeze(); - - assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["a1", "b1"]); - assert_eq!(relation.minimal_upper_bounds("a1", "b1"), vec!["a2", "b2"]); - assert_eq!(relation.postdom_upper_bound("a", "b"), Some("x")); - - assert_eq!(relation.postdom_parent("a"), Some("x")); - assert_eq!(relation.postdom_parent("b"), Some("x")); -} - -#[test] -fn pdub_lub() { - // a -> a1 -> x - // ^ - // | - // b -> b1 ---+ - - let mut relation = TransitiveRelationBuilder::default(); - relation.add("a", "a1"); - relation.add("b", "b1"); - relation.add("a1", "x"); - relation.add("b1", "x"); - let relation = relation.freeze(); - - assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["x"]); - assert_eq!(relation.postdom_upper_bound("a", "b"), Some("x")); - - assert_eq!(relation.postdom_parent("a"), Some("a1")); - assert_eq!(relation.postdom_parent("b"), Some("b1")); - assert_eq!(relation.postdom_parent("a1"), Some("x")); - assert_eq!(relation.postdom_parent("b1"), Some("x")); -} - -#[test] -fn mubs_intermediate_node_on_one_side_only() { - // a -> c -> d - // ^ - // | - // b - - // "digraph { a -> c -> d; b -> d; }", - let mut relation = TransitiveRelationBuilder::default(); - relation.add("a", "c"); - relation.add("c", "d"); - relation.add("b", "d"); - let relation = relation.freeze(); - - assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["d"]); -} - -#[test] -fn mubs_scc_1() { - // +-------------+ - // | +----+ | - // | v | | - // a -> c -> d <-+ - // ^ - // | - // b - - // "digraph { a -> c -> d; d -> c; a -> d; b -> d; }", - let mut relation = TransitiveRelationBuilder::default(); - relation.add("a", "c"); - relation.add("c", "d"); - relation.add("d", "c"); - relation.add("a", "d"); - relation.add("b", "d"); - let relation = relation.freeze(); - - assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["c"]); -} - -#[test] -fn mubs_scc_2() { - // +----+ - // v | - // a -> c -> d - // ^ ^ - // | | - // +--- b - - // "digraph { a -> c -> d; d -> c; b -> d; b -> c; }", - let mut relation = TransitiveRelationBuilder::default(); - relation.add("a", "c"); - relation.add("c", "d"); - relation.add("d", "c"); - relation.add("b", "d"); - relation.add("b", "c"); - let relation = relation.freeze(); - - assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["c"]); -} - -#[test] -fn mubs_scc_3() { - // +---------+ - // v | - // a -> c -> d -> e - // ^ ^ - // | | - // b ---+ - - // "digraph { a -> c -> d -> e -> c; b -> d; b -> e; }", - let mut relation = TransitiveRelationBuilder::default(); - relation.add("a", "c"); - relation.add("c", "d"); - relation.add("d", "e"); - relation.add("e", "c"); - relation.add("b", "d"); - relation.add("b", "e"); - let relation = relation.freeze(); - - assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["c"]); -} - -#[test] -fn mubs_scc_4() { - // +---------+ - // v | - // a -> c -> d -> e - // | ^ ^ - // +---------+ | - // | - // b ---+ - - // "digraph { a -> c -> d -> e -> c; a -> d; b -> e; }" - let mut relation = TransitiveRelationBuilder::default(); - relation.add("a", "c"); - relation.add("c", "d"); - relation.add("d", "e"); - relation.add("e", "c"); - relation.add("a", "d"); - relation.add("b", "e"); - let relation = relation.freeze(); - - assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["c"]); -} - -#[test] -fn parent() { - // An example that was misbehaving in the compiler. - // - // 4 -> 1 -> 3 - // \ | / - // \ v / - // 2 -> 0 - // - // plus a bunch of self-loops - // - // Here `->` represents `<=` and `0` is `'static`. - - let pairs = vec![ - (2, /*->*/ 0), - (2, /*->*/ 2), - (0, /*->*/ 0), - (0, /*->*/ 0), - (1, /*->*/ 0), - (1, /*->*/ 1), - (3, /*->*/ 0), - (3, /*->*/ 3), - (4, /*->*/ 0), - (4, /*->*/ 1), - (1, /*->*/ 3), - ]; - - let mut relation = TransitiveRelationBuilder::default(); - for (a, b) in pairs { - relation.add(a, b); - } - let relation = relation.freeze(); - - let p = relation.postdom_parent(3); - assert_eq!(p, Some(0)); -} +use super::*;implTransitiveRelation{fn postdom_parent(&self, +a:T)->Option{self.mutual_immediate_postdominator( self.parents(a))}}#[test]fn +test_one_step(){;let mut relation=TransitiveRelationBuilder::default();;relation +.add("a","b");;;relation.add("a","c");;;let relation=relation.freeze();;assert!( +relation.contains("a","c"));3;3;assert!(relation.contains("a","b"));3;;assert!(! +relation.contains("b","a"));3;3;assert!(!relation.contains("a","d"));;}#[test]fn +test_many_steps(){();let mut relation=TransitiveRelationBuilder::default();();3; +relation.add("a","b");;relation.add("a","c");relation.add("a","f");relation.add( +"b","c");;;relation.add("b","d");relation.add("b","e");relation.add("e","g");let +relation=relation.freeze();;assert!(relation.contains("a","b"));assert!(relation +.contains("a","c"));3;3;assert!(relation.contains("a","d"));3;;assert!(relation. +contains("a","e"));3;3;assert!(relation.contains("a","f"));3;3;assert!(relation. +contains("a","g"));3;3;assert!(relation.contains("b","g"));3;;assert!(!relation. +contains("a","x"));({});({});assert!(!relation.contains("b","f"));{;};}#[test]fn +mubs_triangle(){;let mut relation=TransitiveRelationBuilder::default();relation. +add("a","tcx");;relation.add("b","tcx");let relation=relation.freeze();assert_eq +!(relation.minimal_upper_bounds("a","b"),vec!["tcx"]);();();assert_eq!(relation. +parents("a"),vec!["tcx"]);;assert_eq!(relation.parents("b"),vec!["tcx"]);}#[test +]fn mubs_best_choice1(){;let mut relation=TransitiveRelationBuilder::default();; +relation.add("0","1");;relation.add("0","2");relation.add("2","1");relation.add( +"3","1");3;;relation.add("3","2");;;let relation=relation.freeze();;;assert_eq!( +relation.minimal_upper_bounds("0","3"),vec!["2"]);;;assert_eq!(relation.parents( +"0"),vec!["2"]);;;assert_eq!(relation.parents("2"),vec!["1"]);;assert!(relation. +parents("1").is_empty());{;};}#[test]fn mubs_best_choice2(){();let mut relation= +TransitiveRelationBuilder::default();;relation.add("0","1");relation.add("0","2" +);3;;relation.add("1","2");;;relation.add("3","1");;;relation.add("3","2");;;let +relation=relation.freeze();3;;assert_eq!(relation.minimal_upper_bounds("0","3"), +vec!["1"]);3;;assert_eq!(relation.parents("0"),vec!["1"]);;;assert_eq!(relation. +parents("1"),vec!["2"]);3;;assert!(relation.parents("2").is_empty());;}#[test]fn +mubs_no_best_choice(){3;let mut relation=TransitiveRelationBuilder::default();;; +relation.add("0","1");;relation.add("0","2");relation.add("3","1");relation.add( +"3","2");({});({});let relation=relation.freeze();({});({});assert_eq!(relation. +minimal_upper_bounds("0","3"),vec!["1","2"]);;;assert_eq!(relation.parents("0"), +vec!["1","2"]);();3;assert_eq!(relation.parents("3"),vec!["1","2"]);3;}#[test]fn +mubs_best_choice_scc(){;let mut relation=TransitiveRelationBuilder::default();;; +relation.add("0","1");;relation.add("0","2");relation.add("1","2");relation.add( +"2","1");;;relation.add("3","1");;;relation.add("3","2");;let relation=relation. +freeze();;assert_eq!(relation.minimal_upper_bounds("0","3"),vec!["1"]);assert_eq +!(relation.parents("0"),vec!["1"]);({});}#[test]fn pdub_crisscross(){{;};let mut +relation=TransitiveRelationBuilder::default();;;relation.add("a","a1");relation. +add("a","b1");;;relation.add("b","a1");relation.add("b","b1");relation.add("a1", +"x");;relation.add("b1","x");let relation=relation.freeze();assert_eq!(relation. +minimal_upper_bounds("a","b"),vec!["a1","b1"]);*&*&();{();};assert_eq!(relation. +postdom_upper_bound("a","b"),Some("x"));;assert_eq!(relation.postdom_parent("a") +,Some("x"));();3;assert_eq!(relation.postdom_parent("b"),Some("x"));3;}#[test]fn +pdub_crisscross_more(){;let mut relation=TransitiveRelationBuilder::default();;; +relation.add("a","a1");;;relation.add("a","b1");relation.add("b","a1");relation. +add("b","b1");;relation.add("a1","a2");relation.add("a1","b2");relation.add("b1" +,"a2");;;relation.add("b1","b2");relation.add("a2","a3");relation.add("a3","x"); +relation.add("b2","x");3;3;let relation=relation.freeze();;;assert_eq!(relation. +minimal_upper_bounds("a","b"),vec!["a1","b1"]);*&*&();{();};assert_eq!(relation. +minimal_upper_bounds("a1","b1"),vec!["a2","b2"]);{();};({});assert_eq!(relation. +postdom_upper_bound("a","b"),Some("x"));;assert_eq!(relation.postdom_parent("a") +,Some("x"));();3;assert_eq!(relation.postdom_parent("b"),Some("x"));3;}#[test]fn +pdub_lub(){;let mut relation=TransitiveRelationBuilder::default();;relation.add( +"a","a1");;relation.add("b","b1");relation.add("a1","x");relation.add("b1","x"); +let relation=relation.freeze();;assert_eq!(relation.minimal_upper_bounds("a","b" +),vec!["x"]);3;3;assert_eq!(relation.postdom_upper_bound("a","b"),Some("x"));3;; +assert_eq!(relation.postdom_parent("a"),Some("a1"));{;};{;};assert_eq!(relation. +postdom_parent("b"),Some("b1"));;;assert_eq!(relation.postdom_parent("a1"),Some( +"x"));{;};{;};assert_eq!(relation.postdom_parent("b1"),Some("x"));{;};}#[test]fn +mubs_intermediate_node_on_one_side_only(){if true{};let _=||();let mut relation= +TransitiveRelationBuilder::default();;relation.add("a","c");relation.add("c","d" +);;;relation.add("b","d");;;let relation=relation.freeze();;assert_eq!(relation. +minimal_upper_bounds("a","b"),vec!["d"]);{;};}#[test]fn mubs_scc_1(){{;};let mut +relation=TransitiveRelationBuilder::default();;;relation.add("a","c");;relation. +add("c","d");;relation.add("d","c");relation.add("a","d");relation.add("b","d"); +let relation=relation.freeze();;assert_eq!(relation.minimal_upper_bounds("a","b" +),vec!["c"]);;}#[test]fn mubs_scc_2(){let mut relation=TransitiveRelationBuilder +::default();;;relation.add("a","c");relation.add("c","d");relation.add("d","c"); +relation.add("b","d");;;relation.add("b","c");;;let relation=relation.freeze();; +assert_eq!(relation.minimal_upper_bounds("a","b"),vec!["c"]);let _=();}#[test]fn +mubs_scc_3(){;let mut relation=TransitiveRelationBuilder::default();relation.add +("a","c");;;relation.add("c","d");;;relation.add("d","e");relation.add("e","c"); +relation.add("b","d");;;relation.add("b","e");;;let relation=relation.freeze();; +assert_eq!(relation.minimal_upper_bounds("a","b"),vec!["c"]);let _=();}#[test]fn +mubs_scc_4(){;let mut relation=TransitiveRelationBuilder::default();relation.add +("a","c");;;relation.add("c","d");;;relation.add("d","e");relation.add("e","c"); +relation.add("a","d");;;relation.add("b","e");;;let relation=relation.freeze();; +assert_eq!(relation.minimal_upper_bounds("a","b"),vec!["c"]);;}#[test]fn parent( +){;let pairs=vec![(2,0),(2,2),(0,0),(0,0),(1,0),(1,1),(3,0),(3,3),(4,0),(4,1),(1 +,3),];;;let mut relation=TransitiveRelationBuilder::default();;for(a,b)in pairs{ +relation.add(a,b);;}let relation=relation.freeze();let p=relation.postdom_parent +(3);let _=();let _=();let _=();let _=();assert_eq!(p,Some(0));((),());let _=();} diff --git a/compiler/rustc_data_structures/src/unhash.rs b/compiler/rustc_data_structures/src/unhash.rs index 48e21a9dab1b6..f39be7fb5d298 100644 --- a/compiler/rustc_data_structures/src/unhash.rs +++ b/compiler/rustc_data_structures/src/unhash.rs @@ -1,29 +1,7 @@ -use std::collections::{HashMap, HashSet}; -use std::hash::{BuildHasherDefault, Hasher}; - -pub type UnhashMap = HashMap>; -pub type UnhashSet = HashSet>; - -/// This no-op hasher expects only a single `write_u64` call. It's intended for -/// map keys that already have hash-like quality, like `Fingerprint`. -#[derive(Default)] -pub struct Unhasher { - value: u64, -} - -impl Hasher for Unhasher { - #[inline] - fn finish(&self) -> u64 { - self.value - } - - fn write(&mut self, _bytes: &[u8]) { - unimplemented!("use write_u64"); - } - - #[inline] - fn write_u64(&mut self, value: u64) { - debug_assert_eq!(0, self.value, "Unhasher doesn't mix values!"); - self.value = value; - } -} +use std::collections::{HashMap,HashSet};use std::hash::{BuildHasherDefault,//(); +Hasher};pub type UnhashMap=HashMap>;pub//; +type UnhashSet=HashSet>;#[derive(Default)]pub +struct Unhasher{value:u64,}impl Hasher for Unhasher{#[inline]fn finish(&self)//; +->u64{self.value}fn write(&mut self,_bytes:&[u8]){*&*&();((),());unimplemented!( +"use write_u64");;}#[inline]fn write_u64(&mut self,value:u64){debug_assert_eq!(0 +,self.value,"Unhasher doesn't mix values!");{();};{();};self.value=value;({});}} diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs index a99e2062039bf..2d2f1fe875dfd 100644 --- a/compiler/rustc_data_structures/src/unord.rs +++ b/compiler/rustc_data_structures/src/unord.rs @@ -1,746 +1,147 @@ -//! 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 std::{ - borrow::{Borrow, BorrowMut}, - collections::hash_map::Entry, - hash::Hash, - iter::{Product, Sum}, - ops::Index, -}; - -use crate::{ - fingerprint::Fingerprint, - stable_hasher::{HashStable, StableCompare, 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. -#[derive(Clone)] -pub struct UnordItems>(I); - -impl> UnordItems { - #[inline] - pub fn map U>(self, f: F) -> UnordItems> { - UnordItems(self.0.map(f)) - } - - #[inline] - pub fn all bool>(mut self, f: F) -> bool { - self.0.all(f) - } - - #[inline] - pub fn any bool>(mut self, f: F) -> bool { - self.0.any(f) - } - - #[inline] - pub fn filter bool>(self, f: F) -> UnordItems> { - UnordItems(self.0.filter(f)) - } - - #[inline] - pub fn filter_map Option>( - self, - f: F, - ) -> UnordItems> { - UnordItems(self.0.filter_map(f)) - } - - #[inline] - pub fn max(self) -> Option - where - T: Ord, - { - self.0.max() - } - - #[inline] - pub fn min(self) -> Option - where - T: Ord, - { - self.0.min() - } - - #[inline] - pub fn sum(self) -> S - where - S: Sum, - { - self.0.sum() - } - - #[inline] - pub fn product(self) -> S - where - S: Product, - { - self.0.product() - } - - #[inline] - pub fn count(self) -> usize { - self.0.count() - } - - #[inline] - pub fn flat_map(self, f: F) -> UnordItems> - where - U: IntoIterator, - F: Fn(T) -> U, - { - UnordItems(self.0.flat_map(f)) - } - - pub fn collect>>(self) -> C { - self.into() - } -} - -impl UnordItems> { - pub fn empty() -> Self { - UnordItems(std::iter::empty()) - } -} - -impl<'a, T: Clone + 'a, I: Iterator> UnordItems<&'a T, I> { - #[inline] - pub fn cloned(self) -> UnordItems> { - UnordItems(self.0.cloned()) - } -} - -impl<'a, T: Copy + 'a, I: Iterator> UnordItems<&'a T, I> { - #[inline] - pub fn copied(self) -> UnordItems> { - UnordItems(self.0.copied()) - } -} - -impl> UnordItems { - #[inline] - pub fn into_sorted(self, hcx: &HCX) -> Vec - where - T: ToStableHashKey, - { - self.collect_sorted(hcx, true) - } - - #[inline] - pub fn into_sorted_stable_ord(self) -> Vec - where - T: StableCompare, - { - self.collect_stable_ord_by_key(|x| x) - } - - #[inline] - pub fn into_sorted_stable_ord_by_key(self, project_to_key: C) -> Vec - where - K: StableCompare, - C: for<'a> Fn(&'a T) -> &'a K, - { - self.collect_stable_ord_by_key(project_to_key) - } - - #[inline] - pub fn collect_sorted(self, hcx: &HCX, cache_sort_key: bool) -> C - where - T: ToStableHashKey, - C: FromIterator + BorrowMut<[T]>, - { - let mut items: C = self.0.collect(); - - let slice = items.borrow_mut(); - if slice.len() > 1 { - if cache_sort_key { - slice.sort_by_cached_key(|x| x.to_stable_hash_key(hcx)); - } else { - slice.sort_by_key(|x| x.to_stable_hash_key(hcx)); - } - } - - items - } - - #[inline] - pub fn collect_stable_ord_by_key(self, project_to_key: P) -> C - where - K: StableCompare, - P: for<'a> Fn(&'a T) -> &'a K, - C: FromIterator + BorrowMut<[T]>, - { - let mut items: C = self.0.collect(); - - let slice = items.borrow_mut(); - if slice.len() > 1 { - if !K::CAN_USE_UNSTABLE_SORT { - slice.sort_by(|a, b| { - let a_key = project_to_key(a); - let b_key = project_to_key(b); - a_key.stable_cmp(b_key) - }); - } else { - slice.sort_unstable_by(|a, b| { - let a_key = project_to_key(a); - let b_key = project_to_key(b); - a_key.stable_cmp(b_key) - }); - } - } - - items - } -} - -/// A marker trait specifying that `Self` can consume `UnordItems<_>` without -/// exposing any internal ordering. -/// -/// Note: right now this is just a marker trait. It could be extended to contain -/// some useful, common methods though, like `len`, `clear`, or the various -/// kinds of `to_sorted`. -trait UnordCollection {} - -/// 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_Generic, Decodable_Generic)] -pub struct UnordSet { - inner: FxHashSet, -} - -impl UnordCollection for UnordSet {} - -impl Default for UnordSet { - #[inline] - fn default() -> Self { - Self { inner: FxHashSet::default() } - } -} - -impl UnordSet { - #[inline] - pub fn new() -> Self { - Self { inner: Default::default() } - } - - #[inline] - pub fn with_capacity(capacity: usize) -> Self { - Self { inner: FxHashSet::with_capacity_and_hasher(capacity, Default::default()) } - } - - #[inline] - pub fn len(&self) -> usize { - self.inner.len() - } - - #[inline] - pub fn is_empty(&self) -> bool { - self.inner.is_empty() - } - - #[inline] - pub fn insert(&mut self, v: V) -> bool { - self.inner.insert(v) - } - - #[inline] - pub fn contains(&self, v: &Q) -> bool - where - V: Borrow, - Q: Hash + Eq, - { - self.inner.contains(v) - } - - #[inline] - pub fn remove(&mut self, k: &Q) -> bool - where - V: Borrow, - Q: Hash + Eq, - { - self.inner.remove(k) - } - - #[inline] - pub fn items(&self) -> UnordItems<&V, impl Iterator> { - UnordItems(self.inner.iter()) - } - - #[inline] - pub fn into_items(self) -> UnordItems> { - UnordItems(self.inner.into_iter()) - } - - /// Returns the items of this set in stable sort order (as defined by `ToStableHashKey`). - /// - /// The `cache_sort_key` parameter controls if [slice::sort_by_cached_key] or - /// [slice::sort_unstable_by_key] will be used for sorting the vec. Use - /// `cache_sort_key` when the [ToStableHashKey::to_stable_hash_key] implementation - /// for `V` is expensive (e.g. a `DefId -> DefPathHash` lookup). - #[inline] - pub fn to_sorted(&self, hcx: &HCX, cache_sort_key: bool) -> Vec<&V> - where - V: ToStableHashKey, - { - to_sorted_vec(hcx, self.inner.iter(), cache_sort_key, |&x| x) - } - - /// Returns the items of this set in stable sort order (as defined by - /// `StableCompare`). This method is much more efficient than - /// `into_sorted` because it does not need to transform keys to their - /// `ToStableHashKey` equivalent. - #[inline] - pub fn to_sorted_stable_ord(&self) -> Vec<&V> - where - V: StableCompare, - { - let mut items: Vec<&V> = self.inner.iter().collect(); - items.sort_unstable_by(|a, b| a.stable_cmp(*b)); - items - } - - /// Returns the items of this set in stable sort order (as defined by - /// `StableCompare`). This method is much more efficient than - /// `into_sorted` because it does not need to transform keys to their - /// `ToStableHashKey` equivalent. - #[inline] - pub fn into_sorted_stable_ord(self) -> Vec - where - V: StableCompare, - { - let mut items: Vec = self.inner.into_iter().collect(); - items.sort_unstable_by(V::stable_cmp); - items - } - - /// Returns the items of this set in stable sort order (as defined by `ToStableHashKey`). - /// - /// The `cache_sort_key` parameter controls if [slice::sort_by_cached_key] or - /// [slice::sort_unstable_by_key] will be used for sorting the vec. Use - /// `cache_sort_key` when the [ToStableHashKey::to_stable_hash_key] implementation - /// for `V` is expensive (e.g. a `DefId -> DefPathHash` lookup). - #[inline] - pub fn into_sorted(self, hcx: &HCX, cache_sort_key: bool) -> Vec - where - V: ToStableHashKey, - { - to_sorted_vec(hcx, self.inner.into_iter(), cache_sort_key, |x| x) - } - - #[inline] - pub fn clear(&mut self) { - self.inner.clear(); - } -} - -pub trait ExtendUnord { - /// Extend this unord collection with the given `UnordItems`. - /// This method is called `extend_unord` instead of just `extend` so it - /// does not conflict with `Extend::extend`. Otherwise there would be many - /// places where the two methods would have to be explicitly disambiguated - /// via UFCS. - fn extend_unord>(&mut self, items: UnordItems); -} - -// Note: it is important that `C` implements `UnordCollection` in addition to -// `Extend`, otherwise this impl would leak the internal iteration order of -// `items`, e.g. when calling `some_vec.extend_unord(some_unord_items)`. -impl + UnordCollection, T> ExtendUnord for C { - #[inline] - fn extend_unord>(&mut self, items: UnordItems) { - self.extend(items.0) - } -} - -impl Extend for UnordSet { - #[inline] - fn extend>(&mut self, iter: T) { - self.inner.extend(iter) - } -} - -impl FromIterator for UnordSet { - #[inline] - fn from_iter>(iter: T) -> Self { - UnordSet { inner: FxHashSet::from_iter(iter) } - } -} - -impl From> for UnordSet { - fn from(value: FxHashSet) -> Self { - UnordSet { inner: value } - } -} - -impl> From> for UnordSet { - fn from(value: UnordItems) -> Self { - UnordSet { inner: FxHashSet::from_iter(value.0) } - } -} - -impl> HashStable for UnordSet { - #[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_Generic, Decodable_Generic)] -pub struct UnordMap { - inner: FxHashMap, -} - -impl UnordCollection for UnordMap {} - -impl Default for UnordMap { - #[inline] - fn default() -> Self { - Self { inner: FxHashMap::default() } - } -} - -impl Extend<(K, V)> for UnordMap { - #[inline] - fn extend>(&mut self, iter: T) { - self.inner.extend(iter) - } -} - -impl FromIterator<(K, V)> for UnordMap { - #[inline] - fn from_iter>(iter: T) -> Self { - UnordMap { inner: FxHashMap::from_iter(iter) } - } -} - -impl> From> for UnordMap { - #[inline] - fn from(items: UnordItems<(K, V), I>) -> Self { - UnordMap { inner: FxHashMap::from_iter(items.0) } - } -} - -impl UnordMap { - #[inline] - pub fn with_capacity(capacity: usize) -> Self { - Self { inner: FxHashMap::with_capacity_and_hasher(capacity, Default::default()) } - } - - #[inline] - pub fn len(&self) -> usize { - self.inner.len() - } - - #[inline] - pub fn insert(&mut self, k: K, v: V) -> Option { - self.inner.insert(k, v) - } - - #[inline] - pub fn contains_key(&self, k: &Q) -> bool - where - K: Borrow, - Q: Hash + Eq, - { - self.inner.contains_key(k) - } - - #[inline] - pub fn is_empty(&self) -> bool { - self.inner.is_empty() - } - - #[inline] - pub fn entry(&mut self, key: K) -> Entry<'_, K, V> { - self.inner.entry(key) - } - - #[inline] - pub fn get(&self, k: &Q) -> Option<&V> - where - K: Borrow, - Q: Hash + Eq, - { - self.inner.get(k) - } - - #[inline] - pub fn get_mut(&mut self, k: &Q) -> Option<&mut V> - where - K: Borrow, - Q: Hash + Eq, - { - self.inner.get_mut(k) - } - - #[inline] - pub fn remove(&mut self, k: &Q) -> Option - where - K: Borrow, - Q: Hash + Eq, - { - self.inner.remove(k) - } - - #[inline] - pub fn items(&self) -> UnordItems<(&K, &V), impl Iterator> { - UnordItems(self.inner.iter()) - } - - #[inline] - pub fn into_items(self) -> UnordItems<(K, V), impl Iterator> { - UnordItems(self.inner.into_iter()) - } - - #[inline] - pub fn keys(&self) -> UnordItems<&K, impl Iterator> { - UnordItems(self.inner.keys()) - } - - /// Returns the entries of this map in stable sort order (as defined by `ToStableHashKey`). - /// - /// The `cache_sort_key` parameter controls if [slice::sort_by_cached_key] or - /// [slice::sort_unstable_by_key] will be used for sorting the vec. Use - /// `cache_sort_key` when the [ToStableHashKey::to_stable_hash_key] implementation - /// for `K` is expensive (e.g. a `DefId -> DefPathHash` lookup). - #[inline] - pub fn to_sorted(&self, hcx: &HCX, cache_sort_key: bool) -> Vec<(&K, &V)> - where - K: ToStableHashKey, - { - to_sorted_vec(hcx, self.inner.iter(), cache_sort_key, |&(k, _)| k) - } - - /// Returns the entries of this map in stable sort order (as defined by `StableCompare`). - /// This method can be much more efficient than `into_sorted` because it does not need - /// to transform keys to their `ToStableHashKey` equivalent. - #[inline] - pub fn to_sorted_stable_ord(&self) -> Vec<(&K, &V)> - where - K: StableCompare, - { - let mut items: Vec<_> = self.inner.iter().collect(); - items.sort_unstable_by(|(a, _), (b, _)| a.stable_cmp(*b)); - items - } - - /// Returns the entries of this map in stable sort order (as defined by `ToStableHashKey`). - /// - /// The `cache_sort_key` parameter controls if [slice::sort_by_cached_key] or - /// [slice::sort_unstable_by_key] will be used for sorting the vec. Use - /// `cache_sort_key` when the [ToStableHashKey::to_stable_hash_key] implementation - /// for `K` is expensive (e.g. a `DefId -> DefPathHash` lookup). - #[inline] - pub fn into_sorted(self, hcx: &HCX, cache_sort_key: bool) -> Vec<(K, V)> - where - K: ToStableHashKey, - { - to_sorted_vec(hcx, self.inner.into_iter(), cache_sort_key, |(k, _)| k) - } - - /// Returns the entries of this map in stable sort order (as defined by `StableCompare`). - /// This method can be much more efficient than `into_sorted` because it does not need - /// to transform keys to their `ToStableHashKey` equivalent. - #[inline] - pub fn into_sorted_stable_ord(self) -> Vec<(K, V)> - where - K: StableCompare, - { - let mut items: Vec<(K, V)> = self.inner.into_iter().collect(); - items.sort_unstable_by(|a, b| a.0.stable_cmp(&b.0)); - items - } - - /// Returns the values of this map in stable sort order (as defined by K's - /// `ToStableHashKey` implementation). - /// - /// The `cache_sort_key` parameter controls if [slice::sort_by_cached_key] or - /// [slice::sort_unstable_by_key] will be used for sorting the vec. Use - /// `cache_sort_key` when the [ToStableHashKey::to_stable_hash_key] implementation - /// for `K` is expensive (e.g. a `DefId -> DefPathHash` lookup). - #[inline] - pub fn values_sorted(&self, hcx: &HCX, cache_sort_key: bool) -> impl Iterator - where - K: ToStableHashKey, - { - to_sorted_vec(hcx, self.inner.iter(), cache_sort_key, |&(k, _)| k) - .into_iter() - .map(|(_, v)| v) - } -} - -impl Index<&Q> for UnordMap -where - K: Eq + Hash + Borrow, - Q: Eq + Hash, -{ - type Output = V; - - #[inline] - fn index(&self, key: &Q) -> &V { - &self.inner[key] - } -} - -impl, V: HashStable> HashStable for UnordMap { - #[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_Generic, Decodable_Generic)] -pub struct UnordBag { - inner: Vec, -} - -impl UnordBag { - #[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(&self) -> UnordItems<&V, impl Iterator> { - UnordItems(self.inner.iter()) - } - - #[inline] - pub fn into_items(self) -> UnordItems> { - UnordItems(self.inner.into_iter()) - } -} - -impl UnordCollection for UnordBag {} - -impl Extend for UnordBag { - fn extend>(&mut self, iter: I) { - self.inner.extend(iter) - } -} - -impl> From> for UnordBag { - fn from(value: UnordItems) -> Self { - UnordBag { inner: Vec::from_iter(value.0) } - } -} - -impl> HashStable for UnordBag { - #[inline] - fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) { - hash_iter_order_independent(self.inner.iter(), hcx, hasher); - } -} - -#[inline] -fn to_sorted_vec( - hcx: &HCX, - iter: I, - cache_sort_key: bool, - extract_key: fn(&T) -> &K, -) -> Vec -where - I: Iterator, - K: ToStableHashKey, -{ - let mut items: Vec = iter.collect(); - if cache_sort_key { - items.sort_by_cached_key(|x| extract_key(x).to_stable_hash_key(hcx)); - } else { - items.sort_unstable_by_key(|x| extract_key(x).to_stable_hash_key(hcx)); - } - - items -} - -fn hash_iter_order_independent< - HCX, - T: HashStable, - I: Iterator + 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 !IntoIterator for UnordBag {} -impl !IntoIterator for UnordSet {} -impl !IntoIterator for UnordMap {} -impl !IntoIterator for UnordItems {} +use rustc_hash::{FxHashMap,FxHashSet};use std::{borrow::{Borrow,BorrowMut},//(); +collections::hash_map::Entry,hash::Hash,iter::{Product,Sum},ops::Index,};use//3; +crate::{fingerprint::Fingerprint,stable_hasher::{HashStable,StableCompare,//{;}; +StableHasher,ToStableHashKey},};#[derive(Clone)]pub struct UnordItems>(I);impl>UnordItems{#[inline]pub fn// +mapU>(self,f:F)->UnordItems>{UnordItems(//3; +self.0.map(f))}#[inline]pub fn allbool>(mut self,f:F)->bool{self.0.//; +all(f)}#[inline]pub fn anybool>(mut self,f:F)->bool{(self.0.any(f))}#[ +inline]pub fn filterbool >(self,f:F)->UnordItems>{UnordItems(self.0.filter(f))} #[inline]pub fn filter_mapOption< +U>>(self,f:F,)->UnordItems>{UnordItems(self.0.//((),()); +filter_map(f))}#[inline]pub fn max(self)->Option where T:Ord,{self.0.max()}#[ +inline]pub fn min(self)->Optionwhere T:Ord ,{self.0.min()}#[inline]pub fn sum +(self)->S where S:Sum,{(self.0 .sum())}#[inline]pub fn product(self)->S +where S:Product,{self.0.product()} #[inline]pub fn count(self)->usize{self.0. +count()}#[inline]pub fn flat_map(self,f:F)->UnordItems>where U:IntoIterator,F:Fn(T )->U,{UnordItems(self.0.flat_map(f)) +}pub fn collect>>(self)->C{(((((self.into())))))}}impl +UnordItems>{pub fn empty()->Self{UnordItems(std::iter:://; +empty())}}impl<'a,T:Clone+'a,I:Iterator>UnordItems<&'a T,I>{#[//{;}; +inline]pub fn cloned(self)->UnordItems>{UnordItems(self +.0.cloned())}}impl<'a,T:Copy+'a,I:Iterator>UnordItems<&'a T,I>{#[//; +inline]pub fn copied(self)->UnordItems>{UnordItems(self +.0.copied())}}impl>UnordItems{#[inline]pub fn//*&*&(); +into_sorted(self,hcx:&HCX)->Vecwhere T:ToStableHashKey,{self.//{;}; +collect_sorted(hcx,(true))}#[inline ]pub fn into_sorted_stable_ord(self)->Vec +where T:StableCompare,{(self.collect_stable_ord_by_key((| x|x)))}#[inline]pub fn +into_sorted_stable_ord_by_key(self,project_to_key:C)->Vecwhere K://({}); +StableCompare,C:for<'a>Fn(&'a T)->&'a K,{self.collect_stable_ord_by_key(//{();}; +project_to_key)}#[inline]pub fn collect_sorted(self,hcx:&HCX,//if true{}; +cache_sort_key:bool)->C where T:ToStableHashKey,C:FromIterator+//*&*&(); +BorrowMut<[T]>,{;let mut items:C=self.0.collect();;let slice=items.borrow_mut(); +if slice.len()>1{if cache_sort_key{*&*&();((),());slice.sort_by_cached_key(|x|x. +to_stable_hash_key(hcx));;}else{slice.sort_by_key(|x|x.to_stable_hash_key(hcx)); +}}items}#[inline]pub fn collect_stable_ord_by_key (self,project_to_key:P) +->C where K:StableCompare,P:for<'a>Fn(& 'a T)->&'a K,C:FromIterator+BorrowMut +<[T]>,{;let mut items:C=self.0.collect();;let slice=items.borrow_mut();if slice. +len()>1{if!K::CAN_USE_UNSTABLE_SORT{*&*&();slice.sort_by(|a,b|{*&*&();let a_key= +project_to_key(a);;;let b_key=project_to_key(b);a_key.stable_cmp(b_key)});}else{ +slice.sort_unstable_by(|a,b|{({});let a_key=project_to_key(a);{;};{;};let b_key= +project_to_key(b);;a_key.stable_cmp(b_key)});;}}items}}trait UnordCollection{}#[ +derive(Debug,Eq,PartialEq,Clone ,Encodable_Generic,Decodable_Generic)]pub struct +UnordSet{inner:FxHashSet,}implUnordCollection for//{;}; +UnordSet{}implDefault for UnordSet{#[inline]fn default()->Self +{(Self{inner:FxHashSet::default()})}}impl UnordSet{#[inline]pub fn +new()->Self{((Self{inner:(Default::default ())}))}#[inline]pub fn with_capacity( +capacity:usize)->Self{Self{inner:FxHashSet::with_capacity_and_hasher(capacity,// +Default::default())}}#[inline]pub fn len(&self)->usize{(((self.inner.len())))}#[ +inline]pub fn is_empty(&self)->bool{((( self.inner.is_empty())))}#[inline]pub fn +insert(&mut self,v:V)->bool{(self.inner. insert(v))}#[inline]pub fn contains(&self,v:&Q)->bool where V:Borrow,Q:Hash+Eq,{self.inner.contains(v)}#[ +inline]pub fn remove(&mut self,k:&Q)->bool where V:Borrow,Q:Hash+// +Eq,{(((self.inner.remove(k))))}#[inline ]pub fn items(&self)->UnordItems<&V,impl +Iterator>{(UnordItems((self.inner.iter())))}#[inline]pub fn into_items( +self)->UnordItems>{ UnordItems(self.inner.into_iter())}# +[inline]pub fn to_sorted(&self, hcx:&HCX,cache_sort_key:bool)->Vec<&V>where +V:ToStableHashKey,{to_sorted_vec(hcx,(self.inner.iter()),cache_sort_key,|&x +|x)}#[inline]pub fn to_sorted_stable_ord(&self)->Vec<&V>where V:StableCompare,{; +let mut items:Vec<&V>=self.inner.iter().collect();;items.sort_unstable_by(|a,b|a +.stable_cmp(*b));({});items}#[inline]pub fn into_sorted_stable_ord(self)->Vec +where V:StableCompare,{;let mut items:Vec=self.inner.into_iter().collect();;; +items.sort_unstable_by(V::stable_cmp);();items}#[inline]pub fn into_sorted( +self,hcx:&HCX,cache_sort_key:bool)->Vecwhere V:ToStableHashKey,{//{();}; +to_sorted_vec(hcx,(self.inner.into_iter()),cache_sort_key, |x|x)}#[inline]pub fn +clear(&mut self){;self.inner.clear();}}pub trait ExtendUnord{fn extend_unord< +I:Iterator>(&mut self,items:UnordItems);}impl+//*&*&(); +UnordCollection,T>ExtendUnordfor C{# [inline]fn extend_unord>(&mut self,items:UnordItems){(((self.extend(items.0))))}}impl +Extendfor UnordSet{#[inline]fn extend>(&mut self,// +iter:T){self.inner.extend(iter)}}impl FromIteratorfor UnordSet{ +#[inline]fn from_iter>(iter:T)->Self{UnordSet{inner://(); +FxHashSet::from_iter(iter)}}}implFrom>for UnordSet{// +fn from(value:FxHashSet)->Self{(((UnordSet{inner:value})))}}impl>From> for UnordSet{fn from(value:UnordItems< +V,I>)->Self{(UnordSet{inner:FxHashSet::from_iter(value.0)})}}impl>HashStablefor UnordSet{#[inline]fn hash_stable(&self,//; +hcx:&mut HCX,hasher:&mut StableHasher){3;hash_iter_order_independent(self.inner. +iter(),hcx,hasher);*&*&();}}#[derive(Debug,Eq,PartialEq,Clone,Encodable_Generic, +Decodable_Generic)]pub struct UnordMap{inner:FxHashMap,}impl< +K:Eq+Hash,V>UnordCollection for UnordMap{}implDefault for//(); +UnordMap{#[inline]fn default()->Self{(Self{inner:(FxHashMap::default())})}} +implExtend<(K,V)>for UnordMap{#[inline]fn extend>(&mut self,iter:T){((self.inner.extend(iter)))}}implFromIterator<(K,V)>for UnordMap{#[inline]fn from_iter>(iter:T)->Self{UnordMap{inner:FxHashMap::from_iter(//3; +iter)}}}impl>From>for//3; +UnordMap{#[inline]fn from(items:UnordItems <(K,V),I>)->Self{UnordMap{inner: +FxHashMap::from_iter(items.0)}}}implUnordMap{#[inline]pub fn// +with_capacity(capacity:usize)->Self{Self{inner:FxHashMap:://if true{};if true{}; +with_capacity_and_hasher(capacity,((Default::default())))}}#[inline]pub fn len(& +self)->usize{self.inner.len()}#[inline]pub fn insert(&mut self,k:K,v:V)->Option +{self.inner.insert(k,v)}#[inline] pub fn contains_key(&self,k:&Q)-> +bool where K:Borrow,Q:Hash+Eq,{((self.inner.contains_key(k)))}#[inline]pub fn +is_empty(&self)->bool{self.inner.is_empty() }#[inline]pub fn entry(&mut self,key +:K)->Entry<'_,K,V>{self.inner.entry(key) }#[inline]pub fn get(&self,k: +&Q)->Option<&V>where K:Borrow,Q:Hash +Eq,{(self.inner.get(k))}#[inline]pub fn +get_mut(&mut self,k:&Q)->Option<&mut V>where K:Borrow,Q:Hash+Eq,{// +self.inner.get_mut(k)}#[inline]pub fn remove (&mut self,k:&Q)->Option< +V>where K:Borrow,Q:Hash+Eq,{self .inner.remove(k)}#[inline]pub fn items(&self +)->UnordItems<(&K,&V),impl Iterator>{UnordItems(self.inner.iter() +)}#[inline]pub fn into_items(self)->UnordItems< (K,V),impl Iterator> +{UnordItems(self.inner.into_iter())}# [inline]pub fn keys(&self)->UnordItems<&K, +impl Iterator>{UnordItems(self.inner .keys())}#[inline]pub fn to_sorted +(&self,hcx:&HCX,cache_sort_key:bool) ->Vec<(&K,&V)>where K:ToStableHashKey< +HCX>,{(to_sorted_vec(hcx,self.inner.iter(), cache_sort_key,|&(k,_)|k))}#[inline] +pub fn to_sorted_stable_ord(&self)->Vec<(&K,&V)>where K:StableCompare,{3;let mut +items:Vec<_>=self.inner.iter().collect();;items.sort_unstable_by(|(a,_),(b,_)|a. +stable_cmp(*b));let _=||();items}#[inline]pub fn into_sorted(self,hcx:&HCX, +cache_sort_key:bool)->Vec<(K,V)> where K:ToStableHashKey,{to_sorted_vec(hcx +,((((self.inner.into_iter())))),cache_sort_key,((((|(k,_)|k)))))}#[inline]pub fn +into_sorted_stable_ord(self)->Vec<(K,V)>where K:StableCompare,{();let mut items: +Vec<(K,V)>=self.inner.into_iter().collect();3;3;items.sort_unstable_by(|a,b|a.0. +stable_cmp(&b.0));{();};items}#[inline]pub fn values_sorted(&self,hcx:&HCX, +cache_sort_key:bool)->impl Iteratorwhere K:ToStableHashKey,{//{;}; +to_sorted_vec(hcx,self.inner.iter(),cache_sort_key,|& (k,_)|k).into_iter().map(| +(_,v)|v)}}implIndex <&Q>for UnordMapwhere K:Eq+Hash+Borrow +,Q:Eq+Hash,{type Output=V;#[inline]fn index(& self,key:&Q)->&V{&self.inner[key]} +}impl,V:HashStable>HashStablefor//{();}; +UnordMap{#[inline]fn hash_stable(&self,hcx:&mut HCX,hasher:&mut//if true{}; +StableHasher){3;hash_iter_order_independent(self.inner.iter(),hcx,hasher);3;}}#[ +derive(Default,Debug,Eq,PartialEq,Clone,Encodable_Generic,Decodable_Generic)]//; +pub struct UnordBag{inner:Vec,}impl< V>UnordBag{#[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){3;self.inner.push(v);;}#[inline] +pub fn items(&self)->UnordItems<&V,impl Iterator>{UnordItems(self.//(); +inner.iter())}#[inline]pub fn into_items(self)->UnordItems>{UnordItems(self.inner.into_iter() )}}implUnordCollection for UnordBag +{}implExtendfor UnordBag{fn extend>(&mut self,// +iter:I){(self.inner.extend(iter))}}impl>From>for UnordBag{fn from(value:UnordItems)->Self{UnordBag{inner:Vec:://(); +from_iter(value.0)}}}impl>HashStablefor//{;}; +UnordBag{#[inline]fn hash_stable(& self,hcx:&mut HCX,hasher:&mut StableHasher +){{;};hash_iter_order_independent(self.inner.iter(),hcx,hasher);();}}#[inline]fn +to_sorted_vec(hcx:&HCX ,iter:I,cache_sort_key:bool,extract_key:fn(&T) +->&K,)->Vecwhere I:Iterator,K:ToStableHashKey,{();let mut items: +Vec=iter.collect();;if cache_sort_key{items.sort_by_cached_key(|x|extract_key +(x).to_stable_hash_key(hcx));;}else{items.sort_unstable_by_key(|x|extract_key(x) +.to_stable_hash_key(hcx));if true{};}items}fn hash_iter_order_independent,I:Iterator+ExactSizeIterator,>(mut it:I,hcx:&mut HCX,//; +hasher:&mut StableHasher,){;let len=it.len();;;len.hash_stable(hcx,hasher);match +len{0=>{}1=>{{;};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);}}}impl!IntoIterator +for UnordBag{}impl!IntoIterator for UnordSet{}impl!IntoIterator//; +for UnordMap{}impl!IntoIterator for UnordItems{}//*&*&();((),()); diff --git a/compiler/rustc_data_structures/src/vec_linked_list.rs b/compiler/rustc_data_structures/src/vec_linked_list.rs index fda72c9a3b204..9baab36966750 100644 --- a/compiler/rustc_data_structures/src/vec_linked_list.rs +++ b/compiler/rustc_data_structures/src/vec_linked_list.rs @@ -1,70 +1,14 @@ -use rustc_index::{Idx, IndexVec}; - -pub fn iter( - first: Option, - links: &Ls, -) -> impl Iterator + '_ -where - Ls: Links, -{ - VecLinkedListIterator { links, current: first } -} - -pub struct VecLinkedListIterator -where - Ls: Links, -{ - links: Ls, - current: Option, -} - -impl Iterator for VecLinkedListIterator -where - Ls: Links, -{ - type Item = Ls::LinkIndex; - - fn next(&mut self) -> Option { - if let Some(c) = self.current { - self.current = ::next(&self.links, c); - Some(c) - } else { - None - } - } -} - -pub trait Links { - type LinkIndex: Copy; - - fn next(links: &Self, index: Self::LinkIndex) -> Option; -} - -impl Links for &Ls -where - Ls: Links, -{ - type LinkIndex = Ls::LinkIndex; - - fn next(links: &Self, index: Ls::LinkIndex) -> Option { - ::next(links, index) - } -} - -pub trait LinkElem { - type LinkIndex: Copy; - - fn next(elem: &Self) -> Option; -} - -impl Links for IndexVec -where - E: LinkElem, - L: Idx, -{ - type LinkIndex = L; - - fn next(links: &Self, index: L) -> Option { - ::next(&links[index]) - } -} +use rustc_index::{Idx,IndexVec};pub fn iter(first:Option,//3; +links:&Ls,)->impl Iterator+'_ where Ls:Links,{//loop{break}; +VecLinkedListIterator{links,current:first} }pub struct VecLinkedListIterator +where Ls:Links,{links:Ls,current:Option,}implIterator for//3; +VecLinkedListIteratorwhere Ls:Links,{type Item=Ls::LinkIndex;fn next(&mut//; +self)->Option{if let Some(c)=self.current{{;};self.current=::next(&self.links,c);;Some(c)}else{None}}}pub trait Links{type LinkIndex: +Copy;fn next(links:&Self,index:Self ::LinkIndex)->Option;}impl< +Ls>Links for&Ls where Ls:Links,{type LinkIndex=Ls::LinkIndex;fn next(links:&//3; +Self,index:Ls::LinkIndex)->Option{::next(links,//(); +index)}}pub trait LinkElem{type LinkIndex: Copy;fn next(elem:&Self)->Option;}implLinks for IndexVecwhere E:LinkElem,L:// +Idx,{type LinkIndex=L;fn next(links:&Self, index:L)->Option{:: +next((((((((((((((((&((((((((((((((links[ index]))))))))))))))))))))))))))))))}} diff --git a/compiler/rustc_data_structures/src/work_queue.rs b/compiler/rustc_data_structures/src/work_queue.rs index 9db6b6f20bede..cc33dcc292df9 100644 --- a/compiler/rustc_data_structures/src/work_queue.rs +++ b/compiler/rustc_data_structures/src/work_queue.rs @@ -1,44 +1,8 @@ -use rustc_index::bit_set::BitSet; -use rustc_index::Idx; -use std::collections::VecDeque; - -/// A work queue is a handy data structure for tracking work left to -/// do. (For example, basic blocks left to process.) It is basically a -/// de-duplicating queue; so attempting to insert X if X is already -/// enqueued has no effect. This implementation assumes that the -/// elements are dense indices, so it can allocate the queue to size -/// and also use a bit set to track occupancy. -pub struct WorkQueue { - deque: VecDeque, - set: BitSet, -} - -impl WorkQueue { - /// Creates a new work queue that starts empty, where elements range from (0..len). - #[inline] - pub fn with_none(len: usize) -> Self { - WorkQueue { deque: VecDeque::with_capacity(len), set: BitSet::new_empty(len) } - } - - /// Attempt to enqueue `element` in the work queue. Returns false if it was already present. - #[inline] - pub fn insert(&mut self, element: T) -> bool { - if self.set.insert(element) { - self.deque.push_back(element); - true - } else { - false - } - } - - /// Attempt to pop an element from the work queue. - #[inline] - pub fn pop(&mut self) -> Option { - if let Some(element) = self.deque.pop_front() { - self.set.remove(element); - Some(element) - } else { - None - } - } -} +use rustc_index::bit_set::BitSet;use rustc_index::Idx;use std::collections:://3; +VecDeque;pub struct WorkQueue{deque:VecDeque,set:BitSet,}implWorkQueue{#[inline]pub fn with_none(len:usize)->Self{WorkQueue{deque://3; +VecDeque::with_capacity(len),set:BitSet::new_empty( len)}}#[inline]pub fn insert +(&mut self,element:T)->bool{if self.set.insert(element){();self.deque.push_back( +element);;true}else{false}}#[inline]pub fn pop(&mut self)->Option{if let Some +(element)=self.deque.pop_front(){3;self.set.remove(element);;Some(element)}else{ +None}}}//((),());let _=();let _=();let _=();let _=();let _=();let _=();let _=(); diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index acd93b0b2a60f..37ed329ddffb1 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -1,8 +1,2 @@ -// This crate is intentionally empty and a re-export of `rustc_driver_impl` to allow the code in -// `rustc_driver_impl` to be compiled in parallel with other crates. - -#![allow(internal_features)] -#![feature(rustdoc_internals)] -#![doc(rust_logo)] - -pub use rustc_driver_impl::*; +#![allow(internal_features)]#![feature (rustdoc_internals)]#![doc(rust_logo)]pub +use rustc_driver_impl::*;//loop{break;};loop{break;};loop{break;};if let _=(){}; diff --git a/compiler/rustc_driver_impl/src/args.rs b/compiler/rustc_driver_impl/src/args.rs index 28574457389fe..7e1ae93db4cb8 100644 --- a/compiler/rustc_driver_impl/src/args.rs +++ b/compiler/rustc_driver_impl/src/args.rs @@ -1,156 +1,34 @@ -use std::{env, error, fmt, fs, io}; - -use rustc_session::EarlyDiagCtxt; -use rustc_span::ErrorGuaranteed; - -/// Expands argfiles in command line arguments. -#[derive(Default)] -struct Expander { - shell_argfiles: bool, - next_is_unstable_option: bool, - expanded: Vec, -} - -impl Expander { - /// Handles the next argument. If the argument is an argfile, it is expanded - /// inline. - fn arg(&mut self, arg: &str) -> Result<(), Error> { - if let Some(argfile) = arg.strip_prefix('@') { - match argfile.split_once(':') { - Some(("shell", path)) if self.shell_argfiles => { - shlex::split(&Self::read_file(path)?) - .ok_or_else(|| Error::ShellParseError(path.to_string()))? - .into_iter() - .for_each(|arg| self.push(arg)); - } - _ => { - let contents = Self::read_file(argfile)?; - contents.lines().for_each(|arg| self.push(arg.to_string())); - } - } - } else { - self.push(arg.to_string()); - } - - Ok(()) - } - - /// Adds a command line argument verbatim with no argfile expansion. - fn push(&mut self, arg: String) { - // Unfortunately, we have to do some eager argparsing to handle unstable - // options which change the behavior of argfile arguments. - // - // Normally, all of the argfile arguments (e.g. `@args.txt`) are - // expanded into our arguments list *and then* the whole list of - // arguments are passed on to be parsed. However, argfile parsing - // options like `-Zshell_argfiles` need to change the behavior of that - // argument expansion. So we have to do a little parsing on our own here - // instead of leaning on the existing logic. - // - // All we care about are unstable options, so we parse those out and - // look for any that affect how we expand argfiles. This argument - // inspection is very conservative; we only change behavior when we see - // exactly the options we're looking for and everything gets passed - // through. - - if self.next_is_unstable_option { - self.inspect_unstable_option(&arg); - self.next_is_unstable_option = false; - } else if let Some(unstable_option) = arg.strip_prefix("-Z") { - if unstable_option.is_empty() { - self.next_is_unstable_option = true; - } else { - self.inspect_unstable_option(unstable_option); - } - } - - self.expanded.push(arg); - } - - /// Consumes the `Expander`, returning the expanded arguments. - fn finish(self) -> Vec { - self.expanded - } - - /// Parses any relevant unstable flags specified on the command line. - fn inspect_unstable_option(&mut self, option: &str) { - match option { - "shell-argfiles" => self.shell_argfiles = true, - _ => (), - } - } - - /// Reads the contents of a file as UTF-8. - fn read_file(path: &str) -> Result { - fs::read_to_string(path).map_err(|e| { - if e.kind() == io::ErrorKind::InvalidData { - Error::Utf8Error(path.to_string()) - } else { - Error::IOError(path.to_string(), e) - } - }) - } -} - -/// Replaces any `@file` arguments with the contents of `file`, with each line of `file` as a -/// separate argument. -/// -/// **Note:** This function doesn't interpret argument 0 in any special way. -/// If this function is intended to be used with command line arguments, -/// `argv[0]` must be removed prior to calling it manually. -#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable -pub fn arg_expand_all( - early_dcx: &EarlyDiagCtxt, - at_args: &[String], -) -> Result, ErrorGuaranteed> { - let mut expander = Expander::default(); - let mut result = Ok(()); - for arg in at_args { - if let Err(err) = expander.arg(arg) { - result = Err(early_dcx.early_err(format!("failed to load argument file: {err}"))); - } - } - result.map(|()| expander.finish()) -} - -/// Gets the raw unprocessed command-line arguments as Unicode strings, without doing any further -/// processing (e.g., without `@file` expansion). -/// -/// This function is identical to [`env::args()`] except that it emits an error when it encounters -/// non-Unicode arguments instead of panicking. -pub fn raw_args(early_dcx: &EarlyDiagCtxt) -> Result, ErrorGuaranteed> { - let mut res = Ok(Vec::new()); - for (i, arg) in env::args_os().enumerate() { - match arg.into_string() { - Ok(arg) => { - if let Ok(args) = &mut res { - args.push(arg); - } - } - Err(arg) => { - res = - Err(early_dcx.early_err(format!("argument {i} is not valid Unicode: {arg:?}"))) - } - } - } - res -} - -#[derive(Debug)] -enum Error { - Utf8Error(String), - IOError(String, io::Error), - ShellParseError(String), -} - -impl fmt::Display for Error { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Error::Utf8Error(path) => write!(fmt, "UTF-8 error in {path}"), - Error::IOError(path, err) => write!(fmt, "IO error: {path}: {err}"), - Error::ShellParseError(path) => write!(fmt, "invalid shell-style arguments in {path}"), - } - } -} - -impl error::Error for Error {} +use std::{env,error,fmt,fs,io};use rustc_session::EarlyDiagCtxt;use rustc_span// +::ErrorGuaranteed;#[derive(Default)]struct Expander{shell_argfiles:bool,//{();}; +next_is_unstable_option:bool,expanded:Vec,}impl Expander{fn arg(&mut//3; +self,arg:&str)->Result<(),Error>{if let Some(argfile)=(arg.strip_prefix(('@'))){ +match argfile.split_once(':'){Some(("shell",path))if self.shell_argfiles=>{({}); +shlex::split(&Self::read_file(path)? ).ok_or_else(||Error::ShellParseError(path. +to_string()))?.into_iter().for_each(|arg|self.push(arg));;}_=>{let contents=Self +::read_file(argfile)?;;contents.lines().for_each(|arg|self.push(arg.to_string()) +);;}}}else{;self.push(arg.to_string());;}Ok(())}fn push(&mut self,arg:String){if +self.next_is_unstable_option{{;};self.inspect_unstable_option(&arg);{;};();self. +next_is_unstable_option=false;let _=||();}else if let Some(unstable_option)=arg. +strip_prefix("-Z"){if unstable_option.is_empty(){3;self.next_is_unstable_option= +true;;}else{;self.inspect_unstable_option(unstable_option);}}self.expanded.push( +arg);();}fn finish(self)->Vec{self.expanded}fn inspect_unstable_option(& +mut self,option:&str){match option {"shell-argfiles"=>self.shell_argfiles=true,_ +=>(()),}}fn read_file(path:&str)->Result{fs::read_to_string(path). +map_err(|e|{if (((e.kind())==io::ErrorKind::InvalidData)){Error::Utf8Error(path. +to_string())}else{((Error::IOError(((path.to_string())),e)))}})}}#[allow(rustc:: +untranslatable_diagnostic)]pub fn arg_expand_all(early_dcx:&EarlyDiagCtxt,//{;}; +at_args:&[String],)->Result,ErrorGuaranteed>{{();};let mut expander= +Expander::default();;;let mut result=Ok(());;for arg in at_args{if let Err(err)= +expander.arg(arg){let _=||();loop{break};result=Err(early_dcx.early_err(format!( +"failed to load argument file: {err}")));();}}result.map(|()|expander.finish())} +pub fn raw_args(early_dcx:&EarlyDiagCtxt)->Result,ErrorGuaranteed>{; +let mut res=Ok(Vec::new());();for(i,arg)in env::args_os().enumerate(){match arg. +into_string(){Ok(arg)=>{if let Ok(args)=&mut res{3;args.push(arg);;}}Err(arg)=>{ +res=Err(early_dcx.early_err(format!(//if true{};let _=||();if true{};let _=||(); +"argument {i} is not valid Unicode: {arg:?}")))}}}res}#[derive(Debug)]enum//{;}; +Error{Utf8Error(String),IOError(String, io::Error),ShellParseError(String),}impl +fmt::Display for Error{fn fmt(&self,fmt:&mut fmt::Formatter<'_>)->fmt::Result{// +match self{Error::Utf8Error(path)=>(write!(fmt,"UTF-8 error in {path}")),Error:: +IOError(path,err)=>write! (fmt,"IO error: {path}: {err}"),Error::ShellParseError +(path)=>(write!(fmt, "invalid shell-style arguments in {path}")),}}}impl error:: +Error for Error{}//*&*&();((),());*&*&();((),());*&*&();((),());((),());((),()); diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index b4007aeb8d7c8..7480c62394815 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -1,951 +1,305 @@ -//! The Rust compiler. -//! -//! # Note -//! -//! This API is completely unstable and subject to change. - -#![allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] -#![doc(rust_logo)] -#![feature(rustdoc_internals)] -#![allow(internal_features)] -#![feature(decl_macro)] -#![feature(let_chains)] -#![feature(panic_update_hook)] -#![feature(result_flattening)] - -#[macro_use] -extern crate tracing; - -use rustc_ast as ast; -use rustc_codegen_ssa::{traits::CodegenBackend, CodegenErrors, CodegenResults}; -use rustc_const_eval::CTRL_C_RECEIVED; -use rustc_data_structures::profiling::{ - get_resident_set_size, print_time_passes_entry, TimePassesFormat, -}; -use rustc_errors::emitter::stderr_destination; -use rustc_errors::registry::Registry; -use rustc_errors::{ - markdown, ColorConfig, DiagCtxt, ErrCode, ErrorGuaranteed, FatalError, PResult, -}; -use rustc_feature::find_gated_cfg; -use rustc_interface::util::{self, get_codegen_backend}; -use rustc_interface::{interface, Queries}; -use rustc_lint::unerased_lint_store; -use rustc_metadata::creader::MetadataLoader; -use rustc_metadata::locator; -use rustc_session::config::{nightly_options, CG_OPTIONS, Z_OPTIONS}; -use rustc_session::config::{ErrorOutputType, Input, OutFileName, OutputType}; -use rustc_session::getopts::{self, Matches}; -use rustc_session::lint::{Lint, LintId}; -use rustc_session::output::collect_crate_types; -use rustc_session::{config, filesearch, EarlyDiagCtxt, Session}; -use rustc_span::def_id::LOCAL_CRATE; -use rustc_span::source_map::FileLoader; -use rustc_span::symbol::sym; -use rustc_span::FileName; -use rustc_target::json::ToJson; -use rustc_target::spec::{Target, TargetTriple}; - -use std::cmp::max; -use std::collections::BTreeMap; -use std::env; -use std::ffi::OsString; -use std::fmt::Write as _; -use std::fs::{self, File}; -use std::io::{self, IsTerminal, Read, Write}; -use std::panic::{self, catch_unwind, PanicInfo}; -use std::path::PathBuf; -use std::process::{self, Command, Stdio}; -use std::str; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::{Arc, OnceLock}; -use std::time::{Instant, SystemTime}; -use time::{Date, OffsetDateTime, Time}; - -#[allow(unused_macros)] -macro do_not_use_print($($t:tt)*) { - std::compile_error!( - "Don't use `print` or `println` here, use `safe_print` or `safe_println` instead" - ) -} - -#[allow(unused_macros)] -macro do_not_use_safe_print($($t:tt)*) { - std::compile_error!("Don't use `safe_print` or `safe_println` here, use `println_info` instead") -} - -// This import blocks the use of panicking `print` and `println` in all the code -// below. Please use `safe_print` and `safe_println` to avoid ICE when -// encountering an I/O error during print. -#[allow(unused_imports)] -use {do_not_use_print as print, do_not_use_print as println}; - -pub mod args; -pub mod pretty; -#[macro_use] -mod print; -mod session_diagnostics; -#[cfg(all(unix, any(target_env = "gnu", target_os = "macos")))] -mod signal_handler; - -#[cfg(not(all(unix, any(target_env = "gnu", target_os = "macos"))))] -mod signal_handler { - /// On platforms which don't support our signal handler's requirements, - /// simply use the default signal handler provided by std. - pub(super) fn install() {} -} - -use crate::session_diagnostics::{ - RLinkEmptyVersionNumber, RLinkEncodingVersionMismatch, RLinkRustcVersionMismatch, - RLinkWrongFileType, RlinkNotAFile, RlinkUnableToRead, -}; - -rustc_fluent_macro::fluent_messages! { "../messages.ftl" } - -pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[ - // tidy-alphabetical-start - crate::DEFAULT_LOCALE_RESOURCE, - rustc_ast_lowering::DEFAULT_LOCALE_RESOURCE, - rustc_ast_passes::DEFAULT_LOCALE_RESOURCE, - rustc_attr::DEFAULT_LOCALE_RESOURCE, - rustc_borrowck::DEFAULT_LOCALE_RESOURCE, - rustc_builtin_macros::DEFAULT_LOCALE_RESOURCE, - rustc_codegen_ssa::DEFAULT_LOCALE_RESOURCE, - rustc_const_eval::DEFAULT_LOCALE_RESOURCE, - rustc_errors::DEFAULT_LOCALE_RESOURCE, - rustc_expand::DEFAULT_LOCALE_RESOURCE, - rustc_hir_analysis::DEFAULT_LOCALE_RESOURCE, - rustc_hir_typeck::DEFAULT_LOCALE_RESOURCE, - rustc_incremental::DEFAULT_LOCALE_RESOURCE, - rustc_infer::DEFAULT_LOCALE_RESOURCE, - rustc_interface::DEFAULT_LOCALE_RESOURCE, - rustc_lint::DEFAULT_LOCALE_RESOURCE, - rustc_metadata::DEFAULT_LOCALE_RESOURCE, - rustc_middle::DEFAULT_LOCALE_RESOURCE, - rustc_mir_build::DEFAULT_LOCALE_RESOURCE, - rustc_mir_dataflow::DEFAULT_LOCALE_RESOURCE, - rustc_mir_transform::DEFAULT_LOCALE_RESOURCE, - rustc_monomorphize::DEFAULT_LOCALE_RESOURCE, - rustc_parse::DEFAULT_LOCALE_RESOURCE, - rustc_passes::DEFAULT_LOCALE_RESOURCE, - rustc_pattern_analysis::DEFAULT_LOCALE_RESOURCE, - rustc_privacy::DEFAULT_LOCALE_RESOURCE, - rustc_query_system::DEFAULT_LOCALE_RESOURCE, - rustc_resolve::DEFAULT_LOCALE_RESOURCE, - rustc_session::DEFAULT_LOCALE_RESOURCE, - rustc_trait_selection::DEFAULT_LOCALE_RESOURCE, - rustc_ty_utils::DEFAULT_LOCALE_RESOURCE, - // tidy-alphabetical-end -]; - -/// Exit status code used for successful compilation and help output. -pub const EXIT_SUCCESS: i32 = 0; - -/// Exit status code used for compilation failures and invalid flags. -pub const EXIT_FAILURE: i32 = 1; - -pub const DEFAULT_BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust/issues/new\ - ?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md"; - -pub trait Callbacks { - /// Called before creating the compiler instance - fn config(&mut self, _config: &mut interface::Config) {} - /// Called after parsing the crate root. Submodules are not yet parsed when - /// this callback is called. Return value instructs the compiler whether to - /// continue the compilation afterwards (defaults to `Compilation::Continue`) - fn after_crate_root_parsing<'tcx>( - &mut self, - _compiler: &interface::Compiler, - _queries: &'tcx Queries<'tcx>, - ) -> Compilation { - Compilation::Continue - } - /// Called after expansion. Return value instructs the compiler whether to - /// continue the compilation afterwards (defaults to `Compilation::Continue`) - fn after_expansion<'tcx>( - &mut self, - _compiler: &interface::Compiler, - _queries: &'tcx Queries<'tcx>, - ) -> Compilation { - Compilation::Continue - } - /// Called after analysis. Return value instructs the compiler whether to - /// continue the compilation afterwards (defaults to `Compilation::Continue`) - fn after_analysis<'tcx>( - &mut self, - _compiler: &interface::Compiler, - _queries: &'tcx Queries<'tcx>, - ) -> Compilation { - Compilation::Continue - } -} - -#[derive(Default)] -pub struct TimePassesCallbacks { - time_passes: Option, -} - -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 --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) - .then(|| config.opts.unstable_opts.time_passes_format); - config.opts.trimmed_def_paths = true; - } -} - -pub fn diagnostics_registry() -> Registry { - Registry::new(rustc_errors::codes::DIAGNOSTICS) -} - -/// This is the primary entry point for rustc. -pub struct RunCompiler<'a, 'b> { - at_args: &'a [String], - callbacks: &'b mut (dyn Callbacks + Send), - file_loader: Option>, - make_codegen_backend: - Option Box + Send>>, - using_internal_features: Arc, -} - -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, - make_codegen_backend: None, - using_internal_features: Arc::default(), - } - } - - /// Set a custom codegen backend. - /// - /// 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< - Box Box + Send>, - >, - ) -> &mut Self { - self.make_codegen_backend = make_codegen_backend; - self - } - - /// Load files from sources other than the file system. - /// - /// 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>, - ) -> &mut Self { - self.file_loader = file_loader; - self - } - - /// Set the session-global flag that checks whether internal features have been used, - /// suppressing the message about submitting an issue in ICEs when enabled. - #[must_use] - pub fn set_using_internal_features(mut self, using_internal_features: Arc) -> Self { - self.using_internal_features = using_internal_features; - self - } - - /// Parse args and run the compiler. - pub fn run(self) -> interface::Result<()> { - run_compiler( - self.at_args, - self.callbacks, - self.file_loader, - self.make_codegen_backend, - self.using_internal_features, - ) - } -} - -fn run_compiler( - at_args: &[String], - callbacks: &mut (dyn Callbacks + Send), - file_loader: Option>, - make_codegen_backend: Option< - Box Box + Send>, - >, - using_internal_features: Arc, -) -> interface::Result<()> { - let mut default_early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default()); - - // Throw away the first argument, the name of the binary. - // In case of at_args being empty, as might be the case by - // passing empty argument array to execve under some platforms, - // just use an empty slice. - // - // This situation was possible before due to arg_expand_all being - // called before removing the argument, enabling a crash by calling - // the compiler with @empty_file as argv[0] and no more arguments. - let at_args = at_args.get(1..).unwrap_or_default(); - - let args = args::arg_expand_all(&default_early_dcx, at_args)?; - - let Some(matches) = handle_options(&default_early_dcx, &args) else { return Ok(()) }; - - let sopts = config::build_session_options(&mut default_early_dcx, &matches); - - if let Some(ref code) = matches.opt_str("explain") { - handle_explain(&default_early_dcx, diagnostics_registry(), code, sopts.color); - return Ok(()); - } - - let (odir, ofile) = make_output(&matches); - let mut config = interface::Config { - opts: sopts, - crate_cfg: matches.opt_strs("cfg"), - crate_check_cfg: matches.opt_strs("check-cfg"), - input: Input::File(PathBuf::new()), - output_file: ofile, - output_dir: odir, - ice_file: ice_path().clone(), - file_loader, - locale_resources: DEFAULT_LOCALE_RESOURCES, - lint_caps: Default::default(), - psess_created: None, - hash_untracked_state: None, - register_lints: None, - override_queries: None, - make_codegen_backend, - registry: diagnostics_registry(), - using_internal_features, - expanded_args: args, - }; - - let has_input = match make_input(&default_early_dcx, &matches.free) { - Err(reported) => return Err(reported), - Ok(Some(input)) => { - config.input = input; - true // has input: normal compilation - } - Ok(None) => match matches.free.len() { - 0 => false, // no input: we will exit early - 1 => panic!("make_input should have provided valid inputs"), - _ => default_early_dcx.early_fatal(format!( - "multiple input filenames provided (first two filenames are `{}` and `{}`)", - matches.free[0], matches.free[1], - )), - }, - }; - - drop(default_early_dcx); - - callbacks.config(&mut config); - - interface::run_compiler(config, |compiler| { - let sess = &compiler.sess; - let codegen_backend = &*compiler.codegen_backend; - - // This is used for early exits unrelated to errors. E.g. when just - // printing some information without compiling, or exiting immediately - // after parsing, etc. - let early_exit = || { - if let Some(guar) = sess.dcx().has_errors() { Err(guar) } else { Ok(()) } - }; - - // This implements `-Whelp`. It should be handled very early, like - // `--help`/`-Zhelp`/`-Chelp`. This is the earliest it can run, because - // it must happen after lints are registered, during session creation. - if sess.opts.describe_lints { - describe_lints(sess); - return early_exit(); - } - - let early_dcx = EarlyDiagCtxt::new(sess.opts.error_format); - - if print_crate_info(&early_dcx, codegen_backend, sess, has_input) == Compilation::Stop { - return early_exit(); - } - - if !has_input { - early_dcx.early_fatal("no input filename given"); // this is fatal - } - - if !sess.opts.unstable_opts.ls.is_empty() { - list_metadata(&early_dcx, sess, &*codegen_backend.metadata_loader()); - return early_exit(); - } - - if sess.opts.unstable_opts.link_only { - process_rlink(sess, compiler); - return early_exit(); - } - - let linker = compiler.enter(|queries| { - let early_exit = || early_exit().map(|_| None); - queries.parse()?; - - if let Some(ppm) = &sess.opts.pretty { - if ppm.needs_ast_map() { - queries.global_ctxt()?.enter(|tcx| { - tcx.ensure().early_lint_checks(()); - pretty::print(sess, *ppm, pretty::PrintExtra::NeedsAstMap { tcx }); - Ok(()) - })?; - - queries.write_dep_info()?; - } else { - let krate = queries.parse()?; - pretty::print( - sess, - *ppm, - pretty::PrintExtra::AfterParsing { krate: &*krate.borrow() }, - ); - } - trace!("finished pretty-printing"); - return early_exit(); - } - - if callbacks.after_crate_root_parsing(compiler, queries) == Compilation::Stop { - return early_exit(); - } - - if sess.opts.unstable_opts.parse_only || sess.opts.unstable_opts.show_span.is_some() { - return early_exit(); - } - - // Make sure name resolution and macro expansion is run. - queries.global_ctxt()?.enter(|tcx| tcx.resolver_for_lowering()); - - if callbacks.after_expansion(compiler, queries) == Compilation::Stop { - return early_exit(); - } - - queries.write_dep_info()?; - - if sess.opts.output_types.contains_key(&OutputType::DepInfo) - && sess.opts.output_types.len() == 1 - { - return early_exit(); - } - - if sess.opts.unstable_opts.no_analysis { - return early_exit(); - } - - queries.global_ctxt()?.enter(|tcx| tcx.analysis(()))?; - - if callbacks.after_analysis(compiler, queries) == Compilation::Stop { - return early_exit(); - } - - let linker = queries.codegen_and_build_linker()?; - - // This must run after monomorphization so that all generic types - // have been instantiated. - if sess.opts.unstable_opts.print_type_sizes { - sess.code_stats.print_type_sizes(); - } - - if sess.opts.unstable_opts.print_vtable_sizes { - let crate_name = queries.global_ctxt()?.enter(|tcx| tcx.crate_name(LOCAL_CRATE)); - - sess.code_stats.print_vtable_sizes(crate_name); - } - - Ok(Some(linker)) - })?; - - // Linking is done outside the `compiler.enter()` so that the - // `GlobalCtxt` within `Queries` can be freed as early as possible. - if let Some(linker) = linker { - let _timer = sess.timer("link"); - linker.link(sess, codegen_backend)? - } - - if sess.opts.unstable_opts.print_fuel.is_some() { - eprintln!( - "Fuel used by {}: {}", - sess.opts.unstable_opts.print_fuel.as_ref().unwrap(), - sess.print_fuel.load(Ordering::SeqCst) - ); - } - - Ok(()) - }) -} - -// Extract output directory and file from matches. -fn make_output(matches: &getopts::Matches) -> (Option, Option) { - let odir = matches.opt_str("out-dir").map(|o| PathBuf::from(&o)); - let ofile = matches.opt_str("o").map(|o| match o.as_str() { - "-" => OutFileName::Stdout, - path => OutFileName::Real(PathBuf::from(path)), - }); - (odir, ofile) -} - -// Extract input (string or file and optional path) from matches. -fn make_input( - early_dcx: &EarlyDiagCtxt, - free_matches: &[String], -) -> Result, ErrorGuaranteed> { - if free_matches.len() == 1 { - let ifile = &free_matches[0]; - if ifile == "-" { - let mut src = String::new(); - if io::stdin().read_to_string(&mut src).is_err() { - // Immediately stop compilation if there was an issue reading - // the input (for example if the input stream is not UTF-8). - let reported = early_dcx - .early_err("couldn't read from stdin, as it did not contain valid UTF-8"); - return Err(reported); - } - if let Ok(path) = env::var("UNSTABLE_RUSTDOC_TEST_PATH") { - let line = env::var("UNSTABLE_RUSTDOC_TEST_LINE").expect( - "when UNSTABLE_RUSTDOC_TEST_PATH is set \ - UNSTABLE_RUSTDOC_TEST_LINE also needs to be set", - ); - let line = isize::from_str_radix(&line, 10) - .expect("UNSTABLE_RUSTDOC_TEST_LINE needs to be an number"); - let file_name = FileName::doc_test_source_code(PathBuf::from(path), line); - Ok(Some(Input::Str { name: file_name, input: src })) - } else { - Ok(Some(Input::Str { name: FileName::anon_source_code(&src), input: src })) - } - } else { - Ok(Some(Input::File(PathBuf::from(ifile)))) - } - } else { - Ok(None) - } -} - -/// Whether to stop or continue compilation. -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum Compilation { - Stop, - Continue, -} - -fn handle_explain(early_dcx: &EarlyDiagCtxt, registry: Registry, code: &str, color: ColorConfig) { - // Allow "E0123" or "0123" form. - let upper_cased_code = code.to_ascii_uppercase(); - let start = if upper_cased_code.starts_with('E') { 1 } else { 0 }; - if let Ok(code) = upper_cased_code[start..].parse::() - && let Ok(description) = registry.try_find_description(ErrCode::from_u32(code)) - { - let mut is_in_code_block = false; - let mut text = String::new(); - // Slice off the leading newline and print. - for line in description.lines() { - let indent_level = - line.find(|c: char| !c.is_whitespace()).unwrap_or_else(|| line.len()); - let dedented_line = &line[indent_level..]; - if dedented_line.starts_with("```") { - is_in_code_block = !is_in_code_block; - text.push_str(&line[..(indent_level + 3)]); - } else if is_in_code_block && dedented_line.starts_with("# ") { - continue; - } else { - text.push_str(line); - } - text.push('\n'); - } - if io::stdout().is_terminal() { - show_md_content_with_pager(&text, color); - } else { - safe_print!("{text}"); - } - } else { - early_dcx.early_fatal(format!("{code} is not a valid error code")); - } -} - -/// If color is always or auto, print formatted & colorized markdown. If color is never or -/// if formatted printing fails, print the raw text. -/// -/// Prefers a pager, falls back standard print -fn show_md_content_with_pager(content: &str, color: ColorConfig) { - let mut fallback_to_println = false; - let pager_name = env::var_os("PAGER").unwrap_or_else(|| { - if cfg!(windows) { OsString::from("more.com") } else { OsString::from("less") } - }); - - let mut cmd = Command::new(&pager_name); - // FIXME: find if other pagers accept color options - let mut print_formatted = if pager_name == "less" { - cmd.arg("-r"); - true - } else { - ["bat", "catbat", "delta"].iter().any(|v| *v == pager_name) - }; - - if color == ColorConfig::Never { - print_formatted = false; - } else if color == ColorConfig::Always { - print_formatted = true; - } - - let mdstream = markdown::MdStream::parse_str(content); - let bufwtr = markdown::create_stdout_bufwtr(); - let mut mdbuf = bufwtr.buffer(); - if mdstream.write_termcolor_buf(&mut mdbuf).is_err() { - print_formatted = false; - } - - if let Ok(mut pager) = cmd.stdin(Stdio::piped()).spawn() { - if let Some(pipe) = pager.stdin.as_mut() { - let res = if print_formatted { - pipe.write_all(mdbuf.as_slice()) - } else { - pipe.write_all(content.as_bytes()) - }; - - if res.is_err() { - fallback_to_println = true; - } - } - - if pager.wait().is_err() { - fallback_to_println = true; - } - } else { - fallback_to_println = true; - } - - // If pager fails for whatever reason, we should still print the content - // to standard output - if fallback_to_println { - let fmt_success = match color { - ColorConfig::Auto => io::stdout().is_terminal() && bufwtr.print(&mdbuf).is_ok(), - ColorConfig::Always => bufwtr.print(&mdbuf).is_ok(), - ColorConfig::Never => false, - }; - - if !fmt_success { - safe_print!("{content}"); - } - } -} - -fn process_rlink(sess: &Session, compiler: &interface::Compiler) { - assert!(sess.opts.unstable_opts.link_only); - let dcx = sess.dcx(); - if let Input::File(file) = &sess.io.input { - let rlink_data = fs::read(file).unwrap_or_else(|err| { - dcx.emit_fatal(RlinkUnableToRead { err }); - }); - let (codegen_results, outputs) = match CodegenResults::deserialize_rlink(sess, rlink_data) { - Ok((codegen, outputs)) => (codegen, outputs), - Err(err) => { - match err { - CodegenErrors::WrongFileType => dcx.emit_fatal(RLinkWrongFileType), - CodegenErrors::EmptyVersionNumber => dcx.emit_fatal(RLinkEmptyVersionNumber), - CodegenErrors::EncodingVersionMismatch { version_array, rlink_version } => sess - .dcx() - .emit_fatal(RLinkEncodingVersionMismatch { version_array, rlink_version }), - CodegenErrors::RustcVersionMismatch { rustc_version } => { - dcx.emit_fatal(RLinkRustcVersionMismatch { - rustc_version, - current_version: sess.cfg_version, - }) - } - }; - } - }; - if compiler.codegen_backend.link(sess, codegen_results, &outputs).is_err() { - FatalError.raise(); - } - } else { - dcx.emit_fatal(RlinkNotAFile {}); - } -} - -fn list_metadata(early_dcx: &EarlyDiagCtxt, sess: &Session, metadata_loader: &dyn MetadataLoader) { - match sess.io.input { - Input::File(ref ifile) => { - let path = &(*ifile); - let mut v = Vec::new(); - locator::list_file_metadata( - &sess.target, - path, - metadata_loader, - &mut v, - &sess.opts.unstable_opts.ls, - sess.cfg_version, - ) - .unwrap(); - safe_println!("{}", String::from_utf8(v).unwrap()); - } - Input::Str { .. } => { - early_dcx.early_fatal("cannot list metadata for stdin"); - } - } -} - -fn print_crate_info( - early_dcx: &EarlyDiagCtxt, - codegen_backend: &dyn CodegenBackend, - sess: &Session, - parse_attrs: bool, -) -> Compilation { - use rustc_session::config::PrintKind::*; - - // This import prevents the following code from using the printing macros - // used by the rest of the module. Within this function, we only write to - // the output specified by `sess.io.output_file`. - #[allow(unused_imports)] - use {do_not_use_safe_print as safe_print, do_not_use_safe_print as safe_println}; - - // NativeStaticLibs and LinkArgs are special - printed during linking - // (empty iterator returns true) - if sess.opts.prints.iter().all(|p| p.kind == NativeStaticLibs || p.kind == LinkArgs) { - return Compilation::Continue; - } - - let attrs = if parse_attrs { - let result = parse_crate_attrs(sess); - match result { - Ok(attrs) => Some(attrs), - Err(parse_error) => { - parse_error.emit(); - return Compilation::Stop; - } - } - } else { - None - }; - - for req in &sess.opts.prints { - let mut crate_info = String::new(); - macro println_info($($arg:tt)*) { - crate_info.write_fmt(format_args!("{}\n", format_args!($($arg)*))).unwrap() - } - - match req.kind { - TargetList => { - let mut targets = rustc_target::spec::TARGETS.to_vec(); - targets.sort_unstable(); - println_info!("{}", targets.join("\n")); - } - Sysroot => println_info!("{}", sess.sysroot.display()), - TargetLibdir => println_info!("{}", sess.target_tlib_path.dir.display()), - TargetSpec => { - println_info!("{}", serde_json::to_string_pretty(&sess.target.to_json()).unwrap()); - } - AllTargetSpecs => { - let mut targets = BTreeMap::new(); - for name in rustc_target::spec::TARGETS { - let triple = TargetTriple::from_triple(name); - let target = Target::expect_builtin(&triple); - targets.insert(name, target.to_json()); - } - println_info!("{}", serde_json::to_string_pretty(&targets).unwrap()); - } - FileNames => { - let Some(attrs) = attrs.as_ref() else { - // no crate attributes, print out an error and exit - return Compilation::Continue; - }; - let t_outputs = rustc_interface::util::build_output_filenames(attrs, sess); - let id = rustc_session::output::find_crate_name(sess, attrs); - let crate_types = collect_crate_types(sess, attrs); - for &style in &crate_types { - let fname = - rustc_session::output::filename_for_input(sess, style, id, &t_outputs); - println_info!("{}", fname.as_path().file_name().unwrap().to_string_lossy()); - } - } - CrateName => { - let Some(attrs) = attrs.as_ref() else { - // no crate attributes, print out an error and exit - return Compilation::Continue; - }; - let id = rustc_session::output::find_crate_name(sess, attrs); - println_info!("{id}"); - } - Cfg => { - let mut cfgs = sess - .psess - .config - .iter() - .filter_map(|&(name, value)| { - // Note that crt-static is a specially recognized cfg - // directive that's printed out here as part of - // rust-lang/rust#37406, but in general the - // `target_feature` cfg is gated under - // rust-lang/rust#29717. For now this is just - // specifically allowing the crt-static cfg and that's - // it, this is intended to get into Cargo and then go - // through to build scripts. - if (name != sym::target_feature || value != Some(sym::crt_dash_static)) - && !sess.is_nightly_build() - && find_gated_cfg(|cfg_sym| cfg_sym == name).is_some() - { - return None; - } - - if let Some(value) = value { - Some(format!("{name}=\"{value}\"")) - } else { - Some(name.to_string()) - } - }) - .collect::>(); - - cfgs.sort(); - for cfg in cfgs { - println_info!("{cfg}"); - } - } - CallingConventions => { - let mut calling_conventions = rustc_target::spec::abi::all_names(); - calling_conventions.sort_unstable(); - println_info!("{}", calling_conventions.join("\n")); - } - RelocationModels - | CodeModels - | TlsModels - | TargetCPUs - | StackProtectorStrategies - | TargetFeatures => { - codegen_backend.print(req, &mut crate_info, sess); - } - // Any output here interferes with Cargo's parsing of other printed output - NativeStaticLibs => {} - LinkArgs => {} - SplitDebuginfo => { - use rustc_target::spec::SplitDebuginfo::{Off, Packed, Unpacked}; - - for split in &[Off, Packed, Unpacked] { - if sess.target.options.supported_split_debuginfo.contains(split) { - println_info!("{split}"); - } - } - } - DeploymentTarget => { - use rustc_target::spec::current_apple_deployment_target; - - if sess.target.is_like_osx { - let (major, minor) = current_apple_deployment_target(&sess.target) - .expect("unknown Apple target OS"); - println_info!("deployment_target={}", format!("{major}.{minor}")) - } else { - early_dcx - .early_fatal("only Apple targets currently support deployment version info") - } - } - } - - req.out.overwrite(&crate_info, sess); - } - Compilation::Stop -} - -/// Prints version information -/// -/// NOTE: this is a macro to support drivers built at a different time than the main `rustc_driver` crate. -pub macro version($early_dcx: expr, $binary: literal, $matches: expr) { - fn unw(x: Option<&str>) -> &str { - x.unwrap_or("unknown") - } - $crate::version_at_macro_invocation( - $early_dcx, - $binary, - $matches, - unw(option_env!("CFG_VERSION")), - unw(option_env!("CFG_VER_HASH")), - unw(option_env!("CFG_VER_DATE")), - unw(option_env!("CFG_RELEASE")), - ) -} - -#[doc(hidden)] // use the macro instead -pub fn version_at_macro_invocation( - early_dcx: &EarlyDiagCtxt, - binary: &str, - matches: &getopts::Matches, - version: &str, - commit_hash: &str, - commit_date: &str, - release: &str, -) { - let verbose = matches.opt_present("verbose"); - - safe_println!("{binary} {version}"); - - if verbose { - safe_println!("binary: {binary}"); - safe_println!("commit-hash: {commit_hash}"); - safe_println!("commit-date: {commit_date}"); - safe_println!("host: {}", config::host_triple()); - safe_println!("release: {release}"); - - let debug_flags = matches.opt_strs("Z"); - let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend=")); - let opts = config::Options::default(); - let sysroot = filesearch::materialize_sysroot(opts.maybe_sysroot.clone()); - let target = config::build_target_config(early_dcx, &opts, &sysroot); - - get_codegen_backend(early_dcx, &sysroot, backend_name, &target).print_version(); - } -} - -fn usage(verbose: bool, include_unstable_options: bool, nightly_build: bool) { - let groups = if verbose { config::rustc_optgroups() } else { config::rustc_short_optgroups() }; - let mut options = getopts::Options::new(); - for option in groups.iter().filter(|x| include_unstable_options || x.is_stable()) { - (option.apply)(&mut options); - } - let message = "Usage: rustc [OPTIONS] INPUT"; - let nightly_help = if nightly_build { - "\n -Z help Print unstable compiler options" - } else { - "" - }; - let verbose_help = if verbose { - "" - } else { - "\n --help -v Print the full set of options rustc accepts" - }; - let at_path = if verbose { - " @path Read newline separated options from `path`\n" - } else { - "" - }; - safe_println!( - "{options}{at_path}\nAdditional help: +#![allow(rustc::untranslatable_diagnostic)]#![doc(html_root_url=//if let _=(){}; +"https://doc.rust-lang.org/nightly/nightly-rustc/")]#![doc(rust_logo)]#![//({}); +feature(rustdoc_internals)]#![allow(internal_features )]#![feature(decl_macro)]# +![feature(let_chains)]#![feature(panic_update_hook)]#![feature(//*&*&();((),()); +result_flattening)]#[macro_use]extern crate tracing;use rustc_ast as ast;use//3; +rustc_codegen_ssa::{traits::CodegenBackend,CodegenErrors,CodegenResults};use//3; +rustc_const_eval::CTRL_C_RECEIVED;use rustc_data_structures::profiling::{//({}); +get_resident_set_size,print_time_passes_entry,TimePassesFormat,};use//if true{}; +rustc_errors::emitter::stderr_destination;use rustc_errors::registry::Registry; +use rustc_errors::{markdown,ColorConfig,DiagCtxt,ErrCode,ErrorGuaranteed,//({}); +FatalError,PResult,};use rustc_feature::find_gated_cfg;use rustc_interface:://3; +util::{self,get_codegen_backend};use rustc_interface::{interface,Queries};use//; +rustc_lint::unerased_lint_store;use rustc_metadata::creader::MetadataLoader;use +rustc_metadata::locator;use rustc_session::config::{nightly_options,CG_OPTIONS// +,Z_OPTIONS};use rustc_session::config::{ErrorOutputType,Input,OutFileName,//{;}; +OutputType};use rustc_session::getopts::{self,Matches};use rustc_session::lint// +::{Lint,LintId};use rustc_session::output::collect_crate_types;use//loop{break}; +rustc_session::{config,filesearch,EarlyDiagCtxt ,Session};use rustc_span::def_id +::LOCAL_CRATE;use rustc_span::source_map::FileLoader;use rustc_span::symbol:://; +sym;use rustc_span::FileName;use rustc_target::json::ToJson;use rustc_target::// +spec::{Target,TargetTriple};use std::cmp::max;use std::collections::BTreeMap;//; +use std::env;use std::ffi::OsString;use std ::fmt::Write as _;use std::fs::{self +,File};use std::io::{self,IsTerminal,Read,Write};use std::panic::{self,//*&*&(); +catch_unwind,PanicInfo};use std::path::PathBuf ;use std::process::{self,Command, +Stdio};use std::str;use std::sync::atomic::{AtomicBool,Ordering};use std::sync// +::{Arc,OnceLock};use std::time::{Instant,SystemTime};use time::{Date,//let _=(); +OffsetDateTime,Time};#[allow(unused_macros)]macro do_not_use_print($($t:tt)*){// +std::compile_error!(//if let _=(){};*&*&();((),());if let _=(){};*&*&();((),()); +"Don't use `print` or `println` here, use `safe_print` or `safe_println` instead" +)}#[allow(unused_macros)]macro do_not_use_safe_print($($t:tt)*){std:://let _=(); +compile_error!(//*&*&();((),());((),());((),());((),());((),());((),());((),()); +"Don't use `safe_print` or `safe_println` here, use `println_info` instead") }#[ +allow(unused_imports)]use{do_not_use_print as print,do_not_use_print as println +};pub mod args;pub mod pretty;#[macro_use]mod print;mod session_diagnostics;#[// +cfg(all(unix,any(target_env="gnu",target_os ="macos")))]mod signal_handler;#[cfg +(not(all(unix,any(target_env="gnu", target_os="macos"))))]mod signal_handler{pub +(super)fn install(){} }use crate::session_diagnostics::{RLinkEmptyVersionNumber, +RLinkEncodingVersionMismatch,RLinkRustcVersionMismatch,RLinkWrongFileType,//{;}; +RlinkNotAFile,RlinkUnableToRead,};rustc_fluent_macro::fluent_messages!{//*&*&(); +"../messages.ftl"}pub static DEFAULT_LOCALE_RESOURCES:&[&str]=&[crate:://*&*&(); +DEFAULT_LOCALE_RESOURCE,rustc_ast_lowering::DEFAULT_LOCALE_RESOURCE,//if true{}; +rustc_ast_passes::DEFAULT_LOCALE_RESOURCE,rustc_attr::DEFAULT_LOCALE_RESOURCE,// +rustc_borrowck::DEFAULT_LOCALE_RESOURCE,rustc_builtin_macros:://((),());((),()); +DEFAULT_LOCALE_RESOURCE,rustc_codegen_ssa::DEFAULT_LOCALE_RESOURCE,//let _=||(); +rustc_const_eval::DEFAULT_LOCALE_RESOURCE ,rustc_errors::DEFAULT_LOCALE_RESOURCE +,rustc_expand::DEFAULT_LOCALE_RESOURCE,rustc_hir_analysis:://let _=();if true{}; +DEFAULT_LOCALE_RESOURCE,rustc_hir_typeck::DEFAULT_LOCALE_RESOURCE,//loop{break}; +rustc_incremental::DEFAULT_LOCALE_RESOURCE ,rustc_infer::DEFAULT_LOCALE_RESOURCE +,rustc_interface::DEFAULT_LOCALE_RESOURCE,rustc_lint::DEFAULT_LOCALE_RESOURCE,// +rustc_metadata::DEFAULT_LOCALE_RESOURCE,rustc_middle::DEFAULT_LOCALE_RESOURCE,// +rustc_mir_build::DEFAULT_LOCALE_RESOURCE,rustc_mir_dataflow:://((),());let _=(); +DEFAULT_LOCALE_RESOURCE,rustc_mir_transform::DEFAULT_LOCALE_RESOURCE,//let _=(); +rustc_monomorphize::DEFAULT_LOCALE_RESOURCE,rustc_parse:://if true{};let _=||(); +DEFAULT_LOCALE_RESOURCE,rustc_passes::DEFAULT_LOCALE_RESOURCE,//((),());((),()); +rustc_pattern_analysis::DEFAULT_LOCALE_RESOURCE,rustc_privacy:://*&*&();((),()); +DEFAULT_LOCALE_RESOURCE,rustc_query_system::DEFAULT_LOCALE_RESOURCE,//if true{}; +rustc_resolve::DEFAULT_LOCALE_RESOURCE,rustc_session::DEFAULT_LOCALE_RESOURCE,// +rustc_trait_selection::DEFAULT_LOCALE_RESOURCE,rustc_ty_utils:://*&*&();((),()); +DEFAULT_LOCALE_RESOURCE,];pub const EXIT_SUCCESS:i32=(0);pub const EXIT_FAILURE: +i32=((((((((((((((((((1))))))))))))))))));pub const DEFAULT_BUG_REPORT_URL:&str= +"https://github.com/rust-lang/rust/issues/new\ + ?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md" +;pub trait Callbacks{fn config(&mut self,_config:&mut interface::Config){}fn//3; +after_crate_root_parsing<'tcx>(&mut self,_compiler:&interface::Compiler,//{();}; +_queries:&'tcx Queries<'tcx>,)->Compilation{Compilation::Continue}fn//if true{}; +after_expansion<'tcx>(&mut self,_compiler:&interface::Compiler,_queries:&'tcx//; +Queries<'tcx>,)->Compilation{Compilation:: Continue}fn after_analysis<'tcx>(&mut +self,_compiler:&interface::Compiler,_queries:&'tcx Queries<'tcx>,)->//if true{}; +Compilation{Compilation::Continue}}#[derive(Default)]pub struct//*&*&();((),()); +TimePassesCallbacks{time_passes:Option,}impl Callbacks for//3; +TimePassesCallbacks{#[allow(rustc::bad_opt_access)] fn config(&mut self,config:& +mut interface::Config){;self.time_passes=(config.opts.prints.is_empty()&&config. +opts.unstable_opts.time_passes).then(||config.opts.unstable_opts.//loop{break;}; +time_passes_format);{();};{();};config.opts.trimmed_def_paths=true;({});}}pub fn +diagnostics_registry()->Registry{Registry ::new(rustc_errors::codes::DIAGNOSTICS +)}pub struct RunCompiler<'a,'b>{at_args:&'a[String],callbacks:&'b mut(dyn//({}); +Callbacks+Send),file_loader:Option>,//loop{break}; +make_codegen_backend:OptionBox+Send>>,using_internal_features:Arc,}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,make_codegen_backend:None,using_internal_features:Arc ::default(),}}pub fn +set_make_codegen_backend(&mut self,make_codegen_backend:OptionBox+Send>,>,)->&mut Self{let _=||();self. +make_codegen_backend=make_codegen_backend;;self}pub fn set_file_loader(&mut self +,file_loader:Option>,)->&mut Self{let _=||();self. +file_loader=file_loader;3;self}#[must_use]pub fn set_using_internal_features(mut +self,using_internal_features:Arc)->Self{let _=||();loop{break};self. +using_internal_features=using_internal_features;let _=();self}pub fn run(self)-> +interface::Result<()>{run_compiler( self.at_args,self.callbacks,self.file_loader +,self.make_codegen_backend,self.using_internal_features,)}}fn run_compiler(//(); +at_args:&[String],callbacks:&mut(dyn Callbacks+Send),file_loader:Option>,make_codegen_backend:OptionBox+Send >,>,using_internal_features:Arc,)->interface::Result<()>{*&*&();let mut default_early_dcx= +EarlyDiagCtxt::new(ErrorOutputType::default());3;3;let at_args=at_args.get(1..). +unwrap_or_default();;let args=args::arg_expand_all(&default_early_dcx,at_args)?; +let Some(matches)=handle_options(&default_early_dcx,&args)else{return Ok(())};;; +let sopts=config::build_session_options(&mut default_early_dcx,&matches);;if let +Some(ref code)=matches.opt_str("explain"){{;};handle_explain(&default_early_dcx, +diagnostics_registry(),code,sopts.color);3;3;return Ok(());3;}3;let(odir,ofile)= +make_output(&matches);3;3;let mut config=interface::Config{opts:sopts,crate_cfg: +matches.opt_strs(("cfg")),crate_check_cfg:(matches.opt_strs("check-cfg")),input: +Input::File(PathBuf::new()) ,output_file:ofile,output_dir:odir,ice_file:ice_path +().clone(),file_loader,locale_resources:DEFAULT_LOCALE_RESOURCES,lint_caps://(); +Default::default(),psess_created :None,hash_untracked_state:None,register_lints: +None,override_queries:None,make_codegen_backend ,registry:diagnostics_registry() +,using_internal_features,expanded_args:args,};;;let has_input=match make_input(& +default_early_dcx,(&matches.free)){Err(reported) =>return Err(reported),Ok(Some( +input))=>{;config.input=input;true}Ok(None)=>match matches.free.len(){0=>false,1 +=>(panic!("make_input should have provided valid inputs")),_=>default_early_dcx. +early_fatal(format!(//if let _=(){};*&*&();((),());if let _=(){};*&*&();((),()); +"multiple input filenames provided (first two filenames are `{}` and `{}`)",//3; +matches.free[0],matches.free[1],)),},};;drop(default_early_dcx);callbacks.config +(&mut config);;interface::run_compiler(config,|compiler|{let sess=&compiler.sess +;;;let codegen_backend=&*compiler.codegen_backend;let early_exit=||{if let Some( +guar)=sess.dcx().has_errors(){Err(guar)}else{Ok(())}};loop{break;};if sess.opts. +describe_lints{3;describe_lints(sess);3;3;return early_exit();3;};let early_dcx= +EarlyDiagCtxt::new(sess.opts.error_format);{();};if print_crate_info(&early_dcx, +codegen_backend,sess,has_input)==Compilation::Stop{();return early_exit();3;}if! +has_input{{;};early_dcx.early_fatal("no input filename given");();}if!sess.opts. +unstable_opts.ls.is_empty(){{;};list_metadata(&early_dcx,sess,&*codegen_backend. +metadata_loader());;;return early_exit();;}if sess.opts.unstable_opts.link_only{ +process_rlink(sess,compiler);;;return early_exit();;}let linker=compiler.enter(| +queries|{3;let early_exit=||early_exit().map(|_|None);;;queries.parse()?;;if let +Some(ppm)=&sess.opts.pretty{if ppm.needs_ast_map(){;queries.global_ctxt()?.enter +(|tcx|{3;tcx.ensure().early_lint_checks(());3;3;pretty::print(sess,*ppm,pretty:: +PrintExtra::NeedsAstMap{tcx});;Ok(())})?;;;queries.write_dep_info()?;;}else{;let +krate=queries.parse()?;;pretty::print(sess,*ppm,pretty::PrintExtra::AfterParsing +{krate:&*krate.borrow()},);();}();trace!("finished pretty-printing");3;3;return +early_exit();let _=();}if callbacks.after_crate_root_parsing(compiler,queries)== +Compilation::Stop{;return early_exit();;}if sess.opts.unstable_opts.parse_only|| +sess.opts.unstable_opts.show_span.is_some(){();return early_exit();3;}3;queries. +global_ctxt()?.enter(|tcx|tcx.resolver_for_lowering());loop{break};if callbacks. +after_expansion(compiler,queries)==Compilation::Stop{3;return early_exit();3;}3; +queries.write_dep_info()?;3;if sess.opts.output_types.contains_key(&OutputType:: +DepInfo)&&sess.opts.output_types.len()==1{3;return early_exit();3;}if sess.opts. +unstable_opts.no_analysis{;return early_exit();;};queries.global_ctxt()?.enter(| +tcx|tcx.analysis(()))?;if true{};if callbacks.after_analysis(compiler,queries)== +Compilation::Stop{((),());return early_exit();*&*&();}*&*&();let linker=queries. +codegen_and_build_linker()?;3;if sess.opts.unstable_opts.print_type_sizes{;sess. +code_stats.print_type_sizes();3;}if sess.opts.unstable_opts.print_vtable_sizes{; +let crate_name=queries.global_ctxt()?.enter(|tcx|tcx.crate_name(LOCAL_CRATE));;; +sess.code_stats.print_vtable_sizes(crate_name);;}Ok(Some(linker))})?;if let Some +(linker)=linker{;let _timer=sess.timer("link");linker.link(sess,codegen_backend) +?}if sess.opts.unstable_opts.print_fuel.is_some(){if true{};if true{};eprintln!( +"Fuel used by {}: {}",sess.opts.unstable_opts.print_fuel .as_ref().unwrap(),sess +.print_fuel.load(Ordering::SeqCst));;}Ok(())})}fn make_output(matches:&getopts:: +Matches)->(Option,Option){*&*&();let odir=matches.opt_str( +"out-dir").map(|o|PathBuf::from(&o));();3;let ofile=matches.opt_str("o").map(|o| +match o.as_str(){"-"=>OutFileName ::Stdout,path=>OutFileName::Real(PathBuf::from +(path)),});3;(odir,ofile)}fn make_input(early_dcx:&EarlyDiagCtxt,free_matches:&[ +String],)->Result,ErrorGuaranteed>{if free_matches.len()==1{();let +ifile=&free_matches[0];;if ifile=="-"{;let mut src=String::new();if io::stdin(). +read_to_string(&mut src).is_err(){loop{break;};let reported=early_dcx.early_err( +"couldn't read from stdin, as it did not contain valid UTF-8");();();return Err( +reported);;}if let Ok(path)=env::var("UNSTABLE_RUSTDOC_TEST_PATH"){;let line=env +::var((((((((((((((((((("UNSTABLE_RUSTDOC_TEST_LINE")))))))))))))))))) ).expect( +"when UNSTABLE_RUSTDOC_TEST_PATH is set \ + UNSTABLE_RUSTDOC_TEST_LINE also needs to be set" +,);*&*&();((),());if let _=(){};let line=isize::from_str_radix(&line,10).expect( +"UNSTABLE_RUSTDOC_TEST_LINE needs to be an number");3;3;let file_name=FileName:: +doc_test_source_code(PathBuf::from(path),line);let _=();Ok(Some(Input::Str{name: +file_name,input:src}))}else{Ok (Some(Input::Str{name:FileName::anon_source_code( +&src),input:src}))}}else{(Ok(Some(Input::File(PathBuf::from(ifile)))))}}else{Ok( +None)}}#[derive(Copy,Clone,Debug,Eq,PartialEq)]pub enum Compilation{Stop,//({}); +Continue,}fn handle_explain(early_dcx:&EarlyDiagCtxt,registry:Registry,code:&//; +str,color:ColorConfig){;let upper_cased_code=code.to_ascii_uppercase();let start +=if upper_cased_code.starts_with('E'){1}else{0};((),());((),());if let Ok(code)= +upper_cased_code[start..].parse::()&&let Ok(description)=registry.//*&*&(); +try_find_description(ErrCode::from_u32(code)){;let mut is_in_code_block=false;;; +let mut text=String::new();3;for line in description.lines(){3;let indent_level= +line.find(|c:char|!c.is_whitespace()).unwrap_or_else(||line.len());({});({});let +dedented_line=&line[indent_level..];{;};if dedented_line.starts_with("```"){{;}; +is_in_code_block=!is_in_code_block;;;text.push_str(&line[..(indent_level+3)]);;} +else if is_in_code_block&&dedented_line.starts_with("# "){;continue;;}else{text. +push_str(line);({});}{;};text.push('\n');{;};}if io::stdout().is_terminal(){{;}; +show_md_content_with_pager(&text,color);3;}else{;safe_print!("{text}");;}}else{; +early_dcx.early_fatal(format!("{code} is not a valid error code"));let _=();}}fn +show_md_content_with_pager(content:&str,color:ColorConfig){if let _=(){};let mut +fallback_to_println=false;;let pager_name=env::var_os("PAGER").unwrap_or_else(|| +{if cfg!(windows){OsString::from("more.com")}else{OsString::from("less")}});;let +mut cmd=Command::new(&pager_name);{;};();let mut print_formatted=if pager_name== +"less"{();cmd.arg("-r");();true}else{["bat","catbat","delta"].iter().any(|v|*v== +pager_name)};;if color==ColorConfig::Never{;print_formatted=false;}else if color +==ColorConfig::Always{;print_formatted=true;;};let mdstream=markdown::MdStream:: +parse_str(content);;;let bufwtr=markdown::create_stdout_bufwtr();;let mut mdbuf= +bufwtr.buffer();{();};if mdstream.write_termcolor_buf(&mut mdbuf).is_err(){({}); +print_formatted=false;3;}if let Ok(mut pager)=cmd.stdin(Stdio::piped()).spawn(){ +if let Some(pipe)=pager.stdin.as_mut(){let _=();let res=if print_formatted{pipe. +write_all(mdbuf.as_slice())}else{pipe.write_all(content.as_bytes())};{;};if res. +is_err(){*&*&();fallback_to_println=true;{();};}}if pager.wait().is_err(){{();}; +fallback_to_println=true;*&*&();}}else{*&*&();fallback_to_println=true;{();};}if +fallback_to_println{;let fmt_success=match color{ColorConfig::Auto=>io::stdout() +.is_terminal()&&bufwtr.print(&mdbuf) .is_ok(),ColorConfig::Always=>bufwtr.print( +&mdbuf).is_ok(),ColorConfig::Never=>false,};({});if!fmt_success{{;};safe_print!( +"{content}");;}}}fn process_rlink(sess:&Session,compiler:&interface::Compiler){; +assert!(sess.opts.unstable_opts.link_only);3;;let dcx=sess.dcx();;if let Input:: +File(file)=&sess.io.input{3;let rlink_data=fs::read(file).unwrap_or_else(|err|{; +dcx.emit_fatal(RlinkUnableToRead{err});;});;;let(codegen_results,outputs)=match +CodegenResults::deserialize_rlink(sess,rlink_data){Ok((codegen,outputs))=>(//(); +codegen,outputs),Err(err)=>{((),());match err{CodegenErrors::WrongFileType=>dcx. +emit_fatal(RLinkWrongFileType),CodegenErrors::EmptyVersionNumber=>dcx.//((),()); +emit_fatal(RLinkEmptyVersionNumber),CodegenErrors::EncodingVersionMismatch{//(); +version_array,rlink_version}=>((((((((((((((sess.dcx())))))))))))))).emit_fatal( +RLinkEncodingVersionMismatch{version_array,rlink_version}),CodegenErrors:://{;}; +RustcVersionMismatch{rustc_version}=>{ dcx.emit_fatal(RLinkRustcVersionMismatch{ +rustc_version,current_version:sess.cfg_version,})}};*&*&();}};{();};if compiler. +codegen_backend.link(sess,codegen_results,&outputs).is_err(){;FatalError.raise() +;{;};}}else{();dcx.emit_fatal(RlinkNotAFile{});();}}fn list_metadata(early_dcx:& +EarlyDiagCtxt,sess:&Session,metadata_loader:& dyn MetadataLoader){match sess.io. +input{Input::File(ref ifile)=>{;let path=&(*ifile);;let mut v=Vec::new();locator +::list_file_metadata(((&sess.target)),path,metadata_loader ,(&mut v),&sess.opts. +unstable_opts.ls,sess.cfg_version,).unwrap();{;};{;};safe_println!("{}",String:: +from_utf8(v).unwrap());let _=();}Input::Str{..}=>{((),());early_dcx.early_fatal( +"cannot list metadata for stdin");loop{break};}}}fn print_crate_info(early_dcx:& +EarlyDiagCtxt,codegen_backend:&dyn CodegenBackend,sess:&Session,parse_attrs://3; +bool,)->Compilation{{;};use rustc_session::config::PrintKind::*;{;};{;};#[allow( +unused_imports)]use{do_not_use_safe_print as safe_print,do_not_use_safe_print//; +as safe_println};;if sess.opts.prints.iter().all(|p|p.kind==NativeStaticLibs||p. +kind==LinkArgs){3;return Compilation::Continue;3;};let attrs=if parse_attrs{;let +result=parse_crate_attrs(sess);let _=();match result{Ok(attrs)=>Some(attrs),Err( +parse_error)=>{;parse_error.emit();;;return Compilation::Stop;;}}}else{None};for +req in&sess.opts.prints{;let mut crate_info=String::new();macro println_info($($ +arg:tt)*){crate_info.write_fmt(format_args!("{}\n",format_args!($($arg)*))).//3; +unwrap()}{;};match req.kind{TargetList=>{();let mut targets=rustc_target::spec:: +TARGETS.to_vec();;targets.sort_unstable();println_info!("{}",targets.join("\n")) +;loop{break};}Sysroot=>println_info!("{}",sess.sysroot.display()),TargetLibdir=> +println_info!("{}",sess.target_tlib_path.dir.display()),TargetSpec=>{let _=||(); +println_info!("{}",serde_json::to_string_pretty(& sess.target.to_json()).unwrap( +));;}AllTargetSpecs=>{let mut targets=BTreeMap::new();for name in rustc_target:: +spec::TARGETS{3;let triple=TargetTriple::from_triple(name);;;let target=Target:: +expect_builtin(&triple);;;targets.insert(name,target.to_json());;}println_info!( +"{}",serde_json::to_string_pretty(&targets).unwrap());3;}FileNames=>{3;let Some( +attrs)=attrs.as_ref()else{();return Compilation::Continue;3;};3;3;let t_outputs= +rustc_interface::util::build_output_filenames(attrs,sess);;;let id=rustc_session +::output::find_crate_name(sess,attrs);;let crate_types=collect_crate_types(sess, +attrs);((),());for&style in&crate_types{*&*&();let fname=rustc_session::output:: +filename_for_input(sess,style,id,&t_outputs);;println_info!("{}",fname.as_path() +.file_name().unwrap().to_string_lossy());3;}}CrateName=>{;let Some(attrs)=attrs. +as_ref()else{3;return Compilation::Continue;3;};;;let id=rustc_session::output:: +find_crate_name(sess,attrs);3;;println_info!("{id}");;}Cfg=>{;let mut cfgs=sess. +psess.config.iter().filter_map(|&(name,value )|{if((name!=sym::target_feature)|| +value!=(Some(sym::crt_dash_static)))&&!sess.is_nightly_build()&&find_gated_cfg(| +cfg_sym|cfg_sym==name).is_some(){3;return None;3;}if let Some(value)=value{Some( +format!("{name}=\"{value}\""))}else{(Some((name.to_string())))}}).collect::>();{;};();cfgs.sort();();for cfg in cfgs{();println_info!("{cfg}");();}} +CallingConventions=>{{();};let mut calling_conventions=rustc_target::spec::abi:: +all_names();{;};();calling_conventions.sort_unstable();();();println_info!("{}", +calling_conventions.join("\n"));let _=();}RelocationModels|CodeModels|TlsModels| +TargetCPUs|StackProtectorStrategies|TargetFeatures=>{;codegen_backend.print(req, +&mut crate_info,sess);();}NativeStaticLibs=>{}LinkArgs=>{}SplitDebuginfo=>{3;use +rustc_target::spec::SplitDebuginfo::{Off,Packed,Unpacked};{;};for split in&[Off, +Packed,Unpacked]{if sess.target.options.supported_split_debuginfo.contains(//(); +split){;println_info!("{split}");;}}}DeploymentTarget=>{use rustc_target::spec:: +current_apple_deployment_target;3;if sess.target.is_like_osx{3;let(major,minor)= +current_apple_deployment_target(&sess.target) .expect("unknown Apple target OS") +;let _=();println_info!("deployment_target={}",format!("{major}.{minor}"))}else{ +early_dcx.early_fatal(//if let _=(){};if let _=(){};if let _=(){};if let _=(){}; +"only Apple targets currently support deployment version info")}}}{();};req.out. +overwrite(&crate_info,sess);{;};}Compilation::Stop}pub macro version($early_dcx: +expr,$binary:literal,$matches:expr){fn unw(x:Option<&str>)->&str{x.unwrap_or(//; +"unknown")}$crate::version_at_macro_invocation($ early_dcx,$binary,$matches,unw( +option_env!("CFG_VERSION")),unw(option_env!("CFG_VER_HASH")),unw(option_env!(//; +"CFG_VER_DATE")),unw(option_env!("CFG_RELEASE")),)}#[doc(hidden)]pub fn//*&*&(); +version_at_macro_invocation(early_dcx:&EarlyDiagCtxt,binary:&str,matches:&//{;}; +getopts::Matches,version:&str,commit_hash:&str,commit_date:&str,release:&str,){; +let verbose=matches.opt_present("verbose");;safe_println!("{binary} {version}"); +if verbose{*&*&();safe_println!("binary: {binary}");*&*&();*&*&();safe_println!( +"commit-hash: {commit_hash}");3;3;safe_println!("commit-date: {commit_date}");;; +safe_println!("host: {}",config::host_triple());let _=();let _=();safe_println!( +"release: {release}");;;let debug_flags=matches.opt_strs("Z");;let backend_name= +debug_flags.iter().find_map(|x|x.strip_prefix("codegen-backend="));3;3;let opts= +config::Options::default();3;3;let sysroot=filesearch::materialize_sysroot(opts. +maybe_sysroot.clone());;let target=config::build_target_config(early_dcx,&opts,& +sysroot);({});({});get_codegen_backend(early_dcx,&sysroot,backend_name,&target). +print_version();if true{};}}fn usage(verbose:bool,include_unstable_options:bool, +nightly_build:bool){;let groups=if verbose{config::rustc_optgroups()}else{config +::rustc_short_optgroups()};;;let mut options=getopts::Options::new();;for option +in groups.iter().filter(|x|include_unstable_options||x.is_stable()){{;};(option. +apply)(&mut options);();}();let message="Usage: rustc [OPTIONS] INPUT";();();let +nightly_help=if nightly_build{//loop{break};loop{break};loop{break};loop{break}; +"\n -Z help Print unstable compiler options"}else{""};{;};{;};let +verbose_help=if verbose{((((((((((((((((((((((((""))))))))))))))))))))))))}else{ +"\n --help -v Print the full set of options rustc accepts"};3;3;let +at_path=if verbose{//if let _=(){};*&*&();((),());*&*&();((),());*&*&();((),()); +" @path Read newline separated options from `path`\n"}else {""} +;((),());((),());((),());let _=();((),());((),());((),());((),());safe_println!( +"{options}{at_path}\nAdditional help: -C help Print codegen options -W help \ - Print 'lint' options and default settings{nightly}{verbose}\n", - options = options.usage(message), - at_path = at_path, - nightly = nightly_help, - verbose = verbose_help - ); -} - -fn print_wall_help() { - safe_println!( - " + Print 'lint' options and default settings{nightly}{verbose}\n" +,options=options.usage(message),at_path=at_path,nightly=nightly_help,verbose=//; +verbose_help);*&*&();((),());}fn print_wall_help(){*&*&();((),());safe_println!( +" The flag `-Wall` does not exist in `rustc`. Most useful lints are enabled by default. Use `rustc -W help` to see all available lints. It's more common to put warning settings in the crate root using `#![warn(LINT_NAME)]` instead of using the command line flag directly. " - ); -} - -/// Write to stdout lint command options, together with a list of all available lints -pub fn describe_lints(sess: &Session) { - safe_println!( - " +);loop{break;};}pub fn describe_lints(sess:&Session){loop{break;};safe_println!( +" Available lint options: -W Warn about -A Allow @@ -953,610 +307,173 @@ Available lint options: -F Forbid (deny and all attempts to override) " - ); - - fn sort_lints(sess: &Session, mut lints: Vec<&'static Lint>) -> Vec<&'static Lint> { - // The sort doesn't case-fold but it's doubtful we care. - lints.sort_by_cached_key(|x: &&Lint| (x.default_level(sess.edition()), x.name)); - lints - } - - fn sort_lint_groups( - lints: Vec<(&'static str, Vec, bool)>, - ) -> Vec<(&'static str, Vec)> { - let mut lints: Vec<_> = lints.into_iter().map(|(x, y, _)| (x, y)).collect(); - lints.sort_by_key(|l| l.0); - lints - } - - let lint_store = unerased_lint_store(sess); - let (loaded, builtin): (Vec<_>, _) = - lint_store.get_lints().iter().cloned().partition(|&lint| lint.is_loaded); - let loaded = sort_lints(sess, loaded); - let builtin = sort_lints(sess, builtin); - - let (loaded_groups, builtin_groups): (Vec<_>, _) = - lint_store.get_lint_groups().partition(|&(.., p)| p); - let loaded_groups = sort_lint_groups(loaded_groups); - let builtin_groups = sort_lint_groups(builtin_groups); - - let max_name_len = - loaded.iter().chain(&builtin).map(|&s| s.name.chars().count()).max().unwrap_or(0); - let padded = |x: &str| { - let mut s = " ".repeat(max_name_len - x.chars().count()); - s.push_str(x); - s - }; - - safe_println!("Lint checks provided by rustc:\n"); - - let print_lints = |lints: Vec<&Lint>| { - safe_println!(" {} {:7.7} {}", padded("name"), "default", "meaning"); - safe_println!(" {} {:7.7} {}", padded("----"), "-------", "-------"); - for lint in lints { - let name = lint.name_lower().replace('_', "-"); - safe_println!( - " {} {:7.7} {}", - padded(&name), - lint.default_level(sess.edition()).as_str(), - lint.desc - ); - } - safe_println!("\n"); - }; - - print_lints(builtin); - - let max_name_len = max( - "warnings".len(), - loaded_groups - .iter() - .chain(&builtin_groups) - .map(|&(s, _)| s.chars().count()) - .max() - .unwrap_or(0), - ); - - let padded = |x: &str| { - let mut s = " ".repeat(max_name_len - x.chars().count()); - s.push_str(x); - s - }; - - safe_println!("Lint groups provided by rustc:\n"); - - let print_lint_groups = |lints: Vec<(&'static str, Vec)>, all_warnings| { - safe_println!(" {} sub-lints", padded("name")); - safe_println!(" {} ---------", padded("----")); - - if all_warnings { - safe_println!(" {} all lints that are set to issue warnings", padded("warnings")); - } - - for (name, to) in lints { - let name = name.to_lowercase().replace('_', "-"); - let desc = to - .into_iter() - .map(|x| x.to_string().replace('_', "-")) - .collect::>() - .join(", "); - safe_println!(" {} {}", padded(&name), desc); - } - safe_println!("\n"); - }; - - print_lint_groups(builtin_groups, true); - - match (sess.registered_lints, loaded.len(), loaded_groups.len()) { - (false, 0, _) | (false, _, 0) => { - safe_println!("Lint tools like Clippy can load additional lints and lint groups."); - } - (false, ..) => panic!("didn't load additional lints but got them anyway!"), - (true, 0, 0) => { - safe_println!("This crate does not load any additional lints or lint groups.") - } - (true, l, g) => { - if l > 0 { - safe_println!("Lint checks loaded by this crate:\n"); - print_lints(loaded); - } - if g > 0 { - safe_println!("Lint groups loaded by this crate:\n"); - print_lint_groups(loaded_groups, false); - } - } - } -} - -/// Show help for flag categories shared between rustdoc and rustc. -/// -/// Returns whether a help option was printed. -pub fn describe_flag_categories(early_dcx: &EarlyDiagCtxt, matches: &Matches) -> bool { - // Handle the special case of -Wall. - let wall = matches.opt_strs("W"); - if wall.iter().any(|x| *x == "all") { - print_wall_help(); - rustc_errors::FatalError.raise(); - } - - // Don't handle -W help here, because we might first load additional lints. - let debug_flags = matches.opt_strs("Z"); - if debug_flags.iter().any(|x| *x == "help") { - describe_debug_flags(); - return true; - } - - let cg_flags = matches.opt_strs("C"); - if cg_flags.iter().any(|x| *x == "help") { - describe_codegen_flags(); - return true; - } - - if cg_flags.iter().any(|x| *x == "no-stack-check") { - early_dcx.early_warn("the --no-stack-check flag is deprecated and does nothing"); - } - - if cg_flags.iter().any(|x| *x == "passes=list") { - let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend=")); - - let opts = config::Options::default(); - let sysroot = filesearch::materialize_sysroot(opts.maybe_sysroot.clone()); - let target = config::build_target_config(early_dcx, &opts, &sysroot); - - get_codegen_backend(early_dcx, &sysroot, backend_name, &target).print_passes(); - return true; - } - - false -} - -fn describe_debug_flags() { - safe_println!("\nAvailable options:\n"); - print_flag_list("-Z", config::Z_OPTIONS); -} - -fn describe_codegen_flags() { - safe_println!("\nAvailable codegen options:\n"); - print_flag_list("-C", config::CG_OPTIONS); -} - -fn print_flag_list( - cmdline_opt: &str, - flag_list: &[(&'static str, T, &'static str, &'static str)], -) { - let max_len = flag_list.iter().map(|&(name, _, _, _)| name.chars().count()).max().unwrap_or(0); - - for &(name, _, _, desc) in flag_list { - safe_println!( - " {} {:>width$}=val -- {}", - cmdline_opt, - name.replace('_', "-"), - desc, - width = max_len - ); - } -} - -/// Process command line options. Emits messages as appropriate. If compilation -/// should continue, returns a getopts::Matches object parsed from args, -/// otherwise returns `None`. -/// -/// The compiler's handling of options is a little complicated as it ties into -/// our stability story. The current intention of each compiler option is to -/// have one of two modes: -/// -/// 1. An option is stable and can be used everywhere. -/// 2. An option is unstable, and can only be used on nightly. -/// -/// Like unstable library and language features, however, unstable options have -/// always required a form of "opt in" to indicate that you're using them. This -/// provides the easy ability to scan a code base to check to see if anything -/// unstable is being used. Currently, this "opt in" is the `-Z` "zed" flag. -/// -/// All options behind `-Z` are considered unstable by default. Other top-level -/// options can also be considered unstable, and they were unlocked through the -/// `-Z unstable-options` flag. Note that `-Z` remains to be the root of -/// instability in both cases, though. -/// -/// So with all that in mind, the comments below have some more detail about the -/// contortions done here to get things to work out correctly. -/// -/// This does not need to be `pub` for rustc itself, but @chaosite needs it to -/// be public when using rustc as a library, see -/// -pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option { - if args.is_empty() { - // user did not write `-v` nor `-Z unstable-options`, so do not - // include that extra information. - let nightly_build = - rustc_feature::UnstableFeatures::from_environment(None).is_nightly_build(); - usage(false, false, nightly_build); - return None; - } - - // Parse with *all* options defined in the compiler, we don't worry about - // option stability here we just want to parse as much as possible. - let mut options = getopts::Options::new(); - for option in config::rustc_optgroups() { - (option.apply)(&mut options); - } - let matches = options.parse(args).unwrap_or_else(|e| { - let msg = match e { - getopts::Fail::UnrecognizedOption(ref opt) => CG_OPTIONS - .iter() - .map(|&(name, ..)| ('C', name)) - .chain(Z_OPTIONS.iter().map(|&(name, ..)| ('Z', name))) - .find(|&(_, name)| *opt == name.replace('_', "-")) - .map(|(flag, _)| format!("{e}. Did you mean `-{flag} {opt}`?")), - _ => None, - }; - early_dcx.early_fatal(msg.unwrap_or_else(|| e.to_string())); - }); - - // For all options we just parsed, we check a few aspects: - // - // * If the option is stable, we're all good - // * If the option wasn't passed, we're all good - // * If `-Z unstable-options` wasn't passed (and we're not a -Z option - // ourselves), then we require the `-Z unstable-options` flag to unlock - // this option that was passed. - // * If we're a nightly compiler, then unstable options are now unlocked, so - // we're good to go. - // * Otherwise, if we're an unstable option then we generate an error - // (unstable option being used on stable) - nightly_options::check_nightly_options(early_dcx, &matches, &config::rustc_optgroups()); - - if matches.opt_present("h") || matches.opt_present("help") { - // Only show unstable options in --help if we accept unstable options. - let unstable_enabled = nightly_options::is_unstable_enabled(&matches); - let nightly_build = nightly_options::match_is_nightly_build(&matches); - usage(matches.opt_present("verbose"), unstable_enabled, nightly_build); - return None; - } - - if describe_flag_categories(early_dcx, &matches) { - return None; - } - - if matches.opt_present("version") { - version!(early_dcx, "rustc", &matches); - return None; - } - - Some(matches) -} - -fn parse_crate_attrs<'a>(sess: &'a Session) -> PResult<'a, ast::AttrVec> { - match &sess.io.input { - Input::File(ifile) => rustc_parse::parse_crate_attrs_from_file(ifile, &sess.psess), - Input::Str { name, input } => { - rustc_parse::parse_crate_attrs_from_source_str(name.clone(), input.clone(), &sess.psess) - } - } -} - -/// Runs a closure and catches unwinds triggered by fatal errors. -/// -/// The compiler currently unwinds with a special sentinel value to abort -/// compilation on fatal errors. This function catches that sentinel and turns -/// the panic into a `Result` instead. -pub fn catch_fatal_errors R, R>(f: F) -> Result { - catch_unwind(panic::AssertUnwindSafe(f)).map_err(|value| { - if value.is::() { - FatalError - } else { - panic::resume_unwind(value); - } - }) -} - -/// Variant of `catch_fatal_errors` for the `interface::Result` return type -/// that also computes the exit code. -pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 { - match catch_fatal_errors(f) { - Ok(Ok(())) => EXIT_SUCCESS, - _ => EXIT_FAILURE, - } -} - -static ICE_PATH: OnceLock> = OnceLock::new(); - -fn ice_path() -> &'static Option { - ICE_PATH.get_or_init(|| { - if !rustc_feature::UnstableFeatures::from_environment(None).is_nightly_build() { - return None; - } - if let Some(s) = std::env::var_os("RUST_BACKTRACE") - && s == "0" - { - return None; - } - let mut path = match std::env::var_os("RUSTC_ICE") { - Some(s) => { - if s == "0" { - // Explicitly opting out of writing ICEs to disk. - return None; - } - PathBuf::from(s) - } - None => std::env::current_dir().unwrap_or_default(), - }; - let now: OffsetDateTime = SystemTime::now().into(); - let file_now = now - .format( - // Don't use a standard datetime format because Windows doesn't support `:` in paths - &time::format_description::parse("[year]-[month]-[day]T[hour]_[minute]_[second]") - .unwrap(), - ) - .unwrap_or_default(); - let pid = std::process::id(); - path.push(format!("rustc-ice-{file_now}-{pid}.txt")); - Some(path) - }) -} - -/// Installs a panic hook that will print the ICE message on unexpected panics. -/// -/// The hook is intended to be useable even by external tools. You can pass a custom -/// `bug_report_url`, or report arbitrary info in `extra_info`. Note that `extra_info` is called in -/// a context where *the thread is currently panicking*, so it must not panic or the process will -/// abort. -/// -/// If you have no extra info to report, pass the empty closure `|_| ()` as the argument to -/// extra_info. -/// -/// Returns a flag that can be set to disable the note for submitting a bug. This can be passed to -/// [`RunCompiler::set_using_internal_features`] to let macro expansion set it when encountering -/// internal features. -/// -/// A custom rustc driver can skip calling this to set up a custom ICE hook. -pub fn install_ice_hook( - bug_report_url: &'static str, - extra_info: fn(&DiagCtxt), -) -> Arc { - // If the user has not explicitly overridden "RUST_BACKTRACE", then produce - // full backtraces. When a compiler ICE happens, we want to gather - // as much information as possible to present in the issue opened - // by the user. Compiler developers and other rustc users can - // opt in to less-verbose backtraces by manually setting "RUST_BACKTRACE" - // (e.g. `RUST_BACKTRACE=1`) - if std::env::var_os("RUST_BACKTRACE").is_none() { - std::env::set_var("RUST_BACKTRACE", "full"); - } - - let using_internal_features = Arc::new(std::sync::atomic::AtomicBool::default()); - let using_internal_features_hook = using_internal_features.clone(); - panic::update_hook(Box::new( - move |default_hook: &(dyn Fn(&PanicInfo<'_>) + Send + Sync + 'static), - info: &PanicInfo<'_>| { - // Lock stderr to prevent interleaving of concurrent panics. - let _guard = io::stderr().lock(); - - // If the error was caused by a broken pipe then this is not a bug. - // Write the error and return immediately. See #98700. - #[cfg(windows)] - if let Some(msg) = info.payload().downcast_ref::() { - if msg.starts_with("failed printing to stdout: ") && msg.ends_with("(os error 232)") - { - // the error code is already going to be reported when the panic unwinds up the stack - let early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default()); - let _ = early_dcx.early_err(msg.clone()); - return; - } - }; - - // Invoke the default handler, which prints the actual panic message and optionally a backtrace - // Don't do this for delayed bugs, which already emit their own more useful backtrace. - if !info.payload().is::() { - default_hook(info); - // Separate the output with an empty line - eprintln!(); - - if let Some(ice_path) = ice_path() - && let Ok(mut out) = File::options().create(true).append(true).open(&ice_path) - { - // The current implementation always returns `Some`. - let location = info.location().unwrap(); - let msg = match info.payload().downcast_ref::<&'static str>() { - Some(s) => *s, - None => match info.payload().downcast_ref::() { - Some(s) => &s[..], - None => "Box", - }, - }; - let thread = std::thread::current(); - let name = thread.name().unwrap_or(""); - let _ = write!( - &mut out, - "thread '{name}' panicked at {location}:\n\ +);;fn sort_lints(sess:&Session,mut lints:Vec<&'static Lint>)->Vec<&'static Lint> +{;lints.sort_by_cached_key(|x:&&Lint|(x.default_level(sess.edition()),x.name));; +lints};;fn sort_lint_groups(lints:Vec<(&'static str,Vec,bool)>,)->Vec<(& +'static str,Vec)>{;let mut lints:Vec<_>=lints.into_iter().map(|(x,y,_)|( +x,y)).collect();{;};{;};lints.sort_by_key(|l|l.0);();lints}();();let lint_store= +unerased_lint_store(sess);;let(loaded,builtin):(Vec<_>,_)=lint_store.get_lints() +.iter().cloned().partition(|&lint|lint.is_loaded);3;;let loaded=sort_lints(sess, +loaded);;let builtin=sort_lints(sess,builtin);let(loaded_groups,builtin_groups): +(Vec<_>,_)=lint_store.get_lint_groups().partition(|&(..,p)|p);;let loaded_groups +=sort_lint_groups(loaded_groups);{();};({});let builtin_groups=sort_lint_groups( +builtin_groups);;;let max_name_len=loaded.iter().chain(&builtin).map(|&s|s.name. +chars().count()).max().unwrap_or(0);;;let padded=|x:&str|{;let mut s=" ".repeat( +max_name_len-x.chars().count());{;};{;};s.push_str(x);();s};();();safe_println!( +"Lint checks provided by rustc:\n");();();let print_lints=|lints:Vec<&Lint>|{(); +safe_println!(" {} {:7.7} {}",padded("name"),"default","meaning");({});{;}; +safe_println!(" {} {:7.7} {}",padded("----"),"-------","-------");;for lint +in lints{({});let name=lint.name_lower().replace('_',"-");{;};{;};safe_println!( +" {} {:7.7} {}",padded(&name),lint.default_level (sess.edition()).as_str(), +lint.desc);;};safe_println!("\n");;};;print_lints(builtin);let max_name_len=max( +"warnings".len(),((loaded_groups.iter()).chain( &builtin_groups)).map(|&(s,_)|s. +chars().count()).max().unwrap_or(0),);;let padded=|x:&str|{let mut s=" ".repeat( +max_name_len-x.chars().count());{;};{;};s.push_str(x);();s};();();safe_println!( +"Lint groups provided by rustc:\n");;;let print_lint_groups=|lints:Vec<(&'static +str,Vec)>,all_warnings|{;safe_println!(" {} sub-lints",padded("name" +));();();safe_println!(" {} ---------",padded("----"));();if all_warnings{3; +safe_println!(" {} all lints that are set to issue warnings",padded(//{();}; +"warnings"));;}for(name,to)in lints{let name=name.to_lowercase().replace('_',"-" +);;let desc=to.into_iter().map(|x|x.to_string().replace('_',"-")).collect::>().join(", ");();();safe_println!(" {} {}",padded(&name),desc);3;}3; +safe_println!("\n");3;};3;3;print_lint_groups(builtin_groups,true);3;match(sess. +registered_lints,loaded.len(),loaded_groups.len()){(false,0,_)|(false,_,0)=>{(); +safe_println!(//((),());((),());((),());((),());((),());((),());((),());((),()); +"Lint tools like Clippy can load additional lints and lint groups.");;}(false,.. +)=>((panic!("didn't load additional lints but got them anyway!"))),(true,0,0)=>{ +safe_println!( "This crate does not load any additional lints or lint groups.")} +(true,l,g)=>{if l>0{();safe_println!("Lint checks loaded by this crate:\n");3;3; +print_lints(loaded);;}if g>0{safe_println!("Lint groups loaded by this crate:\n" +);;;print_lint_groups(loaded_groups,false);;}}}}pub fn describe_flag_categories( +early_dcx:&EarlyDiagCtxt,matches:&Matches)->bool{;let wall=matches.opt_strs("W") +;;if wall.iter().any(|x|*x=="all"){;print_wall_help();;rustc_errors::FatalError. +raise();;};let debug_flags=matches.opt_strs("Z");if debug_flags.iter().any(|x|*x +=="help"){;describe_debug_flags();return true;}let cg_flags=matches.opt_strs("C" +);;if cg_flags.iter().any(|x|*x=="help"){;describe_codegen_flags();return true;} +if cg_flags.iter().any(|x|*x=="no-stack-check"){let _=||();early_dcx.early_warn( +"the --no-stack-check flag is deprecated and does nothing");;}if cg_flags.iter() +.any(|x|*x=="passes=list"){();let backend_name=debug_flags.iter().find_map(|x|x. +strip_prefix("codegen-backend="));3;3;let opts=config::Options::default();3;;let +sysroot=filesearch::materialize_sysroot(opts.maybe_sysroot.clone());;let target= +config::build_target_config(early_dcx,&opts,&sysroot);();();get_codegen_backend( +early_dcx,&sysroot,backend_name,&target).print_passes();;;return true;;}false}fn +describe_debug_flags(){;safe_println!("\nAvailable options:\n");print_flag_list( +"-Z",config::Z_OPTIONS);*&*&();}fn describe_codegen_flags(){{();};safe_println!( +"\nAvailable codegen options:\n");;;print_flag_list("-C",config::CG_OPTIONS);}fn +print_flag_list(cmdline_opt:&str,flag_list:&[(&'static str,T,&'static str,&// +'static str)],){();let max_len=flag_list.iter().map(|&(name,_,_,_)|name.chars(). +count()).max().unwrap_or(0);();for&(name,_,_,desc)in flag_list{();safe_println!( +" {} {:>width$}=val -- {}",cmdline_opt,name.replace('_',"-"),desc,width=//(); +max_len);({});}}pub fn handle_options(early_dcx:&EarlyDiagCtxt,args:&[String])-> +Option{if args.is_empty(){();let nightly_build=rustc_feature:: +UnstableFeatures::from_environment(None).is_nightly_build();;;usage(false,false, +nightly_build);;;return None;}let mut options=getopts::Options::new();for option +in config::rustc_optgroups(){;(option.apply)(&mut options);}let matches=options. +parse(args).unwrap_or_else(|e|{let _=();let _=();let msg=match e{getopts::Fail:: +UnrecognizedOption(ref opt)=>((CG_OPTIONS.iter()).map( |&(name,..)|('C',name))). +chain(Z_OPTIONS.iter().map(|&(name,..)|('Z', name))).find(|&(_,name)|*opt==name. +replace('_',"-")).map( |(flag,_)|format!("{e}. Did you mean `-{flag} {opt}`?")), +_=>None,};3;3;early_dcx.early_fatal(msg.unwrap_or_else(||e.to_string()));3;});;; +nightly_options::check_nightly_options(early_dcx,((((((& matches)))))),&config:: +rustc_optgroups());;if matches.opt_present("h")||matches.opt_present("help"){let +unstable_enabled=nightly_options::is_unstable_enabled(&matches);*&*&();{();};let +nightly_build=nightly_options::match_is_nightly_build(&matches);;;usage(matches. +opt_present("verbose"),unstable_enabled,nightly_build);();();return None;();}if +describe_flag_categories(early_dcx,&matches){{();};return None;({});}if matches. +opt_present("version"){;version!(early_dcx,"rustc",&matches);;return None;}Some( +matches)}fn parse_crate_attrs<'a>(sess:&'a Session)->PResult<'a,ast::AttrVec>{// +match(((((((((((((&sess.io.input))))))))))))){ Input::File(ifile)=>rustc_parse:: +parse_crate_attrs_from_file(ifile,((((&sess.psess))))),Input::Str{name,input}=>{ +rustc_parse::parse_crate_attrs_from_source_str(name.clone() ,input.clone(),&sess +.psess)}}}pub fn catch_fatal_errorsR,R>(f:F)->Result +{((catch_unwind(((panic::AssertUnwindSafe(f)))))).map_err(|value|{if value.is::< +rustc_errors::FatalErrorMarker>(){FatalError}else{;panic::resume_unwind(value);} +})}pub fn catch_with_exit_code(f:impl FnOnce()->interface::Result<()>)->i32{//3; +match (catch_fatal_errors(f)){Ok(Ok( ()))=>EXIT_SUCCESS,_=>EXIT_FAILURE,}}static +ICE_PATH:OnceLock>=(((OnceLock::new())));fn ice_path()->&'static +Option{ICE_PATH.get_or_init(||{if!rustc_feature::UnstableFeatures:://3; +from_environment(None).is_nightly_build(){;return None;;}if let Some(s)=std::env +::var_os("RUST_BACKTRACE")&&s=="0"{;return None;;};let mut path=match std::env:: +var_os("RUSTC_ICE"){Some(s)=>{if s=="0"{;return None;}PathBuf::from(s)}None=>std +::env::current_dir().unwrap_or_default(),};;;let now:OffsetDateTime=SystemTime:: +now().into();({});({});let file_now=now.format(&time::format_description::parse( +"[year]-[month]-[day]T[hour]_[minute]_[second]").unwrap() ,).unwrap_or_default() +;;let pid=std::process::id();path.push(format!("rustc-ice-{file_now}-{pid}.txt") +);3;Some(path)})}pub fn install_ice_hook(bug_report_url:&'static str,extra_info: +fn(&DiagCtxt),)->Arc{if std::env::var_os("RUST_BACKTRACE").is_none( +){;std::env::set_var("RUST_BACKTRACE","full");}let using_internal_features=Arc:: +new(std::sync::atomic::AtomicBool::default());;let using_internal_features_hook= +using_internal_features.clone();;panic::update_hook(Box::new(move|default_hook:& +(dyn Fn(&PanicInfo<'_>)+Send+Sync+'static),info:&PanicInfo<'_>|{;let _guard=io:: +stderr().lock();;;#[cfg(windows)]if let Some(msg)=info.payload().downcast_ref::< +String>(){if (msg.starts_with (("failed printing to stdout: ")))&&msg.ends_with( +"(os error 232)"){;let early_dcx=EarlyDiagCtxt::new(ErrorOutputType::default()); +let _=early_dcx.early_err(msg.clone());3;3;return;3;}};3;if!info.payload().is::< +rustc_errors::DelayedBugPanic>(){;default_hook(info);;;eprintln!();;if let Some( +ice_path)=ice_path()&&let Ok(mut out)= File::options().create(true).append(true) +.open(&ice_path){3;let location=info.location().unwrap();3;3;let msg=match info. +payload().downcast_ref::<&'static str>(){Some( s)=>*s,None=>match info.payload() +.downcast_ref::(){Some(s)=>&s[..],None=>"Box",},};;;let thread= +std::thread::current();3;;let name=thread.name().unwrap_or("");;;let _= +write!(&mut out,//*&*&();((),());((),());((),());*&*&();((),());((),());((),()); +"thread '{name}' panicked at {location}:\n\ {msg}\n\ stack backtrace:\n\ - {:#}", - std::backtrace::Backtrace::force_capture() - ); - } - } - - // Print the ICE message - report_ice(info, bug_report_url, extra_info, &using_internal_features_hook); - }, - )); - - using_internal_features -} - -const DATE_FORMAT: &[time::format_description::FormatItem<'static>] = - &time::macros::format_description!("[year]-[month]-[day]"); - -/// Prints the ICE message, including query stack, but without backtrace. -/// -/// The message will point the user at `bug_report_url` to report the ICE. -/// -/// When `install_ice_hook` is called, this function will be called as the panic -/// hook. -fn report_ice( - info: &panic::PanicInfo<'_>, - bug_report_url: &str, - extra_info: fn(&DiagCtxt), - using_internal_features: &AtomicBool, -) { - let fallback_bundle = - rustc_errors::fallback_fluent_bundle(crate::DEFAULT_LOCALE_RESOURCES.to_vec(), false); - let emitter = Box::new(rustc_errors::emitter::HumanEmitter::new( - stderr_destination(rustc_errors::ColorConfig::Auto), - fallback_bundle, - )); - let dcx = rustc_errors::DiagCtxt::new(emitter); - - // a .span_bug or .bug call has already printed what - // it wants to print. - if !info.payload().is::() - && !info.payload().is::() - { - dcx.emit_err(session_diagnostics::Ice); - } - - use time::ext::NumericalDuration; - - // Try to hint user to update nightly if applicable when reporting an ICE. - // Attempt to calculate when current version was released, and add 12 hours - // as buffer. If the current version's release timestamp is older than - // the system's current time + 24 hours + 12 hours buffer if we're on - // nightly. - if let Some("nightly") = option_env!("CFG_RELEASE_CHANNEL") - && let Some(version) = option_env!("CFG_VERSION") - && let Some(ver_date_str) = option_env!("CFG_VER_DATE") - && let Ok(ver_date) = Date::parse(&ver_date_str, DATE_FORMAT) - && let ver_datetime = OffsetDateTime::new_utc(ver_date, Time::MIDNIGHT) - && let system_datetime = OffsetDateTime::from(SystemTime::now()) - && system_datetime.checked_sub(36.hours()).is_some_and(|d| d > ver_datetime) - && !using_internal_features.load(std::sync::atomic::Ordering::Relaxed) - { - dcx.emit_note(session_diagnostics::IceBugReportOutdated { - version, - bug_report_url, - note_update: (), - note_url: (), - }); - } else { - if using_internal_features.load(std::sync::atomic::Ordering::Relaxed) { - dcx.emit_note(session_diagnostics::IceBugReportInternalFeature); - } else { - dcx.emit_note(session_diagnostics::IceBugReport { bug_report_url }); - } - } - - let version = util::version_str!().unwrap_or("unknown_version"); - let triple = config::host_triple(); - - static FIRST_PANIC: AtomicBool = AtomicBool::new(true); - - let file = if let Some(path) = ice_path() { - // Create the ICE dump target file. - match crate::fs::File::options().create(true).append(true).open(&path) { - Ok(mut file) => { - dcx.emit_note(session_diagnostics::IcePath { path: path.clone() }); - if FIRST_PANIC.swap(false, Ordering::SeqCst) { - let _ = write!(file, "\n\nrustc version: {version}\nplatform: {triple}"); - } - Some(file) - } - Err(err) => { - // The path ICE couldn't be written to disk, provide feedback to the user as to why. - dcx.emit_warn(session_diagnostics::IcePathError { - path: path.clone(), - error: err.to_string(), - env_var: std::env::var_os("RUSTC_ICE") - .map(PathBuf::from) - .map(|env_var| session_diagnostics::IcePathErrorEnv { env_var }), - }); - dcx.emit_note(session_diagnostics::IceVersion { version, triple }); - None - } - } - } else { - dcx.emit_note(session_diagnostics::IceVersion { version, triple }); - None - }; - - if let Some((flags, excluded_cargo_defaults)) = rustc_session::utils::extra_compiler_flags() { - dcx.emit_note(session_diagnostics::IceFlags { flags: flags.join(" ") }); - if excluded_cargo_defaults { - dcx.emit_note(session_diagnostics::IceExcludeCargoDefaults); - } - } - - // If backtraces are enabled, also print the query stack - let backtrace = env::var_os("RUST_BACKTRACE").is_some_and(|x| &x != "0"); - - let num_frames = if backtrace { None } else { Some(2) }; - - interface::try_print_query_stack(&dcx, num_frames, file); - - // We don't trust this callback not to panic itself, so run it at the end after we're sure we've - // printed all the relevant info. - extra_info(&dcx); - - #[cfg(windows)] - if env::var("RUSTC_BREAK_ON_ICE").is_ok() { - // Trigger a debugger if we crashed during bootstrap - unsafe { windows::Win32::System::Diagnostics::Debug::DebugBreak() }; - } -} - -/// This allows tools to enable rust logging without having to magically match rustc's -/// tracing crate version. -pub fn init_rustc_env_logger(early_dcx: &EarlyDiagCtxt) { - init_logger(early_dcx, rustc_log::LoggerConfig::from_env("RUSTC_LOG")); -} - -/// This allows tools to enable rust logging without having to magically match rustc's -/// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to choose -/// the values directly rather than having to set an environment variable. -pub fn init_logger(early_dcx: &EarlyDiagCtxt, cfg: rustc_log::LoggerConfig) { - if let Err(error) = rustc_log::init_logger(cfg) { - early_dcx.early_fatal(error.to_string()); - } -} - -/// Install our usual `ctrlc` handler, which sets [`rustc_const_eval::CTRL_C_RECEIVED`]. -/// Making this handler optional lets tools can install a different handler, if they wish. -pub fn install_ctrlc_handler() { - ctrlc::set_handler(move || { - // Indicate that we have been signaled to stop. If we were already signaled, exit - // immediately. In our interpreter loop we try to consult this value often, but if for - // whatever reason we don't get to that check or the cleanup we do upon finding that - // this bool has become true takes a long time, the exit here will promptly exit the - // process on the second Ctrl-C. - if CTRL_C_RECEIVED.swap(true, Ordering::Relaxed) { - std::process::exit(1); - } - }) - .expect("Unable to install ctrlc handler"); -} - -pub fn main() -> ! { - let start_time = Instant::now(); - let start_rss = get_resident_set_size(); - - let early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default()); - - init_rustc_env_logger(&early_dcx); - signal_handler::install(); - let mut callbacks = TimePassesCallbacks::default(); - let using_internal_features = install_ice_hook(DEFAULT_BUG_REPORT_URL, |_| ()); - install_ctrlc_handler(); - - let exit_code = catch_with_exit_code(|| { - RunCompiler::new(&args::raw_args(&early_dcx)?, &mut callbacks) - .set_using_internal_features(using_internal_features) - .run() - }); - - if let Some(format) = callbacks.time_passes { - let end_rss = get_resident_set_size(); - print_time_passes_entry("total", start_time.elapsed(), start_rss, end_rss, format); - } - - process::exit(exit_code) -} + {:#}" +,std::backtrace::Backtrace::force_capture());;}};report_ice(info,bug_report_url, +extra_info,&using_internal_features_hook);3;},));3;using_internal_features}const +DATE_FORMAT:&[time::format_description::FormatItem<'static>]=&time::macros:://3; +format_description!("[year]-[month]-[day]");fn report_ice(info:&panic:://*&*&(); +PanicInfo<'_>,bug_report_url:&str,extra_info:fn(&DiagCtxt),//let _=();if true{}; +using_internal_features:&AtomicBool,){((),());let fallback_bundle=rustc_errors:: +fallback_fluent_bundle(crate::DEFAULT_LOCALE_RESOURCES.to_vec(),false);();();let +emitter=Box::new(rustc_errors::emitter::HumanEmitter::new(stderr_destination(//; +rustc_errors::ColorConfig::Auto),fallback_bundle,));();();let dcx=rustc_errors:: +DiagCtxt::new(emitter);();if!info.payload().is::()&&! +info.payload().is::(){if let _=(){};dcx.emit_err( +session_diagnostics::Ice);();}();use time::ext::NumericalDuration;3;if let Some( +"nightly")=(option_env!("CFG_RELEASE_CHANNEL"))&& let Some(version)=option_env!( +"CFG_VERSION")&&let Some(ver_date_str)= ((option_env!("CFG_VER_DATE")))&&let Ok( +ver_date)=(((Date::parse((((&ver_date_str ))),DATE_FORMAT))))&&let ver_datetime= +OffsetDateTime::new_utc(ver_date,Time::MIDNIGHT)&&let system_datetime=//((),()); +OffsetDateTime::from(SystemTime::now())&& system_datetime.checked_sub(36.hours() +).is_some_and((|d|(d>ver_datetime)) )&&!using_internal_features.load(std::sync:: +atomic::Ordering::Relaxed){let _=();let _=();dcx.emit_note(session_diagnostics:: +IceBugReportOutdated{version,bug_report_url,note_update:(),note_url:(),});;}else +{if using_internal_features.load(std::sync::atomic::Ordering::Relaxed){({});dcx. +emit_note(session_diagnostics::IceBugReportInternalFeature);;}else{dcx.emit_note +(session_diagnostics::IceBugReport{bug_report_url});{;};}}{;};let version=util:: +version_str!().unwrap_or("unknown_version");;;let triple=config::host_triple();; +static FIRST_PANIC:AtomicBool=AtomicBool::new(true);;let file=if let Some(path)= +ice_path(){match ((crate::fs::File::options().create(true)).append(true)).open(& +path){Ok(mut file)=>{;dcx.emit_note(session_diagnostics::IcePath{path:path.clone +()});*&*&();if FIRST_PANIC.swap(false,Ordering::SeqCst){{();};let _=write!(file, +"\n\nrustc version: {version}\nplatform: {triple}");;}Some(file)}Err(err)=>{dcx. +emit_warn(session_diagnostics::IcePathError{path:((((path.clone())))),error:err. +to_string(),env_var:((std::env::var_os(("RUSTC_ICE"))).map(PathBuf::from)).map(| +env_var|session_diagnostics::IcePathErrorEnv{env_var}),});{;};{;};dcx.emit_note( +session_diagnostics::IceVersion{version,triple});();None}}}else{3;dcx.emit_note( +session_diagnostics::IceVersion{version,triple});();None};();if let Some((flags, +excluded_cargo_defaults))=rustc_session::utils::extra_compiler_flags(){({});dcx. +emit_note(session_diagnostics::IceFlags{flags:flags.join(" ")});if let _=(){};if +excluded_cargo_defaults{if true{};let _=||();dcx.emit_note(session_diagnostics:: +IceExcludeCargoDefaults);({});}}{;};let backtrace=env::var_os("RUST_BACKTRACE"). +is_some_and(|x|&x!="0");();3;let num_frames=if backtrace{None}else{Some(2)};3;3; +interface::try_print_query_stack(&dcx,num_frames,file);;;extra_info(&dcx);#[cfg( +windows)]if env::var("RUSTC_BREAK_ON_ICE").is_ok(){{();};unsafe{windows::Win32:: +System::Diagnostics::Debug::DebugBreak()};*&*&();}}pub fn init_rustc_env_logger( +early_dcx:&EarlyDiagCtxt){*&*&();init_logger(early_dcx,rustc_log::LoggerConfig:: +from_env("RUSTC_LOG"));((),());}pub fn init_logger(early_dcx:&EarlyDiagCtxt,cfg: +rustc_log::LoggerConfig){if let Err(error)=rustc_log::init_logger(cfg){let _=(); +early_dcx.early_fatal(error.to_string());;}}pub fn install_ctrlc_handler(){ctrlc +::set_handler(move||{if CTRL_C_RECEIVED.swap(true,Ordering::Relaxed){{();};std:: +process::exit(1);;}}).expect("Unable to install ctrlc handler");}pub fn main()-> +!{3;let start_time=Instant::now();3;;let start_rss=get_resident_set_size();;;let +early_dcx=EarlyDiagCtxt::new(ErrorOutputType::default());;init_rustc_env_logger( +&early_dcx);;;signal_handler::install();;let mut callbacks=TimePassesCallbacks:: +default();;let using_internal_features=install_ice_hook(DEFAULT_BUG_REPORT_URL,| +_|());;install_ctrlc_handler();let exit_code=catch_with_exit_code(||{RunCompiler +::new(&args::raw_args(&early_dcx) ?,&mut callbacks).set_using_internal_features( +using_internal_features).run()});;if let Some(format)=callbacks.time_passes{;let +end_rss=get_resident_set_size();();3;print_time_passes_entry("total",start_time. +elapsed(),start_rss,end_rss,format);let _=();let _=();}process::exit(exit_code)} diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index c9bbe45b21276..d8d34ecec41ba 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -1,363 +1,102 @@ -//! The various pretty-printing routines. - -use rustc_ast as ast; -use rustc_ast_pretty::pprust as pprust_ast; -use rustc_errors::FatalError; -use rustc_hir as hir; -use rustc_hir_pretty as pprust_hir; -use rustc_middle::bug; -use rustc_middle::mir::{write_mir_graphviz, write_mir_pretty}; -use rustc_middle::ty::{self, TyCtxt}; -use rustc_session::config::{OutFileName, PpHirMode, PpMode, PpSourceMode}; -use rustc_session::Session; -use rustc_smir::rustc_internal::pretty::write_smir_pretty; -use rustc_span::symbol::Ident; -use rustc_span::FileName; - -use std::cell::Cell; -use std::fmt::Write; - -pub use self::PpMode::*; -pub use self::PpSourceMode::*; - -struct AstNoAnn; - -impl pprust_ast::PpAnn for AstNoAnn {} - -struct HirNoAnn<'tcx> { - tcx: TyCtxt<'tcx>, -} - -impl<'tcx> pprust_hir::PpAnn for HirNoAnn<'tcx> { - fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) { - pprust_hir::PpAnn::nested( - &(&self.tcx.hir() as &dyn hir::intravisit::Map<'_>), - state, - nested, - ) - } -} - -struct AstIdentifiedAnn; - -impl pprust_ast::PpAnn for AstIdentifiedAnn { - fn pre(&self, s: &mut pprust_ast::State<'_>, node: pprust_ast::AnnNode<'_>) { - if let pprust_ast::AnnNode::Expr(_) = node { - s.popen(); - } - } - - fn post(&self, s: &mut pprust_ast::State<'_>, node: pprust_ast::AnnNode<'_>) { - match node { - pprust_ast::AnnNode::Crate(_) - | pprust_ast::AnnNode::Ident(_) - | pprust_ast::AnnNode::Name(_) => {} - - pprust_ast::AnnNode::Item(item) => { - s.s.space(); - s.synth_comment(item.id.to_string()) - } - pprust_ast::AnnNode::SubItem(id) => { - s.s.space(); - s.synth_comment(id.to_string()) - } - pprust_ast::AnnNode::Block(blk) => { - s.s.space(); - s.synth_comment(format!("block {}", blk.id)) - } - pprust_ast::AnnNode::Expr(expr) => { - s.s.space(); - s.synth_comment(expr.id.to_string()); - s.pclose() - } - pprust_ast::AnnNode::Pat(pat) => { - s.s.space(); - s.synth_comment(format!("pat {}", pat.id)); - } - } - } -} - -struct HirIdentifiedAnn<'tcx> { - tcx: TyCtxt<'tcx>, -} - -impl<'tcx> pprust_hir::PpAnn for HirIdentifiedAnn<'tcx> { - fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) { - pprust_hir::PpAnn::nested( - &(&self.tcx.hir() as &dyn hir::intravisit::Map<'_>), - state, - nested, - ) - } - - fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) { - if let pprust_hir::AnnNode::Expr(_) = node { - s.popen(); - } - } - - fn post(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) { - match node { - pprust_hir::AnnNode::Name(_) => {} - pprust_hir::AnnNode::Item(item) => { - s.s.space(); - s.synth_comment(format!("hir_id: {}", item.hir_id())); - } - pprust_hir::AnnNode::SubItem(id) => { - s.s.space(); - s.synth_comment(id.to_string()); - } - pprust_hir::AnnNode::Block(blk) => { - s.s.space(); - s.synth_comment(format!("block hir_id: {}", blk.hir_id)); - } - pprust_hir::AnnNode::Expr(expr) => { - s.s.space(); - s.synth_comment(format!("expr hir_id: {}", expr.hir_id)); - s.pclose(); - } - pprust_hir::AnnNode::Pat(pat) => { - s.s.space(); - s.synth_comment(format!("pat hir_id: {}", pat.hir_id)); - } - pprust_hir::AnnNode::Arm(arm) => { - s.s.space(); - s.synth_comment(format!("arm hir_id: {}", arm.hir_id)); - } - } - } -} - -struct AstHygieneAnn<'a> { - sess: &'a Session, -} - -impl<'a> pprust_ast::PpAnn for AstHygieneAnn<'a> { - fn post(&self, s: &mut pprust_ast::State<'_>, node: pprust_ast::AnnNode<'_>) { - match node { - pprust_ast::AnnNode::Ident(&Ident { name, span }) => { - s.s.space(); - s.synth_comment(format!("{}{:?}", name.as_u32(), span.ctxt())) - } - pprust_ast::AnnNode::Name(&name) => { - s.s.space(); - s.synth_comment(name.as_u32().to_string()) - } - pprust_ast::AnnNode::Crate(_) => { - s.s.hardbreak(); - let verbose = self.sess.verbose_internals(); - s.synth_comment(rustc_span::hygiene::debug_hygiene_data(verbose)); - s.s.hardbreak_if_not_bol(); - } - _ => {} - } - } -} - -struct HirTypedAnn<'tcx> { - tcx: TyCtxt<'tcx>, - maybe_typeck_results: Cell>>, -} - -impl<'tcx> pprust_hir::PpAnn for HirTypedAnn<'tcx> { - fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) { - let old_maybe_typeck_results = self.maybe_typeck_results.get(); - if let pprust_hir::Nested::Body(id) = nested { - self.maybe_typeck_results.set(Some(self.tcx.typeck_body(id))); - } - let pp_ann = &(&self.tcx.hir() as &dyn hir::intravisit::Map<'_>); - pprust_hir::PpAnn::nested(pp_ann, state, nested); - self.maybe_typeck_results.set(old_maybe_typeck_results); - } - - fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) { - if let pprust_hir::AnnNode::Expr(_) = node { - s.popen(); - } - } - - fn post(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) { - if let pprust_hir::AnnNode::Expr(expr) = node { - let typeck_results = self.maybe_typeck_results.get().or_else(|| { - self.tcx - .hir() - .maybe_body_owned_by(expr.hir_id.owner.def_id) - .map(|body_id| self.tcx.typeck_body(body_id)) - }); - - if let Some(typeck_results) = typeck_results { - s.s.space(); - s.s.word("as"); - s.s.space(); - s.s.word(typeck_results.expr_ty(expr).to_string()); - } - - s.pclose(); - } - } -} - -fn get_source(sess: &Session) -> (String, FileName) { - let src_name = sess.io.input.source_name(); - let src = String::clone( - sess.source_map() - .get_source_file(&src_name) - .expect("get_source_file") - .src - .as_ref() - .expect("src"), - ); - (src, src_name) -} - -fn write_or_print(out: &str, sess: &Session) { - sess.io.output_file.as_ref().unwrap_or(&OutFileName::Stdout).overwrite(out, sess); -} - -// Extra data for pretty-printing, the form of which depends on what kind of -// pretty-printing we are doing. -pub enum PrintExtra<'tcx> { - AfterParsing { krate: &'tcx ast::Crate }, - NeedsAstMap { tcx: TyCtxt<'tcx> }, -} - -impl<'tcx> PrintExtra<'tcx> { - fn with_krate(&self, f: F) -> R - where - F: FnOnce(&ast::Crate) -> R, - { - match self { - PrintExtra::AfterParsing { krate, .. } => f(krate), - PrintExtra::NeedsAstMap { tcx } => f(&tcx.resolver_for_lowering().borrow().1), - } - } - - fn tcx(&self) -> TyCtxt<'tcx> { - match self { - PrintExtra::AfterParsing { .. } => bug!("PrintExtra::tcx"), - PrintExtra::NeedsAstMap { tcx } => *tcx, - } - } -} - -pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) { - if ppm.needs_analysis() { - if ex.tcx().analysis(()).is_err() { - FatalError.raise(); - } - } - - let (src, src_name) = get_source(sess); - - let out = match ppm { - Source(s) => { - debug!("pretty printing source code {:?}", s); - let annotation: Box = match s { - Normal => Box::new(AstNoAnn), - Expanded => Box::new(AstNoAnn), - Identified => Box::new(AstIdentifiedAnn), - ExpandedIdentified => Box::new(AstIdentifiedAnn), - ExpandedHygiene => Box::new(AstHygieneAnn { sess }), - }; - let psess = &sess.psess; - let is_expanded = ppm.needs_ast_map(); - ex.with_krate(|krate| { - pprust_ast::print_crate( - sess.source_map(), - krate, - src_name, - src, - &*annotation, - is_expanded, - psess.edition, - &sess.psess.attr_id_generator, - ) - }) - } - AstTree => { - debug!("pretty printing AST tree"); - ex.with_krate(|krate| format!("{krate:#?}")) - } - AstTreeExpanded => { - debug!("pretty-printing expanded AST"); - format!("{:#?}", ex.tcx().resolver_for_lowering().borrow().1) - } - Hir(s) => { - debug!("pretty printing HIR {:?}", s); - let tcx = ex.tcx(); - let f = |annotation: &dyn pprust_hir::PpAnn| { - let sm = sess.source_map(); - let hir_map = tcx.hir(); - let attrs = |id| hir_map.attrs(id); - pprust_hir::print_crate( - sm, - hir_map.root_module(), - src_name, - src, - &attrs, - annotation, - ) - }; - match s { - PpHirMode::Normal => { - let annotation = HirNoAnn { tcx }; - f(&annotation) - } - PpHirMode::Identified => { - let annotation = HirIdentifiedAnn { tcx }; - f(&annotation) - } - PpHirMode::Typed => { - let annotation = HirTypedAnn { tcx, maybe_typeck_results: Cell::new(None) }; - tcx.dep_graph.with_ignore(|| f(&annotation)) - } - } - } - HirTree => { - debug!("pretty printing HIR tree"); - format!("{:#?}", ex.tcx().hir().krate()) - } - Mir => { - let mut out = Vec::new(); - write_mir_pretty(ex.tcx(), None, &mut out).unwrap(); - String::from_utf8(out).unwrap() - } - MirCFG => { - let mut out = Vec::new(); - write_mir_graphviz(ex.tcx(), None, &mut out).unwrap(); - String::from_utf8(out).unwrap() - } - StableMir => { - let mut out = Vec::new(); - write_smir_pretty(ex.tcx(), &mut out).unwrap(); - String::from_utf8(out).unwrap() - } - ThirTree => { - let tcx = ex.tcx(); - let mut out = String::new(); - if rustc_hir_analysis::check_crate(tcx).is_err() { - FatalError.raise(); - } - debug!("pretty printing THIR tree"); - for did in tcx.hir().body_owners() { - let _ = writeln!(out, "{:?}:\n{}\n", did, tcx.thir_tree(did)); - } - out - } - ThirFlat => { - let tcx = ex.tcx(); - let mut out = String::new(); - if rustc_hir_analysis::check_crate(tcx).is_err() { - FatalError.raise(); - } - debug!("pretty printing THIR flat"); - for did in tcx.hir().body_owners() { - let _ = writeln!(out, "{:?}:\n{}\n", did, tcx.thir_flat(did)); - } - out - } - }; - - write_or_print(&out, sess); -} +use rustc_ast as ast;use rustc_ast_pretty::pprust as pprust_ast;use//let _=||(); +rustc_errors::FatalError;use rustc_hir as hir;use rustc_hir_pretty as//let _=(); +pprust_hir;use rustc_middle::bug;use rustc_middle::mir::{write_mir_graphviz,//3; +write_mir_pretty};use rustc_middle::ty::{ self,TyCtxt};use rustc_session::config +::{OutFileName,PpHirMode,PpMode,PpSourceMode};use rustc_session::Session;use//3; +rustc_smir::rustc_internal::pretty::write_smir_pretty;use rustc_span::symbol::// +Ident;use rustc_span::FileName;use std::cell::Cell;use std::fmt::Write;pub use// +self::PpMode::*;pub use self:: PpSourceMode::*;struct AstNoAnn;impl pprust_ast:: +PpAnn for AstNoAnn{}struct HirNoAnn<'tcx>{tcx:TyCtxt<'tcx>,}impl<'tcx>//((),()); +pprust_hir::PpAnn for HirNoAnn<'tcx>{fn nested(&self,state:&mut pprust_hir:://3; +State<'_>,nested:pprust_hir::Nested){pprust_hir::PpAnn ::nested(&(&self.tcx.hir( +)as&dyn hir::intravisit::Map<'_>),state,nested,)}}struct AstIdentifiedAnn;impl// +pprust_ast::PpAnn for AstIdentifiedAnn{fn pre( &self,s:&mut pprust_ast::State<'_ +>,node:pprust_ast::AnnNode<'_>){if let pprust_ast::AnnNode::Expr(_)=node{({});s. +popen();3;}}fn post(&self,s:&mut pprust_ast::State<'_>,node:pprust_ast::AnnNode< +'_>){match node{pprust_ast::AnnNode::Crate(_)|pprust_ast::AnnNode::Ident(_)|//3; +pprust_ast::AnnNode::Name(_)=>{}pprust_ast::AnnNode::Item(item)=>{;s.s.space();s +.synth_comment(item.id.to_string())}pprust_ast::AnnNode::SubItem(id)=>{({});s.s. +space();;s.synth_comment(id.to_string())}pprust_ast::AnnNode::Block(blk)=>{;s.s. +space();3;s.synth_comment(format!("block {}",blk.id))}pprust_ast::AnnNode::Expr( +expr)=>{;s.s.space();;s.synth_comment(expr.id.to_string());s.pclose()}pprust_ast +::AnnNode::Pat(pat)=>{;s.s.space();s.synth_comment(format!("pat {}",pat.id));}}} +}struct HirIdentifiedAnn<'tcx>{tcx:TyCtxt<'tcx>,}impl<'tcx>pprust_hir::PpAnn//3; +for HirIdentifiedAnn<'tcx>{fn nested(&self,state:&mut pprust_hir::State<'_>,//3; +nested:pprust_hir::Nested){pprust_hir::PpAnn::nested(&((&(self.tcx.hir()))as&dyn +hir::intravisit::Map<'_>),state,nested,) }fn pre(&self,s:&mut pprust_hir::State< +'_>,node:pprust_hir::AnnNode<'_>){if let pprust_hir::AnnNode::Expr(_)=node{();s. +popen();3;}}fn post(&self,s:&mut pprust_hir::State<'_>,node:pprust_hir::AnnNode< +'_>){match node{pprust_hir::AnnNode::Name (_)=>{}pprust_hir::AnnNode::Item(item) +=>{;s.s.space();s.synth_comment(format!("hir_id: {}",item.hir_id()));}pprust_hir +::AnnNode::SubItem(id)=>{();s.s.space();();3;s.synth_comment(id.to_string());3;} +pprust_hir::AnnNode::Block(blk)=>{{;};s.s.space();();();s.synth_comment(format!( +"block hir_id: {}",blk.hir_id));;}pprust_hir::AnnNode::Expr(expr)=>{s.s.space(); +s.synth_comment(format!("expr hir_id: {}",expr.hir_id));;;s.pclose();}pprust_hir +::AnnNode::Pat(pat)=>{;s.s.space();s.synth_comment(format!("pat hir_id: {}",pat. +hir_id));;}pprust_hir::AnnNode::Arm(arm)=>{;s.s.space();s.synth_comment(format!( +"arm hir_id: {}",arm.hir_id));();}}}}struct AstHygieneAnn<'a>{sess:&'a Session,} +impl<'a>pprust_ast::PpAnn for AstHygieneAnn<'a> {fn post(&self,s:&mut pprust_ast +::State<'_>,node:pprust_ast::AnnNode< '_>){match node{pprust_ast::AnnNode::Ident +(&Ident{name,span})=>{;s.s.space();s.synth_comment(format!("{}{:?}",name.as_u32( +),span.ctxt()))}pprust_ast::AnnNode::Name(&name)=>{;s.s.space();s.synth_comment( +name.as_u32().to_string())}pprust_ast::AnnNode::Crate(_)=>{;s.s.hardbreak();;let +verbose=self.sess.verbose_internals();();3;s.synth_comment(rustc_span::hygiene:: +debug_hygiene_data(verbose));();();s.s.hardbreak_if_not_bol();();}_=>{}}}}struct +HirTypedAnn<'tcx>{tcx:TyCtxt<'tcx>,maybe_typeck_results:Cell>>,}impl<'tcx>pprust_hir::PpAnn for HirTypedAnn<'tcx>{fn//(); +nested(&self,state:&mut pprust_hir::State<'_>,nested:pprust_hir::Nested){{;};let +old_maybe_typeck_results=self.maybe_typeck_results.get();{;};if let pprust_hir:: +Nested::Body(id)=nested{;self.maybe_typeck_results.set(Some(self.tcx.typeck_body +(id)));;}let pp_ann=&(&self.tcx.hir()as&dyn hir::intravisit::Map<'_>);pprust_hir +::PpAnn::nested(pp_ann,state,nested);*&*&();{();};self.maybe_typeck_results.set( +old_maybe_typeck_results);{();};}fn pre(&self,s:&mut pprust_hir::State<'_>,node: +pprust_hir::AnnNode<'_>){if let pprust_hir::AnnNode::Expr(_)=node{;s.popen();;}} +fn post(&self,s:&mut pprust_hir::State< '_>,node:pprust_hir::AnnNode<'_>){if let +pprust_hir::AnnNode::Expr(expr)=node{let _=();if true{};let typeck_results=self. +maybe_typeck_results.get().or_else(||{(self.tcx.hir()).maybe_body_owned_by(expr. +hir_id.owner.def_id).map(|body_id|self.tcx.typeck_body(body_id))});;if let Some( +typeck_results)=typeck_results{;s.s.space();s.s.word("as");s.s.space();s.s.word( +typeck_results.expr_ty(expr).to_string());;};s.pclose();;}}}fn get_source(sess:& +Session)->(String,FileName){;let src_name=sess.io.input.source_name();;;let src= +String::clone((((((sess.source_map())).get_source_file(((&src_name)))))).expect( +"get_source_file").src.as_ref().expect("src"),);*&*&();((),());(src,src_name)}fn +write_or_print(out:&str,sess:&Session){;sess.io.output_file.as_ref().unwrap_or(& +OutFileName::Stdout).overwrite(out,sess);loop{break};}pub enum PrintExtra<'tcx>{ +AfterParsing{krate:&'tcx ast::Crate},NeedsAstMap{tcx:TyCtxt<'tcx>},}impl<'tcx>// +PrintExtra<'tcx>{fn with_krate(&self,f :F)->R where F:FnOnce(&ast::Crate)-> +R,{match self{PrintExtra::AfterParsing{krate ,..}=>((((f(krate))))),PrintExtra:: +NeedsAstMap{tcx}=>(f(&tcx.resolver_for_lowering().borrow().1)),}}fn tcx(&self)-> +TyCtxt<'tcx>{match self{PrintExtra::AfterParsing{..}=>(bug!("PrintExtra::tcx")), +PrintExtra::NeedsAstMap{tcx}=>((*tcx)),}}} pub fn print<'tcx>(sess:&Session,ppm: +PpMode,ex:PrintExtra<'tcx>){if (ppm.needs_analysis()){ if ex.tcx().analysis(()). +is_err(){;FatalError.raise();;}}let(src,src_name)=get_source(sess);let out=match +ppm{Source(s)=>{;debug!("pretty printing source code {:?}",s);let annotation:Box +=match s{Normal=>(Box::new(AstNoAnn)),Expanded=>Box::new( +AstNoAnn),Identified=>(Box::new(AstIdentifiedAnn)),ExpandedIdentified=>Box::new( +AstIdentifiedAnn),ExpandedHygiene=>Box::new(AstHygieneAnn{sess}),};;;let psess=& +sess.psess;;let is_expanded=ppm.needs_ast_map();ex.with_krate(|krate|{pprust_ast +::print_crate((sess.source_map()),krate,src_name,src,(&*annotation),is_expanded, +psess.edition,&sess.psess.attr_id_generator,)})}AstTree=>{*&*&();((),());debug!( +"pretty printing AST tree");((),());ex.with_krate(|krate|format!("{krate:#?}"))} +AstTreeExpanded=>{;debug!("pretty-printing expanded AST");format!("{:#?}",ex.tcx +().resolver_for_lowering().borrow().1)}Hir(s)=>{loop{break};loop{break;};debug!( +"pretty printing HIR {:?}",s);();();let tcx=ex.tcx();();3;let f=|annotation:&dyn +pprust_hir::PpAnn|{;let sm=sess.source_map();let hir_map=tcx.hir();let attrs=|id +|hir_map.attrs(id);();pprust_hir::print_crate(sm,hir_map.root_module(),src_name, +src,&attrs,annotation,)};3;match s{PpHirMode::Normal=>{;let annotation=HirNoAnn{ +tcx};;f(&annotation)}PpHirMode::Identified=>{let annotation=HirIdentifiedAnn{tcx +};*&*&();f(&annotation)}PpHirMode::Typed=>{{();};let annotation=HirTypedAnn{tcx, +maybe_typeck_results:Cell::new(None)};;tcx.dep_graph.with_ignore(||f(&annotation +))}}}HirTree=>{;debug!("pretty printing HIR tree");format!("{:#?}",ex.tcx().hir( +).krate())}Mir=>{;let mut out=Vec::new();write_mir_pretty(ex.tcx(),None,&mut out +).unwrap();3;String::from_utf8(out).unwrap()}MirCFG=>{;let mut out=Vec::new();;; +write_mir_graphviz(ex.tcx(),None,&mut out).unwrap();({});String::from_utf8(out). +unwrap()}StableMir=>{;let mut out=Vec::new();write_smir_pretty(ex.tcx(),&mut out +).unwrap();;String::from_utf8(out).unwrap()}ThirTree=>{;let tcx=ex.tcx();let mut +out=String::new();;if rustc_hir_analysis::check_crate(tcx).is_err(){;FatalError. +raise();;}debug!("pretty printing THIR tree");for did in tcx.hir().body_owners() +{;let _=writeln!(out,"{:?}:\n{}\n",did,tcx.thir_tree(did));;}out}ThirFlat=>{;let +tcx=ex.tcx();;let mut out=String::new();if rustc_hir_analysis::check_crate(tcx). +is_err(){;FatalError.raise();}debug!("pretty printing THIR flat");for did in tcx +.hir().body_owners(){;let _=writeln!(out,"{:?}:\n{}\n",did,tcx.thir_flat(did));} +out}};((),());((),());((),());((),());write_or_print(&out,sess);*&*&();((),());} diff --git a/compiler/rustc_driver_impl/src/print.rs b/compiler/rustc_driver_impl/src/print.rs index 70de55320f7ae..8f407f3b15537 100644 --- a/compiler/rustc_driver_impl/src/print.rs +++ b/compiler/rustc_driver_impl/src/print.rs @@ -1,20 +1,5 @@ -use std::fmt; -use std::io::{self, Write as _}; - -macro_rules! safe_print { - ($($arg:tt)*) => {{ - $crate::print::print(std::format_args!($($arg)*)); - }}; -} - -macro_rules! safe_println { - ($($arg:tt)*) => { - safe_print!("{}\n", std::format_args!($($arg)*)) - }; -} - -pub(crate) fn print(args: fmt::Arguments<'_>) { - if let Err(_) = io::stdout().write_fmt(args) { - rustc_errors::FatalError.raise(); - } -} +use std::fmt;use std::io::{self,Write as _};macro_rules!safe_print{($($arg:tt)* +)=>{{$crate::print::print(std::format_args!($($arg)*));}};}macro_rules!//*&*&(); +safe_println{($($arg:tt)*)=>{safe_print!( "{}\n",std::format_args!($($arg)*))};} +pub(crate)fn print(args:fmt::Arguments<'_>){ if let Err(_)=((((io::stdout())))). +write_fmt(args){*&*&();((),());rustc_errors::FatalError.raise();if let _=(){};}} diff --git a/compiler/rustc_driver_impl/src/session_diagnostics.rs b/compiler/rustc_driver_impl/src/session_diagnostics.rs index 62d0da62d2a79..79793ecc6ce12 100644 --- a/compiler/rustc_driver_impl/src/session_diagnostics.rs +++ b/compiler/rustc_driver_impl/src/session_diagnostics.rs @@ -1,96 +1,30 @@ -use rustc_macros::{Diagnostic, Subdiagnostic}; - -#[derive(Diagnostic)] -#[diag(driver_impl_rlink_unable_to_read)] -pub(crate) struct RlinkUnableToRead { - pub err: std::io::Error, -} - -#[derive(Diagnostic)] -#[diag(driver_impl_rlink_wrong_file_type)] -pub(crate) struct RLinkWrongFileType; - -#[derive(Diagnostic)] -#[diag(driver_impl_rlink_empty_version_number)] -pub(crate) struct RLinkEmptyVersionNumber; - -#[derive(Diagnostic)] -#[diag(driver_impl_rlink_encoding_version_mismatch)] -pub(crate) struct RLinkEncodingVersionMismatch { - pub version_array: String, - pub rlink_version: u32, -} - -#[derive(Diagnostic)] -#[diag(driver_impl_rlink_rustc_version_mismatch)] -pub(crate) struct RLinkRustcVersionMismatch<'a> { - pub rustc_version: String, - pub current_version: &'a str, -} - -#[derive(Diagnostic)] -#[diag(driver_impl_rlink_no_a_file)] -pub(crate) struct RlinkNotAFile; - -#[derive(Diagnostic)] -#[diag(driver_impl_ice)] -pub(crate) struct Ice; - -#[derive(Diagnostic)] -#[diag(driver_impl_ice_bug_report)] -pub(crate) struct IceBugReport<'a> { - pub bug_report_url: &'a str, -} - -#[derive(Diagnostic)] -#[diag(driver_impl_ice_bug_report_internal_feature)] -pub(crate) struct IceBugReportInternalFeature; - -#[derive(Diagnostic)] -#[diag(driver_impl_ice_bug_report_outdated)] -pub(crate) struct IceBugReportOutdated<'a> { - pub version: &'a str, - pub bug_report_url: &'a str, - #[note(driver_impl_update)] - pub note_update: (), - #[note(driver_impl_url)] - pub note_url: (), -} - -#[derive(Diagnostic)] -#[diag(driver_impl_ice_version)] -pub(crate) struct IceVersion<'a> { - pub version: &'a str, - pub triple: &'a str, -} - -#[derive(Diagnostic)] -#[diag(driver_impl_ice_path)] -pub(crate) struct IcePath { - pub path: std::path::PathBuf, -} - -#[derive(Diagnostic)] -#[diag(driver_impl_ice_path_error)] -pub(crate) struct IcePathError { - pub path: std::path::PathBuf, - pub error: String, - #[subdiagnostic] - pub env_var: Option, -} - -#[derive(Subdiagnostic)] -#[note(driver_impl_ice_path_error_env)] -pub(crate) struct IcePathErrorEnv { - pub env_var: std::path::PathBuf, -} - -#[derive(Diagnostic)] -#[diag(driver_impl_ice_flags)] -pub(crate) struct IceFlags { - pub flags: String, -} - -#[derive(Diagnostic)] -#[diag(driver_impl_ice_exclude_cargo_defaults)] -pub(crate) struct IceExcludeCargoDefaults; +use rustc_macros::{Diagnostic,Subdiagnostic};#[derive(Diagnostic)]#[diag(//({}); +driver_impl_rlink_unable_to_read)]pub(crate)struct RlinkUnableToRead{pub err://; +std::io::Error,}#[derive (Diagnostic)]#[diag(driver_impl_rlink_wrong_file_type)] +pub(crate)struct RLinkWrongFileType;#[derive(Diagnostic)]#[diag(//if let _=(){}; +driver_impl_rlink_empty_version_number)]pub(crate)struct//let _=||();let _=||(); +RLinkEmptyVersionNumber;#[derive(Diagnostic)]#[diag(//loop{break;};loop{break;}; +driver_impl_rlink_encoding_version_mismatch)]pub(crate)struct//((),());let _=(); +RLinkEncodingVersionMismatch{pub version_array:String, pub rlink_version:u32,}#[ +derive(Diagnostic)]#[diag(driver_impl_rlink_rustc_version_mismatch)]pub(crate)// +struct RLinkRustcVersionMismatch<'a>{pub rustc_version:String,pub//loop{break;}; +current_version:&'a str,}#[derive(Diagnostic)]#[diag(//loop{break};loop{break;}; +driver_impl_rlink_no_a_file)]pub(crate)struct RlinkNotAFile;#[derive(Diagnostic +)]#[diag(driver_impl_ice)]pub(crate)struct Ice;#[derive(Diagnostic)]#[diag(//(); +driver_impl_ice_bug_report)]pub(crate)struct IceBugReport<'a>{pub//loop{break;}; +bug_report_url:&'a str,}#[derive(Diagnostic)]#[diag(//loop{break;};loop{break;}; +driver_impl_ice_bug_report_internal_feature)]pub(crate)struct//((),());let _=(); +IceBugReportInternalFeature;#[derive(Diagnostic)]#[diag(//let _=||();let _=||(); +driver_impl_ice_bug_report_outdated)]pub(crate) struct IceBugReportOutdated<'a>{ +pub version:&'a str,pub bug_report_url:&'a str,#[note(driver_impl_update)]pub//; +note_update:(),#[note(driver_impl_url)]pub note_url:(),}#[derive(Diagnostic)]#[ +diag(driver_impl_ice_version)]pub(crate)struct IceVersion<'a>{pub version:&'a//; +str,pub triple:&'a str,}#[derive(Diagnostic)]#[diag(driver_impl_ice_path)]pub(// +crate)struct IcePath{pub path:std::path::PathBuf,}#[derive(Diagnostic)]#[diag(// +driver_impl_ice_path_error)]pub(crate)struct IcePathError{pub path:std::path::// +PathBuf,pub error:String,#[subdiagnostic ]pub env_var:Option,}# +[derive(Subdiagnostic)]#[note(driver_impl_ice_path_error_env)]pub(crate)struct// +IcePathErrorEnv{pub env_var:std::path::PathBuf,}#[derive(Diagnostic)]#[diag(//3; +driver_impl_ice_flags)]pub(crate)struct IceFlags{pub flags:String,}#[derive(//3; +Diagnostic)]#[diag(driver_impl_ice_exclude_cargo_defaults)]pub(crate)struct//(); +IceExcludeCargoDefaults;//loop{break;};if let _=(){};loop{break;};if let _=(){}; diff --git a/compiler/rustc_driver_impl/src/signal_handler.rs b/compiler/rustc_driver_impl/src/signal_handler.rs index 441219eec90dc..6a13a11db3c5e 100644 --- a/compiler/rustc_driver_impl/src/signal_handler.rs +++ b/compiler/rustc_driver_impl/src/signal_handler.rs @@ -1,146 +1,50 @@ -//! Signal handler for rustc -//! Primarily used to extract a backtrace from stack overflow - -use rustc_interface::util::{DEFAULT_STACK_SIZE, STACK_SIZE}; -use std::alloc::{alloc, Layout}; -use std::{fmt, mem, ptr}; - -extern "C" { - fn backtrace_symbols_fd(buffer: *const *mut libc::c_void, size: libc::c_int, fd: libc::c_int); -} - -fn backtrace_stderr(buffer: &[*mut libc::c_void]) { - let size = buffer.len().try_into().unwrap_or_default(); - unsafe { backtrace_symbols_fd(buffer.as_ptr(), size, libc::STDERR_FILENO) }; -} - -/// Unbuffered, unsynchronized writer to stderr. -/// -/// Only acceptable because everything will end soon anyways. -struct RawStderr(()); - -impl fmt::Write for RawStderr { - fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> { - let ret = unsafe { libc::write(libc::STDERR_FILENO, s.as_ptr().cast(), s.len()) }; - if ret == -1 { Err(fmt::Error) } else { Ok(()) } - } -} - -/// We don't really care how many bytes we actually get out. SIGSEGV comes for our head. -/// Splash stderr with letters of our own blood to warn our friends about the monster. -macro raw_errln($tokens:tt) { - let _ = ::core::fmt::Write::write_fmt(&mut RawStderr(()), format_args!($tokens)); - let _ = ::core::fmt::Write::write_char(&mut RawStderr(()), '\n'); -} - -/// Signal handler installed for SIGSEGV -extern "C" fn print_stack_trace(_: libc::c_int) { - const MAX_FRAMES: usize = 256; - // Reserve data segment so we don't have to malloc in a signal handler, which might fail - // in incredibly undesirable and unexpected ways due to e.g. the allocator deadlocking - static mut STACK_TRACE: [*mut libc::c_void; MAX_FRAMES] = [ptr::null_mut(); MAX_FRAMES]; - let stack = unsafe { - // Collect return addresses - let depth = libc::backtrace(STACK_TRACE.as_mut_ptr(), MAX_FRAMES as i32); - if depth == 0 { - return; - } - &STACK_TRACE.as_slice()[0..(depth as _)] - }; - - // Just a stack trace is cryptic. Explain what we're doing. - raw_errln!("error: rustc interrupted by SIGSEGV, printing backtrace\n"); - let mut written = 1; - let mut consumed = 0; - // Begin elaborating return addrs into symbols and writing them directly to stderr - // Most backtraces are stack overflow, most stack overflows are from recursion - // Check for cycles before writing 250 lines of the same ~5 symbols - let cycled = |(runner, walker)| runner == walker; - let mut cyclic = false; - if let Some(period) = stack.iter().skip(1).step_by(2).zip(stack).position(cycled) { - let period = period.saturating_add(1); // avoid "what if wrapped?" branches - let Some(offset) = stack.iter().skip(period).zip(stack).position(cycled) else { - // impossible. - return; - }; - - // Count matching trace slices, else we could miscount "biphasic cycles" - // with the same period + loop entry but a different inner loop - let next_cycle = stack[offset..].chunks_exact(period).skip(1); - let cycles = 1 + next_cycle - .zip(stack[offset..].chunks_exact(period)) - .filter(|(next, prev)| next == prev) - .count(); - backtrace_stderr(&stack[..offset]); - written += offset; - consumed += offset; - if cycles > 1 { - raw_errln!("\n### cycle encountered after {offset} frames with period {period}"); - backtrace_stderr(&stack[consumed..consumed + period]); - raw_errln!("### recursed {cycles} times\n"); - written += period + 4; - consumed += period * cycles; - cyclic = true; - }; - } - let rem = &stack[consumed..]; - backtrace_stderr(rem); - raw_errln!(""); - written += rem.len() + 1; - - let random_depth = || 8 * 16; // chosen by random diceroll (2d20) - if cyclic || stack.len() > random_depth() { - // technically speculation, but assert it with confidence anyway. - // rustc only arrived in this signal handler because bad things happened - // and this message is for explaining it's not the programmer's fault - raw_errln!("note: rustc unexpectedly overflowed its stack! this is a bug"); - written += 1; - } - if stack.len() == MAX_FRAMES { - raw_errln!("note: maximum backtrace depth reached, frames may have been lost"); - written += 1; - } - raw_errln!("note: we would appreciate a report at https://github.com/rust-lang/rust"); - // get the current stack size WITHOUT blocking and double it - let new_size = STACK_SIZE.get().copied().unwrap_or(DEFAULT_STACK_SIZE) * 2; - raw_errln!("help: you can increase rustc's stack size by setting RUST_MIN_STACK={new_size}"); - written += 2; - if written > 24 { - // We probably just scrolled the earlier "we got SIGSEGV" message off the terminal - raw_errln!("note: backtrace dumped due to SIGSEGV! resuming signal"); - }; -} - -/// When SIGSEGV is delivered to the process, print a stack trace and then exit. -pub(super) fn install() { - unsafe { - let alt_stack_size: usize = min_sigstack_size() + 64 * 1024; - let mut alt_stack: libc::stack_t = mem::zeroed(); - alt_stack.ss_sp = alloc(Layout::from_size_align(alt_stack_size, 1).unwrap()).cast(); - alt_stack.ss_size = alt_stack_size; - libc::sigaltstack(&alt_stack, ptr::null_mut()); - - let mut sa: libc::sigaction = mem::zeroed(); - sa.sa_sigaction = print_stack_trace as libc::sighandler_t; - sa.sa_flags = libc::SA_NODEFER | libc::SA_RESETHAND | libc::SA_ONSTACK; - libc::sigemptyset(&mut sa.sa_mask); - libc::sigaction(libc::SIGSEGV, &sa, ptr::null_mut()); - } -} - -/// Modern kernels on modern hardware can have dynamic signal stack sizes. -#[cfg(any(target_os = "linux", target_os = "android"))] -fn min_sigstack_size() -> usize { - const AT_MINSIGSTKSZ: core::ffi::c_ulong = 51; - let dynamic_sigstksz = unsafe { libc::getauxval(AT_MINSIGSTKSZ) }; - // If getauxval couldn't find the entry, it returns 0, - // so take the higher of the "constant" and auxval. - // This transparently supports older kernels which don't provide AT_MINSIGSTKSZ - libc::MINSIGSTKSZ.max(dynamic_sigstksz as _) -} - -/// Not all OS support hardware where this is needed. -#[cfg(not(any(target_os = "linux", target_os = "android")))] -fn min_sigstack_size() -> usize { - libc::MINSIGSTKSZ -} +use rustc_interface::util::{DEFAULT_STACK_SIZE,STACK_SIZE};use std::alloc::{//3; +alloc,Layout};use std::{fmt,mem ,ptr};extern "C"{fn backtrace_symbols_fd(buffer: +*const*mut libc::c_void,size:libc::c_int,fd:libc::c_int);}fn backtrace_stderr(// +buffer:&[*mut libc::c_void]){;let size=buffer.len().try_into().unwrap_or_default +();3;3;unsafe{backtrace_symbols_fd(buffer.as_ptr(),size,libc::STDERR_FILENO)};;} +struct RawStderr(());impl fmt::Write for RawStderr{fn write_str(&mut self,s:&//; +str)->Result<(),fmt::Error>{();let ret=unsafe{libc::write(libc::STDERR_FILENO,s. +as_ptr().cast(),s.len())};((),());if ret==-1{Err(fmt::Error)}else{Ok(())}}}macro +raw_errln($tokens:tt){let _=::core::fmt::Write::write_fmt(&mut RawStderr(()),//; +format_args!($tokens));let _=::core:: fmt::Write::write_char(&mut RawStderr(()), +'\n');}extern "C" fn print_stack_trace(_:libc::c_int){();const MAX_FRAMES:usize= +256;();3;static mut STACK_TRACE:[*mut libc::c_void;MAX_FRAMES]=[ptr::null_mut(); +MAX_FRAMES];;let stack=unsafe{let depth=libc::backtrace(STACK_TRACE.as_mut_ptr() +,MAX_FRAMES as i32);;if depth==0{return;}&STACK_TRACE.as_slice()[0..(depth as _) +]};;;raw_errln!("error: rustc interrupted by SIGSEGV, printing backtrace\n");let +mut written=1;;let mut consumed=0;let cycled=|(runner,walker)|runner==walker;let +mut cyclic=false;3;if let Some(period)=stack.iter().skip(1).step_by(2).zip(stack +).position(cycled){;let period=period.saturating_add(1);;let Some(offset)=stack. +iter().skip(period).zip(stack).position(cycled)else{;return;;};;;let next_cycle= +stack[offset..].chunks_exact(period).skip(1);;let cycles=1+next_cycle.zip(stack[ +offset..].chunks_exact(period)).filter(|(next,prev)|next==prev).count();{;};{;}; +backtrace_stderr(&stack[..offset]);;written+=offset;consumed+=offset;if cycles>1 +{((),());let _=();((),());let _=();((),());let _=();((),());let _=();raw_errln!( +"\n### cycle encountered after {offset} frames with period {period}");({});({}); +backtrace_stderr(&stack[consumed..consumed+period]);let _=();((),());raw_errln!( +"### recursed {cycles} times\n");;;written+=period+4;;;consumed+=period*cycles;; +cyclic=true;;};}let rem=&stack[consumed..];backtrace_stderr(rem);raw_errln!(""); +written+=rem.len()+1;{;};{;};let random_depth=||8*16;{;};if cyclic||stack.len()> +random_depth(){loop{break;};if let _=(){};loop{break;};if let _=(){};raw_errln!( +"note: rustc unexpectedly overflowed its stack! this is a bug");;written+=1;}if +stack.len()==MAX_FRAMES{let _=||();let _=||();let _=||();loop{break};raw_errln!( +"note: maximum backtrace depth reached, frames may have been lost");;written+=1; +}((),());let _=();((),());let _=();((),());let _=();((),());let _=();raw_errln!( +"note: we would appreciate a report at https://github.com/rust-lang/rust");;;let +new_size=STACK_SIZE.get().copied().unwrap_or(DEFAULT_STACK_SIZE)*2;;;raw_errln!( +"help: you can increase rustc's stack size by setting RUST_MIN_STACK={new_size}" +);let _=();let _=();written+=2;((),());((),());if written>24{((),());raw_errln!( +"note: backtrace dumped due to SIGSEGV! resuming signal");{;};};();}pub(super)fn +install(){unsafe{;let alt_stack_size:usize=min_sigstack_size()+64*1024;;;let mut +alt_stack:libc::stack_t=mem::zeroed();{();};{();};alt_stack.ss_sp=alloc(Layout:: +from_size_align(alt_stack_size,1).unwrap()).cast();{();};({});alt_stack.ss_size= +alt_stack_size;;;libc::sigaltstack(&alt_stack,ptr::null_mut());let mut sa:libc:: +sigaction=mem::zeroed();;sa.sa_sigaction=print_stack_trace as libc::sighandler_t +;3;3;sa.sa_flags=libc::SA_NODEFER|libc::SA_RESETHAND|libc::SA_ONSTACK;3;3;libc:: +sigemptyset(&mut sa.sa_mask);;libc::sigaction(libc::SIGSEGV,&sa,ptr::null_mut()) +;();}}#[cfg(any(target_os="linux",target_os="android"))]fn min_sigstack_size()-> +usize{;const AT_MINSIGSTKSZ:core::ffi::c_ulong=51;;;let dynamic_sigstksz=unsafe{ +libc::getauxval(AT_MINSIGSTKSZ)};;libc::MINSIGSTKSZ.max(dynamic_sigstksz as _)}# +[cfg(not(any(target_os="linux",target_os="android")))]fn min_sigstack_size()->// +usize{libc::MINSIGSTKSZ}//loop{break;};if let _=(){};loop{break;};if let _=(){}; diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index da688e385aa09..1d99fc73d1fa7 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -1,677 +1,76 @@ -//! This library is used to gather all error codes into one place, to make -//! their maintenance easier. - -#![allow(internal_features)] -#![feature(rustdoc_internals)] -#![doc(rust_logo)] -#![deny(rustdoc::invalid_codeblock_attributes)] - -// This higher-order macro defines the error codes that are in use. It is used -// in the `rustc_errors` crate. Removed error codes are listed in the comment -// below. -// -// /!\ IMPORTANT /!\ -// -// Error code explanation are defined in `error_codes/EXXXX.md` files. They must follow the RFC -// 1567 available here: -// https://rust-lang.github.io/rfcs/1567-long-error-codes-explanation-normalization.html -// -// Also, the contents of this macro is checked by tidy (in `check_error_codes_docs`). If you change -// the macro syntax you will need to change tidy as well. -// -// Both columns are necessary because it's not possible in Rust to create a new identifier such as -// `E0123` from an integer literal such as `0123`, unfortunately. -#[macro_export] -macro_rules! error_codes { - ($macro:path) => ( - $macro!( -E0001: 0001, -E0002: 0002, -E0004: 0004, -E0005: 0005, -E0007: 0007, -E0009: 0009, -E0010: 0010, -E0013: 0013, -E0014: 0014, -E0015: 0015, -E0023: 0023, -E0025: 0025, -E0026: 0026, -E0027: 0027, -E0029: 0029, -E0030: 0030, -E0033: 0033, -E0034: 0034, -E0038: 0038, -E0040: 0040, -E0044: 0044, -E0045: 0045, -E0046: 0046, -E0049: 0049, -E0050: 0050, -E0053: 0053, -E0054: 0054, -E0055: 0055, -E0057: 0057, -E0059: 0059, -E0060: 0060, -E0061: 0061, -E0062: 0062, -E0063: 0063, -E0067: 0067, -E0069: 0069, -E0070: 0070, -E0071: 0071, -E0072: 0072, -E0073: 0073, -E0074: 0074, -E0075: 0075, -E0076: 0076, -E0077: 0077, -E0080: 0080, -E0081: 0081, -E0084: 0084, -E0087: 0087, -E0088: 0088, -E0089: 0089, -E0090: 0090, -E0091: 0091, -E0092: 0092, -E0093: 0093, -E0094: 0094, -E0106: 0106, -E0107: 0107, -E0109: 0109, -E0110: 0110, -E0116: 0116, -E0117: 0117, -E0118: 0118, -E0119: 0119, -E0120: 0120, -E0121: 0121, -E0124: 0124, -E0128: 0128, -E0130: 0130, -E0131: 0131, -E0132: 0132, -E0133: 0133, -E0136: 0136, -E0137: 0137, -E0138: 0138, -E0139: 0139, -E0152: 0152, -E0154: 0154, -E0158: 0158, -E0161: 0161, -E0162: 0162, -E0164: 0164, -E0165: 0165, -E0170: 0170, -E0178: 0178, -E0183: 0183, -E0184: 0184, -E0185: 0185, -E0186: 0186, -E0191: 0191, -E0192: 0192, -E0193: 0193, -E0195: 0195, -E0197: 0197, -E0198: 0198, -E0199: 0199, -E0200: 0200, -E0201: 0201, -E0203: 0203, -E0204: 0204, -E0205: 0205, -E0206: 0206, -E0207: 0207, -E0208: 0208, -E0210: 0210, -E0211: 0211, -E0212: 0212, -E0214: 0214, -E0220: 0220, -E0221: 0221, -E0222: 0222, -E0223: 0223, -E0224: 0224, -E0225: 0225, -E0226: 0226, -E0227: 0227, -E0228: 0228, -E0229: 0229, -E0230: 0230, -E0231: 0231, -E0232: 0232, -E0243: 0243, -E0244: 0244, -E0251: 0251, -E0252: 0252, -E0253: 0253, -E0254: 0254, -E0255: 0255, -E0256: 0256, -E0259: 0259, -E0260: 0260, -E0261: 0261, -E0262: 0262, -E0263: 0263, -E0264: 0264, -E0267: 0267, -E0268: 0268, -E0271: 0271, -E0275: 0275, -E0276: 0276, -E0277: 0277, -E0281: 0281, -E0282: 0282, -E0283: 0283, -E0284: 0284, -E0297: 0297, -E0301: 0301, -E0302: 0302, -E0303: 0303, -E0307: 0307, -E0308: 0308, -E0309: 0309, -E0310: 0310, -E0311: 0311, -E0312: 0312, -E0316: 0316, -E0317: 0317, -E0320: 0320, -E0321: 0321, -E0322: 0322, -E0323: 0323, -E0324: 0324, -E0325: 0325, -E0326: 0326, -E0328: 0328, -E0329: 0329, -E0364: 0364, -E0365: 0365, -E0366: 0366, -E0367: 0367, -E0368: 0368, -E0369: 0369, -E0370: 0370, -E0371: 0371, -E0373: 0373, -E0374: 0374, -E0375: 0375, -E0376: 0376, -E0377: 0377, -E0378: 0378, -E0379: 0379, -E0380: 0380, -E0381: 0381, -E0382: 0382, -E0383: 0383, -E0384: 0384, -E0386: 0386, -E0387: 0387, -E0388: 0388, -E0389: 0389, -E0390: 0390, -E0391: 0391, -E0392: 0392, -E0393: 0393, -E0398: 0398, -E0399: 0399, -E0401: 0401, -E0403: 0403, -E0404: 0404, -E0405: 0405, -E0407: 0407, -E0408: 0408, -E0409: 0409, -E0411: 0411, -E0412: 0412, -E0415: 0415, -E0416: 0416, -E0422: 0422, -E0423: 0423, -E0424: 0424, -E0425: 0425, -E0426: 0426, -E0428: 0428, -E0429: 0429, -E0430: 0430, -E0431: 0431, -E0432: 0432, -E0433: 0433, -E0434: 0434, -E0435: 0435, -E0436: 0436, -E0437: 0437, -E0438: 0438, -E0439: 0439, -E0445: 0445, -E0446: 0446, -E0447: 0447, -E0448: 0448, -E0449: 0449, -E0451: 0451, -E0452: 0452, -E0453: 0453, -E0454: 0454, -E0455: 0455, -E0457: 0457, -E0458: 0458, -E0459: 0459, -E0460: 0460, -E0461: 0461, -E0462: 0462, -E0463: 0463, -E0464: 0464, -E0466: 0466, -E0468: 0468, -E0469: 0469, -E0472: 0472, -E0476: 0476, -E0477: 0477, -E0478: 0478, -E0482: 0482, -E0491: 0491, -E0492: 0492, -E0493: 0493, -E0495: 0495, -E0496: 0496, -E0497: 0497, -E0498: 0498, -E0499: 0499, -E0500: 0500, -E0501: 0501, -E0502: 0502, -E0503: 0503, -E0504: 0504, -E0505: 0505, -E0506: 0506, -E0507: 0507, -E0508: 0508, -E0509: 0509, -E0510: 0510, -E0511: 0511, -E0512: 0512, -E0514: 0514, -E0515: 0515, -E0516: 0516, -E0517: 0517, -E0518: 0518, -E0519: 0519, -E0520: 0520, -E0521: 0521, -E0522: 0522, -E0523: 0523, -E0524: 0524, -E0525: 0525, -E0527: 0527, -E0528: 0528, -E0529: 0529, -E0530: 0530, -E0531: 0531, -E0532: 0532, -E0533: 0533, -E0534: 0534, -E0535: 0535, -E0536: 0536, -E0537: 0537, -E0538: 0538, -E0539: 0539, -E0541: 0541, -E0542: 0542, -E0543: 0543, -E0544: 0544, -E0545: 0545, -E0546: 0546, -E0547: 0547, -E0549: 0549, -E0550: 0550, -E0551: 0551, -E0552: 0552, -E0554: 0554, -E0556: 0556, -E0557: 0557, -E0559: 0559, -E0560: 0560, -E0561: 0561, -E0562: 0562, -E0565: 0565, -E0566: 0566, -E0567: 0567, -E0568: 0568, -E0569: 0569, -E0570: 0570, -E0571: 0571, -E0572: 0572, -E0573: 0573, -E0574: 0574, -E0575: 0575, -E0576: 0576, -E0577: 0577, -E0578: 0578, -E0579: 0579, -E0580: 0580, -E0581: 0581, -E0582: 0582, -E0583: 0583, -E0584: 0584, -E0585: 0585, -E0586: 0586, -E0587: 0587, -E0588: 0588, -E0589: 0589, -E0590: 0590, -E0591: 0591, -E0592: 0592, -E0593: 0593, -E0594: 0594, -E0595: 0595, -E0596: 0596, -E0597: 0597, -E0599: 0599, -E0600: 0600, -E0601: 0601, -E0602: 0602, -E0603: 0603, -E0604: 0604, -E0605: 0605, -E0606: 0606, -E0607: 0607, -E0608: 0608, -E0609: 0609, -E0610: 0610, -E0614: 0614, -E0615: 0615, -E0616: 0616, -E0617: 0617, -E0618: 0618, -E0619: 0619, -E0620: 0620, -E0621: 0621, -E0622: 0622, -E0623: 0623, -E0624: 0624, -E0625: 0625, -E0626: 0626, -E0627: 0627, -E0628: 0628, -E0631: 0631, -E0632: 0632, -E0633: 0633, -E0634: 0634, -E0635: 0635, -E0636: 0636, -E0637: 0637, -E0638: 0638, -E0639: 0639, -E0640: 0640, -E0641: 0641, -E0642: 0642, -E0643: 0643, -E0644: 0644, -E0646: 0646, -E0647: 0647, -E0648: 0648, -E0657: 0657, -E0658: 0658, -E0659: 0659, -E0660: 0660, -E0661: 0661, -E0662: 0662, -E0663: 0663, -E0664: 0664, -E0665: 0665, -E0666: 0666, -E0667: 0667, -E0668: 0668, -E0669: 0669, -E0670: 0670, -E0671: 0671, -E0687: 0687, -E0688: 0688, -E0689: 0689, -E0690: 0690, -E0691: 0691, -E0692: 0692, -E0693: 0693, -E0695: 0695, -E0696: 0696, -E0697: 0697, -E0698: 0698, -E0699: 0699, -E0700: 0700, -E0701: 0701, -E0703: 0703, -E0704: 0704, -E0705: 0705, -E0706: 0706, -E0708: 0708, -E0710: 0710, -E0712: 0712, -E0713: 0713, -E0714: 0714, -E0715: 0715, -E0716: 0716, -E0711: 0711, -E0717: 0717, -E0718: 0718, -E0719: 0719, -E0720: 0720, -E0722: 0722, -E0724: 0724, -E0725: 0725, -E0726: 0726, -E0727: 0727, -E0728: 0728, -E0729: 0729, -E0730: 0730, -E0731: 0731, -E0732: 0732, -E0733: 0733, -E0734: 0734, -E0735: 0735, -E0736: 0736, -E0737: 0737, -E0739: 0739, -E0740: 0740, -E0741: 0741, -E0742: 0742, -E0743: 0743, -E0744: 0744, -E0745: 0745, -E0746: 0746, -E0747: 0747, -E0748: 0748, -E0749: 0749, -E0750: 0750, -E0751: 0751, -E0752: 0752, -E0753: 0753, -E0754: 0754, -E0755: 0755, -E0756: 0756, -E0757: 0757, -E0758: 0758, -E0759: 0759, -E0760: 0760, -E0761: 0761, -E0762: 0762, -E0763: 0763, -E0764: 0764, -E0765: 0765, -E0766: 0766, -E0767: 0767, -E0768: 0768, -E0769: 0769, -E0770: 0770, -E0771: 0771, -E0772: 0772, -E0773: 0773, -E0774: 0774, -E0775: 0775, -E0776: 0776, -E0777: 0777, -E0778: 0778, -E0779: 0779, -E0780: 0780, -E0781: 0781, -E0782: 0782, -E0783: 0783, -E0784: 0784, -E0785: 0785, -E0786: 0786, -E0787: 0787, -E0788: 0788, -E0789: 0789, -E0790: 0790, -E0791: 0791, -E0792: 0792, -E0793: 0793, -E0794: 0794, -E0795: 0795, -E0796: 0796, -E0797: 0797, - ); - ) -} - -// Undocumented removed error codes. Note that many removed error codes are kept in the list above -// and marked as no-longer emitted with a note in the markdown file (see E0001 for an example). -// E0006, // merged with E0005 -// E0008, // cannot bind by-move into a pattern guard -// E0019, // merged into E0015 -// E0035, // merged into E0087/E0089 -// E0036, // merged into E0087/E0089 -// E0068, -// E0085, -// E0086, -// E0101, // replaced with E0282 -// E0102, // replaced with E0282 -// E0103, -// E0104, -// E0122, // bounds in type aliases are ignored, turned into proper lint -// E0123, -// E0127, -// E0129, -// E0134, -// E0135, -// E0141, -// E0153, // unused error code -// E0157, // unused error code -// E0159, // use of trait `{}` as struct constructor -// E0163, // merged into E0071 -// E0167, -// E0168, -// E0172, // non-trait found in a type sum, moved to resolve -// E0173, // manual implementations of unboxed closure traits are experimental -// E0174, -// E0182, // merged into E0229 -// E0187, // cannot infer the kind of the closure -// E0188, // can not cast an immutable reference to a mutable pointer -// E0189, // deprecated: can only cast a boxed pointer to a boxed object -// E0190, // deprecated: can only cast a &-pointer to an &-object -// E0194, // merged into E0403 -// E0196, // cannot determine a type for this closure -// E0209, // builtin traits can only be implemented on structs or enums -// E0213, // associated types are not accepted in this context -// E0215, // angle-bracket notation is not stable with `Fn` -// E0216, // parenthetical notation is only stable with `Fn` -// E0217, // ambiguous associated type, defined in multiple supertraits -// E0218, // no associated type defined -// E0219, // associated type defined in higher-ranked supertrait -// E0233, -// E0234, -// E0235, // structure constructor specifies a structure of type but -// E0236, // no lang item for range syntax -// E0237, // no lang item for range syntax -// E0238, // parenthesized parameters may only be used with a trait -// E0239, // `next` method of `Iterator` trait has unexpected type -// E0240, -// E0241, -// E0242, -// E0245, // not a trait -// E0246, // invalid recursive type -// E0247, -// E0248, // value used as a type, now reported earlier during resolution -// // as E0412 -// E0249, -// E0257, -// E0258, -// E0272, // on_unimplemented #0 -// E0273, // on_unimplemented #1 -// E0274, // on_unimplemented #2 -// E0278, // requirement is not satisfied -// E0279, -// E0280, // changed to ICE -// E0285, // overflow evaluation builtin bounds -// E0296, // replaced with a generic attribute input check -// E0298, // cannot compare constants -// E0299, // mismatched types between arms -// E0300, // unexpanded macro -// E0304, // expected signed integer constant -// E0305, // expected constant -// E0313, // removed: found unreachable -// E0314, // closure outlives stack frame -// E0315, // cannot invoke closure outside of its lifetime -// E0319, // trait impls for defaulted traits allowed just for structs/enums -// E0372, // coherence not object safe -// E0385, // {} in an aliasable location -// E0402, // cannot use an outer type parameter in this context -// E0406, // merged into 420 -// E0410, // merged into 408 -// E0413, // merged into 530 -// E0414, // merged into 530 -// E0417, // merged into 532 -// E0418, // merged into 532 -// E0419, // merged into 531 -// E0420, // merged into 532 -// E0421, // merged into 531 -// E0427, // merged into 530 -// E0445, // merged into 446 and type privacy lints -// E0456, // plugin `..` is not available for triple `..` -// E0465, // removed: merged with E0464 -// E0467, // removed -// E0470, // removed -// E0471, // constant evaluation error (in pattern) -// E0473, // dereference of reference outside its lifetime -// E0474, // captured variable `..` does not outlive the enclosing closure -// E0475, // index of slice outside its lifetime -// E0479, // the type `..` (provided as the value of a type parameter) is... -// E0480, // lifetime of method receiver does not outlive the method call -// E0481, // lifetime of function argument does not outlive the function call -// E0483, // lifetime of operand does not outlive the operation -// E0484, // reference is not valid at the time of borrow -// E0485, // automatically reference is not valid at the time of borrow -// E0486, // type of expression contains references that are not valid during.. -// E0487, // unsafe use of destructor: destructor might be called while... -// E0488, // lifetime of variable does not enclose its declaration -// E0489, // type/lifetime parameter not in scope here -// E0490, // removed: unreachable -// E0526, // shuffle indices are not constant -// E0540, // multiple rustc_deprecated attributes -// E0548, // replaced with a generic attribute input check -// E0553, // multiple rustc_const_unstable attributes -// E0555, // replaced with a generic attribute input check -// E0558, // replaced with a generic attribute input check -// E0563, // cannot determine a type for this `impl Trait` removed in 6383de15 -// E0564, // only named lifetimes are allowed in `impl Trait`, -// // but `{}` was found in the type `{}` -// E0598, // lifetime of {} is too short to guarantee its contents can be... -// E0611, // merged into E0616 -// E0612, // merged into E0609 -// E0613, // Removed (merged with E0609) -// E0629, // missing 'feature' (rustc_const_unstable) -// E0630, // rustc_const_unstable attribute must be paired with stable/unstable -// // attribute -// E0645, // trait aliases not finished -// E0694, // an unknown tool name found in scoped attributes -// E0702, // replaced with a generic attribute input check -// E0707, // multiple elided lifetimes used in arguments of `async fn` -// E0709, // multiple different lifetimes used in arguments of `async fn` -// E0721, // `await` keyword -// E0723, // unstable feature in `const` context -// E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`. -// E0744, // merged into E0728 +#![allow(internal_features)]#![feature( rustdoc_internals)]#![doc(rust_logo)]#![ +deny(rustdoc::invalid_codeblock_attributes)]#[macro_export]macro_rules!//*&*&(); +error_codes{($macro:path)=>($macro!( E0001:0001,E0002:0002,E0004:0004,E0005:0005 +,E0007:0007,E0009:0009,E0010:0010,E0013:0013,E0014:0014,E0015:0015,E0023:0023,// +E0025:0025,E0026:0026,E0027:0027,E0029:0029,E0030:0030,E0033:0033,E0034:0034,//; +E0038:0038,E0040:0040,E0044:0044,E0045:0045,E0046:0046,E0049:0049,E0050:0050,//; +E0053:0053,E0054:0054,E0055:0055,E0057:0057,E0059:0059,E0060:0060,E0061:0061,//; +E0062:0062,E0063:0063,E0067:0067,E0069:0069,E0070:0070,E0071:0071,E0072:0072,//; +E0073:0073,E0074:0074,E0075:0075,E0076:0076,E0077:0077,E0080:0080,E0081:0081,//; +E0084:0084,E0087:0087,E0088:0088,E0089:0089,E0090:0090,E0091:0091,E0092:0092,//; +E0093:0093,E0094:0094,E0106:0106,E0107:0107,E0109:0109,E0110:0110,E0116:0116,//; +E0117:0117,E0118:0118,E0119:0119,E0120:0120,E0121:0121,E0124:0124,E0128:0128,//; +E0130:0130,E0131:0131,E0132:0132,E0133:0133,E0136:0136,E0137:0137,E0138:0138,//; +E0139:0139,E0152:0152,E0154:0154,E0158:0158,E0161:0161,E0162:0162,E0164:0164,//; +E0165:0165,E0170:0170,E0178:0178,E0183:0183,E0184:0184,E0185:0185,E0186:0186,//; +E0191:0191,E0192:0192,E0193:0193,E0195:0195,E0197:0197,E0198:0198,E0199:0199,//; +E0200:0200,E0201:0201,E0203:0203,E0204:0204,E0205:0205,E0206:0206,E0207:0207,//; +E0208:0208,E0210:0210,E0211:0211,E0212:0212,E0214:0214,E0220:0220,E0221:0221,//; +E0222:0222,E0223:0223,E0224:0224,E0225:0225,E0226:0226,E0227:0227,E0228:0228,//; +E0229:0229,E0230:0230,E0231:0231,E0232:0232,E0243:0243,E0244:0244,E0251:0251,//; +E0252:0252,E0253:0253,E0254:0254,E0255:0255,E0256:0256,E0259:0259,E0260:0260,//; +E0261:0261,E0262:0262,E0263:0263,E0264:0264,E0267:0267,E0268:0268,E0271:0271,//; +E0275:0275,E0276:0276,E0277:0277,E0281:0281,E0282:0282,E0283:0283,E0284:0284,//; +E0297:0297,E0301:0301,E0302:0302,E0303:0303,E0307:0307,E0308:0308,E0309:0309,//; +E0310:0310,E0311:0311,E0312:0312,E0316:0316,E0317:0317,E0320:0320,E0321:0321,//; +E0322:0322,E0323:0323,E0324:0324,E0325:0325,E0326:0326,E0328:0328,E0329:0329,//; +E0364:0364,E0365:0365,E0366:0366,E0367:0367,E0368:0368,E0369:0369,E0370:0370,//; +E0371:0371,E0373:0373,E0374:0374,E0375:0375,E0376:0376,E0377:0377,E0378:0378,//; +E0379:0379,E0380:0380,E0381:0381,E0382:0382,E0383:0383,E0384:0384,E0386:0386,//; +E0387:0387,E0388:0388,E0389:0389,E0390:0390,E0391:0391,E0392:0392,E0393:0393,//; +E0398:0398,E0399:0399,E0401:0401,E0403:0403,E0404:0404,E0405:0405,E0407:0407,//; +E0408:0408,E0409:0409,E0411:0411,E0412:0412,E0415:0415,E0416:0416,E0422:0422,//; +E0423:0423,E0424:0424,E0425:0425,E0426:0426,E0428:0428,E0429:0429,E0430:0430,//; +E0431:0431,E0432:0432,E0433:0433,E0434:0434,E0435:0435,E0436:0436,E0437:0437,//; +E0438:0438,E0439:0439,E0445:0445,E0446:0446,E0447:0447,E0448:0448,E0449:0449,//; +E0451:0451,E0452:0452,E0453:0453,E0454:0454,E0455:0455,E0457:0457,E0458:0458,//; +E0459:0459,E0460:0460,E0461:0461,E0462:0462,E0463:0463,E0464:0464,E0466:0466,//; +E0468:0468,E0469:0469,E0472:0472,E0476:0476,E0477:0477,E0478:0478,E0482:0482,//; +E0491:0491,E0492:0492,E0493:0493,E0495:0495,E0496:0496,E0497:0497,E0498:0498,//; +E0499:0499,E0500:0500,E0501:0501,E0502:0502,E0503:0503,E0504:0504,E0505:0505,//; +E0506:0506,E0507:0507,E0508:0508,E0509:0509,E0510:0510,E0511:0511,E0512:0512,//; +E0514:0514,E0515:0515,E0516:0516,E0517:0517,E0518:0518,E0519:0519,E0520:0520,//; +E0521:0521,E0522:0522,E0523:0523,E0524:0524,E0525:0525,E0527:0527,E0528:0528,//; +E0529:0529,E0530:0530,E0531:0531,E0532:0532,E0533:0533,E0534:0534,E0535:0535,//; +E0536:0536,E0537:0537,E0538:0538,E0539:0539,E0541:0541,E0542:0542,E0543:0543,//; +E0544:0544,E0545:0545,E0546:0546,E0547:0547,E0549:0549,E0550:0550,E0551:0551,//; +E0552:0552,E0554:0554,E0556:0556,E0557:0557,E0559:0559,E0560:0560,E0561:0561,//; +E0562:0562,E0565:0565,E0566:0566,E0567:0567,E0568:0568,E0569:0569,E0570:0570,//; +E0571:0571,E0572:0572,E0573:0573,E0574:0574,E0575:0575,E0576:0576,E0577:0577,//; +E0578:0578,E0579:0579,E0580:0580,E0581:0581,E0582:0582,E0583:0583,E0584:0584,//; +E0585:0585,E0586:0586,E0587:0587,E0588:0588,E0589:0589,E0590:0590,E0591:0591,//; +E0592:0592,E0593:0593,E0594:0594,E0595:0595,E0596:0596,E0597:0597,E0599:0599,//; +E0600:0600,E0601:0601,E0602:0602,E0603:0603,E0604:0604,E0605:0605,E0606:0606,//; +E0607:0607,E0608:0608,E0609:0609,E0610:0610,E0614:0614,E0615:0615,E0616:0616,//; +E0617:0617,E0618:0618,E0619:0619,E0620:0620,E0621:0621,E0622:0622,E0623:0623,//; +E0624:0624,E0625:0625,E0626:0626,E0627:0627,E0628:0628,E0631:0631,E0632:0632,//; +E0633:0633,E0634:0634,E0635:0635,E0636:0636,E0637:0637,E0638:0638,E0639:0639,//; +E0640:0640,E0641:0641,E0642:0642,E0643:0643,E0644:0644,E0646:0646,E0647:0647,//; +E0648:0648,E0657:0657,E0658:0658,E0659:0659,E0660:0660,E0661:0661,E0662:0662,//; +E0663:0663,E0664:0664,E0665:0665,E0666:0666,E0667:0667,E0668:0668,E0669:0669,//; +E0670:0670,E0671:0671,E0687:0687,E0688:0688,E0689:0689,E0690:0690,E0691:0691,//; +E0692:0692,E0693:0693,E0695:0695,E0696:0696,E0697:0697,E0698:0698,E0699:0699,//; +E0700:0700,E0701:0701,E0703:0703,E0704:0704,E0705:0705,E0706:0706,E0708:0708,//; +E0710:0710,E0712:0712,E0713:0713,E0714:0714,E0715:0715,E0716:0716,E0711:0711,//; +E0717:0717,E0718:0718,E0719:0719,E0720:0720,E0722:0722,E0724:0724,E0725:0725,//; +E0726:0726,E0727:0727,E0728:0728,E0729:0729,E0730:0730,E0731:0731,E0732:0732,//; +E0733:0733,E0734:0734,E0735:0735,E0736:0736,E0737:0737,E0739:0739,E0740:0740,//; +E0741:0741,E0742:0742,E0743:0743,E0744:0744,E0745:0745,E0746:0746,E0747:0747,//; +E0748:0748,E0749:0749,E0750:0750,E0751:0751,E0752:0752,E0753:0753,E0754:0754,//; +E0755:0755,E0756:0756,E0757:0757,E0758:0758,E0759:0759,E0760:0760,E0761:0761,//; +E0762:0762,E0763:0763,E0764:0764,E0765:0765,E0766:0766,E0767:0767,E0768:0768,//; +E0769:0769,E0770:0770,E0771:0771,E0772:0772,E0773:0773,E0774:0774,E0775:0775,//; +E0776:0776,E0777:0777,E0778:0778,E0779:0779,E0780:0780,E0781:0781,E0782:0782,//; +E0783:0783,E0784:0784,E0785:0785,E0786:0786,E0787:0787,E0788:0788,E0789:0789,//; +E0790:0790,E0791:0791,E0792:0792,E0793:0793,E0794:0794,E0795:0795,E0796:0796,//; +E0797:0797,);)}//*&*&();((),());((),());((),());((),());((),());((),());((),()); diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index ad82c2d96e7a7..7292f6f577b0c 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -1,627 +1,174 @@ -#![doc(rust_logo)] -#![feature(rustdoc_internals)] -#![feature(lazy_cell)] -#![feature(rustc_attrs)] -#![feature(type_alias_impl_trait)] -#![allow(internal_features)] - -#[macro_use] -extern crate tracing; - -use fluent_bundle::FluentResource; -use fluent_syntax::parser::ParserError; -use icu_provider_adapters::fallback::{LocaleFallbackProvider, LocaleFallbacker}; -use rustc_data_structures::sync::{IntoDynSyncSend, Lrc}; -use rustc_macros::{Decodable, Encodable}; -use rustc_span::Span; -use std::borrow::Cow; -use std::error::Error; -use std::fmt; -use std::fs; -use std::io; -use std::path::{Path, PathBuf}; - -#[cfg(not(parallel_compiler))] -use std::cell::LazyCell as Lazy; -#[cfg(parallel_compiler)] -use std::sync::LazyLock as Lazy; - -#[cfg(parallel_compiler)] -use intl_memoizer::concurrent::IntlLangMemoizer; -#[cfg(not(parallel_compiler))] -use intl_memoizer::IntlLangMemoizer; - -pub use fluent_bundle::{self, types::FluentType, FluentArgs, FluentError, FluentValue}; -pub use unic_langid::{langid, LanguageIdentifier}; - -pub type FluentBundle = - IntoDynSyncSend>; - -#[cfg(not(parallel_compiler))] -fn new_bundle(locales: Vec) -> FluentBundle { - IntoDynSyncSend(fluent_bundle::bundle::FluentBundle::new(locales)) -} - -#[cfg(parallel_compiler)] -fn new_bundle(locales: Vec) -> FluentBundle { - IntoDynSyncSend(fluent_bundle::bundle::FluentBundle::new_concurrent(locales)) -} - -#[derive(Debug)] -pub enum TranslationBundleError { - /// Failed to read from `.ftl` file. - ReadFtl(io::Error), - /// Failed to parse contents of `.ftl` file. - ParseFtl(ParserError), - /// Failed to add `FluentResource` to `FluentBundle`. - AddResource(FluentError), - /// `$sysroot/share/locale/$locale` does not exist. - MissingLocale, - /// Cannot read directory entries of `$sysroot/share/locale/$locale`. - ReadLocalesDir(io::Error), - /// Cannot read directory entry of `$sysroot/share/locale/$locale`. - ReadLocalesDirEntry(io::Error), - /// `$sysroot/share/locale/$locale` is not a directory. - LocaleIsNotDir, -} - -impl fmt::Display for TranslationBundleError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - TranslationBundleError::ReadFtl(e) => write!(f, "could not read ftl file: {e}"), - TranslationBundleError::ParseFtl(e) => { - write!(f, "could not parse ftl file: {e}") - } - TranslationBundleError::AddResource(e) => write!(f, "failed to add resource: {e}"), - TranslationBundleError::MissingLocale => write!(f, "missing locale directory"), - TranslationBundleError::ReadLocalesDir(e) => { - write!(f, "could not read locales dir: {e}") - } - TranslationBundleError::ReadLocalesDirEntry(e) => { - write!(f, "could not read locales dir entry: {e}") - } - TranslationBundleError::LocaleIsNotDir => { - write!(f, "`$sysroot/share/locales/$locale` is not a directory") - } - } - } -} - -impl Error for TranslationBundleError { - fn source(&self) -> Option<&(dyn Error + 'static)> { - match self { - TranslationBundleError::ReadFtl(e) => Some(e), - TranslationBundleError::ParseFtl(e) => Some(e), - TranslationBundleError::AddResource(e) => Some(e), - TranslationBundleError::MissingLocale => None, - TranslationBundleError::ReadLocalesDir(e) => Some(e), - TranslationBundleError::ReadLocalesDirEntry(e) => Some(e), - TranslationBundleError::LocaleIsNotDir => None, - } - } -} - -impl From<(FluentResource, Vec)> for TranslationBundleError { - fn from((_, mut errs): (FluentResource, Vec)) -> Self { - TranslationBundleError::ParseFtl(errs.pop().expect("failed ftl parse with no errors")) - } -} - -impl From> for TranslationBundleError { - fn from(mut errs: Vec) -> Self { - TranslationBundleError::AddResource( - errs.pop().expect("failed adding resource to bundle with no errors"), - ) - } -} - -/// Returns Fluent bundle with the user's locale resources from -/// `$sysroot/share/locale/$requested_locale/*.ftl`. -/// -/// If `-Z additional-ftl-path` was provided, load that resource and add it to the bundle -/// (overriding any conflicting messages). -#[instrument(level = "trace")] -pub fn fluent_bundle( - mut user_provided_sysroot: Option, - mut sysroot_candidates: Vec, - requested_locale: Option, - additional_ftl_path: Option<&Path>, - with_directionality_markers: bool, -) -> Result>, TranslationBundleError> { - if requested_locale.is_none() && additional_ftl_path.is_none() { - return Ok(None); - } - - let fallback_locale = langid!("en-US"); - let requested_fallback_locale = requested_locale.as_ref() == Some(&fallback_locale); - trace!(?requested_fallback_locale); - if requested_fallback_locale && additional_ftl_path.is_none() { - return Ok(None); - } - // If there is only `-Z additional-ftl-path`, assume locale is "en-US", otherwise use user - // provided locale. - let locale = requested_locale.clone().unwrap_or(fallback_locale); - trace!(?locale); - let mut bundle = new_bundle(vec![locale]); - - // Add convenience functions available to ftl authors. - register_functions(&mut bundle); - - // Fluent diagnostics can insert directionality isolation markers around interpolated variables - // indicating that there may be a shift from right-to-left to left-to-right text (or - // vice-versa). These are disabled because they are sometimes visible in the error output, but - // may be worth investigating in future (for example: if type names are left-to-right and the - // surrounding diagnostic messages are right-to-left, then these might be helpful). - bundle.set_use_isolating(with_directionality_markers); - - // If the user requests the default locale then don't try to load anything. - if let Some(requested_locale) = requested_locale { - let mut found_resources = false; - for sysroot in user_provided_sysroot.iter_mut().chain(sysroot_candidates.iter_mut()) { - sysroot.push("share"); - sysroot.push("locale"); - sysroot.push(requested_locale.to_string()); - trace!(?sysroot); - - if !sysroot.exists() { - trace!("skipping"); - continue; - } - - if !sysroot.is_dir() { - return Err(TranslationBundleError::LocaleIsNotDir); - } - - for entry in sysroot.read_dir().map_err(TranslationBundleError::ReadLocalesDir)? { - let entry = entry.map_err(TranslationBundleError::ReadLocalesDirEntry)?; - let path = entry.path(); - trace!(?path); - if path.extension().and_then(|s| s.to_str()) != Some("ftl") { - trace!("skipping"); - continue; - } - - let resource_str = - fs::read_to_string(path).map_err(TranslationBundleError::ReadFtl)?; - let resource = - FluentResource::try_new(resource_str).map_err(TranslationBundleError::from)?; - trace!(?resource); - bundle.add_resource(resource).map_err(TranslationBundleError::from)?; - found_resources = true; - } - } - - if !found_resources { - return Err(TranslationBundleError::MissingLocale); - } - } - - if let Some(additional_ftl_path) = additional_ftl_path { - let resource_str = - fs::read_to_string(additional_ftl_path).map_err(TranslationBundleError::ReadFtl)?; - let resource = - FluentResource::try_new(resource_str).map_err(TranslationBundleError::from)?; - trace!(?resource); - bundle.add_resource_overriding(resource); - } - - let bundle = Lrc::new(bundle); - Ok(Some(bundle)) -} - -fn register_functions(bundle: &mut FluentBundle) { - bundle - .add_function("STREQ", |positional, _named| match positional { - [FluentValue::String(a), FluentValue::String(b)] => format!("{}", (a == b)).into(), - _ => FluentValue::Error, - }) - .expect("Failed to add a function to the bundle."); -} - -/// Type alias for the result of `fallback_fluent_bundle` - a reference-counted pointer to a lazily -/// evaluated fluent bundle. -pub type LazyFallbackBundle = Lrc FluentBundle>>; - -/// Return the default `FluentBundle` with standard "en-US" diagnostic messages. -#[instrument(level = "trace", skip(resources))] -pub fn fallback_fluent_bundle( - resources: Vec<&'static str>, - with_directionality_markers: bool, -) -> LazyFallbackBundle { - Lrc::new(Lazy::new(move || { - let mut fallback_bundle = new_bundle(vec![langid!("en-US")]); - - register_functions(&mut fallback_bundle); - - // See comment in `fluent_bundle`. - fallback_bundle.set_use_isolating(with_directionality_markers); - - for resource in resources { - let resource = FluentResource::try_new(resource.to_string()) - .expect("failed to parse fallback fluent resource"); - fallback_bundle.add_resource_overriding(resource); - } - - fallback_bundle - })) -} - -/// Identifier for the Fluent message/attribute corresponding to a diagnostic message. -type FluentId = Cow<'static, str>; - -/// Abstraction over a message in a subdiagnostic (i.e. label, note, help, etc) to support both -/// translatable and non-translatable diagnostic messages. -/// -/// Translatable messages for subdiagnostics are typically attributes attached to a larger Fluent -/// message so messages of this type must be combined with a `DiagMessage` (using -/// `DiagMessage::with_subdiagnostic_message`) before rendering. However, subdiagnostics from -/// the `Subdiagnostic` derive refer to Fluent identifiers directly. -#[rustc_diagnostic_item = "SubdiagMessage"] -pub enum SubdiagMessage { - /// Non-translatable diagnostic message. - Str(Cow<'static, str>), - /// 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. These subdiagnostics' messages - /// are translated when they are added to the parent diagnostic, producing this variant of - /// `DiagMessage`. - Translated(Cow<'static, str>), - /// Identifier of a Fluent message. Instances of this variant are generated by the - /// `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` - /// macro. - /// - /// - FluentAttr(FluentId), -} - -impl From for SubdiagMessage { - fn from(s: String) -> Self { - SubdiagMessage::Str(Cow::Owned(s)) - } -} -impl From<&'static str> for SubdiagMessage { - fn from(s: &'static str) -> Self { - SubdiagMessage::Str(Cow::Borrowed(s)) - } -} -impl From> for SubdiagMessage { - fn from(s: Cow<'static, str>) -> Self { - SubdiagMessage::Str(s) - } -} - -/// Abstraction over a message in a diagnostic to support both translatable and non-translatable -/// diagnostic messages. -/// -/// Intended to be removed once diagnostics are entirely translatable. -#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)] -#[rustc_diagnostic_item = "DiagMessage"] -pub enum DiagMessage { - /// Non-translatable diagnostic message. - Str(Cow<'static, str>), - /// Translatable message which has been already translated. - /// - /// Some diagnostics have repeated subdiagnostics where the same interpolated variables would - /// be instantiated multiple times with different values. These subdiagnostics' messages - /// are translated when they are added to the parent diagnostic, producing this variant of - /// `DiagMessage`. - Translated(Cow<'static, str>), - /// Identifier for a Fluent message (with optional attribute) corresponding to the diagnostic - /// message. Yet to be translated. - /// - /// - /// - FluentIdentifier(FluentId, Option), -} - -impl DiagMessage { - /// Given a `SubdiagMessage` which may contain a Fluent attribute, create a new - /// `DiagMessage` that combines that attribute with the Fluent identifier of `self`. - /// - /// - If the `SubdiagMessage` is non-translatable then return the message as a `DiagMessage`. - /// - If `self` is non-translatable then return `self`'s message. - pub fn with_subdiagnostic_message(&self, sub: SubdiagMessage) -> Self { - let attr = match sub { - SubdiagMessage::Str(s) => return DiagMessage::Str(s), - SubdiagMessage::Translated(s) => return DiagMessage::Translated(s), - SubdiagMessage::FluentIdentifier(id) => { - return DiagMessage::FluentIdentifier(id, None); - } - SubdiagMessage::FluentAttr(attr) => attr, - }; - - match self { - DiagMessage::Str(s) => DiagMessage::Str(s.clone()), - DiagMessage::Translated(s) => DiagMessage::Translated(s.clone()), - DiagMessage::FluentIdentifier(id, _) => { - DiagMessage::FluentIdentifier(id.clone(), Some(attr)) - } - } - } - - pub fn as_str(&self) -> Option<&str> { - match self { - DiagMessage::Translated(s) | DiagMessage::Str(s) => Some(s), - DiagMessage::FluentIdentifier(_, _) => None, - } - } -} - -impl From for DiagMessage { - fn from(s: String) -> Self { - DiagMessage::Str(Cow::Owned(s)) - } -} -impl From<&'static str> for DiagMessage { - fn from(s: &'static str) -> Self { - DiagMessage::Str(Cow::Borrowed(s)) - } -} -impl From> for DiagMessage { - fn from(s: Cow<'static, str>) -> Self { - DiagMessage::Str(s) - } -} - -/// A workaround for must_produce_diag ICEs when formatting types in disabled lints. -/// -/// Delays formatting until `.into(): DiagMessage` is used. -pub struct DelayDm(pub F); - -impl String> From> for DiagMessage { - fn from(DelayDm(f): DelayDm) -> Self { - DiagMessage::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 `SubdiagMessage` and the -/// subdiagnostic derive refers to typed identifiers that are `DiagMessage`s, so need to be -/// able to convert between these, as much as they'll be converted back into `DiagMessage` -/// using `with_subdiagnostic_message` eventually. Don't use this other than for the derive. -impl Into for DiagMessage { - fn into(self) -> SubdiagMessage { - match self { - DiagMessage::Str(s) => SubdiagMessage::Str(s), - DiagMessage::Translated(s) => SubdiagMessage::Translated(s), - DiagMessage::FluentIdentifier(id, None) => SubdiagMessage::FluentIdentifier(id), - // There isn't really a sensible behaviour for this because it loses information but - // this is the most sensible of the behaviours. - DiagMessage::FluentIdentifier(_, Some(attr)) => SubdiagMessage::FluentAttr(attr), - } - } -} - -/// A span together with some additional data. -#[derive(Clone, Debug)] -pub struct SpanLabel { - /// The span we are going to include in the final snippet. - pub span: Span, - - /// Is this a primary span? This is the "locus" of the message, - /// and is indicated with a `^^^^` underline, versus `----`. - pub is_primary: bool, - - /// What label should we attach to this span (if any)? - pub label: Option, -} - -/// A collection of `Span`s. -/// -/// Spans have two orthogonal attributes: -/// -/// - They can be *primary spans*. In this case they are the locus of -/// the error, and would be rendered with `^^^`. -/// - They can have a *label*. In this case, the label is written next -/// to the mark in the snippet when we render. -#[derive(Clone, Debug, Hash, PartialEq, Eq, Encodable, Decodable)] -pub struct MultiSpan { - primary_spans: Vec, - span_labels: Vec<(Span, DiagMessage)>, -} - -impl MultiSpan { - #[inline] - pub fn new() -> MultiSpan { - MultiSpan { primary_spans: vec![], span_labels: vec![] } - } - - pub fn from_span(primary_span: Span) -> MultiSpan { - MultiSpan { primary_spans: vec![primary_span], span_labels: vec![] } - } - - pub fn from_spans(mut vec: Vec) -> MultiSpan { - vec.sort(); - MultiSpan { primary_spans: vec, span_labels: vec![] } - } - - pub fn push_span_label(&mut self, span: Span, label: impl Into) { - self.span_labels.push((span, label.into())); - } - - /// Selects the first primary span (if any). - pub fn primary_span(&self) -> Option { - self.primary_spans.first().cloned() - } - - /// Returns all primary spans. - pub fn primary_spans(&self) -> &[Span] { - &self.primary_spans - } - - /// Returns `true` if any of the primary spans are displayable. - pub fn has_primary_spans(&self) -> bool { - !self.is_dummy() - } - - /// Returns `true` if this contains only a dummy primary span with any hygienic context. - pub fn is_dummy(&self) -> bool { - self.primary_spans.iter().all(|sp| sp.is_dummy()) - } - - /// Replaces all occurrences of one Span with another. Used to move `Span`s in areas that don't - /// display well (like std macros). Returns whether replacements occurred. - pub fn replace(&mut self, before: Span, after: Span) -> bool { - let mut replacements_occurred = false; - for primary_span in &mut self.primary_spans { - if *primary_span == before { - *primary_span = after; - replacements_occurred = true; - } - } - for span_label in &mut self.span_labels { - if span_label.0 == before { - span_label.0 = after; - replacements_occurred = true; - } - } - replacements_occurred - } - - pub fn pop_span_label(&mut self) -> Option<(Span, DiagMessage)> { - self.span_labels.pop() - } - - /// Returns the strings to highlight. We always ensure that there - /// is an entry for each of the primary spans -- for each primary - /// span `P`, if there is at least one label with span `P`, we return - /// those labels (marked as primary). But otherwise we return - /// `SpanLabel` instances with empty labels. - pub fn span_labels(&self) -> Vec { - let is_primary = |span| self.primary_spans.contains(&span); - - let mut span_labels = self - .span_labels - .iter() - .map(|&(span, ref label)| SpanLabel { - span, - is_primary: is_primary(span), - label: Some(label.clone()), - }) - .collect::>(); - - for &span in &self.primary_spans { - if !span_labels.iter().any(|sl| sl.span == span) { - span_labels.push(SpanLabel { span, is_primary: true, label: None }); - } - } - - span_labels - } - - /// Returns `true` if any of the span labels is displayable. - pub fn has_span_labels(&self) -> bool { - self.span_labels.iter().any(|(sp, _)| !sp.is_dummy()) - } - - /// Clone this `MultiSpan` without keeping any of the span labels - sometimes a `MultiSpan` is - /// to be re-used in another diagnostic, but includes `span_labels` which have translated - /// messages. These translated messages would fail to translate without their diagnostic - /// arguments which are unlikely to be cloned alongside the `Span`. - pub fn clone_ignoring_labels(&self) -> Self { - Self { primary_spans: self.primary_spans.clone(), ..MultiSpan::new() } - } -} - -impl From for MultiSpan { - fn from(span: Span) -> MultiSpan { - MultiSpan::from_span(span) - } -} - -impl From> for MultiSpan { - fn from(spans: Vec) -> MultiSpan { - MultiSpan::from_spans(spans) - } -} - -fn icu_locale_from_unic_langid(lang: LanguageIdentifier) -> Option { - icu_locid::Locale::try_from_bytes(lang.to_string().as_bytes()).ok() -} - -pub fn fluent_value_from_str_list_sep_by_and(l: Vec>) -> FluentValue<'_> { - // Fluent requires 'static value here for its AnyEq usages. - #[derive(Clone, PartialEq, Debug)] - struct FluentStrListSepByAnd(Vec); - - impl FluentType for FluentStrListSepByAnd { - fn duplicate(&self) -> Box { - Box::new(self.clone()) - } - - fn as_string(&self, intls: &intl_memoizer::IntlLangMemoizer) -> Cow<'static, str> { - let result = intls - .with_try_get::((), |list_formatter| { - list_formatter.format_to_string(self.0.iter()) - }) - .unwrap(); - Cow::Owned(result) - } - - #[cfg(not(parallel_compiler))] - fn as_string_threadsafe( - &self, - _intls: &intl_memoizer::concurrent::IntlLangMemoizer, - ) -> Cow<'static, str> { - unreachable!("`as_string_threadsafe` is not used in non-parallel rustc") - } - - #[cfg(parallel_compiler)] - fn as_string_threadsafe( - &self, - intls: &intl_memoizer::concurrent::IntlLangMemoizer, - ) -> Cow<'static, str> { - let result = intls - .with_try_get::((), |list_formatter| { - list_formatter.format_to_string(self.0.iter()) - }) - .unwrap(); - Cow::Owned(result) - } - } - - struct MemoizableListFormatter(icu_list::ListFormatter); - - impl std::ops::Deref for MemoizableListFormatter { - type Target = icu_list::ListFormatter; - fn deref(&self) -> &Self::Target { - &self.0 - } - } - - impl intl_memoizer::Memoizable for MemoizableListFormatter { - type Args = (); - type Error = (); - - fn construct(lang: LanguageIdentifier, _args: Self::Args) -> Result - where - Self: Sized, - { - let baked_data_provider = rustc_baked_icu_data::baked_data_provider(); - let locale_fallbacker = - LocaleFallbacker::try_new_with_any_provider(&baked_data_provider) - .expect("Failed to create fallback provider"); - let data_provider = - LocaleFallbackProvider::new_with_fallbacker(baked_data_provider, locale_fallbacker); - let locale = icu_locale_from_unic_langid(lang) - .unwrap_or_else(|| rustc_baked_icu_data::supported_locales::EN); - let list_formatter = - icu_list::ListFormatter::try_new_and_with_length_with_any_provider( - &data_provider, - &locale.into(), - icu_list::ListLength::Wide, - ) - .expect("Failed to create list formatter"); - - Ok(MemoizableListFormatter(list_formatter)) - } - } - - let l = l.into_iter().map(|x| x.into_owned()).collect(); - - FluentValue::Custom(Box::new(FluentStrListSepByAnd(l))) -} +#![doc(rust_logo)]#![feature(rustdoc_internals)]#![feature(lazy_cell)]#![//({}); +feature(rustc_attrs)]#![feature(type_alias_impl_trait)]#![allow(//if let _=(){}; +internal_features)]#[macro_use]extern crate tracing;use fluent_bundle:://*&*&(); +FluentResource;use fluent_syntax:: parser::ParserError;use icu_provider_adapters +::fallback::{LocaleFallbackProvider, LocaleFallbacker};use rustc_data_structures +::sync::{IntoDynSyncSend,Lrc};use rustc_macros::{Decodable,Encodable};use//({}); +rustc_span::Span;use std::borrow::Cow;use std::error::Error;use std::fmt;use//3; +std::fs;use std::io;use std::path ::{Path,PathBuf};#[cfg(not(parallel_compiler)) +]use std::cell::LazyCell as Lazy;#[cfg(parallel_compiler)]use std::sync:://({}); +LazyLock as Lazy;#[cfg(parallel_compiler)]use intl_memoizer::concurrent:://({}); +IntlLangMemoizer;#[cfg(not(parallel_compiler))]use intl_memoizer:://loop{break}; +IntlLangMemoizer;pub use fluent_bundle::{self,types::FluentType,FluentArgs,//(); +FluentError,FluentValue};pub use unic_langid::{langid,LanguageIdentifier};pub//; +type FluentBundle=IntoDynSyncSend>;#[cfg(not(parallel_compiler))]fn new_bundle(// +locales:Vec)->FluentBundle{IntoDynSyncSend(fluent_bundle::// +bundle::FluentBundle::new(locales))}#[cfg(parallel_compiler)]fn new_bundle(//(); +locales:Vec)->FluentBundle{IntoDynSyncSend(fluent_bundle::// +bundle::FluentBundle::new_concurrent(locales))}#[derive(Debug)]pub enum//*&*&(); +TranslationBundleError{ReadFtl(io::Error),ParseFtl(ParserError),AddResource(//3; +FluentError),MissingLocale,ReadLocalesDir(io::Error),ReadLocalesDirEntry(io:://; +Error),LocaleIsNotDir,}impl fmt::Display for TranslationBundleError{fn fmt(&//3; +self,f:&mut fmt::Formatter<'_>)->fmt::Result{match self{TranslationBundleError// +::ReadFtl(e)=>write! (f,"could not read ftl file: {e}"),TranslationBundleError:: +ParseFtl(e)=>{(write!(f,"could not parse ftl file: {e}"))}TranslationBundleError +::AddResource(e)=>(((((((((((write!(f,"failed to add resource: {e}")))))))))))), +TranslationBundleError::MissingLocale=>((write!(f,"missing locale directory"))), +TranslationBundleError::ReadLocalesDir(e)=>{write!(f,//loop{break};loop{break;}; +"could not read locales dir: {e}")} TranslationBundleError::ReadLocalesDirEntry( +e)=>{write!( f,"could not read locales dir entry: {e}")}TranslationBundleError:: +LocaleIsNotDir=>{write !(f,"`$sysroot/share/locales/$locale` is not a directory" +)}}}}impl Error for TranslationBundleError{ fn source(&self)->Option<&(dyn Error ++'static)>{match self{TranslationBundleError::ReadFtl(e)=>(((((((Some(e)))))))), +TranslationBundleError::ParseFtl(e)=>((((( Some(e)))))),TranslationBundleError:: +AddResource(e)=>((((((Some(e))))))),TranslationBundleError::MissingLocale=>None, +TranslationBundleError::ReadLocalesDir(e)=>(( Some(e))),TranslationBundleError:: +ReadLocalesDirEntry(e)=>Some(e) ,TranslationBundleError::LocaleIsNotDir=>None,}} +}impl From<(FluentResource,Vec< ParserError>)>for TranslationBundleError{fn from +((_,mut errs):(FluentResource, Vec))->Self{TranslationBundleError:: +ParseFtl((errs.pop().expect("failed ftl parse with no errors")))}}impl From>for TranslationBundleError{fn from(mut errs:Vec)->//3; +Self{TranslationBundleError::AddResource((((((((((( errs.pop())))))))))).expect( +"failed adding resource to bundle with no errors"),)}}#[instrument(level=//({}); +"trace")]pub fn fluent_bundle(mut user_provided_sysroot:Option,mut//(); +sysroot_candidates:Vec,requested_locale:Option,//3; +additional_ftl_path:Option<&Path>,with_directionality_markers:bool,)->Result>,TranslationBundleError>{ if requested_locale.is_none() +&&additional_ftl_path.is_none(){;return Ok(None);;};let fallback_locale=langid!( +"en-US");{;};{;};let requested_fallback_locale=requested_locale.as_ref()==Some(& +fallback_locale);let _=();((),());trace!(?requested_fallback_locale);((),());if +requested_fallback_locale&&additional_ftl_path.is_none(){;return Ok(None);;};let +locale=requested_locale.clone().unwrap_or(fallback_locale);;;trace!(?locale);let +mut bundle=new_bundle(vec![locale]);3;;register_functions(&mut bundle);;;bundle. +set_use_isolating(with_directionality_markers);();if let Some(requested_locale)= +requested_locale{let _=();let mut found_resources=false;let _=();for sysroot in +user_provided_sysroot.iter_mut().chain(sysroot_candidates.iter_mut()){3;sysroot. +push("share");;sysroot.push("locale");sysroot.push(requested_locale.to_string()) +;;;trace!(?sysroot);if!sysroot.exists(){trace!("skipping");continue;}if!sysroot. +is_dir(){();return Err(TranslationBundleError::LocaleIsNotDir);();}for entry in +sysroot.read_dir().map_err(TranslationBundleError::ReadLocalesDir)?{3;let entry= +entry.map_err(TranslationBundleError::ReadLocalesDirEntry)?;;let path=entry.path +();;trace!(?path);if path.extension().and_then(|s|s.to_str())!=Some("ftl"){trace +!("skipping");3;3;continue;;};let resource_str=fs::read_to_string(path).map_err( +TranslationBundleError::ReadFtl)?;({});{;};let resource=FluentResource::try_new( +resource_str).map_err(TranslationBundleError::from)?;;;trace!(?resource);bundle. +add_resource(resource).map_err(TranslationBundleError::from)?;;;found_resources= +true;;}}if!found_resources{;return Err(TranslationBundleError::MissingLocale);}} +if let Some(additional_ftl_path)=additional_ftl_path{{();};let resource_str=fs:: +read_to_string(additional_ftl_path).map_err(TranslationBundleError::ReadFtl)?;;; +let resource=((((((((((FluentResource ::try_new(resource_str))))))))))).map_err( +TranslationBundleError::from)?;;trace!(?resource);bundle.add_resource_overriding +(resource);;}let bundle=Lrc::new(bundle);Ok(Some(bundle))}fn register_functions( +bundle:&mut FluentBundle){3;bundle.add_function("STREQ",|positional,_named|match +positional{[FluentValue::String(a),FluentValue::String(b )]=>format!("{}",(a==b) +).into(),_=>FluentValue::Error,}).expect(//let _=();let _=();let _=();if true{}; +"Failed to add a function to the bundle.");{;};}pub type LazyFallbackBundle=Lrc< +LazyFluentBundle >>;#[instrument(level="trace",skip +(resources))]pub fn fallback_fluent_bundle(resources:Vec<&'static str>,//*&*&(); +with_directionality_markers:bool,)->LazyFallbackBundle{Lrc::new(Lazy::new(move// +||{{();};let mut fallback_bundle=new_bundle(vec![langid!("en-US")]);{();};{();}; +register_functions(&mut fallback_bundle);();3;fallback_bundle.set_use_isolating( +with_directionality_markers);{();};for resource in resources{{();};let resource= +FluentResource::try_new((((((((((((((resource.to_string ())))))))))))))).expect( +"failed to parse fallback fluent resource");if true{};if true{};fallback_bundle. +add_resource_overriding(resource);;}fallback_bundle}))}type FluentId=Cow<'static +,str>;#[rustc_diagnostic_item="SubdiagMessage" ]pub enum SubdiagMessage{Str(Cow< +'static,str>),Translated(Cow<'static,str>),FluentIdentifier(FluentId),//((),()); +FluentAttr(FluentId),}impl Fromfor SubdiagMessage{fn from(s:String)->//; +Self{(((SubdiagMessage::Str((((Cow::Owned(s) )))))))}}impl From<&'static str>for +SubdiagMessage{fn from(s:&'static str) ->Self{SubdiagMessage::Str(Cow::Borrowed( +s))}}impl From>for SubdiagMessage{fn from(s:Cow<'static,str>)// +->Self{SubdiagMessage::Str(s)}}# [derive(Clone,Debug,PartialEq,Eq,Hash,Encodable +,Decodable)]#[rustc_diagnostic_item="DiagMessage" ]pub enum DiagMessage{Str(Cow< +'static,str>),Translated(Cow<'static,str>),FluentIdentifier(FluentId,Option),}impl DiagMessage{pub fn with_subdiagnostic_message(&self,sub://({}); +SubdiagMessage)->Self{((),());let attr=match sub{SubdiagMessage::Str(s)=>return +DiagMessage::Str(s),SubdiagMessage::Translated(s)=>return DiagMessage:://*&*&(); +Translated(s),SubdiagMessage::FluentIdentifier(id)=>{*&*&();return DiagMessage:: +FluentIdentifier(id,None);;}SubdiagMessage::FluentAttr(attr)=>attr,};match self{ +DiagMessage::Str(s)=>(DiagMessage::Str(s. clone())),DiagMessage::Translated(s)=> +DiagMessage::Translated((((s.clone())))) ,DiagMessage::FluentIdentifier(id,_)=>{ +DiagMessage::FluentIdentifier((id.clone()),Some(attr ))}}}pub fn as_str(&self)-> +Option<&str>{match self{DiagMessage::Translated(s )|DiagMessage::Str(s)=>Some(s) +,DiagMessage::FluentIdentifier(_,_)=>None,}}}impl Fromfor DiagMessage{// +fn from(s:String)->Self{DiagMessage::Str(Cow ::Owned(s))}}impl From<&'static str +>for DiagMessage{fn from(s:&'static str )->Self{DiagMessage::Str(Cow::Borrowed(s +))}}impl From>for DiagMessage{fn from(s:Cow<'static,str>)->//3; +Self{DiagMessage::Str(s)}}pub struct DelayDm< F>(pub F);implString> +From>for DiagMessage{fn from(DelayDm(f):DelayDm)->Self{//let _=(); +DiagMessage::from((f()))}}impl Intofor DiagMessage{fn into(self) +->SubdiagMessage{match self{DiagMessage::Str(s)=>((((SubdiagMessage::Str(s))))), +DiagMessage::Translated(s)=>((((SubdiagMessage ::Translated(s))))),DiagMessage:: +FluentIdentifier(id,None)=>(SubdiagMessage ::FluentIdentifier(id)),DiagMessage:: +FluentIdentifier(_,Some(attr))=>(SubdiagMessage:: FluentAttr(attr)),}}}#[derive( +Clone,Debug)]pub struct SpanLabel{pub span:Span,pub is_primary:bool,pub label:// +Option,}#[derive(Clone ,Debug,Hash,PartialEq,Eq,Encodable,Decodable +)]pub struct MultiSpan{primary_spans:Vec,span_labels:Vec<(Span,//let _=(); +DiagMessage)>,}impl MultiSpan{#[inline]pub fn new()->MultiSpan{MultiSpan{//({}); +primary_spans:(vec![]),span_labels:vec![]}}pub fn from_span(primary_span:Span)-> +MultiSpan{MultiSpan{primary_spans:vec![primary_span] ,span_labels:vec![]}}pub fn +from_spans(mut vec:Vec)->MultiSpan{3;vec.sort();3;MultiSpan{primary_spans: +vec,span_labels:(vec![])}}pub fn push_span_label(&mut self,span:Span,label:impl +Into){{();};self.span_labels.push((span,label.into()));({});}pub fn +primary_span(&self)->Option{((self.primary_spans.first()).cloned())}pub fn +primary_spans(&self)->&[Span]{((&self.primary_spans))}pub fn has_primary_spans(& +self)->bool{(!self.is_dummy())}pub fn is_dummy(&self)->bool{self.primary_spans. +iter().all((|sp|sp.is_dummy()))}pub fn replace(&mut self,before:Span,after:Span) +->bool{{;};let mut replacements_occurred=false;{;};for primary_span in&mut self. +primary_spans{if*primary_span==before{;*primary_span=after;replacements_occurred +=true;({});}}for span_label in&mut self.span_labels{if span_label.0==before{{;}; +span_label.0=after;3;;replacements_occurred=true;;}}replacements_occurred}pub fn +pop_span_label(&mut self)->Option<(Span, DiagMessage)>{(self.span_labels.pop())} +pub fn span_labels(&self)->Vec{loop{break};let is_primary=|span|self. +primary_spans.contains(&span);;let mut span_labels=self.span_labels.iter().map(| +&(span,ref label)|SpanLabel{span,is_primary:(is_primary(span)),label:Some(label. +clone()),}).collect::>();3;for&span in&self.primary_spans{if!span_labels. +iter().any(|sl|sl.span==span){3;span_labels.push(SpanLabel{span,is_primary:true, +label:None});;}}span_labels}pub fn has_span_labels(&self)->bool{self.span_labels +.iter().any((|(sp,_)|!sp.is_dummy()))}pub fn clone_ignoring_labels(&self)->Self{ +Self{primary_spans:(self.primary_spans.clone()),.. MultiSpan::new()}}}impl From< +Span>for MultiSpan{fn from(span:Span )->MultiSpan{(MultiSpan::from_span(span))}} +impl From>for MultiSpan{fn from(spans:Vec)->MultiSpan{MultiSpan +::from_spans(spans)}}fn icu_locale_from_unic_langid(lang:LanguageIdentifier)->// +Option{icu_locid::Locale ::try_from_bytes((lang.to_string()). +as_bytes()).ok()}pub fn fluent_value_from_str_list_sep_by_and(l:Vec>)->FluentValue<'_>{if true{};let _=||();#[derive(Clone,PartialEq,Debug)]struct +FluentStrListSepByAnd(Vec);;impl FluentType for FluentStrListSepByAnd{fn +duplicate(&self)->Box{(Box::new(self.clone()))}fn as_string +(&self,intls:&intl_memoizer::IntlLangMemoizer)->Cow<'static,str>{{;};let result= +intls.with_try_get::((((((()))))),|list_formatter|{ +list_formatter.format_to_string(self.0.iter())}).unwrap();;Cow::Owned(result)}#[ +cfg(not(parallel_compiler))]fn as_string_threadsafe(&self,_intls:&intl_memoizer +::concurrent::IntlLangMemoizer,)->Cow<'static,str>{unreachable!(//if let _=(){}; +"`as_string_threadsafe` is not used in non-parallel rustc")}#[cfg(//loop{break}; +parallel_compiler)]fn as_string_threadsafe(&self,intls:&intl_memoizer:://*&*&(); +concurrent::IntlLangMemoizer,)->Cow<'static,str>{3;let result=intls.with_try_get +::(((((((( ))))))),|list_formatter|{list_formatter. +format_to_string(self.0.iter())}).unwrap();{;};Cow::Owned(result)}}{;};();struct +MemoizableListFormatter(icu_list::ListFormatter);{;};();impl std::ops::Deref for +MemoizableListFormatter{type Target=icu_list::ListFormatter;fn deref(&self)->&// +Self::Target{&self.0}}loop{break};loop{break};impl intl_memoizer::Memoizable for +MemoizableListFormatter{type Args=();type Error=();fn construct(lang://let _=(); +LanguageIdentifier,_args:Self::Args)->Result< Self,Self::Error>where Self:Sized, +{();let baked_data_provider=rustc_baked_icu_data::baked_data_provider();();3;let +locale_fallbacker=LocaleFallbacker::try_new_with_any_provider(&//*&*&();((),()); +baked_data_provider).expect("Failed to create fallback provider");{();};({});let +data_provider=LocaleFallbackProvider::new_with_fallbacker(baked_data_provider,// +locale_fallbacker);;let locale=icu_locale_from_unic_langid(lang).unwrap_or_else( +||rustc_baked_icu_data::supported_locales::EN);3;3;let list_formatter=icu_list:: +ListFormatter::try_new_and_with_length_with_any_provider(& data_provider,&locale +.into(),icu_list::ListLength::Wide,).expect("Failed to create list formatter");; +Ok(MemoizableListFormatter(list_formatter))}}();();let l=l.into_iter().map(|x|x. +into_owned()).collect();;FluentValue::Custom(Box::new(FluentStrListSepByAnd(l))) +}//let _=();if true{};let _=();if true{};let _=();if true{};if true{};if true{}; diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index b71b93cc67c16..89ec7f64c3d45 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -1,221 +1,58 @@ -//! Emit diagnostics using the `annotate-snippets` library -//! -//! This is the equivalent of `./emitter.rs` but making use of the -//! [`annotate-snippets`][annotate_snippets] library instead of building the output ourselves. -//! -//! [annotate_snippets]: https://docs.rs/crate/annotate-snippets/ - -use crate::emitter::FileWithAnnotatedLines; -use crate::snippet::Line; -use crate::translation::{to_fluent_args, Translate}; -use crate::{ - CodeSuggestion, DiagInner, DiagMessage, Emitter, ErrCode, FluentBundle, LazyFallbackBundle, - Level, MultiSpan, Style, Subdiag, -}; -use annotate_snippets::{Annotation, AnnotationType, Renderer, Slice, Snippet, SourceAnnotation}; -use rustc_data_structures::sync::Lrc; -use rustc_error_messages::FluentArgs; -use rustc_span::source_map::SourceMap; -use rustc_span::SourceFile; - -/// Generates diagnostics using annotate-snippet -pub struct AnnotateSnippetEmitter { - source_map: Option>, - fluent_bundle: Option>, - fallback_bundle: LazyFallbackBundle, - - /// If true, hides the longer explanation text - short_message: bool, - /// If true, will normalize line numbers with `LL` to prevent noise in UI test diffs. - ui_testing: bool, - - macro_backtrace: bool, -} - -impl Translate for AnnotateSnippetEmitter { - fn fluent_bundle(&self) -> Option<&Lrc> { - self.fluent_bundle.as_ref() - } - - fn fallback_fluent_bundle(&self) -> &FluentBundle { - &self.fallback_bundle - } -} - -impl Emitter for AnnotateSnippetEmitter { - /// The entry point for the diagnostics generation - fn emit_diagnostic(&mut self, mut diag: DiagInner) { - let fluent_args = to_fluent_args(diag.args.iter()); - - let mut suggestions = diag.suggestions.unwrap_or(vec![]); - self.primary_span_formatted(&mut diag.span, &mut suggestions, &fluent_args); - - self.fix_multispans_in_extern_macros_and_render_macro_backtrace( - &mut diag.span, - &mut diag.children, - &diag.level, - self.macro_backtrace, - ); - - self.emit_messages_default( - &diag.level, - &diag.messages, - &fluent_args, - &diag.code, - &diag.span, - &diag.children, - &suggestions, - ); - } - - fn source_map(&self) -> Option<&Lrc> { - self.source_map.as_ref() - } - - fn should_show_explain(&self) -> bool { - !self.short_message - } -} - -/// Provides the source string for the given `line` of `file` -fn source_string(file: Lrc, line: &Line) -> String { - file.get_line(line.line_index - 1).map(|a| a.to_string()).unwrap_or_default() -} - -/// Maps `diagnostic::Level` to `snippet::AnnotationType` -fn annotation_type_for_level(level: Level) -> AnnotationType { - match level { - Level::Bug | Level::Fatal | Level::Error | Level::DelayedBug => AnnotationType::Error, - Level::ForceWarning(_) | Level::Warning => AnnotationType::Warning, - Level::Note | Level::OnceNote => AnnotationType::Note, - Level::Help | Level::OnceHelp => AnnotationType::Help, - // FIXME(#59346): Not sure how to map this level - Level::FailureNote => AnnotationType::Error, - Level::Allow => panic!("Should not call with Allow"), - Level::Expect(_) => panic!("Should not call with Expect"), - } -} - -impl AnnotateSnippetEmitter { - pub fn new( - source_map: Option>, - fluent_bundle: Option>, - fallback_bundle: LazyFallbackBundle, - short_message: bool, - macro_backtrace: bool, - ) -> Self { - Self { - source_map, - fluent_bundle, - fallback_bundle, - short_message, - ui_testing: false, - macro_backtrace, - } - } - - /// Allows to modify `Self` to enable or disable the `ui_testing` flag. - /// - /// If this is set to true, line numbers will be normalized as `LL` in the output. - pub fn ui_testing(mut self, ui_testing: bool) -> Self { - self.ui_testing = ui_testing; - self - } - - fn emit_messages_default( - &mut self, - level: &Level, - messages: &[(DiagMessage, Style)], - args: &FluentArgs<'_>, - code: &Option, - msp: &MultiSpan, - _children: &[Subdiag], - _suggestions: &[CodeSuggestion], - ) { - let message = self.translate_messages(messages, args); - if let Some(source_map) = &self.source_map { - // Make sure our primary file comes first - let primary_lo = if let Some(primary_span) = msp.primary_span().as_ref() { - if primary_span.is_dummy() { - // FIXME(#59346): Not sure when this is the case and what - // should be done if it happens - return; - } else { - source_map.lookup_char_pos(primary_span.lo()) - } - } else { - // FIXME(#59346): Not sure when this is the case and what - // should be done if it happens - return; - }; - let mut annotated_files = FileWithAnnotatedLines::collect_annotations(self, args, msp); - if let Ok(pos) = - annotated_files.binary_search_by(|x| x.file.name.cmp(&primary_lo.file.name)) - { - annotated_files.swap(0, pos); - } - // owned: file name, line source, line index, annotations - type Owned = (String, String, usize, Vec); - let annotated_files: Vec = annotated_files - .into_iter() - .flat_map(|annotated_file| { - let file = annotated_file.file; - annotated_file - .lines - .into_iter() - .map(|line| { - // Ensure the source file is present before we try - // to load a string from it. - // FIXME(#115869): support -Z ignore-directory-in-diagnostics-source-blocks - source_map.ensure_source_file_source_present(&file); - ( - format!("{}", source_map.filename_for_diagnostics(&file.name)), - source_string(file.clone(), &line), - line.line_index, - line.annotations, - ) - }) - .collect::>() - }) - .collect(); - let code = code.map(|code| code.to_string()); - let snippet = Snippet { - title: Some(Annotation { - label: Some(&message), - id: code.as_deref(), - annotation_type: annotation_type_for_level(*level), - }), - footer: vec![], - slices: annotated_files - .iter() - .map(|(file_name, source, line_index, annotations)| { - Slice { - source, - line_start: *line_index, - origin: Some(file_name), - // FIXME(#59346): Not really sure when `fold` should be true or false - fold: false, - annotations: annotations - .iter() - .map(|annotation| SourceAnnotation { - range: ( - annotation.start_col.display, - annotation.end_col.display, - ), - label: annotation.label.as_deref().unwrap_or_default(), - annotation_type: annotation_type_for_level(*level), - }) - .collect(), - } - }) - .collect(), - }; - // FIXME(#59346): Figure out if we can _always_ print to stderr or not. - // `emitter.rs` has the `Destination` enum that lists various possible output - // destinations. - let renderer = Renderer::plain().anonymized_line_numbers(self.ui_testing); - eprintln!("{}", renderer.render(snippet)) - } - // FIXME(#59346): Is it ok to return None if there's no source_map? - } -} +use crate::emitter::FileWithAnnotatedLines;use crate::snippet::Line;use crate:: +translation::{to_fluent_args,Translate};use crate::{CodeSuggestion,DiagInner,//; +DiagMessage,Emitter,ErrCode,FluentBundle,LazyFallbackBundle,Level,MultiSpan,//3; +Style,Subdiag,};use annotate_snippets::{Annotation,AnnotationType,Renderer,//(); +Slice,Snippet,SourceAnnotation};use rustc_data_structures::sync::Lrc;use//{();}; +rustc_error_messages::FluentArgs;use rustc_span::source_map::SourceMap;use//{;}; +rustc_span::SourceFile;pub struct AnnotateSnippetEmitter{source_map:Option>,fluent_bundle:Option>,fallback_bundle://if true{}; +LazyFallbackBundle,short_message:bool,ui_testing:bool,macro_backtrace:bool,}//3; +impl Translate for AnnotateSnippetEmitter{fn fluent_bundle(&self)->Option<&Lrc< +FluentBundle>>{(self.fluent_bundle.as_ref())}fn fallback_fluent_bundle(&self)->& +FluentBundle{(&self.fallback_bundle)}}impl Emitter for AnnotateSnippetEmitter{fn +emit_diagnostic(&mut self,mut diag:DiagInner){();let fluent_args=to_fluent_args( +diag.args.iter());;;let mut suggestions=diag.suggestions.unwrap_or(vec![]);self. +primary_span_formatted(&mut diag.span,&mut suggestions,&fluent_args);();();self. +fix_multispans_in_extern_macros_and_render_macro_backtrace((&mut diag.span),&mut +diag.children,&diag.level,self.macro_backtrace,);3;;self.emit_messages_default(& +diag.level,(&diag.messages),&fluent_args,&diag .code,&diag.span,&diag.children,& +suggestions,);();}fn source_map(&self)->Option<&Lrc>{self.source_map. +as_ref()}fn should_show_explain(&self)->bool{((((((!self.short_message))))))}}fn +source_string(file:Lrc,line:&Line)->String{file.get_line(line.//{;}; +line_index-((((1))))).map(((((|a|(((a.to_string())))))))).unwrap_or_default()}fn +annotation_type_for_level(level:Level)->AnnotationType{match level{Level::Bug|// +Level::Fatal|Level::Error|Level::DelayedBug=>AnnotationType::Error,Level:://{;}; +ForceWarning(_)|Level::Warning=>AnnotationType::Warning,Level::Note|Level:://(); +OnceNote=>AnnotationType::Note,Level::Help|Level::OnceHelp=>AnnotationType:://3; +Help,Level::FailureNote=>AnnotationType::Error,Level::Allow=>panic!(//if true{}; +"Should not call with Allow"),Level::Expect(_)=>panic!(//let _=||();loop{break}; +"Should not call with Expect"),}}impl AnnotateSnippetEmitter{pub fn new(//{();}; +source_map:Option>,fluent_bundle:Option>,//{;}; +fallback_bundle:LazyFallbackBundle,short_message:bool,macro_backtrace:bool,)->// +Self{Self{source_map,fluent_bundle,fallback_bundle,short_message,ui_testing://3; +false,macro_backtrace,}}pub fn ui_testing(mut self,ui_testing:bool)->Self{;self. +ui_testing=ui_testing;({});self}fn emit_messages_default(&mut self,level:&Level, +messages:&[(DiagMessage,Style)],args:& FluentArgs<'_>,code:&Option,msp: +&MultiSpan,_children:&[Subdiag],_suggestions:&[CodeSuggestion],){();let message= +self.translate_messages(messages,args);;if let Some(source_map)=&self.source_map +{*&*&();let primary_lo=if let Some(primary_span)=msp.primary_span().as_ref(){if +primary_span.is_dummy(){;return;}else{source_map.lookup_char_pos(primary_span.lo +())}}else{{;};return;();};();();let mut annotated_files=FileWithAnnotatedLines:: +collect_annotations(self,args,msp);if let _=(){};if let Ok(pos)=annotated_files. +binary_search_by(|x|x.file.name.cmp(&primary_lo.file.name)){{;};annotated_files. +swap(0,pos);;};type Owned=(String,String,usize,Vec); +let annotated_files:Vec= (((((annotated_files.into_iter()))))).flat_map(| +annotated_file|{;let file=annotated_file.file;;annotated_file.lines.into_iter(). +map(|line|{3;source_map.ensure_source_file_source_present(&file);;(format!("{}", +source_map.filename_for_diagnostics(&file.name)), source_string((file.clone()),& +line),line.line_index,line.annotations,)}).collect::>()}).collect();; +let code=code.map(|code|code.to_string());{;};();let snippet=Snippet{title:Some( +Annotation{label:((Some(((&message))))) ,id:((code.as_deref())),annotation_type: +annotation_type_for_level(*level),}),footer: vec![],slices:annotated_files.iter( +).map(|(file_name,source,line_index,annotations)|{Slice{source,line_start:*//(); +line_index,origin:Some(file_name),fold: false,annotations:annotations.iter().map +(|annotation|SourceAnnotation{range:(annotation.start_col.display,annotation.//; +end_col.display,),label:((((annotation.label.as_deref())).unwrap_or_default())), +annotation_type:annotation_type_for_level(*level),}).collect(),}}).collect(),};; +let renderer=Renderer::plain().anonymized_line_numbers(self.ui_testing);((),()); +eprintln!("{}",renderer.render(snippet))}}}//((),());let _=();let _=();let _=(); diff --git a/compiler/rustc_errors/src/codes.rs b/compiler/rustc_errors/src/codes.rs index 947cf27ca7957..a25ce91143dd5 100644 --- a/compiler/rustc_errors/src/codes.rs +++ b/compiler/rustc_errors/src/codes.rs @@ -1,39 +1,9 @@ -//! This module defines the following. -//! - The `ErrCode` type. -//! - A constant for every error code, with a name like `E0123`. -//! - A static table `DIAGNOSTICS` pairing every error code constant with its -//! long description text. - -use std::fmt; - -rustc_index::newtype_index! { - #[max = 9999] // Because all error codes have four digits. - #[orderable] - #[encodable] - #[debug_format = "ErrCode({})"] - pub struct ErrCode {} -} - -impl fmt::Display for ErrCode { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "E{:04}", self.as_u32()) - } -} - -macro_rules! define_error_code_constants_and_diagnostics_table { - ($($name:ident: $num:literal,)*) => ( - $( - pub const $name: $crate::ErrCode = $crate::ErrCode::from_u32($num); - )* - pub static DIAGNOSTICS: &[($crate::ErrCode, &str)] = &[ - $( ( - $name, - include_str!( - concat!("../../rustc_error_codes/src/error_codes/", stringify!($name), ".md") - ) - ), )* - ]; - ) -} - -rustc_error_codes::error_codes!(define_error_code_constants_and_diagnostics_table); +use std::fmt;rustc_index::newtype_index!{#[max=9999]#[orderable]#[encodable]#[// +debug_format="ErrCode({})"]pub struct ErrCode{}}impl fmt::Display for ErrCode{// +fn fmt(&self,f:&mut fmt::Formatter<'_>)->fmt::Result{write!(f,"E{:04}",self.//3; +as_u32())}}macro_rules!define_error_code_constants_and_diagnostics_table{($($//; +name:ident:$num:literal,)*)=>($(pub const$name:$crate::ErrCode=$crate::ErrCode// +::from_u32($num);)*pub static DIAGNOSTICS:&[( $crate::ErrCode,&str)]=&[$(($name, +include_str!(concat!("../../rustc_error_codes/src/error_codes/",stringify!($//3; +name),".md"))),)*];)}rustc_error_codes::error_codes!(//loop{break};loop{break;}; +define_error_code_constants_and_diagnostics_table);//loop{break;};if let _=(){}; diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 5d345e788e94e..14d21b305ebf0 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -1,1387 +1,312 @@ -use crate::snippet::Style; -use crate::{ - CodeSuggestion, DiagCtxt, DiagMessage, ErrCode, ErrorGuaranteed, ExplicitBug, Level, MultiSpan, - StashKey, SubdiagMessage, Substitution, SubstitutionPart, SuggestionStyle, -}; -use rustc_data_structures::fx::FxIndexMap; -use rustc_error_messages::fluent_value_from_str_list_sep_by_and; -use rustc_error_messages::FluentValue; -use rustc_lint_defs::{Applicability, LintExpectationId}; -use rustc_span::source_map::Spanned; -use rustc_span::symbol::Symbol; -use rustc_span::{Span, DUMMY_SP}; -use std::borrow::Cow; -use std::fmt::{self, Debug}; -use std::hash::{Hash, Hasher}; -use std::marker::PhantomData; -use std::ops::{Deref, DerefMut}; -use std::panic; -use std::thread::panicking; - -/// Error type for `DiagInner`'s `suggestions` field, indicating that -/// `.disable_suggestions()` was called on the `DiagInner`. -#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)] -pub struct SuggestionsDisabled; - -/// Simplified version of `FluentArg` that can implement `Encodable` and `Decodable`. Collection of -/// `DiagArg` are converted to `FluentArgs` (consuming the collection) at the start of diagnostic -/// emission. -pub type DiagArg<'iter> = (&'iter DiagArgName, &'iter DiagArgValue); - -/// Name of a diagnostic argument. -pub type DiagArgName = Cow<'static, str>; - -/// Simplified version of `FluentValue` that can implement `Encodable` and `Decodable`. Converted -/// to a `FluentValue` by the emitter to be used in diagnostic translation. -#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)] -pub enum DiagArgValue { - Str(Cow<'static, str>), - // This gets converted to a `FluentNumber`, which is an `f64`. An `i32` - // safely fits in an `f64`. Any integers bigger than that will be converted - // to strings in `into_diag_arg` and stored using the `Str` variant. - Number(i32), - StrListSepByAnd(Vec>), -} - -pub type DiagArgMap = FxIndexMap; - -/// Trait for types that `Diag::emit` can return as a "guarantee" (or "proof") -/// token that the emission happened. -pub trait EmissionGuarantee: Sized { - /// This exists so that bugs and fatal errors can both result in `!` (an - /// abort) when emitted, but have different aborting behaviour. - type EmitResult = Self; - - /// Implementation of `Diag::emit`, fully controlled by each `impl` of - /// `EmissionGuarantee`, to make it impossible to create a value of - /// `Self::EmitResult` without actually performing the emission. - #[track_caller] - fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult; -} - -impl EmissionGuarantee for ErrorGuaranteed { - fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult { - diag.emit_producing_error_guaranteed() - } -} - -impl EmissionGuarantee for () { - fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult { - diag.emit_producing_nothing(); - } -} - -/// Marker type which enables implementation of `create_bug` and `emit_bug` functions for -/// bug diagnostics. -#[derive(Copy, Clone)] -pub struct BugAbort; - -impl EmissionGuarantee for BugAbort { - type EmitResult = !; - - fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult { - diag.emit_producing_nothing(); - panic::panic_any(ExplicitBug); - } -} - -/// Marker type which enables implementation of `create_fatal` and `emit_fatal` functions for -/// fatal diagnostics. -#[derive(Copy, Clone)] -pub struct FatalAbort; - -impl EmissionGuarantee for FatalAbort { - type EmitResult = !; - - fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult { - diag.emit_producing_nothing(); - crate::FatalError.raise() - } -} - -impl EmissionGuarantee for rustc_span::fatal_error::FatalError { - fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult { - diag.emit_producing_nothing(); - rustc_span::fatal_error::FatalError - } -} - -/// Trait implemented by error types. This is rarely implemented manually. Instead, use -/// `#[derive(Diagnostic)]` -- see [rustc_macros::Diagnostic]. -/// -/// When implemented manually, it should be generic over the emission -/// guarantee, i.e.: -/// ```ignore (fragment) -/// impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for Foo { ... } -/// ``` -/// rather than being specific: -/// ```ignore (fragment) -/// impl<'a> Diagnostic<'a> for Bar { ... } // the default type param is `ErrorGuaranteed` -/// impl<'a> Diagnostic<'a, ()> for Baz { ... } -/// ``` -/// There are two reasons for this. -/// - A diagnostic like `Foo` *could* be emitted at any level -- `level` is -/// passed in to `into_diag` from outside. Even if in practice it is -/// always emitted at a single level, we let the diagnostic creation/emission -/// site determine the level (by using `create_err`, `emit_warn`, etc.) -/// rather than the `Diagnostic` impl. -/// - Derived impls are always generic, and it's good for the hand-written -/// impls to be consistent with them. -#[rustc_diagnostic_item = "Diagnostic"] -pub trait Diagnostic<'a, G: EmissionGuarantee = ErrorGuaranteed> { - /// Write out as a diagnostic out of `DiagCtxt`. - #[must_use] - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G>; -} - -impl<'a, T, G> Diagnostic<'a, G> for Spanned -where - T: Diagnostic<'a, G>, - G: EmissionGuarantee, -{ - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { - self.node.into_diag(dcx, level).with_span(self.span) - } -} - -/// Converts a value of a type into a `DiagArg` (typically a field of an `Diag` struct). -/// Implemented as a custom trait rather than `From` so that it is implemented on the type being -/// converted rather than on `DiagArgValue`, which enables types from other `rustc_*` crates to -/// implement this. -pub trait IntoDiagArg { - fn into_diag_arg(self) -> DiagArgValue; -} - -impl IntoDiagArg for DiagArgValue { - fn into_diag_arg(self) -> DiagArgValue { - self - } -} - -impl Into> for DiagArgValue { - fn into(self) -> FluentValue<'static> { - match self { - DiagArgValue::Str(s) => From::from(s), - DiagArgValue::Number(n) => From::from(n), - DiagArgValue::StrListSepByAnd(l) => fluent_value_from_str_list_sep_by_and(l), - } - } -} - -/// Trait implemented by error types. This should not be implemented manually. Instead, use -/// `#[derive(Subdiagnostic)]` -- see [rustc_macros::Subdiagnostic]. -#[rustc_diagnostic_item = "Subdiagnostic"] -pub trait Subdiagnostic -where - Self: Sized, -{ - /// Add a subdiagnostic to an existing diagnostic. - fn add_to_diag(self, diag: &mut Diag<'_, G>) { - self.add_to_diag_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_diag_with>( - self, - diag: &mut Diag<'_, G>, - f: F, - ); -} - -pub trait SubdiagMessageOp = - Fn(&mut Diag<'_, G>, SubdiagMessage) -> SubdiagMessage; - -/// Trait implemented by lint types. This should not be implemented manually. Instead, use -/// `#[derive(LintDiagnostic)]` -- see [rustc_macros::LintDiagnostic]. -#[rustc_diagnostic_item = "LintDiagnostic"] -pub trait LintDiagnostic<'a, G: EmissionGuarantee> { - /// Decorate and emit a lint. - fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, G>); - - fn msg(&self) -> DiagMessage; -} - -#[derive(Clone, Debug, Encodable, Decodable)] -pub struct DiagLocation { - file: Cow<'static, str>, - line: u32, - col: u32, -} - -impl DiagLocation { - #[track_caller] - fn caller() -> Self { - let loc = panic::Location::caller(); - DiagLocation { file: loc.file().into(), line: loc.line(), col: loc.column() } - } -} - -impl fmt::Display for DiagLocation { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}:{}:{}", self.file, self.line, self.col) - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)] -pub struct IsLint { - /// The lint name. - pub(crate) name: String, - /// Indicates whether this lint should show up in cargo's future breakage report. - has_future_breakage: bool, -} - -#[derive(Debug, PartialEq, Eq)] -pub struct DiagStyledString(pub Vec); - -impl DiagStyledString { - pub fn new() -> DiagStyledString { - DiagStyledString(vec![]) - } - pub fn push_normal>(&mut self, t: S) { - self.0.push(StringPart::normal(t)); - } - pub fn push_highlighted>(&mut self, t: S) { - self.0.push(StringPart::highlighted(t)); - } - pub fn push>(&mut self, t: S, highlight: bool) { - if highlight { - self.push_highlighted(t); - } else { - self.push_normal(t); - } - } - pub fn normal>(t: S) -> DiagStyledString { - DiagStyledString(vec![StringPart::normal(t)]) - } - - pub fn highlighted>(t: S) -> DiagStyledString { - DiagStyledString(vec![StringPart::highlighted(t)]) - } - - pub fn content(&self) -> String { - self.0.iter().map(|x| x.content.as_str()).collect::() - } -} - -#[derive(Debug, PartialEq, Eq)] -pub struct StringPart { - content: String, - style: Style, -} - -impl StringPart { - pub fn normal>(content: S) -> StringPart { - StringPart { content: content.into(), style: Style::NoStyle } - } - - pub fn highlighted>(content: S) -> StringPart { - StringPart { content: content.into(), style: Style::Highlight } - } -} - -/// The main part of a diagnostic. Note that `Diag`, which wraps this type, is -/// used for most operations, and should be used instead whenever possible. -/// This type should only be used when `Diag`'s lifetime causes difficulties, -/// e.g. when storing diagnostics within `DiagCtxt`. -#[must_use] -#[derive(Clone, Debug, Encodable, Decodable)] -pub struct DiagInner { - // NOTE(eddyb) this is private to disallow arbitrary after-the-fact changes, - // outside of what methods in this crate themselves allow. - pub(crate) level: Level, - - pub messages: Vec<(DiagMessage, Style)>, - pub code: Option, - pub span: MultiSpan, - pub children: Vec, - pub suggestions: Result, SuggestionsDisabled>, - pub args: DiagArgMap, - - /// 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 - /// `span` if there is one. Otherwise, it is `DUMMY_SP`. - pub sort_span: Span, - - pub is_lint: Option, - - /// With `-Ztrack_diagnostics` enabled, - /// we print where in rustc this error was emitted. - pub(crate) emitted_at: DiagLocation, -} - -impl DiagInner { - #[track_caller] - pub fn new>(level: Level, message: M) -> Self { - DiagInner::new_with_messages(level, vec![(message.into(), Style::NoStyle)]) - } - - #[track_caller] - pub fn new_with_messages(level: Level, messages: Vec<(DiagMessage, Style)>) -> Self { - DiagInner { - level, - messages, - code: None, - span: MultiSpan::new(), - children: vec![], - suggestions: Ok(vec![]), - args: Default::default(), - sort_span: DUMMY_SP, - is_lint: None, - emitted_at: DiagLocation::caller(), - } - } - - #[inline(always)] - pub fn level(&self) -> Level { - self.level - } - - pub fn is_error(&self) -> bool { - match self.level { - Level::Bug | Level::Fatal | Level::Error | Level::DelayedBug => true, - - Level::ForceWarning(_) - | Level::Warning - | Level::Note - | Level::OnceNote - | Level::Help - | Level::OnceHelp - | Level::FailureNote - | Level::Allow - | Level::Expect(_) => false, - } - } - - pub(crate) fn update_unstable_expectation_id( - &mut self, - unstable_to_stable: &FxIndexMap, - ) { - if let Level::Expect(expectation_id) | Level::ForceWarning(Some(expectation_id)) = - &mut self.level - { - if expectation_id.is_stable() { - return; - } - - // The unstable to stable map only maps the unstable `AttrId` to a stable `HirId` with an attribute index. - // 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 - .get(expectation_id) - .expect("each unstable `LintExpectationId` must have a matching stable id") - .normalize(); - - stable_id.set_lint_index(lint_index); - *expectation_id = stable_id; - } - } - - /// Indicates whether this diagnostic should show up in cargo's future breakage report. - pub(crate) fn has_future_breakage(&self) -> bool { - matches!(self.is_lint, Some(IsLint { has_future_breakage: true, .. })) - } - - pub(crate) fn is_force_warn(&self) -> bool { - match self.level { - Level::ForceWarning(_) => { - assert!(self.is_lint.is_some()); - true - } - _ => false, - } - } - - // See comment on `Diag::subdiagnostic_message_to_diagnostic_message`. - pub(crate) fn subdiagnostic_message_to_diagnostic_message( - &self, - attr: impl Into, - ) -> DiagMessage { - let msg = - self.messages.iter().map(|(msg, _)| msg).next().expect("diagnostic with no messages"); - msg.with_subdiagnostic_message(attr.into()) - } - - pub(crate) fn sub( - &mut self, - level: Level, - message: impl Into, - span: MultiSpan, - ) { - let sub = Subdiag { - level, - messages: vec![( - self.subdiagnostic_message_to_diagnostic_message(message), - Style::NoStyle, - )], - span, - }; - self.children.push(sub); - } - - pub(crate) fn arg(&mut self, name: impl Into, arg: impl IntoDiagArg) { - self.args.insert(name.into(), arg.into_diag_arg()); - } - - /// Fields used for Hash, and PartialEq trait. - fn keys( - &self, - ) -> ( - &Level, - &[(DiagMessage, Style)], - &Option, - &MultiSpan, - &[Subdiag], - &Result, SuggestionsDisabled>, - Vec<(&DiagArgName, &DiagArgValue)>, - &Option, - ) { - ( - &self.level, - &self.messages, - &self.code, - &self.span, - &self.children, - &self.suggestions, - self.args.iter().collect(), - // omit self.sort_span - &self.is_lint, - // omit self.emitted_at - ) - } -} - -impl Hash for DiagInner { - fn hash(&self, state: &mut H) - where - H: Hasher, - { - self.keys().hash(state); - } -} - -impl PartialEq for DiagInner { - fn eq(&self, other: &Self) -> bool { - self.keys() == other.keys() - } -} - -/// A "sub"-diagnostic attached to a parent diagnostic. -/// For example, a note attached to an error. -#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)] -pub struct Subdiag { - pub level: Level, - pub messages: Vec<(DiagMessage, Style)>, - pub span: MultiSpan, -} - -/// Used for emitting structured error messages and other diagnostic information. -/// Wraps a `DiagInner`, adding some useful things. -/// - The `dcx` field, allowing it to (a) emit itself, and (b) do a drop check -/// that it has been emitted or cancelled. -/// - The `EmissionGuarantee`, which determines the type returned from `emit`. -/// -/// Each constructed `Diag` must be consumed by a function such as `emit`, -/// `cancel`, `delay_as_bug`, or `into_diag`. A panic occurrs if a `Diag` -/// is dropped without being consumed by one of these functions. -/// -/// If there is some state in a downstream crate you would like to access in -/// the methods of `Diag` here, consider extending `DiagCtxtFlags`. -#[must_use] -pub struct Diag<'a, G: EmissionGuarantee = ErrorGuaranteed> { - pub dcx: &'a DiagCtxt, - - /// Why the `Option`? It is always `Some` until the `Diag` is consumed via - /// `emit`, `cancel`, etc. At that point it is consumed and replaced with - /// `None`. Then `drop` checks that it is `None`; if not, it panics because - /// a diagnostic was built but not used. - /// - /// Why the Box? `DiagInner` is a large type, and `Diag` is often used as a - /// return value, especially within the frequently-used `PResult` type. In - /// theory, return value optimization (RVO) should avoid unnecessary - /// copying. In practice, it does not (at the time of writing). - diag: Option>, - - _marker: PhantomData, -} - -// Cloning a `Diag` is a recipe for a diagnostic being emitted twice, which -// would be bad. -impl !Clone for Diag<'_, G> {} - -rustc_data_structures::static_assert_size!(Diag<'_, ()>, 2 * std::mem::size_of::()); - -impl Deref for Diag<'_, G> { - type Target = DiagInner; - - fn deref(&self) -> &DiagInner { - self.diag.as_ref().unwrap() - } -} - -impl DerefMut for Diag<'_, G> { - fn deref_mut(&mut self) -> &mut DiagInner { - self.diag.as_mut().unwrap() - } -} - -impl Debug for Diag<'_, G> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.diag.fmt(f) - } -} - -/// `Diag` impls many `&mut self -> &mut Self` methods. Each one modifies an -/// existing diagnostic, either in a standalone fashion, e.g. -/// `err.code(code);`, or in a chained fashion to make multiple modifications, -/// e.g. `err.code(code).span(span);`. -/// -/// This macro creates an equivalent `self -> Self` method, with a `with_` -/// prefix. This can be used in a chained fashion when making a new diagnostic, -/// e.g. `let err = struct_err(msg).with_code(code);`, or emitting a new -/// diagnostic, e.g. `struct_err(msg).with_code(code).emit();`. -/// -/// Although the latter method can be used to modify an existing diagnostic, -/// e.g. `err = err.with_code(code);`, this should be avoided because the former -/// method gives shorter code, e.g. `err.code(code);`. -/// -/// Note: the `with_` methods are added only when needed. If you want to use -/// one and it's not defined, feel free to add it. -/// -/// Note: any doc comments must be within the `with_fn!` call. -macro_rules! with_fn { - { - $with_f:ident, - $(#[$attrs:meta])* - pub fn $f:ident(&mut $self:ident, $($name:ident: $ty:ty),* $(,)?) -> &mut Self { - $($body:tt)* - } - } => { - // The original function. - $(#[$attrs])* - #[doc = concat!("See [`Diag::", stringify!($f), "()`].")] - pub fn $f(&mut $self, $($name: $ty),*) -> &mut Self { - $($body)* - } - - // The `with_*` variant. - $(#[$attrs])* - #[doc = concat!("See [`Diag::", stringify!($f), "()`].")] - pub fn $with_f(mut $self, $($name: $ty),*) -> Self { - $self.$f($($name),*); - $self - } - }; -} - -impl<'a, G: EmissionGuarantee> Diag<'a, G> { - #[rustc_lint_diagnostics] - #[track_caller] - pub fn new(dcx: &'a DiagCtxt, level: Level, message: impl Into) -> Self { - Self::new_diagnostic(dcx, DiagInner::new(level, message)) - } - - /// Creates a new `Diag` with an already constructed diagnostic. - #[track_caller] - pub(crate) fn new_diagnostic(dcx: &'a DiagCtxt, diag: DiagInner) -> Self { - debug!("Created new diagnostic"); - Self { dcx, diag: Some(Box::new(diag)), _marker: PhantomData } - } - - /// Delay emission of this diagnostic as a bug. - /// - /// This can be useful in contexts where an error indicates a bug but - /// typically this only happens when other compilation errors have already - /// happened. In those cases this can be used to defer emission of this - /// diagnostic as a bug in the compiler only if no other errors have been - /// emitted. - /// - /// In the meantime, though, callsites are required to deal with the "bug" - /// locally in whichever way makes the most sense. - #[rustc_lint_diagnostics] - #[track_caller] - pub fn downgrade_to_delayed_bug(&mut self) { - assert!( - matches!(self.level, Level::Error | Level::DelayedBug), - "downgrade_to_delayed_bug: cannot downgrade {:?} to DelayedBug: not an error", - self.level - ); - self.level = Level::DelayedBug; - } - - with_fn! { with_span_label, - /// Appends a labeled span to the diagnostic. - /// - /// Labels are used to convey additional context for the diagnostic's primary span. They will - /// be shown together with the original diagnostic's span, *not* with spans added by - /// `span_note`, `span_help`, etc. Therefore, if the primary span is not displayable (because - /// the span is `DUMMY_SP` or the source code isn't found), labels will not be displayed - /// either. - /// - /// Implementation-wise, the label span is pushed onto the [`MultiSpan`] that was created when - /// the diagnostic was constructed. However, the label span is *not* considered a - /// ["primary span"][`MultiSpan`]; only the `Span` supplied when creating the diagnostic is - /// primary. - #[rustc_lint_diagnostics] - pub fn span_label(&mut self, span: Span, label: impl Into) -> &mut Self { - let msg = self.subdiagnostic_message_to_diagnostic_message(label); - self.span.push_span_label(span, msg); - self - } } - - with_fn! { with_span_labels, - /// Labels all the given spans with the provided label. - /// See [`Self::span_label()`] for more information. - #[rustc_lint_diagnostics] - pub fn span_labels(&mut self, spans: impl IntoIterator, label: &str) -> &mut Self { - for span in spans { - self.span_label(span, label.to_string()); - } - self - } } - - #[rustc_lint_diagnostics] - pub fn replace_span_with(&mut self, after: Span, keep_label: bool) -> &mut Self { - let before = self.span.clone(); - self.span(after); - for span_label in before.span_labels() { - if let Some(label) = span_label.label { - if span_label.is_primary && keep_label { - self.span.push_span_label(after, label); - } else { - self.span.push_span_label(span_label.span, label); - } - } - } - self - } - - #[rustc_lint_diagnostics] - pub fn note_expected_found( - &mut self, - expected_label: &dyn fmt::Display, - expected: DiagStyledString, - found_label: &dyn fmt::Display, - found: DiagStyledString, - ) -> &mut Self { - self.note_expected_found_extra(expected_label, expected, found_label, found, &"", &"") - } - - #[rustc_lint_diagnostics] - pub fn note_expected_found_extra( - &mut self, - expected_label: &dyn fmt::Display, - expected: DiagStyledString, - found_label: &dyn fmt::Display, - found: DiagStyledString, - expected_extra: &dyn fmt::Display, - found_extra: &dyn fmt::Display, - ) -> &mut Self { - let expected_label = expected_label.to_string(); - let expected_label = if expected_label.is_empty() { - "expected".to_string() - } else { - format!("expected {expected_label}") - }; - let found_label = found_label.to_string(); - let found_label = if found_label.is_empty() { - "found".to_string() - } else { - format!("found {found_label}") - }; - let (found_padding, expected_padding) = if expected_label.len() > found_label.len() { - (expected_label.len() - found_label.len(), 0) - } else { - (0, found_label.len() - expected_label.len()) - }; - let mut msg = vec![StringPart::normal(format!( - "{}{} `", - " ".repeat(expected_padding), - expected_label - ))]; - msg.extend(expected.0.into_iter()); - msg.push(StringPart::normal(format!("`{expected_extra}\n"))); - msg.push(StringPart::normal(format!("{}{} `", " ".repeat(found_padding), found_label))); - msg.extend(found.0.into_iter()); - msg.push(StringPart::normal(format!("`{found_extra}"))); - - // For now, just attach these as notes. - self.highlighted_note(msg); - self - } - - #[rustc_lint_diagnostics] - pub fn note_trait_signature(&mut self, name: Symbol, signature: String) -> &mut Self { - self.highlighted_note(vec![ - StringPart::normal(format!("`{name}` from trait: `")), - StringPart::highlighted(signature), - StringPart::normal("`"), - ]); - self - } - - with_fn! { with_note, - /// Add a note attached to this diagnostic. - #[rustc_lint_diagnostics] - pub fn note(&mut self, msg: impl Into) -> &mut Self { - self.sub(Level::Note, msg, MultiSpan::new()); - self - } } - - #[rustc_lint_diagnostics] - fn highlighted_note(&mut self, msg: Vec) -> &mut Self { - self.sub_with_highlights(Level::Note, msg, MultiSpan::new()); - self - } - - /// This is like [`Diag::note()`], but it's only printed once. - #[rustc_lint_diagnostics] - pub fn note_once(&mut self, msg: impl Into) -> &mut Self { - self.sub(Level::OnceNote, msg, MultiSpan::new()); - self - } - - with_fn! { with_span_note, - /// Prints the span with a note above it. - /// This is like [`Diag::note()`], but it gets its own span. - #[rustc_lint_diagnostics] - pub fn span_note( - &mut self, - sp: impl Into, - msg: impl Into, - ) -> &mut Self { - self.sub(Level::Note, msg, sp.into()); - self - } } - - /// Prints the span with a note above it. - /// This is like [`Diag::note_once()`], but it gets its own span. - #[rustc_lint_diagnostics] - pub fn span_note_once>( - &mut self, - sp: S, - msg: impl Into, - ) -> &mut Self { - self.sub(Level::OnceNote, msg, sp.into()); - self - } - - with_fn! { with_warn, - /// Add a warning attached to this diagnostic. - #[rustc_lint_diagnostics] - pub fn warn(&mut self, msg: impl Into) -> &mut Self { - self.sub(Level::Warning, msg, MultiSpan::new()); - self - } } - - /// Prints the span with a warning above it. - /// This is like [`Diag::warn()`], but it gets its own span. - #[rustc_lint_diagnostics] - pub fn span_warn>( - &mut self, - sp: S, - msg: impl Into, - ) -> &mut Self { - self.sub(Level::Warning, msg, sp.into()); - self - } - - with_fn! { with_help, - /// Add a help message attached to this diagnostic. - #[rustc_lint_diagnostics] - pub fn help(&mut self, msg: impl Into) -> &mut Self { - self.sub(Level::Help, msg, MultiSpan::new()); - self - } } - - /// This is like [`Diag::help()`], but it's only printed once. - #[rustc_lint_diagnostics] - pub fn help_once(&mut self, msg: impl Into) -> &mut Self { - self.sub(Level::OnceHelp, msg, MultiSpan::new()); - self - } - - /// Add a help message attached to this diagnostic with a customizable highlighted message. - #[rustc_lint_diagnostics] - pub fn highlighted_help(&mut self, msg: Vec) -> &mut Self { - self.sub_with_highlights(Level::Help, msg, MultiSpan::new()); - self - } - - /// Prints the span with some help above it. - /// This is like [`Diag::help()`], but it gets its own span. - #[rustc_lint_diagnostics] - pub fn span_help>( - &mut self, - sp: S, - msg: impl Into, - ) -> &mut Self { - self.sub(Level::Help, msg, sp.into()); - self - } - - /// Disallow attaching suggestions this diagnostic. - /// Any suggestions attached e.g. with the `span_suggestion_*` methods - /// (before and after the call to `disable_suggestions`) will be ignored. - #[rustc_lint_diagnostics] - pub fn disable_suggestions(&mut self) -> &mut Self { - self.suggestions = Err(SuggestionsDisabled); - self - } - - /// Helper for pushing to `self.suggestions`, if available (not disable). - #[rustc_lint_diagnostics] - fn push_suggestion(&mut self, suggestion: CodeSuggestion) { - for subst in &suggestion.substitutions { - for part in &subst.parts { - let span = part.span; - let call_site = span.ctxt().outer_expn_data().call_site; - if span.in_derive_expansion() && span.overlaps_or_adjacent(call_site) { - // Ignore if spans is from derive macro. - return; - } - } - } - - if let Ok(suggestions) = &mut self.suggestions { - suggestions.push(suggestion); - } - } - - with_fn! { with_multipart_suggestion, - /// Show a suggestion that has multiple parts to it. - /// In other words, multiple changes need to be applied as part of this suggestion. - #[rustc_lint_diagnostics] - pub fn multipart_suggestion( - &mut self, - msg: impl Into, - suggestion: Vec<(Span, String)>, - applicability: Applicability, - ) -> &mut Self { - self.multipart_suggestion_with_style( - msg, - suggestion, - applicability, - SuggestionStyle::ShowCode, - ) - } } - - /// Show a suggestion that has multiple parts to it, always as it's own subdiagnostic. - /// In other words, multiple changes need to be applied as part of this suggestion. - #[rustc_lint_diagnostics] - pub fn multipart_suggestion_verbose( - &mut self, - msg: impl Into, - suggestion: Vec<(Span, String)>, - applicability: Applicability, - ) -> &mut Self { - self.multipart_suggestion_with_style( - msg, - suggestion, - applicability, - SuggestionStyle::ShowAlways, - ) - } - - /// [`Diag::multipart_suggestion()`] but you can set the [`SuggestionStyle`]. - #[rustc_lint_diagnostics] - pub fn multipart_suggestion_with_style( - &mut self, - msg: impl Into, - mut suggestion: Vec<(Span, String)>, - applicability: Applicability, - style: SuggestionStyle, - ) -> &mut Self { - suggestion.sort_unstable(); - suggestion.dedup(); - - let parts = suggestion - .into_iter() - .map(|(span, snippet)| SubstitutionPart { snippet, span }) - .collect::>(); - - assert!(!parts.is_empty()); - debug_assert_eq!( - parts.iter().find(|part| part.span.is_empty() && part.snippet.is_empty()), - None, - "Span must not be empty and have no suggestion", - ); - debug_assert_eq!( - parts.array_windows().find(|[a, b]| a.span.overlaps(b.span)), - None, - "suggestion must not have overlapping parts", - ); - - self.push_suggestion(CodeSuggestion { - substitutions: vec![Substitution { parts }], - msg: self.subdiagnostic_message_to_diagnostic_message(msg), - style, - applicability, - }); - self - } - - /// Prints out a message with for a multipart suggestion without showing the suggested code. - /// - /// This is intended to be used for suggestions that are obvious in what the changes need to - /// be from the message, showing the span label inline would be visually unpleasant - /// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't - /// improve understandability. - #[rustc_lint_diagnostics] - pub fn tool_only_multipart_suggestion( - &mut self, - msg: impl Into, - suggestion: Vec<(Span, String)>, - applicability: Applicability, - ) -> &mut Self { - self.multipart_suggestion_with_style( - msg, - suggestion, - applicability, - SuggestionStyle::CompletelyHidden, - ) - } - - with_fn! { with_span_suggestion, - /// Prints out a message with a suggested edit of the code. - /// - /// In case of short messages and a simple suggestion, rustc displays it as a label: - /// - /// ```text - /// try adding parentheses: `(tup.0).1` - /// ``` - /// - /// The message - /// - /// * should not end in any punctuation (a `:` is added automatically) - /// * should not be a question (avoid language like "did you mean") - /// * should not contain any phrases like "the following", "as shown", etc. - /// * may look like "to do xyz, use" or "to do xyz, use abc" - /// * may contain a name of a function, variable, or type, but not whole expressions - /// - /// See `CodeSuggestion` for more information. - #[rustc_lint_diagnostics] - pub fn span_suggestion( - &mut self, - sp: Span, - msg: impl Into, - suggestion: impl ToString, - applicability: Applicability, - ) -> &mut Self { - self.span_suggestion_with_style( - sp, - msg, - suggestion, - applicability, - SuggestionStyle::ShowCode, - ); - self - } } - - /// [`Diag::span_suggestion()`] but you can set the [`SuggestionStyle`]. - #[rustc_lint_diagnostics] - pub fn span_suggestion_with_style( - &mut self, - sp: Span, - msg: impl Into, - suggestion: impl ToString, - 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 }], - }], - msg: self.subdiagnostic_message_to_diagnostic_message(msg), - style, - applicability, - }); - self - } - - with_fn! { with_span_suggestion_verbose, - /// Always show the suggested change. - #[rustc_lint_diagnostics] - pub fn span_suggestion_verbose( - &mut self, - sp: Span, - msg: impl Into, - suggestion: impl ToString, - applicability: Applicability, - ) -> &mut Self { - self.span_suggestion_with_style( - sp, - msg, - suggestion, - applicability, - SuggestionStyle::ShowAlways, - ); - self - } } - - with_fn! { with_span_suggestions, - /// Prints out a message with multiple suggested edits of the code. - /// See also [`Diag::span_suggestion()`]. - #[rustc_lint_diagnostics] - pub fn span_suggestions( - &mut self, - sp: Span, - msg: impl Into, - suggestions: impl IntoIterator, - applicability: Applicability, - ) -> &mut Self { - self.span_suggestions_with_style( - sp, - msg, - suggestions, - applicability, - SuggestionStyle::ShowCode, - ) - } } - - #[rustc_lint_diagnostics] - pub fn span_suggestions_with_style( - &mut self, - sp: Span, - msg: impl Into, - suggestions: impl IntoIterator, - applicability: Applicability, - style: SuggestionStyle, - ) -> &mut Self { - let substitutions = suggestions - .into_iter() - .map(|snippet| { - debug_assert!( - !(sp.is_empty() && snippet.is_empty()), - "Span must not be empty and have no suggestion" - ); - Substitution { parts: vec![SubstitutionPart { snippet, span: sp }] } - }) - .collect(); - self.push_suggestion(CodeSuggestion { - substitutions, - msg: self.subdiagnostic_message_to_diagnostic_message(msg), - style, - applicability, - }); - self - } - - /// Prints out a message with multiple suggested edits of the code, where each edit consists of - /// multiple parts. - /// See also [`Diag::multipart_suggestion()`]. - #[rustc_lint_diagnostics] - pub fn multipart_suggestions( - &mut self, - msg: impl Into, - suggestions: impl IntoIterator>, - applicability: Applicability, - ) -> &mut Self { - let substitutions = suggestions - .into_iter() - .map(|sugg| { - let mut parts = sugg - .into_iter() - .map(|(span, snippet)| SubstitutionPart { snippet, span }) - .collect::>(); - - parts.sort_unstable_by_key(|part| part.span); - - assert!(!parts.is_empty()); - debug_assert_eq!( - parts.iter().find(|part| part.span.is_empty() && part.snippet.is_empty()), - None, - "Span must not be empty and have no suggestion", - ); - debug_assert_eq!( - parts.array_windows().find(|[a, b]| a.span.overlaps(b.span)), - None, - "suggestion must not have overlapping parts", - ); - - Substitution { parts } - }) - .collect(); - - self.push_suggestion(CodeSuggestion { - substitutions, - msg: self.subdiagnostic_message_to_diagnostic_message(msg), - style: SuggestionStyle::ShowCode, - applicability, - }); - self - } - - with_fn! { with_span_suggestion_short, - /// 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. - /// - /// See `CodeSuggestion` for more information. - #[rustc_lint_diagnostics] - pub fn span_suggestion_short( - &mut self, - sp: Span, - msg: impl Into, - suggestion: impl ToString, - applicability: Applicability, - ) -> &mut Self { - self.span_suggestion_with_style( - sp, - msg, - suggestion, - applicability, - SuggestionStyle::HideCodeInline, - ); - self - } } - - /// Prints out a message for a suggestion without showing the suggested code. - /// - /// This is intended to be used for suggestions that are obvious in what the changes need to - /// be from the message, showing the span label inline would be visually unpleasant - /// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't - /// improve understandability. - #[rustc_lint_diagnostics] - pub fn span_suggestion_hidden( - &mut self, - sp: Span, - msg: impl Into, - suggestion: impl ToString, - applicability: Applicability, - ) -> &mut Self { - self.span_suggestion_with_style( - sp, - msg, - suggestion, - applicability, - SuggestionStyle::HideCodeAlways, - ); - self - } - - with_fn! { with_tool_only_span_suggestion, - /// Adds a suggestion to the JSON output that will not be shown in the CLI. - /// - /// This is intended to be used for suggestions that are *very* obvious in what the changes - /// need to be from the message, but we still want other tools to be able to apply them. - #[rustc_lint_diagnostics] - pub fn tool_only_span_suggestion( - &mut self, - sp: Span, - msg: impl Into, - suggestion: impl ToString, - applicability: Applicability, - ) -> &mut Self { - self.span_suggestion_with_style( - sp, - msg, - suggestion, - applicability, - SuggestionStyle::CompletelyHidden, - ); - 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). - #[rustc_lint_diagnostics] - pub fn subdiagnostic( - &mut self, - dcx: &crate::DiagCtxt, - subdiagnostic: impl Subdiagnostic, - ) -> &mut Self { - subdiagnostic.add_to_diag_with(self, |diag, msg| { - let args = diag.args.iter(); - let msg = diag.subdiagnostic_message_to_diagnostic_message(msg); - dcx.eagerly_translate(msg, args) - }); - self - } - - with_fn! { with_span, - /// Add a span. - #[rustc_lint_diagnostics] - pub fn span(&mut self, sp: impl Into) -> &mut Self { - self.span = sp.into(); - if let Some(span) = self.span.primary_span() { - self.sort_span = span; - } - self - } } - - #[rustc_lint_diagnostics] - pub fn is_lint(&mut self, name: String, has_future_breakage: bool) -> &mut Self { - self.is_lint = Some(IsLint { name, has_future_breakage }); - self - } - - with_fn! { with_code, - /// Add an error code. - #[rustc_lint_diagnostics] - pub fn code(&mut self, code: ErrCode) -> &mut Self { - self.code = Some(code); - self - } } - - with_fn! { with_primary_message, - /// Add a primary message. - #[rustc_lint_diagnostics] - pub fn primary_message(&mut self, msg: impl Into) -> &mut Self { - self.messages[0] = (msg.into(), Style::NoStyle); - self - } } - - with_fn! { with_arg, - /// Add an argument. - #[rustc_lint_diagnostics] - pub fn arg( - &mut self, - name: impl Into, - arg: impl IntoDiagArg, - ) -> &mut Self { - self.deref_mut().arg(name, arg); - self - } } - - /// Helper function that takes a `SubdiagMessage` and returns a `DiagMessage` by - /// combining it with the primary message of the diagnostic (if translatable, otherwise it just - /// passes the user's string along). - pub(crate) fn subdiagnostic_message_to_diagnostic_message( - &self, - attr: impl Into, - ) -> DiagMessage { - self.deref().subdiagnostic_message_to_diagnostic_message(attr) - } - - /// Convenience function for internal use, clients should use one of the - /// public methods above. - /// - /// Used by `proc_macro_server` for implementing `server::Diagnostic`. - pub fn sub(&mut self, level: Level, message: impl Into, span: MultiSpan) { - self.deref_mut().sub(level, message, span); - } - - /// Convenience function for internal use, clients should use one of the - /// public methods above. - fn sub_with_highlights(&mut self, level: Level, messages: Vec, span: MultiSpan) { - let messages = messages - .into_iter() - .map(|m| (self.subdiagnostic_message_to_diagnostic_message(m.content), m.style)) - .collect(); - let sub = Subdiag { level, messages, span }; - self.children.push(sub); - } - - /// Takes the diagnostic. For use by methods that consume the Diag: `emit`, - /// `cancel`, etc. Afterwards, `drop` is the only code that will be run on - /// `self`. - fn take_diag(&mut self) -> DiagInner { - Box::into_inner(self.diag.take().unwrap()) - } - - /// Most `emit_producing_guarantee` functions use this as a starting point. - fn emit_producing_nothing(mut self) { - let diag = self.take_diag(); - self.dcx.emit_diagnostic(diag); - } - - /// `ErrorGuaranteed::emit_producing_guarantee` uses this. - fn emit_producing_error_guaranteed(mut self) -> ErrorGuaranteed { - let diag = self.take_diag(); - - // The only error levels that produce `ErrorGuaranteed` are - // `Error` and `DelayedBug`. But `DelayedBug` should never occur here - // because delayed bugs have their level changed to `Bug` when they are - // actually printed, so they produce an ICE. - // - // (Also, even though `level` isn't `pub`, the whole `DiagInner` could - // be overwritten with a new one thanks to `DerefMut`. So this assert - // protects against that, too.) - assert!( - matches!(diag.level, Level::Error | Level::DelayedBug), - "invalid diagnostic level ({:?})", - diag.level, - ); - - let guar = self.dcx.emit_diagnostic(diag); - guar.unwrap() - } - - /// Emit and consume the diagnostic. - #[track_caller] - pub fn emit(self) -> G::EmitResult { - G::emit_producing_guarantee(self) - } - - /// Emit the diagnostic unless `delay` is true, - /// in which case the emission will be delayed as a bug. - /// - /// See `emit` and `delay_as_bug` for details. - #[track_caller] - pub fn emit_unless(mut self, delay: bool) -> G::EmitResult { - if delay { - self.downgrade_to_delayed_bug(); - } - self.emit() - } - - /// Cancel and consume the diagnostic. (A diagnostic must either be emitted or - /// cancelled or it will panic when dropped). - pub fn cancel(mut self) { - self.diag = None; - drop(self); - } - - /// See `DiagCtxt::stash_diagnostic` for details. - pub fn stash(mut self, span: Span, key: StashKey) -> Option { - self.dcx.stash_diagnostic(span, key, self.take_diag()) - } - - /// Delay emission of this diagnostic as a bug. - /// - /// This can be useful in contexts where an error indicates a bug but - /// typically this only happens when other compilation errors have already - /// happened. In those cases this can be used to defer emission of this - /// diagnostic as a bug in the compiler only if no other errors have been - /// emitted. - /// - /// In the meantime, though, callsites are required to deal with the "bug" - /// locally in whichever way makes the most sense. - #[track_caller] - pub fn delay_as_bug(mut self) -> G::EmitResult { - self.downgrade_to_delayed_bug(); - self.emit() - } -} - -/// Destructor bomb: every `Diag` must be consumed (emitted, cancelled, etc.) -/// or we emit a bug. -impl Drop for Diag<'_, G> { - fn drop(&mut self) { - match self.diag.take() { - Some(diag) if !panicking() => { - self.dcx.emit_diagnostic(DiagInner::new( - Level::Bug, - DiagMessage::from("the following error was constructed but not emitted"), - )); - self.dcx.emit_diagnostic(*diag); - panic!("error was constructed but not emitted"); - } - _ => {} - } - } -} - -#[macro_export] -macro_rules! struct_span_code_err { - ($dcx:expr, $span:expr, $code:expr, $($message:tt)*) => ({ - $dcx.struct_span_err($span, format!($($message)*)).with_code($code) - }) -} +use crate::snippet::Style;use crate::{CodeSuggestion,DiagCtxt,DiagMessage,//{;}; +ErrCode,ErrorGuaranteed,ExplicitBug,Level,MultiSpan,StashKey,SubdiagMessage,//3; +Substitution,SubstitutionPart,SuggestionStyle,} ;use rustc_data_structures::fx:: +FxIndexMap;use rustc_error_messages::fluent_value_from_str_list_sep_by_and;use// +rustc_error_messages::FluentValue;use rustc_lint_defs::{Applicability,//((),()); +LintExpectationId};use rustc_span::source_map ::Spanned;use rustc_span::symbol:: +Symbol;use rustc_span::{Span,DUMMY_SP};use std::borrow::Cow;use std::fmt::{self +,Debug};use std::hash::{Hash,Hasher};use std::marker::PhantomData;use std::ops// +::{Deref,DerefMut};use std::panic;use std::thread::panicking;#[derive(Clone,//3; +Debug,PartialEq,Eq,Hash,Encodable, Decodable)]pub struct SuggestionsDisabled;pub +type DiagArg<'iter>=(&'iter DiagArgName,&'iter DiagArgValue);pub type//let _=(); +DiagArgName=Cow<'static,str>;#[derive(Clone,Debug,PartialEq,Eq,Hash,Encodable,// +Decodable)]pub enum DiagArgValue{Str(Cow<'static,str>),Number(i32),//let _=||(); +StrListSepByAnd(Vec>),}pub type DiagArgMap=FxIndexMap;pub trait EmissionGuarantee:Sized{type EmitResult=//3; +Self;#[track_caller]fn emit_producing_guarantee(diag:Diag<'_,Self>)->Self:://(); +EmitResult;}impl EmissionGuarantee for ErrorGuaranteed{fn//if true{};let _=||(); +emit_producing_guarantee(diag:Diag<'_,Self>)->Self::EmitResult{diag.//if true{}; +emit_producing_error_guaranteed()}}impl EmissionGuarantee for(){fn//loop{break}; +emit_producing_guarantee(diag:Diag<'_,Self>)->Self::EmitResult{loop{break};diag. +emit_producing_nothing();((),());}}#[derive(Copy,Clone)]pub struct BugAbort;impl +EmissionGuarantee for BugAbort{type EmitResult=!;fn emit_producing_guarantee(//; +diag:Diag<'_,Self>)->Self::EmitResult{3;diag.emit_producing_nothing();3;;panic:: +panic_any(ExplicitBug);((),());}}#[derive(Copy,Clone)]pub struct FatalAbort;impl +EmissionGuarantee for FatalAbort{type EmitResult=!;fn emit_producing_guarantee( +diag:Diag<'_,Self>)->Self::EmitResult{();diag.emit_producing_nothing();3;crate:: +FatalError.raise()}}impl EmissionGuarantee for rustc_span::fatal_error:://{();}; +FatalError{fn emit_producing_guarantee(diag:Diag<'_,Self>)->Self::EmitResult{(); +diag.emit_producing_nothing();let _=||();rustc_span::fatal_error::FatalError}}#[ +rustc_diagnostic_item="Diagnostic"]pub trait Diagnostic<'a,G:EmissionGuarantee= +ErrorGuaranteed>{#[must_use]fn into_diag(self,dcx:&'a DiagCtxt,level:Level)->//; +Diag<'a,G>;}impl<'a,T,G>Diagnostic<'a ,G>for Spannedwhere T:Diagnostic<'a,G>, +G:EmissionGuarantee,{fn into_diag(self,dcx:& 'a DiagCtxt,level:Level)->Diag<'a,G +>{self.node.into_diag(dcx,level). with_span(self.span)}}pub trait IntoDiagArg{fn +into_diag_arg(self)->DiagArgValue;}impl IntoDiagArg for DiagArgValue{fn//*&*&(); +into_diag_arg(self)->DiagArgValue{self}}impl Into>for//{;}; +DiagArgValue{fn into(self)->FluentValue< 'static>{match self{DiagArgValue::Str(s +)=>(((From::from(s)))),DiagArgValue::Number(n)=>((From::from(n))),DiagArgValue:: +StrListSepByAnd(l)=>(((((((fluent_value_from_str_list_sep_by_and(l)))))))),}}}#[ +rustc_diagnostic_item="Subdiagnostic"]pub trait Subdiagnostic where Self:Sized, +{fn add_to_diag(self,diag:&mut Diag<'_,G>){let _=||();self. +add_to_diag_with(diag,|_,m|m);*&*&();}fn add_to_diag_with>(self,diag:&mut Diag<'_,G>,f:F,);}pub trait//*&*&();((),()); +SubdiagMessageOp=Fn(&mut Diag<'_,G>,SubdiagMessage)->//{;}; +SubdiagMessage;#[rustc_diagnostic_item="LintDiagnostic"]pub trait +LintDiagnostic<'a,G:EmissionGuarantee>{fn decorate_lint<'b>(self,diag:&'b mut//; +Diag<'a,G>);fn msg(&self)->DiagMessage;}#[derive(Clone,Debug,Encodable,//*&*&(); +Decodable)]pub struct DiagLocation{file:Cow<'static ,str>,line:u32,col:u32,}impl +DiagLocation{#[track_caller]fn caller()->Self{3;let loc=panic::Location::caller( +);();DiagLocation{file:loc.file().into(),line:loc.line(),col:loc.column()}}}impl +fmt::Display for DiagLocation{fn fmt(&self,f:&mut fmt::Formatter<'_>)->fmt:://3; +Result{write!(f,"{}:{}:{}",self.file,self. line,self.col)}}#[derive(Clone,Debug, +PartialEq,Eq,Hash,Encodable,Decodable)]pub struct IsLint{pub(crate)name:String, +has_future_breakage:bool,}#[derive(Debug,PartialEq,Eq)]pub struct//loop{break;}; +DiagStyledString(pub Vec);impl DiagStyledString{pub fn new()->//{;}; +DiagStyledString{(DiagStyledString(vec![]))}pub fn push_normal>(& +mut self,t:S){3;self.0.push(StringPart::normal(t));3;}pub fn push_highlighted>(&mut self,t:S){3;self.0.push(StringPart::highlighted(t));3;}pub fn +push>(&mut self,t:S,highlight:bool){if highlight{let _=||();self. +push_highlighted(t);;}else{self.push_normal(t);}}pub fn normal>(t +:S)->DiagStyledString{((DiagStyledString((vec![StringPart::normal(t)]))))}pub fn +highlighted>(t:S)->DiagStyledString{DiagStyledString(vec![//({}); +StringPart::highlighted(t)])}pub fn content(&self) ->String{self.0.iter().map(|x +|(((x.content.as_str())))).collect::()}}#[derive(Debug,PartialEq,Eq)]pub +struct StringPart{content:String,style:Style,}impl StringPart{pub fn normal>(content:S)->StringPart{ StringPart{content:(content.into()),style: +Style::NoStyle}}pub fn highlighted>(content:S)->StringPart{//{;}; +StringPart{content:content.into(),style: Style::Highlight}}}#[must_use]#[derive( +Clone,Debug,Encodable,Decodable)]pub struct DiagInner{pub(crate)level:Level,pub +messages:Vec<(DiagMessage,Style)>,pub code:Option,pub span:MultiSpan,// +pub children:Vec,pub suggestions:Result,//let _=(); +SuggestionsDisabled>,pub args:DiagArgMap,pub sort_span:Span,pub is_lint:Option< +IsLint>,pub(crate)emitted_at:DiagLocation, }impl DiagInner{#[track_caller]pub fn +new>(level:Level,message:M)->Self{DiagInner:://loop{break;}; +new_with_messages(level,(vec![(message.into(),Style::NoStyle)]))}#[track_caller] +pub fn new_with_messages(level:Level,messages:Vec<(DiagMessage,Style)>)->Self{// +DiagInner{level,messages,code:None,span:((MultiSpan ::new())),children:(vec![]), +suggestions:Ok(vec![]),args: Default::default(),sort_span:DUMMY_SP,is_lint:None, +emitted_at:DiagLocation::caller(),}}#[ inline(always)]pub fn level(&self)->Level +{self.level}pub fn is_error(&self)->bool{match self.level{Level::Bug|Level:://3; +Fatal|Level::Error|Level::DelayedBug=>((( true))),Level::ForceWarning(_)|Level:: +Warning|Level::Note|Level::OnceNote|Level::Help|Level::OnceHelp|Level:://*&*&(); +FailureNote|Level::Allow|Level::Expect(_) =>((((((((false)))))))),}}pub(crate)fn +update_unstable_expectation_id(&mut self,unstable_to_stable:&FxIndexMap,){if let Level::Expect(expectation_id)|//3; +Level::ForceWarning(Some(expectation_id))=((&mut self.level)){if expectation_id. +is_stable(){();return;();}();let lint_index=expectation_id.get_lint_index();3;3; +expectation_id.set_lint_index(None);3;;let mut stable_id=unstable_to_stable.get( +expectation_id).expect(//loop{break;};if let _=(){};if let _=(){};if let _=(){}; +"each unstable `LintExpectationId` must have a matching stable id") .normalize() +;;;stable_id.set_lint_index(lint_index);*expectation_id=stable_id;}}pub(crate)fn +has_future_breakage(&self)->bool{matches!(self.is_lint,Some(IsLint{//let _=||(); +has_future_breakage:true,..}))}pub(crate)fn is_force_warn(&self)->bool{match//3; +self.level{Level::ForceWarning(_)=>{3;assert!(self.is_lint.is_some());3;true}_=> +false,}}pub(crate)fn subdiagnostic_message_to_diagnostic_message(&self,attr://3; +impl Into,)->DiagMessage{;let msg=self.messages.iter().map(|(msg +,_)|msg).next().expect("diagnostic with no messages");let _=||();let _=||();msg. +with_subdiagnostic_message(attr.into())}pub( crate)fn sub(&mut self,level:Level, +message:impl Into,span:MultiSpan,){*&*&();let sub=Subdiag{level, +messages:vec![(self.subdiagnostic_message_to_diagnostic_message(message),Style// +::NoStyle,)],span,};;;self.children.push(sub);;}pub(crate)fn arg(&mut self,name: +impl Into,arg:impl IntoDiagArg){3;self.args.insert(name.into(),arg. +into_diag_arg());{();};}fn keys(&self,)->(&Level,&[(DiagMessage,Style)],&Option< +ErrCode>,&MultiSpan,&[Subdiag] ,&Result,SuggestionsDisabled> +,Vec<(&DiagArgName,&DiagArgValue)>,&Option,){(((((&self.level)))),&self. +messages,&self.code,&self.span,& self.children,&self.suggestions,self.args.iter( +).collect(),(&self.is_lint),)}}impl Hash for DiagInner{fn hash(&self,state:& +mut H)where H:Hasher,{;self.keys().hash(state);}}impl PartialEq for DiagInner{fn +eq(&self,other:&Self)->bool{((self.keys())==other.keys())}}#[derive(Clone,Debug, +PartialEq,Hash,Encodable,Decodable)]pub struct Subdiag{pub level:Level,pub//{;}; +messages:Vec<(DiagMessage,Style)>,pub span:MultiSpan,}#[must_use]pub struct//(); +Diag<'a,G:EmissionGuarantee=ErrorGuaranteed>{pub dcx:&'a DiagCtxt,diag:Option>,_marker:PhantomData,}impl!Clone for Diag<'_,G>{}//((),()); +rustc_data_structures::static_assert_size!(Diag<'_,()>,2*std::mem::size_of::());implDeref for Diag<'_,G>{type Target=DiagInner;// +fn deref(&self)->&DiagInner{((((((((self.diag.as_ref())))).unwrap()))))}}implDerefMut for Diag<'_,G>{fn deref_mut(&mut self)->&mut//*&*&(); +DiagInner{self.diag.as_mut().unwrap( )}}implDebug for Diag< +'_,G>{fn fmt(&self,f:&mut fmt::Formatter <'_>)->fmt::Result{(self.diag.fmt(f))}} +macro_rules!with_fn{{$with_f:ident,$(#[$attrs:meta])*pub fn$f:ident(&mut$self:// +ident,$($name:ident:$ty:ty),*$(,)?)->&mut Self{$($body:tt)*}}=>{$(#[$attrs])*#[ +doc=concat!("See [`Diag::",stringify!($f),"()`].")] pub fn$f(&mut$self,$($name:$ +ty),*)->&mut Self{$($body)*} $(#[$attrs])*#[doc=concat!("See [`Diag::",stringify +!($f),"()`].")]pub fn$with_f(mut$self,$($name :$ty),*)->Self{$self.$f($($name),* +);$self}};}impl<'a,G:EmissionGuarantee>Diag<'a,G>{#[rustc_lint_diagnostics]#[//; +track_caller]pub fn new(dcx:&'a DiagCtxt,level:Level,message:impl Into)->Self{(Self::new_diagnostic(dcx,DiagInner::new(level,message)))}#[ +track_caller]pub(crate)fn new_diagnostic(dcx :&'a DiagCtxt,diag:DiagInner)->Self +{3;debug!("Created new diagnostic");;Self{dcx,diag:Some(Box::new(diag)),_marker: +PhantomData}}#[rustc_lint_diagnostics]#[track_caller]pub fn//let _=();if true{}; +downgrade_to_delayed_bug(&mut self){();assert!(matches!(self.level,Level::Error| +Level::DelayedBug),//if let _=(){};*&*&();((),());*&*&();((),());*&*&();((),()); +"downgrade_to_delayed_bug: cannot downgrade {:?} to DelayedBug: not an error",// +self.level);{;};{;};self.level=Level::DelayedBug;();}with_fn!{with_span_label,#[ +rustc_lint_diagnostics]pub fn span_label(&mut self,span:Span,label:impl Into)->&mut Self{let msg=self.//let _=();let _=();let _=();if true{}; +subdiagnostic_message_to_diagnostic_message(label);self.span.push_span_label(//; +span,msg);self}}with_fn!{with_span_labels,#[rustc_lint_diagnostics]pub fn//({}); +span_labels(&mut self,spans:impl IntoIterator,label:&str)->&mut Self +{for span in spans{self.span_label(span,label.to_string());}self}}#[//if true{}; +rustc_lint_diagnostics]pub fn replace_span_with(& mut self,after:Span,keep_label +:bool)->&mut Self{;let before=self.span.clone();;self.span(after);for span_label +in (((before.span_labels()))){if let Some(label)=span_label.label{if span_label. +is_primary&&keep_label{;self.span.push_span_label(after,label);;}else{self.span. +push_span_label(span_label.span,label);3;}}}self}#[rustc_lint_diagnostics]pub fn +note_expected_found(&mut self,expected_label:&dyn fmt::Display,expected://{();}; +DiagStyledString,found_label:&dyn fmt::Display,found:DiagStyledString,)->&mut//; +Self{self.note_expected_found_extra(expected_label, expected,found_label,found,& +"",(&("")))}#[rustc_lint_diagnostics]pub fn note_expected_found_extra(&mut self, +expected_label:&dyn fmt::Display, expected:DiagStyledString,found_label:&dyn fmt +::Display,found:DiagStyledString,expected_extra: &dyn fmt::Display,found_extra:& +dyn fmt::Display,)->&mut Self{;let expected_label=expected_label.to_string();let +expected_label=if (expected_label.is_empty()){"expected".to_string()}else{format +!("expected {expected_label}")};3;;let found_label=found_label.to_string();;;let +found_label=if ((found_label.is_empty())){(( "found").to_string())}else{format!( +"found {found_label}")};;;let(found_padding,expected_padding)=if expected_label. +len()>(found_label.len()){((expected_label.len()- found_label.len(),0))}else{(0, +found_label.len()-expected_label.len())};3;;let mut msg=vec![StringPart::normal( +format!("{}{} `"," ".repeat(expected_padding),expected_label))];();3;msg.extend( +expected.0.into_iter());if true{};if true{};msg.push(StringPart::normal(format!( +"`{expected_extra}\n")));();();msg.push(StringPart::normal(format!("{}{} `"," ". +repeat(found_padding),found_label)));;;msg.extend(found.0.into_iter());msg.push( +StringPart::normal(format!("`{found_extra}")));;self.highlighted_note(msg);self} +#[rustc_lint_diagnostics]pub fn note_trait_signature(&mut self,name:Symbol,//(); +signature:String)->&mut Self{({});self.highlighted_note(vec![StringPart::normal( +format!("`{name}` from trait: `")),StringPart::highlighted(signature),//((),()); +StringPart::normal("`"),]);;self}with_fn!{with_note,#[rustc_lint_diagnostics]pub +fn note(&mut self,msg:impl Into)->&mut Self{self.sub(Level:://3; +Note,msg,MultiSpan::new()); self}}#[rustc_lint_diagnostics]fn highlighted_note(& +mut self,msg:Vec)->&mut Self{3;self.sub_with_highlights(Level::Note, +msg,MultiSpan::new());;self}#[rustc_lint_diagnostics]pub fn note_once(&mut self, +msg:impl Into)->&mut Self{let _=();self.sub(Level::OnceNote,msg, +MultiSpan::new());3;self}with_fn!{with_span_note,#[rustc_lint_diagnostics]pub fn +span_note(&mut self,sp:impl Into,msg:impl Into,)->&// +mut Self{self.sub(Level::Note,msg, sp.into());self}}#[rustc_lint_diagnostics]pub +fn span_note_once>(&mut self,sp:S,msg:impl Into,)->&mut Self{();self.sub(Level::OnceNote,msg,sp.into());();self} +with_fn!{with_warn,#[rustc_lint_diagnostics]pub fn warn(&mut self,msg:impl Into +)->&mut Self{self.sub( Level::Warning,msg,MultiSpan::new());self +}}#[rustc_lint_diagnostics]pub fn span_warn>(&mut self,sp:S,// +msg:impl Into,)->&mut Self{;self.sub(Level::Warning,msg,sp.into( +));3;self}with_fn!{with_help,#[rustc_lint_diagnostics]pub fn help(&mut self,msg: +impl Into)->&mut Self{self .sub(Level::Help,msg,MultiSpan::new() +);self}}#[rustc_lint_diagnostics]pub fn help_once(&mut self,msg:impl Into)->&mut Self{;self.sub(Level::OnceHelp,msg,MultiSpan::new());self +}#[rustc_lint_diagnostics]pub fn highlighted_help( &mut self,msg:Vec +)->&mut Self{;self.sub_with_highlights(Level::Help,msg,MultiSpan::new());self}#[ +rustc_lint_diagnostics]pub fn span_help>(&mut self,sp:S,msg:// +impl Into,)->&mut Self{;self.sub(Level::Help,msg,sp.into());self +}#[rustc_lint_diagnostics]pub fn disable_suggestions(&mut self)->&mut Self{;self +.suggestions=Err(SuggestionsDisabled);if true{};self}#[rustc_lint_diagnostics]fn +push_suggestion(&mut self,suggestion:CodeSuggestion){for subst in&suggestion.//; +substitutions{for part in&subst.parts{3;let span=part.span;;;let call_site=span. +ctxt().outer_expn_data().call_site;let _=();if span.in_derive_expansion()&&span. +overlaps_or_adjacent(call_site){();return;3;}}}if let Ok(suggestions)=&mut self. +suggestions{;suggestions.push(suggestion);}}with_fn!{with_multipart_suggestion,# +[rustc_lint_diagnostics]pub fn multipart_suggestion(&mut self,msg:impl Into,suggestion:Vec<(Span,String)>,applicability:Applicability,)->&// +mut Self{self.multipart_suggestion_with_style(msg,suggestion,applicability,//(); +SuggestionStyle::ShowCode,)}}#[rustc_lint_diagnostics]pub fn//let _=();let _=(); +multipart_suggestion_verbose(&mut self,msg :impl Into,suggestion +:Vec<(Span,String)>,applicability:Applicability,)->&mut Self{self.//loop{break}; +multipart_suggestion_with_style(msg,suggestion,applicability,SuggestionStyle::// +ShowAlways,)}#[rustc_lint_diagnostics]pub fn multipart_suggestion_with_style(&// +mut self,msg:impl Into,mut suggestion:Vec<(Span,String)>,//({}); +applicability:Applicability,style:SuggestionStyle,)->&mut Self{{();};suggestion. +sort_unstable();;suggestion.dedup();let parts=suggestion.into_iter().map(|(span, +snippet)|SubstitutionPart{snippet,span}).collect::>();3;3;assert!(!parts. +is_empty());;debug_assert_eq!(parts.iter().find(|part|part.span.is_empty()&&part +.snippet.is_empty()),None,"Span must not be empty and have no suggestion",);3;3; +debug_assert_eq!(parts.array_windows().find(|[a,b]|a.span.overlaps(b.span)),//3; +None,"suggestion must not have overlapping parts",);{;};();self.push_suggestion( +CodeSuggestion{substitutions:((((((((vec![Substitution{parts}])))))))),msg:self. +subdiagnostic_message_to_diagnostic_message(msg),style,applicability,});;self}#[ +rustc_lint_diagnostics]pub fn tool_only_multipart_suggestion( &mut self,msg:impl +Into,suggestion:Vec<(Span,String)>,applicability:Applicability// +,)->&mut Self{ self.multipart_suggestion_with_style(msg,suggestion,applicability +,SuggestionStyle::CompletelyHidden,)}with_fn!{with_span_suggestion,#[//let _=(); +rustc_lint_diagnostics]pub fn span_suggestion(&mut self,sp:Span,msg:impl Into,suggestion:impl ToString,applicability:Applicability,)->&mut//3; +Self{self.span_suggestion_with_style(sp,msg,suggestion,applicability,//let _=(); +SuggestionStyle::ShowCode,);self}}#[rustc_lint_diagnostics]pub fn//loop{break;}; +span_suggestion_with_style(&mut self,sp:Span,msg:impl Into,//(); +suggestion:impl ToString,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}],}],msg:self.//loop{break};loop{break;}; +subdiagnostic_message_to_diagnostic_message(msg),style,applicability,});();self} +with_fn!{with_span_suggestion_verbose,#[rustc_lint_diagnostics]pub fn//let _=(); +span_suggestion_verbose(&mut self,sp:Span,msg:impl Into,//{();}; +suggestion:impl ToString,applicability:Applicability,)->&mut Self{self.//*&*&(); +span_suggestion_with_style(sp,msg,suggestion,applicability,SuggestionStyle:://3; +ShowAlways,);self}}with_fn!{with_span_suggestions,#[rustc_lint_diagnostics]pub// +fn span_suggestions(&mut self,sp: Span,msg:impl Into,suggestions +:impl IntoIterator,applicability:Applicability,)->&mut Self{self.// +span_suggestions_with_style(sp,msg,suggestions,applicability,SuggestionStyle::// +ShowCode,)}}#[rustc_lint_diagnostics]pub fn span_suggestions_with_style(&mut//3; +self,sp:Span,msg:impl Into,suggestions:impl IntoIterator,applicability:Applicability,style:SuggestionStyle,)->&mut Self{{();};let +substitutions=suggestions.into_iter().map(|snippet|{;debug_assert!(!(sp.is_empty +()&&snippet.is_empty()),"Span must not be empty and have no suggestion");*&*&(); +Substitution{parts:vec![SubstitutionPart{snippet,span:sp}]}}).collect();3;;self. +push_suggestion(CodeSuggestion{substitutions,msg:self.//loop{break};loop{break}; +subdiagnostic_message_to_diagnostic_message(msg),style,applicability,});;self}#[ +rustc_lint_diagnostics]pub fn multipart_suggestions(&mut self,msg:impl Into,suggestions:impl IntoIterator>,//*&*&(); +applicability:Applicability,)->&mut Self{let _=();let substitutions=suggestions. +into_iter().map(|sugg|{{();};let mut parts=sugg.into_iter().map(|(span,snippet)| +SubstitutionPart{snippet,span}).collect::>();;parts.sort_unstable_by_key( +|part|part.span);;assert!(!parts.is_empty());debug_assert_eq!(parts.iter().find( +|part|part.span.is_empty()&&part.snippet.is_empty()),None,//if true{};if true{}; +"Span must not be empty and have no suggestion",);{;};();debug_assert_eq!(parts. +array_windows().find(|[a,b]|a.span.overlaps(b.span)),None,//if true{};if true{}; +"suggestion must not have overlapping parts",);;Substitution{parts}}).collect(); +self.push_suggestion(CodeSuggestion{substitutions,msg:self.//let _=();if true{}; +subdiagnostic_message_to_diagnostic_message(msg),style:SuggestionStyle:://{();}; +ShowCode,applicability,});let _=||();self}with_fn!{with_span_suggestion_short,#[ +rustc_lint_diagnostics]pub fn span_suggestion_short(&mut self,sp:Span,msg:impl// +Into,suggestion:impl ToString,applicability:Applicability,)->&// +mut Self{self.span_suggestion_with_style(sp,msg,suggestion,applicability,//({}); +SuggestionStyle::HideCodeInline,);self}}#[rustc_lint_diagnostics]pub fn//*&*&(); +span_suggestion_hidden(&mut self,sp:Span,msg:impl Into,//*&*&(); +suggestion:impl ToString,applicability:Applicability,)->&mut Self{let _=();self. +span_suggestion_with_style(sp,msg,suggestion,applicability,SuggestionStyle:://3; +HideCodeAlways,);((),());((),());self}with_fn!{with_tool_only_span_suggestion,#[ +rustc_lint_diagnostics]pub fn tool_only_span_suggestion(&mut self,sp:Span,msg:// +impl Into,suggestion :impl ToString,applicability:Applicability, +)->&mut Self{self.span_suggestion_with_style(sp,msg,suggestion,applicability,//; +SuggestionStyle::CompletelyHidden,);self}}#[rustc_lint_diagnostics]pub fn//({}); +subdiagnostic(&mut self,dcx:& crate::DiagCtxt,subdiagnostic:impl Subdiagnostic,) +->&mut Self{;subdiagnostic.add_to_diag_with(self,|diag,msg|{;let args=diag.args. +iter();();3;let msg=diag.subdiagnostic_message_to_diagnostic_message(msg);3;dcx. +eagerly_translate(msg,args)});;self}with_fn!{with_span,#[rustc_lint_diagnostics] +pub fn span(&mut self,sp:impl Into)->&mut Self{self.span=sp.into();// +if let Some(span)=self.span.primary_span(){self.sort_span=span;}self}}#[//{();}; +rustc_lint_diagnostics]pub fn is_lint(& mut self,name:String,has_future_breakage +:bool)->&mut Self{();self.is_lint=Some(IsLint{name,has_future_breakage});3;self} +with_fn!{with_code,#[rustc_lint_diagnostics]pub fn code(&mut self,code:ErrCode) +->&mut Self{self.code=Some(code);self}}with_fn!{with_primary_message,#[//*&*&(); +rustc_lint_diagnostics]pub fn primary_message(&mut self,msg:impl Into)->&mut Self{self.messages[0]=(msg.into(),Style::NoStyle);self}}//3; +with_fn!{with_arg,#[rustc_lint_diagnostics]pub fn arg(&mut self,name:impl Into< +DiagArgName>,arg:impl IntoDiagArg,)->&mut Self{self.deref_mut().arg(name,arg);// +self}}pub(crate)fn subdiagnostic_message_to_diagnostic_message(&self,attr:impl// +Into,)->DiagMessage{ (((((((((((((((self.deref()))))))))))))))). +subdiagnostic_message_to_diagnostic_message(attr)}pub fn sub(&mut self,level://; +Level,message:impl Into,span:MultiSpan){();self.deref_mut().sub( +level,message,span);;}fn sub_with_highlights(&mut self,level:Level,messages:Vec< +StringPart>,span:MultiSpan){({});let messages=messages.into_iter().map(|m|(self. +subdiagnostic_message_to_diagnostic_message(m.content),m.style)).collect();;;let +sub=Subdiag{level,messages,span};3;3;self.children.push(sub);;}fn take_diag(&mut +self)->DiagInner{(((Box::into_inner(((((((self.diag.take()))).unwrap())))))))}fn +emit_producing_nothing(mut self){{;};let diag=self.take_diag();{;};{;};self.dcx. +emit_diagnostic(diag);let _=||();}fn emit_producing_error_guaranteed(mut self)-> +ErrorGuaranteed{;let diag=self.take_diag();;;assert!(matches!(diag.level,Level:: +Error|Level::DelayedBug),"invalid diagnostic level ({:?})",diag.level,);();3;let +guar=self.dcx.emit_diagnostic(diag);();guar.unwrap()}#[track_caller]pub fn emit( +self)->G::EmitResult{((G::emit_producing_guarantee(self)))}#[track_caller]pub fn +emit_unless(mut self,delay:bool)->G::EmitResult{if delay{let _=();let _=();self. +downgrade_to_delayed_bug();;}self.emit()}pub fn cancel(mut self){self.diag=None; +drop(self);if let _=(){};}pub fn stash(mut self,span:Span,key:StashKey)->Option< +ErrorGuaranteed>{((self.dcx.stash_diagnostic(span,key,((self.take_diag())))))}#[ +track_caller]pub fn delay_as_bug(mut self)->G::EmitResult{((),());let _=();self. +downgrade_to_delayed_bug();;self.emit()}}implDrop for Diag< +'_,G>{fn drop(&mut self){match self.diag.take(){Some(diag)if!panicking()=>{;self +.dcx.emit_diagnostic(DiagInner::new(Level::Bug,DiagMessage::from(//loop{break;}; +"the following error was constructed but not emitted"),));*&*&();{();};self.dcx. +emit_diagnostic(*diag);;panic!("error was constructed but not emitted");}_=>{}}} +}#[macro_export]macro_rules!struct_span_code_err{($dcx:expr,$span:expr,$code://; +expr,$($message:tt)*)=>({$dcx.struct_span_err($span,format!($($message)*)).//(); +with_code($code)})}//if let _=(){};*&*&();((),());*&*&();((),());*&*&();((),()); diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index f90190797aee9..29a320ad04f69 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -1,349 +1,103 @@ -use crate::diagnostic::DiagLocation; -use crate::{fluent_generated as fluent, Subdiagnostic}; -use crate::{ - Diag, DiagArgValue, DiagCtxt, Diagnostic, EmissionGuarantee, ErrCode, IntoDiagArg, Level, - SubdiagMessageOp, -}; -use rustc_ast as ast; -use rustc_ast_pretty::pprust; -use rustc_hir as hir; -use rustc_span::edition::Edition; -use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol}; -use rustc_span::Span; -use rustc_target::abi::TargetDataLayoutErrors; -use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple}; -use rustc_type_ir as type_ir; -use std::backtrace::Backtrace; -use std::borrow::Cow; -use std::fmt; -use std::num::ParseIntError; -use std::path::{Path, PathBuf}; -use std::process::ExitStatus; - -pub struct DiagArgFromDisplay<'a>(pub &'a dyn fmt::Display); - -impl IntoDiagArg for DiagArgFromDisplay<'_> { - fn into_diag_arg(self) -> DiagArgValue { - self.0.to_string().into_diag_arg() - } -} - -impl<'a> From<&'a dyn fmt::Display> for DiagArgFromDisplay<'a> { - fn from(t: &'a dyn fmt::Display) -> Self { - DiagArgFromDisplay(t) - } -} - -impl<'a, T: fmt::Display> From<&'a T> for DiagArgFromDisplay<'a> { - fn from(t: &'a T) -> Self { - DiagArgFromDisplay(t) - } -} - -impl<'a, T: Clone + IntoDiagArg> IntoDiagArg for &'a T { - fn into_diag_arg(self) -> DiagArgValue { - self.clone().into_diag_arg() - } -} - -macro_rules! into_diag_arg_using_display { - ($( $ty:ty ),+ $(,)?) => { - $( - impl IntoDiagArg for $ty { - fn into_diag_arg(self) -> DiagArgValue { - self.to_string().into_diag_arg() - } - } - )+ - } -} - -macro_rules! into_diag_arg_for_number { - ($( $ty:ty ),+ $(,)?) => { - $( - impl IntoDiagArg for $ty { - fn into_diag_arg(self) -> DiagArgValue { - // Convert to a string if it won't fit into `Number`. - if let Ok(n) = TryInto::::try_into(self) { - DiagArgValue::Number(n) - } else { - self.to_string().into_diag_arg() - } - } - } - )+ - } -} - -into_diag_arg_using_display!( - ast::ParamKindOrd, - std::io::Error, - Box, - std::num::NonZero, - hir::Target, - Edition, - Ident, - MacroRulesNormalizedIdent, - ParseIntError, - StackProtector, - &TargetTriple, - SplitDebuginfo, - ExitStatus, - ErrCode, -); - -into_diag_arg_for_number!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize); - -impl IntoDiagArg for bool { - fn into_diag_arg(self) -> DiagArgValue { - if self { - DiagArgValue::Str(Cow::Borrowed("true")) - } else { - DiagArgValue::Str(Cow::Borrowed("false")) - } - } -} - -impl IntoDiagArg for char { - fn into_diag_arg(self) -> DiagArgValue { - DiagArgValue::Str(Cow::Owned(format!("{self:?}"))) - } -} - -impl IntoDiagArg for Vec { - fn into_diag_arg(self) -> DiagArgValue { - DiagArgValue::StrListSepByAnd( - self.into_iter().map(|c| Cow::Owned(format!("{c:?}"))).collect(), - ) - } -} - -impl IntoDiagArg for Symbol { - fn into_diag_arg(self) -> DiagArgValue { - self.to_ident_string().into_diag_arg() - } -} - -impl<'a> IntoDiagArg for &'a str { - fn into_diag_arg(self) -> DiagArgValue { - self.to_string().into_diag_arg() - } -} - -impl IntoDiagArg for String { - fn into_diag_arg(self) -> DiagArgValue { - DiagArgValue::Str(Cow::Owned(self)) - } -} - -impl<'a> IntoDiagArg for Cow<'a, str> { - fn into_diag_arg(self) -> DiagArgValue { - DiagArgValue::Str(Cow::Owned(self.into_owned())) - } -} - -impl<'a> IntoDiagArg for &'a Path { - fn into_diag_arg(self) -> DiagArgValue { - DiagArgValue::Str(Cow::Owned(self.display().to_string())) - } -} - -impl IntoDiagArg for PathBuf { - fn into_diag_arg(self) -> DiagArgValue { - DiagArgValue::Str(Cow::Owned(self.display().to_string())) - } -} - -impl IntoDiagArg for PanicStrategy { - fn into_diag_arg(self) -> DiagArgValue { - DiagArgValue::Str(Cow::Owned(self.desc().to_string())) - } -} - -impl IntoDiagArg for hir::ConstContext { - fn into_diag_arg(self) -> DiagArgValue { - DiagArgValue::Str(Cow::Borrowed(match self { - hir::ConstContext::ConstFn => "const_fn", - hir::ConstContext::Static(_) => "static", - hir::ConstContext::Const { .. } => "const", - })) - } -} - -impl IntoDiagArg for ast::Expr { - fn into_diag_arg(self) -> DiagArgValue { - DiagArgValue::Str(Cow::Owned(pprust::expr_to_string(&self))) - } -} - -impl IntoDiagArg for ast::Path { - fn into_diag_arg(self) -> DiagArgValue { - DiagArgValue::Str(Cow::Owned(pprust::path_to_string(&self))) - } -} - -impl IntoDiagArg for ast::token::Token { - fn into_diag_arg(self) -> DiagArgValue { - DiagArgValue::Str(pprust::token_to_string(&self)) - } -} - -impl IntoDiagArg for ast::token::TokenKind { - fn into_diag_arg(self) -> DiagArgValue { - DiagArgValue::Str(pprust::token_kind_to_string(&self)) - } -} - -impl IntoDiagArg for type_ir::FloatTy { - fn into_diag_arg(self) -> DiagArgValue { - DiagArgValue::Str(Cow::Borrowed(self.name_str())) - } -} - -impl IntoDiagArg for std::ffi::CString { - fn into_diag_arg(self) -> DiagArgValue { - DiagArgValue::Str(Cow::Owned(self.to_string_lossy().into_owned())) - } -} - -impl IntoDiagArg for rustc_data_structures::small_c_str::SmallCStr { - fn into_diag_arg(self) -> DiagArgValue { - DiagArgValue::Str(Cow::Owned(self.to_string_lossy().into_owned())) - } -} - -impl IntoDiagArg for ast::Visibility { - fn into_diag_arg(self) -> DiagArgValue { - let s = pprust::vis_to_string(&self); - let s = s.trim_end().to_string(); - DiagArgValue::Str(Cow::Owned(s)) - } -} - -impl IntoDiagArg for rustc_lint_defs::Level { - fn into_diag_arg(self) -> DiagArgValue { - DiagArgValue::Str(Cow::Borrowed(self.to_cmd_flag())) - } -} - -#[derive(Clone)] -pub struct DiagSymbolList(Vec); - -impl From> for DiagSymbolList { - fn from(v: Vec) -> Self { - DiagSymbolList(v) - } -} - -impl IntoDiagArg for DiagSymbolList { - fn into_diag_arg(self) -> DiagArgValue { - DiagArgValue::StrListSepByAnd( - self.0.into_iter().map(|sym| Cow::Owned(format!("`{sym}`"))).collect(), - ) - } -} - -impl IntoDiagArg for hir::def::Res { - fn into_diag_arg(self) -> DiagArgValue { - DiagArgValue::Str(Cow::Borrowed(self.descr())) - } -} - -impl Diagnostic<'_, G> for TargetDataLayoutErrors<'_> { - fn into_diag(self, dcx: &DiagCtxt, level: Level) -> Diag<'_, G> { - match self { - TargetDataLayoutErrors::InvalidAddressSpace { addr_space, err, cause } => { - Diag::new(dcx, level, fluent::errors_target_invalid_address_space) - .with_arg("addr_space", addr_space) - .with_arg("cause", cause) - .with_arg("err", err) - } - TargetDataLayoutErrors::InvalidBits { kind, bit, cause, err } => { - Diag::new(dcx, level, fluent::errors_target_invalid_bits) - .with_arg("kind", kind) - .with_arg("bit", bit) - .with_arg("cause", cause) - .with_arg("err", err) - } - TargetDataLayoutErrors::MissingAlignment { cause } => { - Diag::new(dcx, level, fluent::errors_target_missing_alignment) - .with_arg("cause", cause) - } - TargetDataLayoutErrors::InvalidAlignment { cause, err } => { - Diag::new(dcx, level, fluent::errors_target_invalid_alignment) - .with_arg("cause", cause) - .with_arg("err_kind", err.diag_ident()) - .with_arg("align", err.align()) - } - TargetDataLayoutErrors::InconsistentTargetArchitecture { dl, target } => { - Diag::new(dcx, level, fluent::errors_target_inconsistent_architecture) - .with_arg("dl", dl) - .with_arg("target", target) - } - TargetDataLayoutErrors::InconsistentTargetPointerWidth { pointer_size, target } => { - Diag::new(dcx, level, fluent::errors_target_inconsistent_pointer_width) - .with_arg("pointer_size", pointer_size) - .with_arg("target", target) - } - TargetDataLayoutErrors::InvalidBitsSize { err } => { - Diag::new(dcx, level, fluent::errors_target_invalid_bits_size).with_arg("err", err) - } - } - } -} - -/// Utility struct used to apply a single label while highlighting multiple spans -pub struct SingleLabelManySpans { - pub spans: Vec, - pub label: &'static str, -} -impl Subdiagnostic for SingleLabelManySpans { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _: F, - ) { - diag.span_labels(self.spans, self.label); - } -} - -#[derive(Subdiagnostic)] -#[label(errors_expected_lifetime_parameter)] -pub struct ExpectedLifetimeParameter { - #[primary_span] - pub span: Span, - pub count: usize, -} - -impl IntoDiagArg for DiagLocation { - fn into_diag_arg(self) -> DiagArgValue { - DiagArgValue::Str(Cow::from(self.to_string())) - } -} - -impl IntoDiagArg for Backtrace { - fn into_diag_arg(self) -> DiagArgValue { - DiagArgValue::Str(Cow::from(self.to_string())) - } -} - -impl IntoDiagArg for Level { - fn into_diag_arg(self) -> DiagArgValue { - DiagArgValue::Str(Cow::from(self.to_string())) - } -} - -#[derive(Subdiagnostic)] -#[suggestion(errors_indicate_anonymous_lifetime, code = "{suggestion}", style = "verbose")] -pub struct IndicateAnonymousLifetime { - #[primary_span] - pub span: Span, - pub count: usize, - pub suggestion: String, -} - -impl IntoDiagArg for type_ir::ClosureKind { - fn into_diag_arg(self) -> DiagArgValue { - DiagArgValue::Str(self.as_str().into()) - } -} +use crate::diagnostic::DiagLocation;use crate::{fluent_generated as fluent,//(); +Subdiagnostic};use crate::{Diag,DiagArgValue,DiagCtxt,Diagnostic,//loop{break;}; +EmissionGuarantee,ErrCode,IntoDiagArg,Level, SubdiagMessageOp,};use rustc_ast as +ast;use rustc_ast_pretty::pprust;use rustc_hir as hir;use rustc_span::edition//; +::Edition;use rustc_span::symbol::{Ident,MacroRulesNormalizedIdent,Symbol};use// +rustc_span::Span;use rustc_target ::abi::TargetDataLayoutErrors;use rustc_target +::spec::{PanicStrategy,SplitDebuginfo,StackProtector,TargetTriple};use//((),()); +rustc_type_ir as type_ir;use std::backtrace ::Backtrace;use std::borrow::Cow;use +std::fmt;use std::num::ParseIntError;use std::path::{Path,PathBuf};use std:://3; +process::ExitStatus;pub struct DiagArgFromDisplay<'a> (pub&'a dyn fmt::Display); +impl IntoDiagArg for DiagArgFromDisplay<'_>{fn into_diag_arg(self)->//if true{}; +DiagArgValue{((self.0.to_string()).into_diag_arg() )}}impl<'a>From<&'a dyn fmt:: +Display>for DiagArgFromDisplay<'a>{fn from(t:&'a dyn fmt::Display)->Self{//({}); +DiagArgFromDisplay(t)}}impl<'a,T: fmt::Display>From<&'a T>for DiagArgFromDisplay +<'a>{fn from(t:&'a T)->Self{ DiagArgFromDisplay(t)}}impl<'a,T:Clone+IntoDiagArg> +IntoDiagArg for&'a T{fn into_diag_arg(self )->DiagArgValue{((((self.clone())))). +into_diag_arg()}}macro_rules!into_diag_arg_using_display{($($ ty:ty),+$(,)?)=>{$ +(impl IntoDiagArg for$ty{fn into_diag_arg (self)->DiagArgValue{self.to_string(). +into_diag_arg()}})+}}macro_rules!into_diag_arg_for_number{($ ($ty:ty),+$(,)?)=>{ +$(impl IntoDiagArg for$ty{fn into_diag_arg(self)->DiagArgValue{if let Ok(n)=//3; +TryInto::::try_into(self){DiagArgValue::Number(n)}else{self.to_string().//; +into_diag_arg()}}})+}}into_diag_arg_using_display!(ast::ParamKindOrd,std::io::// +Error,Box,std::num::NonZero,hir::Target,Edition,//3; +Ident,MacroRulesNormalizedIdent,ParseIntError,StackProtector,&TargetTriple,//(); +SplitDebuginfo,ExitStatus,ErrCode,);into_diag_arg_for_number! (i8,u8,i16,u16,i32 +,u32,i64,u64,i128,u128,isize,usize );impl IntoDiagArg for bool{fn into_diag_arg( +self)->DiagArgValue{if self{(DiagArgValue::Str((Cow::Borrowed(("true")))))}else{ +DiagArgValue::Str(((Cow::Borrowed((("false"))))))}}}impl IntoDiagArg for char{fn +into_diag_arg(self)->DiagArgValue{DiagArgValue::Str(Cow::Owned(format!(//*&*&(); +"{self:?}")))}}impl IntoDiagArg for Vec{fn into_diag_arg(self)->//((),()); +DiagArgValue{DiagArgValue::StrListSepByAnd((self.into_iter()).map(|c|Cow::Owned( +format!("{c:?}"))).collect(),)}}impl IntoDiagArg for Symbol{fn into_diag_arg(//; +self)->DiagArgValue{self.to_ident_string() .into_diag_arg()}}impl<'a>IntoDiagArg +for&'a str{fn into_diag_arg(self)->DiagArgValue{(self.to_string()).into_diag_arg +()}}impl IntoDiagArg for String{fn into_diag_arg(self)->DiagArgValue{//let _=(); +DiagArgValue::Str(((Cow::Owned(self))))}} impl<'a>IntoDiagArg for Cow<'a,str>{fn +into_diag_arg(self)->DiagArgValue{DiagArgValue::Str (Cow::Owned(self.into_owned( +)))}}impl<'a>IntoDiagArg for&'a Path{fn into_diag_arg(self)->DiagArgValue{//{;}; +DiagArgValue::Str(Cow::Owned(self.display() .to_string()))}}impl IntoDiagArg for +PathBuf{fn into_diag_arg(self)->DiagArgValue{DiagArgValue::Str(Cow::Owned(self// +.display().to_string()))}}impl IntoDiagArg for PanicStrategy{fn into_diag_arg(// +self)->DiagArgValue{(DiagArgValue::Str((Cow::Owned(self.desc().to_string()))))}} +impl IntoDiagArg for hir::ConstContext{fn into_diag_arg(self)->DiagArgValue{//3; +DiagArgValue::Str(Cow::Borrowed(match self{hir::ConstContext::ConstFn=>//*&*&(); +"const_fn",hir::ConstContext::Static(_)=>("static"),hir::ConstContext::Const{..} +=>((((("const"))))),}))}}impl IntoDiagArg for ast::Expr{fn into_diag_arg(self)-> +DiagArgValue{DiagArgValue::Str(Cow::Owned(pprust:: expr_to_string(&self)))}}impl +IntoDiagArg for ast::Path{fn into_diag_arg(self)->DiagArgValue{DiagArgValue:://; +Str(Cow::Owned(pprust::path_to_string(&self )))}}impl IntoDiagArg for ast::token +::Token{fn into_diag_arg(self)->DiagArgValue{DiagArgValue::Str(pprust:://*&*&(); +token_to_string((((((&self)))))))}}impl IntoDiagArg for ast::token::TokenKind{fn +into_diag_arg(self)->DiagArgValue{DiagArgValue::Str(pprust:://let _=();let _=(); +token_kind_to_string((((((&self)))))))}}impl IntoDiagArg for type_ir::FloatTy{fn +into_diag_arg(self)->DiagArgValue{DiagArgValue:: Str(Cow::Borrowed(self.name_str +()))}}impl IntoDiagArg for std::ffi::CString{fn into_diag_arg(self)->//let _=(); +DiagArgValue{DiagArgValue::Str(Cow::Owned( self.to_string_lossy().into_owned())) +}}impl IntoDiagArg for rustc_data_structures::small_c_str::SmallCStr{fn//*&*&(); +into_diag_arg(self)->DiagArgValue{DiagArgValue::Str(Cow::Owned(self.//if true{}; +to_string_lossy().into_owned()))}}impl IntoDiagArg for ast::Visibility{fn//({}); +into_diag_arg(self)->DiagArgValue{;let s=pprust::vis_to_string(&self);;;let s=s. +trim_end().to_string();();DiagArgValue::Str(Cow::Owned(s))}}impl IntoDiagArg for +rustc_lint_defs::Level{fn into_diag_arg(self)->DiagArgValue{DiagArgValue::Str(// +Cow::Borrowed((self.to_cmd_flag())))}}#[derive(Clone)]pub struct DiagSymbolList( +Vec);impl From>for DiagSymbolList{fn from(v:Vec)->// +Self{(DiagSymbolList(v))}}impl IntoDiagArg for DiagSymbolList{fn into_diag_arg( +self)->DiagArgValue{DiagArgValue::StrListSepByAnd((self.0.into_iter()).map(|sym| +Cow::Owned(format!("`{sym}`"))).collect( ),)}}implIntoDiagArg for hir::def:: +Res{fn into_diag_arg(self)->DiagArgValue{DiagArgValue::Str(Cow::Borrowed(//; +self.descr()))}}implDiagnostic<'_,G>for//let _=();let _=(); +TargetDataLayoutErrors<'_>{fn into_diag(self,dcx:&DiagCtxt,level:Level)->Diag{match self{TargetDataLayoutErrors::InvalidAddressSpace{addr_space,err,//3; +cause}=>{(((Diag::new(dcx,level,fluent::errors_target_invalid_address_space)))). +with_arg(("addr_space"),addr_space).with_arg("cause",cause).with_arg("err",err)} +TargetDataLayoutErrors::InvalidBits{kind,bit,cause,err}=>{Diag::new(dcx,level,// +fluent::errors_target_invalid_bits).with_arg(("kind"),kind).with_arg("bit",bit). +with_arg(((("cause"))),cause).with_arg(((("err"))),err)}TargetDataLayoutErrors:: +MissingAlignment{cause}=>{Diag::new(dcx,level,fluent:://loop{break};loop{break}; +errors_target_missing_alignment).with_arg( "cause",cause)}TargetDataLayoutErrors +::InvalidAlignment{cause,err}=>{Diag::new(dcx,level,fluent:://let _=();let _=(); +errors_target_invalid_alignment).with_arg(("cause"), cause).with_arg("err_kind", +err.diag_ident()).with_arg((("align")),((err.align())))}TargetDataLayoutErrors:: +InconsistentTargetArchitecture{dl,target}=>{Diag::new(dcx,level,fluent:://{();}; +errors_target_inconsistent_architecture).with_arg(("dl"), dl).with_arg("target", +target)}TargetDataLayoutErrors::InconsistentTargetPointerWidth{pointer_size,//3; +target}=>{Diag::new (dcx,level,fluent::errors_target_inconsistent_pointer_width) +.with_arg((((("pointer_size")))),pointer_size) .with_arg(((("target"))),target)} +TargetDataLayoutErrors::InvalidBitsSize{err}=>{Diag::new(dcx,level,fluent:://(); +errors_target_invalid_bits_size).with_arg(((((((("err"))))))),err)}}}}pub struct +SingleLabelManySpans{pub spans:Vec,pub label:&'static str,}impl//let _=(); +Subdiagnostic for SingleLabelManySpans{fn add_to_diag_with>(self,diag:&mut Diag<'_,G>,_:F,){();diag.span_labels(self. +spans,self.label);if let _=(){};if let _=(){};}}#[derive(Subdiagnostic)]#[label( +errors_expected_lifetime_parameter)]pub struct ExpectedLifetimeParameter{#[//(); +primary_span]pub span:Span,pub count:usize,}impl IntoDiagArg for DiagLocation{// +fn into_diag_arg(self)->DiagArgValue{DiagArgValue ::Str(Cow::from(self.to_string +()))}}impl IntoDiagArg for Backtrace{fn into_diag_arg(self)->DiagArgValue{//{;}; +DiagArgValue::Str((Cow::from(self.to_string() )))}}impl IntoDiagArg for Level{fn +into_diag_arg(self)->DiagArgValue{DiagArgValue::Str( Cow::from(self.to_string()) +)}}#[derive(Subdiagnostic )]#[suggestion(errors_indicate_anonymous_lifetime,code +="{suggestion}",style="verbose")]pub struct IndicateAnonymousLifetime{#[//{();}; +primary_span]pub span:Span,pub count:usize,pub suggestion:String,}impl//((),()); +IntoDiagArg for type_ir::ClosureKind{fn into_diag_arg(self)->DiagArgValue{//{;}; +DiagArgValue::Str((((((((((((((((((((self.as_str( )))))))))).into())))))))))))}} diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index bd8e78bda2639..ffd2dbbd1cd40 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1,2778 +1,642 @@ -//! The current rustc diagnostics emitter. -//! -//! An `Emitter` takes care of generating the output from a `Diag` struct. -//! -//! There are various `Emitter` implementations that generate different output formats such as -//! JSON and human readable output. -//! -//! The output types are defined in `rustc_session::config::ErrorOutputType`. - -use rustc_span::source_map::SourceMap; -use rustc_span::{FileLines, FileName, SourceFile, Span}; - -use crate::snippet::{ - Annotation, AnnotationColumn, AnnotationType, Line, MultilineAnnotation, Style, StyledString, -}; -use crate::styled_buffer::StyledBuffer; -use crate::translation::{to_fluent_args, Translate}; -use crate::{ - diagnostic::DiagLocation, CodeSuggestion, DiagCtxt, DiagInner, DiagMessage, ErrCode, - FluentBundle, LazyFallbackBundle, Level, MultiSpan, Subdiag, SubstitutionHighlight, - SuggestionStyle, TerminalUrl, -}; -use derive_setters::Setters; -use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; -use rustc_data_structures::sync::{DynSend, IntoDynSyncSend, Lrc}; -use rustc_error_messages::{FluentArgs, SpanLabel}; -use rustc_lint_defs::pluralize; -use rustc_span::hygiene::{ExpnKind, MacroKind}; -use std::borrow::Cow; -use std::cmp::{max, min, Reverse}; -use std::error::Report; -use std::io::prelude::*; -use std::io::{self, IsTerminal}; -use std::iter; -use std::path::Path; -use termcolor::{Buffer, BufferWriter, ColorChoice, ColorSpec, StandardStream}; -use termcolor::{Color, WriteColor}; - -/// Default column width, used in tests and when terminal dimensions cannot be determined. -const DEFAULT_COLUMN_WIDTH: usize = 140; - -/// Describes the way the content of the `rendered` field of the json output is generated -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum HumanReadableErrorType { - Default(ColorConfig), - AnnotateSnippet(ColorConfig), - Short(ColorConfig), -} - -impl HumanReadableErrorType { - /// Returns a (`short`, `color`) tuple - pub fn unzip(self) -> (bool, ColorConfig) { - match self { - HumanReadableErrorType::Default(cc) => (false, cc), - HumanReadableErrorType::Short(cc) => (true, cc), - HumanReadableErrorType::AnnotateSnippet(cc) => (false, cc), - } - } -} - -#[derive(Clone, Copy, Debug)] -struct Margin { - /// The available whitespace in the left that can be consumed when centering. - pub whitespace_left: usize, - /// The column of the beginning of left-most span. - pub span_left: usize, - /// The column of the end of right-most span. - pub span_right: usize, - /// The beginning of the line to be displayed. - pub computed_left: usize, - /// The end of the line to be displayed. - pub computed_right: usize, - /// The current width of the terminal. Uses value of `DEFAULT_COLUMN_WIDTH` constant by default - /// and in tests. - pub column_width: usize, - /// The end column of a span label, including the span. Doesn't account for labels not in the - /// same line as the span. - pub label_right: usize, -} - -impl Margin { - fn new( - whitespace_left: usize, - span_left: usize, - span_right: usize, - label_right: usize, - column_width: usize, - max_line_len: usize, - ) -> Self { - // The 6 is padding to give a bit of room for `...` when displaying: - // ``` - // error: message - // --> file.rs:16:58 - // | - // 16 | ... fn foo(self) -> Self::Bar { - // | ^^^^^^^^^ - // ``` - - let mut m = Margin { - whitespace_left: whitespace_left.saturating_sub(6), - span_left: span_left.saturating_sub(6), - span_right: span_right + 6, - computed_left: 0, - computed_right: 0, - column_width, - label_right: label_right + 6, - }; - m.compute(max_line_len); - m - } - - fn was_cut_left(&self) -> bool { - self.computed_left > 0 - } - - fn was_cut_right(&self, line_len: usize) -> bool { - let right = - if self.computed_right == self.span_right || self.computed_right == self.label_right { - // Account for the "..." padding given above. Otherwise we end up with code lines - // that do fit but end in "..." as if they were trimmed. - self.computed_right - 6 - } else { - self.computed_right - }; - right < line_len && self.computed_left + self.column_width < line_len - } - - fn compute(&mut self, max_line_len: usize) { - // When there's a lot of whitespace (>20), we want to trim it as it is useless. - self.computed_left = if self.whitespace_left > 20 { - self.whitespace_left - 16 // We want some padding. - } else { - 0 - }; - // We want to show as much as possible, max_line_len is the right-most boundary for the - // relevant code. - self.computed_right = max(max_line_len, self.computed_left); - - if self.computed_right - self.computed_left > self.column_width { - // Trimming only whitespace isn't enough, let's get craftier. - if self.label_right - self.whitespace_left <= self.column_width { - // Attempt to fit the code window only trimming whitespace. - self.computed_left = self.whitespace_left; - self.computed_right = self.computed_left + self.column_width; - } else if self.label_right - self.span_left <= self.column_width { - // Attempt to fit the code window considering only the spans and labels. - let padding_left = (self.column_width - (self.label_right - self.span_left)) / 2; - self.computed_left = self.span_left.saturating_sub(padding_left); - self.computed_right = self.computed_left + self.column_width; - } else if self.span_right - self.span_left <= self.column_width { - // Attempt to fit the code window considering the spans and labels plus padding. - let padding_left = (self.column_width - (self.span_right - self.span_left)) / 5 * 2; - self.computed_left = self.span_left.saturating_sub(padding_left); - self.computed_right = self.computed_left + self.column_width; - } else { - // Mostly give up but still don't show the full line. - self.computed_left = self.span_left; - self.computed_right = self.span_right; - } - } - } - - fn left(&self, line_len: usize) -> usize { - min(self.computed_left, line_len) - } - - fn right(&self, line_len: usize) -> usize { - if line_len.saturating_sub(self.computed_left) <= self.column_width { - line_len - } else { - min(line_len, self.computed_right) - } - } -} - -const ANONYMIZED_LINE_NUM: &str = "LL"; - -pub type DynEmitter = dyn Emitter + DynSend; - -/// Emitter trait for emitting errors. -pub trait Emitter: Translate { - /// Emit a structured diagnostic. - fn emit_diagnostic(&mut self, diag: DiagInner); - - /// Emit a notification that an artifact has been output. - /// Currently only supported for the JSON format. - fn emit_artifact_notification(&mut self, _path: &Path, _artifact_type: &str) {} - - /// Emit a report about future breakage. - /// Currently only supported for the JSON format. - fn emit_future_breakage_report(&mut self, _diags: Vec) {} - - /// Emit list of unused externs. - /// Currently only supported for the JSON format. - fn emit_unused_externs( - &mut self, - _lint_level: rustc_lint_defs::Level, - _unused_externs: &[&str], - ) { - } - - /// Checks if should show explanations about "rustc --explain" - fn should_show_explain(&self) -> bool { - true - } - - /// Checks if we can use colors in the current output stream. - fn supports_color(&self) -> bool { - false - } - - fn source_map(&self) -> Option<&Lrc>; - - /// Formats the substitutions of the primary_span - /// - /// There are a lot of conditions to this method, but in short: - /// - /// * If the current `DiagInner` has only one visible `CodeSuggestion`, - /// we format the `help` suggestion depending on the content of the - /// substitutions. In that case, we modify the span and clear the - /// suggestions. - /// - /// * If the current `DiagInner` has multiple suggestions, - /// we leave `primary_span` and the suggestions untouched. - fn primary_span_formatted( - &mut self, - primary_span: &mut MultiSpan, - suggestions: &mut Vec, - fluent_args: &FluentArgs<'_>, - ) { - if let Some((sugg, rest)) = suggestions.split_first() { - let msg = self.translate_message(&sugg.msg, fluent_args).map_err(Report::new).unwrap(); - if rest.is_empty() && - // ^ if there is only one suggestion - // don't display multi-suggestions as labels - sugg.substitutions.len() == 1 && - // don't display multipart suggestions as labels - sugg.substitutions[0].parts.len() == 1 && - // don't display long messages as labels - msg.split_whitespace().count() < 10 && - // don't display multiline suggestions as labels - !sugg.substitutions[0].parts[0].snippet.contains('\n') && - ![ - // when this style is set we want the suggestion to be a message, not inline - SuggestionStyle::HideCodeAlways, - // trivial suggestion for tooling's sake, never shown - SuggestionStyle::CompletelyHidden, - // subtle suggestion, never shown inline - SuggestionStyle::ShowAlways, - ].contains(&sugg.style) - { - let substitution = &sugg.substitutions[0].parts[0].snippet.trim(); - let msg = if substitution.is_empty() || sugg.style.hide_inline() { - // This substitution is only removal OR we explicitly don't want to show the - // code inline (`hide_inline`). Therefore, we don't show the substitution. - format!("help: {msg}") - } else { - // Show the default suggestion text with the substitution - format!( - "help: {}{}: `{}`", - msg, - if self.source_map().is_some_and(|sm| is_case_difference( - sm, - substitution, - sugg.substitutions[0].parts[0].span, - )) { - " (notice the capitalization)" - } else { - "" - }, - substitution, - ) - }; - primary_span.push_span_label(sugg.substitutions[0].parts[0].span, msg); - - // We return only the modified primary_span - suggestions.clear(); - } else { - // if there are multiple suggestions, print them all in full - // to be consistent. We could try to figure out if we can - // make one (or the first one) inline, but that would give - // undue importance to a semi-random suggestion - } - } else { - // do nothing - } - } - - fn fix_multispans_in_extern_macros_and_render_macro_backtrace( - &self, - span: &mut MultiSpan, - children: &mut Vec, - level: &Level, - backtrace: bool, - ) { - // Check for spans in macros, before `fix_multispans_in_extern_macros` - // has a chance to replace them. - let has_macro_spans: Vec<_> = iter::once(&*span) - .chain(children.iter().map(|child| &child.span)) - .flat_map(|span| span.primary_spans()) - .flat_map(|sp| sp.macro_backtrace()) - .filter_map(|expn_data| { - match expn_data.kind { - ExpnKind::Root => None, - - // Skip past non-macro entries, just in case there - // are some which do actually involve macros. - ExpnKind::Desugaring(..) | ExpnKind::AstPass(..) => None, - - ExpnKind::Macro(macro_kind, name) => Some((macro_kind, name)), - } - }) - .collect(); - - if !backtrace { - self.fix_multispans_in_extern_macros(span, children); - } - - self.render_multispans_macro_backtrace(span, children, backtrace); - - if !backtrace { - if let Some((macro_kind, name)) = has_macro_spans.first() { - // Mark the actual macro this originates from - let and_then = if let Some((macro_kind, last_name)) = has_macro_spans.last() - && last_name != name - { - let descr = macro_kind.descr(); - format!(" which comes from the expansion of the {descr} `{last_name}`",) - } else { - "".to_string() - }; - - let descr = macro_kind.descr(); - let msg = format!( - "this {level} originates in the {descr} `{name}`{and_then} \ - (in Nightly builds, run with -Z macro-backtrace for more info)", - ); - - children.push(Subdiag { - level: Level::Note, - messages: vec![(DiagMessage::from(msg), Style::NoStyle)], - span: MultiSpan::new(), - }); - } - } - } - - fn render_multispans_macro_backtrace( - &self, - span: &mut MultiSpan, - children: &mut Vec, - backtrace: bool, - ) { - for span in iter::once(span).chain(children.iter_mut().map(|child| &mut child.span)) { - self.render_multispan_macro_backtrace(span, backtrace); - } - } - - fn render_multispan_macro_backtrace(&self, span: &mut MultiSpan, always_backtrace: bool) { - let mut new_labels = FxIndexSet::default(); - - for &sp in span.primary_spans() { - if sp.is_dummy() { - continue; - } - - // FIXME(eddyb) use `retain` on `macro_backtrace` to remove all the - // entries we don't want to print, to make sure the indices being - // printed are contiguous (or omitted if there's only one entry). - let macro_backtrace: Vec<_> = sp.macro_backtrace().collect(); - for (i, trace) in macro_backtrace.iter().rev().enumerate() { - if trace.def_site.is_dummy() { - continue; - } - - if always_backtrace { - new_labels.insert(( - trace.def_site, - format!( - "in this expansion of `{}`{}", - trace.kind.descr(), - if macro_backtrace.len() > 1 { - // if macro_backtrace.len() == 1 it'll be - // pointed at by "in this macro invocation" - format!(" (#{})", i + 1) - } else { - String::new() - }, - ), - )); - } - - // Don't add a label on the call site if the diagnostic itself - // already points to (a part of) that call site, as the label - // is meant for showing the relevant invocation when the actual - // diagnostic is pointing to some part of macro definition. - // - // This also handles the case where an external span got replaced - // with the call site span by `fix_multispans_in_extern_macros`. - // - // NB: `-Zmacro-backtrace` overrides this, for uniformity, as the - // "in this expansion of" label above is always added in that mode, - // and it needs an "in this macro invocation" label to match that. - let redundant_span = trace.call_site.contains(sp); - - if !redundant_span || always_backtrace { - let msg: Cow<'static, _> = match trace.kind { - ExpnKind::Macro(MacroKind::Attr, _) => { - "this procedural macro expansion".into() - } - ExpnKind::Macro(MacroKind::Derive, _) => { - "this derive macro expansion".into() - } - ExpnKind::Macro(MacroKind::Bang, _) => "this macro invocation".into(), - ExpnKind::Root => "the crate root".into(), - ExpnKind::AstPass(kind) => kind.descr().into(), - ExpnKind::Desugaring(kind) => { - format!("this {} desugaring", kind.descr()).into() - } - }; - new_labels.insert(( - trace.call_site, - format!( - "in {}{}", - msg, - if macro_backtrace.len() > 1 && always_backtrace { - // only specify order when the macro - // backtrace is multiple levels deep - format!(" (#{})", i + 1) - } else { - String::new() - }, - ), - )); - } - if !always_backtrace { - break; - } - } - } - - for (label_span, label_text) in new_labels { - span.push_span_label(label_span, label_text); - } - } - - // This does a small "fix" for multispans by looking to see if it can find any that - // point directly at external macros. Since these are often difficult to read, - // this will change the span to point at the use site. - fn fix_multispans_in_extern_macros(&self, span: &mut MultiSpan, children: &mut Vec) { - debug!("fix_multispans_in_extern_macros: before: span={:?} children={:?}", span, children); - self.fix_multispan_in_extern_macros(span); - for child in children.iter_mut() { - self.fix_multispan_in_extern_macros(&mut child.span); - } - debug!("fix_multispans_in_extern_macros: after: span={:?} children={:?}", span, children); - } - - // This "fixes" MultiSpans that contain `Span`s pointing to locations inside of external macros. - // Since these locations are often difficult to read, - // we move these spans from the external macros to their corresponding use site. - fn fix_multispan_in_extern_macros(&self, span: &mut MultiSpan) { - let Some(source_map) = self.source_map() else { return }; - // First, find all the spans in external macros and point instead at their use site. - let replacements: Vec<(Span, Span)> = span - .primary_spans() - .iter() - .copied() - .chain(span.span_labels().iter().map(|sp_label| sp_label.span)) - .filter_map(|sp| { - if !sp.is_dummy() && source_map.is_imported(sp) { - let maybe_callsite = sp.source_callsite(); - if sp != maybe_callsite { - return Some((sp, maybe_callsite)); - } - } - None - }) - .collect(); - - // After we have them, make sure we replace these 'bad' def sites with their use sites. - for (from, to) in replacements { - span.replace(from, to); - } - } -} - -impl Translate for HumanEmitter { - fn fluent_bundle(&self) -> Option<&Lrc> { - self.fluent_bundle.as_ref() - } - - fn fallback_fluent_bundle(&self) -> &FluentBundle { - &self.fallback_bundle - } -} - -impl Emitter for HumanEmitter { - fn source_map(&self) -> Option<&Lrc> { - self.sm.as_ref() - } - - fn emit_diagnostic(&mut self, mut diag: DiagInner) { - let fluent_args = to_fluent_args(diag.args.iter()); - - let mut suggestions = diag.suggestions.unwrap_or(vec![]); - self.primary_span_formatted(&mut diag.span, &mut suggestions, &fluent_args); - - self.fix_multispans_in_extern_macros_and_render_macro_backtrace( - &mut diag.span, - &mut diag.children, - &diag.level, - self.macro_backtrace, - ); - - self.emit_messages_default( - &diag.level, - &diag.messages, - &fluent_args, - &diag.code, - &diag.span, - &diag.children, - &suggestions, - self.track_diagnostics.then_some(&diag.emitted_at), - ); - } - - fn should_show_explain(&self) -> bool { - !self.short_message - } - - fn supports_color(&self) -> bool { - self.dst.supports_color() - } -} - -/// An emitter that does nothing when emitting a non-fatal diagnostic. -/// Fatal diagnostics are forwarded to `fatal_dcx` to avoid silent -/// failures of rustc, as witnessed e.g. in issue #89358. -pub struct SilentEmitter { - pub fallback_bundle: LazyFallbackBundle, - pub fatal_dcx: DiagCtxt, - pub fatal_note: Option, - pub emit_fatal_diagnostic: bool, -} - -impl Translate for SilentEmitter { - fn fluent_bundle(&self) -> Option<&Lrc> { - None - } - - fn fallback_fluent_bundle(&self) -> &FluentBundle { - // Ideally this field wouldn't be necessary and the fallback bundle in `fatal_dcx` would be - // used but the lock prevents this. - &self.fallback_bundle - } -} - -impl Emitter for SilentEmitter { - fn source_map(&self) -> Option<&Lrc> { - None - } - - fn emit_diagnostic(&mut self, mut diag: DiagInner) { - if self.emit_fatal_diagnostic && diag.level == Level::Fatal { - if let Some(fatal_note) = &self.fatal_note { - diag.sub(Level::Note, fatal_note.clone(), MultiSpan::new()); - } - self.fatal_dcx.emit_diagnostic(diag); - } - } -} - -/// Maximum number of suggestions to be shown -/// -/// Arbitrary, but taken from trait import suggestion limit -pub const MAX_SUGGESTIONS: usize = 4; - -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum ColorConfig { - Auto, - Always, - Never, -} - -impl ColorConfig { - pub fn to_color_choice(self) -> ColorChoice { - match self { - ColorConfig::Always => { - if io::stderr().is_terminal() { - ColorChoice::Always - } else { - ColorChoice::AlwaysAnsi - } - } - ColorConfig::Never => ColorChoice::Never, - ColorConfig::Auto if io::stderr().is_terminal() => ColorChoice::Auto, - ColorConfig::Auto => ColorChoice::Never, - } - } -} - -/// Handles the writing of `HumanReadableErrorType::Default` and `HumanReadableErrorType::Short` -#[derive(Setters)] -pub struct HumanEmitter { - #[setters(skip)] - dst: IntoDynSyncSend, - sm: Option>, - fluent_bundle: Option>, - #[setters(skip)] - fallback_bundle: LazyFallbackBundle, - short_message: bool, - teach: bool, - ui_testing: bool, - ignored_directories_in_source_blocks: Vec, - diagnostic_width: Option, - - macro_backtrace: bool, - track_diagnostics: bool, - terminal_url: TerminalUrl, -} - -#[derive(Debug)] -pub(crate) struct FileWithAnnotatedLines { - pub(crate) file: Lrc, - pub(crate) lines: Vec, - multiline_depth: usize, -} - -impl HumanEmitter { - pub fn new(dst: Destination, fallback_bundle: LazyFallbackBundle) -> HumanEmitter { - HumanEmitter { - dst: IntoDynSyncSend(dst), - sm: None, - fluent_bundle: None, - fallback_bundle, - short_message: false, - teach: false, - ui_testing: false, - ignored_directories_in_source_blocks: Vec::new(), - diagnostic_width: None, - macro_backtrace: false, - track_diagnostics: false, - terminal_url: TerminalUrl::No, - } - } - - fn maybe_anonymized(&self, line_num: usize) -> Cow<'static, str> { - if self.ui_testing { - Cow::Borrowed(ANONYMIZED_LINE_NUM) - } else { - Cow::Owned(line_num.to_string()) - } - } - - fn draw_line( - &self, - buffer: &mut StyledBuffer, - source_string: &str, - line_index: usize, - line_offset: usize, - width_offset: usize, - code_offset: usize, - margin: Margin, - ) { - // Tabs are assumed to have been replaced by spaces in calling code. - debug_assert!(!source_string.contains('\t')); - let line_len = source_string.len(); - // Create the source line we will highlight. - let left = margin.left(line_len); - let right = margin.right(line_len); - // On long lines, we strip the source line, accounting for unicode. - let mut taken = 0; - let code: String = source_string - .chars() - .skip(left) - .take_while(|ch| { - // Make sure that the trimming on the right will fall within the terminal width. - // FIXME: `unicode_width` sometimes disagrees with terminals on how wide a `char` - // is. For now, just accept that sometimes the code line will be longer than - // desired. - let next = unicode_width::UnicodeWidthChar::width(*ch).unwrap_or(1); - if taken + next > right - left { - return false; - } - taken += next; - true - }) - .collect(); - buffer.puts(line_offset, code_offset, &code, Style::Quotation); - if margin.was_cut_left() { - // We have stripped some code/whitespace from the beginning, make it clear. - buffer.puts(line_offset, code_offset, "...", Style::LineNumber); - } - if margin.was_cut_right(line_len) { - // We have stripped some code after the right-most span end, make it clear we did so. - buffer.puts(line_offset, code_offset + taken - 3, "...", Style::LineNumber); - } - buffer.puts(line_offset, 0, &self.maybe_anonymized(line_index), Style::LineNumber); - - draw_col_separator_no_space(buffer, line_offset, width_offset - 2); - } - - #[instrument(level = "trace", skip(self), ret)] - fn render_source_line( - &self, - buffer: &mut StyledBuffer, - file: Lrc, - line: &Line, - width_offset: usize, - code_offset: usize, - margin: Margin, - ) -> Vec<(usize, Style)> { - // Draw: - // - // LL | ... code ... - // | ^^-^ span label - // | | - // | secondary span label - // - // ^^ ^ ^^^ ^^^^ ^^^ we don't care about code too far to the right of a span, we trim it - // | | | | - // | | | actual code found in your source code and the spans we use to mark it - // | | when there's too much wasted space to the left, trim it - // | vertical divider between the column number and the code - // column number - - if line.line_index == 0 { - return Vec::new(); - } - - let source_string = match file.get_line(line.line_index - 1) { - Some(s) => normalize_whitespace(&s), - None => return Vec::new(), - }; - trace!(?source_string); - - let line_offset = buffer.num_lines(); - - // Left trim - let left = margin.left(source_string.len()); - - // Account for unicode characters of width !=0 that were removed. - let left = source_string - .chars() - .take(left) - .map(|ch| unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1)) - .sum(); - - self.draw_line( - buffer, - &source_string, - line.line_index, - line_offset, - width_offset, - code_offset, - margin, - ); - - // Special case when there's only one annotation involved, it is the start of a multiline - // span and there's no text at the beginning of the code line. Instead of doing the whole - // graph: - // - // 2 | fn foo() { - // | _^ - // 3 | | - // 4 | | } - // | |_^ test - // - // we simplify the output to: - // - // 2 | / fn foo() { - // 3 | | - // 4 | | } - // | |_^ test - let mut buffer_ops = vec![]; - let mut annotations = vec![]; - let mut short_start = true; - for ann in &line.annotations { - if let AnnotationType::MultilineStart(depth) = ann.annotation_type { - if source_string.chars().take(ann.start_col.display).all(|c| c.is_whitespace()) { - let style = if ann.is_primary { - Style::UnderlinePrimary - } else { - Style::UnderlineSecondary - }; - annotations.push((depth, style)); - buffer_ops.push((line_offset, width_offset + depth - 1, '/', style)); - } else { - short_start = false; - break; - } - } else if let AnnotationType::MultilineLine(_) = ann.annotation_type { - } else { - short_start = false; - break; - } - } - if short_start { - for (y, x, c, s) in buffer_ops { - buffer.putc(y, x, c, s); - } - return annotations; - } - - // We want to display like this: - // - // vec.push(vec.pop().unwrap()); - // --- ^^^ - previous borrow ends here - // | | - // | error occurs here - // previous borrow of `vec` occurs here - // - // But there are some weird edge cases to be aware of: - // - // vec.push(vec.pop().unwrap()); - // -------- - previous borrow ends here - // || - // |this makes no sense - // previous borrow of `vec` occurs here - // - // For this reason, we group the lines into "highlight lines" - // and "annotations lines", where the highlight lines have the `^`. - - // Sort the annotations by (start, end col) - // The labels are reversed, sort and then reversed again. - // Consider a list of annotations (A1, A2, C1, C2, B1, B2) where - // the letter signifies the span. Here we are only sorting by the - // span and hence, the order of the elements with the same span will - // not change. On reversing the ordering (|a, b| but b.cmp(a)), you get - // (C1, C2, B1, B2, A1, A2). All the elements with the same span are - // still ordered first to last, but all the elements with different - // spans are ordered by their spans in last to first order. Last to - // first order is important, because the jiggly lines and | are on - // the left, so the rightmost span needs to be rendered first, - // otherwise the lines would end up needing to go over a message. - - let mut annotations = line.annotations.clone(); - annotations.sort_by_key(|a| Reverse(a.start_col)); - - // First, figure out where each label will be positioned. - // - // In the case where you have the following annotations: - // - // vec.push(vec.pop().unwrap()); - // -------- - previous borrow ends here [C] - // || - // |this makes no sense [B] - // previous borrow of `vec` occurs here [A] - // - // `annotations_position` will hold [(2, A), (1, B), (0, C)]. - // - // We try, when possible, to stick the rightmost annotation at the end - // of the highlight line: - // - // vec.push(vec.pop().unwrap()); - // --- --- - previous borrow ends here - // - // But sometimes that's not possible because one of the other - // annotations overlaps it. For example, from the test - // `span_overlap_label`, we have the following annotations - // (written on distinct lines for clarity): - // - // fn foo(x: u32) { - // -------------- - // - - // - // In this case, we can't stick the rightmost-most label on - // the highlight line, or we would get: - // - // fn foo(x: u32) { - // -------- x_span - // | - // fn_span - // - // which is totally weird. Instead we want: - // - // fn foo(x: u32) { - // -------------- - // | | - // | x_span - // fn_span - // - // which is...less weird, at least. In fact, in general, if - // the rightmost span overlaps with any other span, we should - // use the "hang below" version, so we can at least make it - // clear where the span *starts*. There's an exception for this - // logic, when the labels do not have a message: - // - // fn foo(x: u32) { - // -------------- - // | - // x_span - // - // instead of: - // - // fn foo(x: u32) { - // -------------- - // | | - // | x_span - // - // - let mut annotations_position = vec![]; - let mut line_len = 0; - let mut p = 0; - for (i, annotation) in annotations.iter().enumerate() { - for (j, next) in annotations.iter().enumerate() { - if overlaps(next, annotation, 0) // This label overlaps with another one and both - && annotation.has_label() // take space (they have text and are not - && j > i // multiline lines). - && p == 0 - // We're currently on the first line, move the label one line down - { - // If we're overlapping with an un-labelled annotation with the same span - // we can just merge them in the output - if next.start_col == annotation.start_col - && next.end_col == annotation.end_col - && !next.has_label() - { - continue; - } - - // This annotation needs a new line in the output. - p += 1; - break; - } - } - annotations_position.push((p, annotation)); - for (j, next) in annotations.iter().enumerate() { - if j > i { - let l = next.label.as_ref().map_or(0, |label| label.len() + 2); - if (overlaps(next, annotation, l) // Do not allow two labels to be in the same - // line if they overlap including padding, to - // avoid situations like: - // - // fn foo(x: u32) { - // -------^------ - // | | - // fn_spanx_span - // - && annotation.has_label() // Both labels must have some text, otherwise - && next.has_label()) // they are not overlapping. - // Do not add a new line if this annotation - // or the next are vertical line placeholders. - || (annotation.takes_space() // If either this or the next annotation is - && next.has_label()) // multiline start/end, move it to a new line - || (annotation.has_label() // so as not to overlap the horizontal lines. - && next.takes_space()) - || (annotation.takes_space() && next.takes_space()) - || (overlaps(next, annotation, l) - && next.end_col <= annotation.end_col - && next.has_label() - && p == 0) - // Avoid #42595. - { - // This annotation needs a new line in the output. - p += 1; - break; - } - } - } - line_len = max(line_len, p); - } - - if line_len != 0 { - line_len += 1; - } - - // If there are no annotations or the only annotations on this line are - // MultilineLine, then there's only code being shown, stop processing. - if line.annotations.iter().all(|a| a.is_line()) { - return vec![]; - } - - // Write the column separator. - // - // After this we will have: - // - // 2 | fn foo() { - // | - // | - // | - // 3 | - // 4 | } - // | - for pos in 0..=line_len { - draw_col_separator(buffer, line_offset + pos + 1, width_offset - 2); - } - - // Write the horizontal lines for multiline annotations - // (only the first and last lines need this). - // - // After this we will have: - // - // 2 | fn foo() { - // | __________ - // | - // | - // 3 | - // 4 | } - // | _ - for &(pos, annotation) in &annotations_position { - let style = if annotation.is_primary { - Style::UnderlinePrimary - } else { - Style::UnderlineSecondary - }; - let pos = pos + 1; - match annotation.annotation_type { - AnnotationType::MultilineStart(depth) | AnnotationType::MultilineEnd(depth) => { - draw_range( - buffer, - '_', - line_offset + pos, - width_offset + depth, - (code_offset + annotation.start_col.display).saturating_sub(left), - style, - ); - } - _ if self.teach => { - buffer.set_style_range( - line_offset, - (code_offset + annotation.start_col.display).saturating_sub(left), - (code_offset + annotation.end_col.display).saturating_sub(left), - style, - annotation.is_primary, - ); - } - _ => {} - } - } - - // Write the vertical lines for labels that are on a different line as the underline. - // - // After this we will have: - // - // 2 | fn foo() { - // | __________ - // | | | - // | | - // 3 | | - // 4 | | } - // | |_ - for &(pos, annotation) in &annotations_position { - let style = if annotation.is_primary { - Style::UnderlinePrimary - } else { - Style::UnderlineSecondary - }; - let pos = pos + 1; - - if pos > 1 && (annotation.has_label() || annotation.takes_space()) { - for p in line_offset + 1..=line_offset + pos { - buffer.putc( - p, - (code_offset + annotation.start_col.display).saturating_sub(left), - '|', - style, - ); - } - } - match annotation.annotation_type { - AnnotationType::MultilineStart(depth) => { - for p in line_offset + pos + 1..line_offset + line_len + 2 { - buffer.putc(p, width_offset + depth - 1, '|', style); - } - } - AnnotationType::MultilineEnd(depth) => { - for p in line_offset..=line_offset + pos { - buffer.putc(p, width_offset + depth - 1, '|', style); - } - } - _ => (), - } - } - - // Write the labels on the annotations that actually have a label. - // - // After this we will have: - // - // 2 | fn foo() { - // | __________ - // | | - // | something about `foo` - // 3 | - // 4 | } - // | _ test - for &(pos, annotation) in &annotations_position { - let style = - if annotation.is_primary { Style::LabelPrimary } else { Style::LabelSecondary }; - let (pos, col) = if pos == 0 { - (pos + 1, (annotation.end_col.display + 1).saturating_sub(left)) - } else { - (pos + 2, annotation.start_col.display.saturating_sub(left)) - }; - if let Some(ref label) = annotation.label { - buffer.puts(line_offset + pos, code_offset + col, label, style); - } - } - - // Sort from biggest span to smallest span so that smaller spans are - // represented in the output: - // - // x | fn foo() - // | ^^^---^^ - // | | | - // | | something about `foo` - // | something about `fn foo()` - annotations_position.sort_by_key(|(_, ann)| { - // Decreasing order. When annotations share the same length, prefer `Primary`. - (Reverse(ann.len()), ann.is_primary) - }); - - // Write the underlines. - // - // After this we will have: - // - // 2 | fn foo() { - // | ____-_____^ - // | | - // | something about `foo` - // 3 | - // 4 | } - // | _^ test - for &(_, annotation) in &annotations_position { - let (underline, style) = if annotation.is_primary { - ('^', Style::UnderlinePrimary) - } else { - ('-', Style::UnderlineSecondary) - }; - for p in annotation.start_col.display..annotation.end_col.display { - buffer.putc( - line_offset + 1, - (code_offset + p).saturating_sub(left), - underline, - style, - ); - } - } - annotations_position - .iter() - .filter_map(|&(_, annotation)| match annotation.annotation_type { - AnnotationType::MultilineStart(p) | AnnotationType::MultilineEnd(p) => { - let style = if annotation.is_primary { - Style::LabelPrimary - } else { - Style::LabelSecondary - }; - Some((p, style)) - } - _ => None, - }) - .collect::>() - } - - fn get_multispan_max_line_num(&mut self, msp: &MultiSpan) -> usize { - let Some(ref sm) = self.sm else { - return 0; - }; - - let will_be_emitted = |span: Span| { - !span.is_dummy() && { - let file = sm.lookup_source_file(span.hi()); - should_show_source_code(&self.ignored_directories_in_source_blocks, sm, &file) - } - }; - - let mut max = 0; - for primary_span in msp.primary_spans() { - if will_be_emitted(*primary_span) { - let hi = sm.lookup_char_pos(primary_span.hi()); - max = (hi.line).max(max); - } - } - if !self.short_message { - for span_label in msp.span_labels() { - if will_be_emitted(span_label.span) { - let hi = sm.lookup_char_pos(span_label.span.hi()); - max = (hi.line).max(max); - } - } - } - - max - } - - fn get_max_line_num(&mut self, span: &MultiSpan, children: &[Subdiag]) -> usize { - let primary = self.get_multispan_max_line_num(span); - children - .iter() - .map(|sub| self.get_multispan_max_line_num(&sub.span)) - .max() - .unwrap_or(0) - .max(primary) - } - - /// Adds a left margin to every line but the first, given a padding length and the label being - /// displayed, keeping the provided highlighting. - fn msgs_to_buffer( - &self, - buffer: &mut StyledBuffer, - msgs: &[(DiagMessage, Style)], - args: &FluentArgs<'_>, - padding: usize, - label: &str, - override_style: Option

(&self,base:&P,proj_elem:mir::PlaceElem<'tcx>)->InterpResultwhere P:Projectable<'tcx,M ::Provenance>+From>+std::fmt::Debug,{;use rustc_middle::mir::ProjectionElem::*;Ok(match proj_elem +{OpaqueCast(ty)=>{span_bug!(self.cur_span(),//((),());let _=();((),());let _=(); +"OpaqueCast({ty}) encountered after borrowck")}Subtype(_)=> base.transmute(base. +layout(),self)?,Field(field,_)=>(((self.project_field(base,(field.index())))?)), +Downcast(_,variant)=>(((((self.project_downcast(base,variant)))?))),Deref=>self. +deref_pointer(&base.to_op(self)?)?.into(),Index(local)=>{*&*&();let layout=self. +layout_of(self.tcx.types.usize)?;;;let n=self.local_to_op(local,Some(layout))?;; +let n=self.read_target_usize(&n)?;{;};self.project_index(base,n)?}ConstantIndex{ +offset,min_length,from_end}=>{self.project_constant_index(base,offset,//((),()); +min_length,from_end)?}Subslice{from,to,from_end}=>self.project_subslice(base,//; +from,to,from_end)?,})}}//loop{break;};if let _=(){};if let _=(){};if let _=(){}; diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 9114ffff6fde9..70ed1d933c7e5 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -1,371 +1,98 @@ -//! This module contains the `InterpCx` methods for executing a single step of the interpreter. -//! -//! The main entry point is the `step` method. - -use either::Either; - -use rustc_index::IndexSlice; -use rustc_middle::mir; -use rustc_middle::ty::layout::LayoutOf; -use rustc_target::abi::{FieldIdx, FIRST_VARIANT}; - -use super::{ImmTy, InterpCx, InterpResult, Machine, PlaceTy, Projectable, Scalar}; -use crate::util; - -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - /// Returns `true` as long as there are more things to do. - /// - /// This is used by [priroda](https://github.com/oli-obk/priroda) - /// - /// This is marked `#inline(always)` to work around adversarial codegen when `opt-level = 3` - #[inline(always)] - pub fn step(&mut self) -> InterpResult<'tcx, bool> { - if self.stack().is_empty() { - return Ok(false); - } - - let Either::Left(loc) = self.frame().loc else { - // We are unwinding and this fn has no cleanup code. - // Just go on unwinding. - trace!("unwinding: skipping frame"); - self.pop_stack_frame(/* unwinding */ true)?; - return Ok(true); - }; - let basic_block = &self.body().basic_blocks[loc.block]; - - if let Some(stmt) = basic_block.statements.get(loc.statement_index) { - let old_frames = self.frame_idx(); - self.statement(stmt)?; - // Make sure we are not updating `statement_index` of the wrong frame. - assert_eq!(old_frames, self.frame_idx()); - // Advance the program counter. - self.frame_mut().loc.as_mut().left().unwrap().statement_index += 1; - return Ok(true); - } - - M::before_terminator(self)?; - - let terminator = basic_block.terminator(); - self.terminator(terminator)?; - Ok(true) - } - - /// Runs the interpretation logic for the given `mir::Statement` at the current frame and - /// statement counter. - /// - /// This does NOT move the statement counter forward, the caller has to do that! - pub fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> { - info!("{:?}", stmt); - - use rustc_middle::mir::StatementKind::*; - - match &stmt.kind { - Assign(box (place, rvalue)) => self.eval_rvalue_into_place(rvalue, *place)?, - - SetDiscriminant { place, variant_index } => { - let dest = self.eval_place(**place)?; - self.write_discriminant(*variant_index, &dest)?; - } - - Deinit(place) => { - let dest = self.eval_place(**place)?; - self.write_uninit(&dest)?; - } - - // Mark locals as alive - StorageLive(local) => { - self.storage_live(*local)?; - } - - // Mark locals as dead - StorageDead(local) => { - self.storage_dead(*local)?; - } - - // No dynamic semantics attached to `FakeRead`; MIR - // interpreter is solely intended for borrowck'ed code. - FakeRead(..) => {} - - // Stacked Borrows. - Retag(kind, place) => { - let dest = self.eval_place(**place)?; - M::retag_place_contents(self, *kind, &dest)?; - } - - Intrinsic(box intrinsic) => self.emulate_nondiverging_intrinsic(intrinsic)?, - - // Evaluate the place expression, without reading from it. - PlaceMention(box place) => { - let _ = self.eval_place(*place)?; - } - - // This exists purely to guide borrowck lifetime inference, and does not have - // an operational effect. - AscribeUserType(..) => {} - - // Currently, Miri discards Coverage statements. Coverage statements are only injected - // via an optional compile time MIR pass and have no side effects. Since Coverage - // statements don't exist at the source level, it is safe for Miri to ignore them, even - // for undefined behavior (UB) checks. - // - // A coverage counter inside a const expression (for example, a counter injected in a - // const function) is discarded when the const is evaluated at compile time. Whether - // this should change, and/or how to implement a const eval counter, is a subject of the - // following issue: - // - // FIXME(#73156): Handle source code coverage in const eval - Coverage(..) => {} - - ConstEvalCounter => { - M::increment_const_eval_counter(self)?; - } - - // Defined to do nothing. These are added by optimization passes, to avoid changing the - // size of MIR constantly. - Nop => {} - } - - Ok(()) - } - - /// Evaluate an assignment statement. - /// - /// There is no separate `eval_rvalue` function. Instead, the code for handling each rvalue - /// type writes its results directly into the memory specified by the place. - pub fn eval_rvalue_into_place( - &mut self, - rvalue: &mir::Rvalue<'tcx>, - place: mir::Place<'tcx>, - ) -> InterpResult<'tcx> { - let dest = self.eval_place(place)?; - // FIXME: ensure some kind of non-aliasing between LHS and RHS? - // Also see https://github.com/rust-lang/rust/issues/68364. - - use rustc_middle::mir::Rvalue::*; - match *rvalue { - ThreadLocalRef(did) => { - let ptr = M::thread_local_static_base_pointer(self, did)?; - self.write_pointer(ptr, &dest)?; - } - - Use(ref operand) => { - // Avoid recomputing the layout - let op = self.eval_operand(operand, Some(dest.layout))?; - self.copy_op(&op, &dest)?; - } - - CopyForDeref(place) => { - let op = self.eval_place_to_op(place, Some(dest.layout))?; - self.copy_op(&op, &dest)?; - } - - BinaryOp(bin_op, box (ref left, ref right)) => { - let layout = util::binop_left_homogeneous(bin_op).then_some(dest.layout); - let left = self.read_immediate(&self.eval_operand(left, layout)?)?; - let layout = util::binop_right_homogeneous(bin_op).then_some(left.layout); - let right = self.read_immediate(&self.eval_operand(right, layout)?)?; - self.binop_ignore_overflow(bin_op, &left, &right, &dest)?; - } - - CheckedBinaryOp(bin_op, box (ref left, ref right)) => { - // Due to the extra boolean in the result, we can never reuse the `dest.layout`. - let left = self.read_immediate(&self.eval_operand(left, None)?)?; - let layout = util::binop_right_homogeneous(bin_op).then_some(left.layout); - let right = self.read_immediate(&self.eval_operand(right, layout)?)?; - self.binop_with_overflow(bin_op, &left, &right, &dest)?; - } - - UnaryOp(un_op, ref operand) => { - // The operand always has the same type as the result. - let val = self.read_immediate(&self.eval_operand(operand, Some(dest.layout))?)?; - let val = self.wrapping_unary_op(un_op, &val)?; - assert_eq!(val.layout, dest.layout, "layout mismatch for result of {un_op:?}"); - self.write_immediate(*val, &dest)?; - } - - Aggregate(box ref kind, ref operands) => { - self.write_aggregate(kind, operands, &dest)?; - } - - Repeat(ref operand, _) => { - self.write_repeat(operand, &dest)?; - } - - Len(place) => { - let src = self.eval_place(place)?; - let len = src.len(self)?; - self.write_scalar(Scalar::from_target_usize(len, self), &dest)?; - } - - Ref(_, borrow_kind, place) => { - let src = self.eval_place(place)?; - let place = self.force_allocation(&src)?; - let val = ImmTy::from_immediate(place.to_ref(self), dest.layout); - // A fresh reference was created, make sure it gets retagged. - let val = M::retag_ptr_value( - self, - if borrow_kind.allows_two_phase_borrow() { - mir::RetagKind::TwoPhase - } else { - mir::RetagKind::Default - }, - &val, - )?; - self.write_immediate(*val, &dest)?; - } - - AddressOf(_, place) => { - // Figure out whether this is an addr_of of an already raw place. - let place_base_raw = if place.is_indirect_first_projection() { - let ty = self.frame().body.local_decls[place.local].ty; - ty.is_unsafe_ptr() - } else { - // Not a deref, and thus not raw. - false - }; - - let src = self.eval_place(place)?; - let place = self.force_allocation(&src)?; - let mut val = ImmTy::from_immediate(place.to_ref(self), dest.layout); - if !place_base_raw { - // If this was not already raw, it needs retagging. - val = M::retag_ptr_value(self, mir::RetagKind::Raw, &val)?; - } - self.write_immediate(*val, &dest)?; - } - - NullaryOp(ref null_op, ty) => { - let ty = self.instantiate_from_current_frame_and_normalize_erasing_regions(ty)?; - let layout = self.layout_of(ty)?; - if let mir::NullOp::SizeOf | mir::NullOp::AlignOf = null_op - && layout.is_unsized() - { - span_bug!( - self.frame().current_span(), - "{null_op:?} MIR operator called for unsized type {ty}", - ); - } - let val = match null_op { - mir::NullOp::SizeOf => { - let val = layout.size.bytes(); - Scalar::from_target_usize(val, self) - } - mir::NullOp::AlignOf => { - let val = layout.align.abi.bytes(); - Scalar::from_target_usize(val, self) - } - mir::NullOp::OffsetOf(fields) => { - let val = layout.offset_of_subfield(self, fields.iter()).bytes(); - Scalar::from_target_usize(val, self) - } - mir::NullOp::UbChecks => Scalar::from_bool(self.tcx.sess.opts.debug_assertions), - }; - self.write_scalar(val, &dest)?; - } - - ShallowInitBox(ref operand, _) => { - let src = self.eval_operand(operand, None)?; - let v = self.read_immediate(&src)?; - self.write_immediate(*v, &dest)?; - } - - Cast(cast_kind, ref operand, cast_ty) => { - let src = self.eval_operand(operand, None)?; - let cast_ty = - self.instantiate_from_current_frame_and_normalize_erasing_regions(cast_ty)?; - self.cast(&src, cast_kind, cast_ty, &dest)?; - } - - Discriminant(place) => { - let op = self.eval_place_to_op(place, None)?; - let variant = self.read_discriminant(&op)?; - let discr = self.discriminant_for_variant(op.layout.ty, variant)?; - self.write_immediate(*discr, &dest)?; - } - } - - trace!("{:?}", self.dump_place(&dest)); - - Ok(()) - } - - /// Writes the aggregate to the destination. - #[instrument(skip(self), level = "trace")] - fn write_aggregate( - &mut self, - kind: &mir::AggregateKind<'tcx>, - operands: &IndexSlice>, - dest: &PlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx> { - self.write_uninit(dest)?; // make sure all the padding ends up as uninit - let (variant_index, variant_dest, active_field_index) = match *kind { - mir::AggregateKind::Adt(_, variant_index, _, _, active_field_index) => { - let variant_dest = self.project_downcast(dest, variant_index)?; - (variant_index, variant_dest, active_field_index) - } - _ => (FIRST_VARIANT, dest.clone(), None), - }; - if active_field_index.is_some() { - assert_eq!(operands.len(), 1); - } - for (field_index, operand) in operands.iter_enumerated() { - let field_index = active_field_index.unwrap_or(field_index); - let field_dest = self.project_field(&variant_dest, field_index.as_usize())?; - let op = self.eval_operand(operand, Some(field_dest.layout))?; - self.copy_op(&op, &field_dest)?; - } - self.write_discriminant(variant_index, dest) - } - - /// Repeats `operand` into the destination. `dest` must have array type, and that type - /// determines how often `operand` is repeated. - fn write_repeat( - &mut self, - operand: &mir::Operand<'tcx>, - dest: &PlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx> { - let src = self.eval_operand(operand, None)?; - assert!(src.layout.is_sized()); - let dest = self.force_allocation(&dest)?; - let length = dest.len(self)?; - - if length == 0 { - // Nothing to copy... but let's still make sure that `dest` as a place is valid. - self.get_place_alloc_mut(&dest)?; - } else { - // Write the src to the first element. - let first = self.project_index(&dest, 0)?; - self.copy_op(&src, &first)?; - - // This is performance-sensitive code for big static/const arrays! So we - // avoid writing each operand individually and instead just make many copies - // of the first element. - let elem_size = first.layout.size; - let first_ptr = first.ptr(); - let rest_ptr = first_ptr.offset(elem_size, self)?; - // No alignment requirement since `copy_op` above already checked it. - self.mem_copy_repeatedly( - first_ptr, - rest_ptr, - elem_size, - length - 1, - /*nonoverlapping:*/ true, - )?; - } - - Ok(()) - } - - /// Evaluate the given terminator. Will also adjust the stack frame and statement position accordingly. - fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> InterpResult<'tcx> { - info!("{:?}", terminator.kind); - - self.eval_terminator(terminator)?; - if !self.stack().is_empty() { - if let Either::Left(loc) = self.frame().loc { - info!("// executing {:?}", loc.block); - } - } - Ok(()) - } -} +use either::Either;use rustc_index::IndexSlice;use rustc_middle::mir;use//{();}; +rustc_middle::ty::layout::LayoutOf;use rustc_target::abi::{FieldIdx,//if true{}; +FIRST_VARIANT};use super::{ImmTy,InterpCx,InterpResult,Machine,PlaceTy,//*&*&(); +Projectable,Scalar};use crate::util;impl<'mir,'tcx:'mir,M:Machine<'mir,'tcx>>//; +InterpCx<'mir,'tcx,M>{#[inline(always)]pub fn step(&mut self)->InterpResult{if self.stack().is_empty(){;return Ok(false);;}let Either::Left(loc)= +self.frame().loc else{;trace!("unwinding: skipping frame");self.pop_stack_frame( +true)?;;;return Ok(true);};let basic_block=&self.body().basic_blocks[loc.block]; +if let Some(stmt)=basic_block.statements.get(loc.statement_index){let _=||();let +old_frames=self.frame_idx();;;self.statement(stmt)?;;assert_eq!(old_frames,self. +frame_idx());;;self.frame_mut().loc.as_mut().left().unwrap().statement_index+=1; +return Ok(true);3;}3;M::before_terminator(self)?;3;3;let terminator=basic_block. +terminator();;;self.terminator(terminator)?;Ok(true)}pub fn statement(&mut self, +stmt:&mir::Statement<'tcx>)->InterpResult<'tcx>{{;};info!("{:?}",stmt);();();use +rustc_middle::mir::StatementKind::*;;match&stmt.kind{Assign(box(place,rvalue))=> +self.eval_rvalue_into_place(rvalue,*place )?,SetDiscriminant{place,variant_index +}=>{;let dest=self.eval_place(**place)?;self.write_discriminant(*variant_index,& +dest)?;;}Deinit(place)=>{;let dest=self.eval_place(**place)?;self.write_uninit(& +dest)?;;}StorageLive(local)=>{;self.storage_live(*local)?;}StorageDead(local)=>{ +self.storage_dead(*local)?;;}FakeRead(..)=>{}Retag(kind,place)=>{;let dest=self. +eval_place(**place)?;;;M::retag_place_contents(self,*kind,&dest)?;}Intrinsic(box +intrinsic)=>((self.emulate_nondiverging_intrinsic(intrinsic))?),PlaceMention(box +place)=>{;let _=self.eval_place(*place)?;}AscribeUserType(..)=>{}Coverage(..)=>{ +}ConstEvalCounter=>{;M::increment_const_eval_counter(self)?;;}Nop=>{}}Ok(())}pub +fn eval_rvalue_into_place(&mut self,rvalue:& mir::Rvalue<'tcx>,place:mir::Place< +'tcx>,)->InterpResult<'tcx>{;let dest=self.eval_place(place)?;use rustc_middle:: +mir::Rvalue::*;if true{};match*rvalue{ThreadLocalRef(did)=>{let _=();let ptr=M:: +thread_local_static_base_pointer(self,did)?;;self.write_pointer(ptr,&dest)?;}Use +(ref operand)=>{3;let op=self.eval_operand(operand,Some(dest.layout))?;3;3;self. +copy_op(&op,&dest)?;;}CopyForDeref(place)=>{;let op=self.eval_place_to_op(place, +Some(dest.layout))?;;;self.copy_op(&op,&dest)?;}BinaryOp(bin_op,box(ref left,ref +right))=>{;let layout=util::binop_left_homogeneous(bin_op).then_some(dest.layout +);;;let left=self.read_immediate(&self.eval_operand(left,layout)?)?;;let layout= +util::binop_right_homogeneous(bin_op).then_some(left.layout);3;3;let right=self. +read_immediate(&self.eval_operand(right,layout)?)?;;;self.binop_ignore_overflow( +bin_op,&left,&right,&dest)?;;}CheckedBinaryOp(bin_op,box(ref left,ref right))=>{ +let left=self.read_immediate(&self.eval_operand(left,None)?)?;;let layout=util:: +binop_right_homogeneous(bin_op).then_some(left.layout);({});({});let right=self. +read_immediate(&self.eval_operand(right,layout)?)?;3;3;self.binop_with_overflow( +bin_op,&left,&right,&dest)?;({});}UnaryOp(un_op,ref operand)=>{{;};let val=self. +read_immediate(&self.eval_operand(operand,Some(dest.layout))?)?;3;;let val=self. +wrapping_unary_op(un_op,&val)?;((),());*&*&();assert_eq!(val.layout,dest.layout, +"layout mismatch for result of {un_op:?}");;;self.write_immediate(*val,&dest)?;} +Aggregate(box ref kind,ref operands)=>{;self.write_aggregate(kind,operands,&dest +)?;;}Repeat(ref operand,_)=>{self.write_repeat(operand,&dest)?;}Len(place)=>{let +src=self.eval_place(place)?;;;let len=src.len(self)?;;self.write_scalar(Scalar:: +from_target_usize(len,self),&dest)?;3;}Ref(_,borrow_kind,place)=>{;let src=self. +eval_place(place)?;3;3;let place=self.force_allocation(&src)?;3;;let val=ImmTy:: +from_immediate(place.to_ref(self),dest.layout);;let val=M::retag_ptr_value(self, +if ((borrow_kind.allows_two_phase_borrow())){mir::RetagKind::TwoPhase}else{mir:: +RetagKind::Default},&val,)?;3;3;self.write_immediate(*val,&dest)?;;}AddressOf(_, +place)=>{;let place_base_raw=if place.is_indirect_first_projection(){let ty=self +.frame().body.local_decls[place.local].ty;3;ty.is_unsafe_ptr()}else{false};;;let +src=self.eval_place(place)?;;let place=self.force_allocation(&src)?;let mut val= +ImmTy::from_immediate(place.to_ref(self),dest.layout);;if!place_base_raw{val=M:: +retag_ptr_value(self,mir::RetagKind::Raw,&val)?;3;}3;self.write_immediate(*val,& +dest)?;((),());((),());}NullaryOp(ref null_op,ty)=>{((),());((),());let ty=self. +instantiate_from_current_frame_and_normalize_erasing_regions(ty)?;3;;let layout= +self.layout_of(ty)?;();if let mir::NullOp::SizeOf|mir::NullOp::AlignOf=null_op&& +layout.is_unsized(){let _=||();let _=||();span_bug!(self.frame().current_span(), +"{null_op:?} MIR operator called for unsized type {ty}",);{;};}{;};let val=match +null_op{mir::NullOp::SizeOf=>{*&*&();let val=layout.size.bytes();*&*&();Scalar:: +from_target_usize(val,self)}mir::NullOp::AlignOf=>{{;};let val=layout.align.abi. +bytes();;Scalar::from_target_usize(val,self)}mir::NullOp::OffsetOf(fields)=>{let +val=layout.offset_of_subfield(self,fields.iter()).bytes();if let _=(){};Scalar:: +from_target_usize(val,self)}mir::NullOp::UbChecks=>Scalar::from_bool(self.tcx.// +sess.opts.debug_assertions),};;self.write_scalar(val,&dest)?;}ShallowInitBox(ref +operand,_)=>{({});let src=self.eval_operand(operand,None)?;({});({});let v=self. +read_immediate(&src)?;();3;self.write_immediate(*v,&dest)?;3;}Cast(cast_kind,ref +operand,cast_ty)=>{;let src=self.eval_operand(operand,None)?;;;let cast_ty=self. +instantiate_from_current_frame_and_normalize_erasing_regions(cast_ty)?;3;3;self. +cast(&src,cast_kind,cast_ty,&dest)?;({});}Discriminant(place)=>{{;};let op=self. +eval_place_to_op(place,None)?;3;3;let variant=self.read_discriminant(&op)?;;;let +discr=self.discriminant_for_variant(op.layout.ty,variant)?;;self.write_immediate +(*discr,&dest)?;3;}};trace!("{:?}",self.dump_place(&dest));;Ok(())}#[instrument( +skip(self),level="trace")]fn write_aggregate(&mut self,kind:&mir::AggregateKind +<'tcx>,operands:&IndexSlice>,dest:&PlaceTy<'tcx,M:: +Provenance>,)->InterpResult<'tcx>{;self.write_uninit(dest)?;;;let(variant_index, +variant_dest,active_field_index)=match(((((*kind))))){mir::AggregateKind::Adt(_, +variant_index,_,_,active_field_index)=>{;let variant_dest=self.project_downcast( +dest,variant_index)?;*&*&();(variant_index,variant_dest,active_field_index)}_=>( +FIRST_VARIANT,dest.clone(),None),};;if active_field_index.is_some(){;assert_eq!( +operands.len(),1);3;}for(field_index,operand)in operands.iter_enumerated(){3;let +field_index=active_field_index.unwrap_or(field_index);();();let field_dest=self. +project_field(&variant_dest,field_index.as_usize())?;;;let op=self.eval_operand( +operand,Some(field_dest.layout))?;();();self.copy_op(&op,&field_dest)?;();}self. +write_discriminant(variant_index,dest)}fn write_repeat (&mut self,operand:&mir:: +Operand<'tcx>,dest:&PlaceTy<'tcx,M::Provenance>,)->InterpResult<'tcx>{3;let src= +self.eval_operand(operand,None)?;;;assert!(src.layout.is_sized());let dest=self. +force_allocation(&dest)?;();();let length=dest.len(self)?;3;if length==0{3;self. +get_place_alloc_mut(&dest)?;;}else{;let first=self.project_index(&dest,0)?;self. +copy_op(&src,&first)?;;let elem_size=first.layout.size;let first_ptr=first.ptr() +;3;3;let rest_ptr=first_ptr.offset(elem_size,self)?;3;;self.mem_copy_repeatedly( +first_ptr,rest_ptr,elem_size,length-1,true,)?;3;}Ok(())}fn terminator(&mut self, +terminator:&mir::Terminator<'tcx>)->InterpResult<'tcx>{;info!("{:?}",terminator. +kind);();3;self.eval_terminator(terminator)?;3;if!self.stack().is_empty(){if let +Either::Left(loc)=self.frame().loc{;info!("// executing {:?}",loc.block);}}Ok(() +)}}//let _=();let _=();let _=();if true{};let _=();if true{};let _=();if true{}; diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index c0e27e86d500a..4668a4d1d0a63 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -1,973 +1,238 @@ -use std::borrow::Cow; - -use either::Either; - -use rustc_middle::{ - mir, - ty::{ - self, - layout::{FnAbiOf, IntegerExt, LayoutOf, TyAndLayout}, - AdtDef, Instance, Ty, - }, -}; -use rustc_span::{source_map::Spanned, sym}; -use rustc_target::abi::{self, FieldIdx}; -use rustc_target::abi::{ - call::{ArgAbi, FnAbi, PassMode}, - Integer, -}; -use rustc_target::spec::abi::Abi; - -use super::{ - CtfeProvenance, FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy, - Projectable, Provenance, Scalar, StackPopCleanup, -}; -use crate::fluent_generated as fluent; - -/// An argment passed to a function. -#[derive(Clone, Debug)] -pub enum FnArg<'tcx, Prov: Provenance = CtfeProvenance> { - /// Pass a copy of the given operand. - Copy(OpTy<'tcx, Prov>), - /// Allow for the argument to be passed in-place: destroy the value originally stored at that place and - /// make the place inaccessible for the duration of the function call. - InPlace(MPlaceTy<'tcx, Prov>), -} - -impl<'tcx, Prov: Provenance> FnArg<'tcx, Prov> { - pub fn layout(&self) -> &TyAndLayout<'tcx> { - match self { - FnArg::Copy(op) => &op.layout, - FnArg::InPlace(mplace) => &mplace.layout, - } - } -} - -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - /// Make a copy of the given fn_arg. Any `InPlace` are degenerated to copies, no protection of the - /// original memory occurs. - pub fn copy_fn_arg(&self, arg: &FnArg<'tcx, M::Provenance>) -> OpTy<'tcx, M::Provenance> { - match arg { - FnArg::Copy(op) => op.clone(), - FnArg::InPlace(mplace) => mplace.clone().into(), - } - } - - /// Make a copy of the given fn_args. Any `InPlace` are degenerated to copies, no protection of the - /// original memory occurs. - pub fn copy_fn_args( - &self, - args: &[FnArg<'tcx, M::Provenance>], - ) -> Vec> { - args.iter().map(|fn_arg| self.copy_fn_arg(fn_arg)).collect() - } - - pub fn fn_arg_field( - &self, - arg: &FnArg<'tcx, M::Provenance>, - field: usize, - ) -> InterpResult<'tcx, FnArg<'tcx, M::Provenance>> { - Ok(match arg { - FnArg::Copy(op) => FnArg::Copy(self.project_field(op, field)?), - FnArg::InPlace(mplace) => FnArg::InPlace(self.project_field(mplace, field)?), - }) - } - - pub(super) fn eval_terminator( - &mut self, - terminator: &mir::Terminator<'tcx>, - ) -> InterpResult<'tcx> { - use rustc_middle::mir::TerminatorKind::*; - match terminator.kind { - Return => { - self.pop_stack_frame(/* unwinding */ false)? - } - - Goto { target } => self.go_to_block(target), - - SwitchInt { ref discr, ref targets } => { - let discr = self.read_immediate(&self.eval_operand(discr, None)?)?; - trace!("SwitchInt({:?})", *discr); - - // Branch to the `otherwise` case by default, if no match is found. - let mut target_block = targets.otherwise(); - - for (const_int, target) in targets.iter() { - // Compare using MIR BinOp::Eq, to also support pointer values. - // (Avoiding `self.binary_op` as that does some redundant layout computation.) - let res = self.wrapping_binary_op( - mir::BinOp::Eq, - &discr, - &ImmTy::from_uint(const_int, discr.layout), - )?; - if res.to_scalar().to_bool()? { - target_block = target; - break; - } - } - - self.go_to_block(target_block); - } - - Call { - ref func, - ref args, - destination, - target, - unwind, - call_source: _, - fn_span: _, - } => { - let old_stack = self.frame_idx(); - let old_loc = self.frame().loc; - let func = self.eval_operand(func, None)?; - let args = self.eval_fn_call_arguments(args)?; - - let fn_sig_binder = func.layout.ty.fn_sig(*self.tcx); - let fn_sig = - self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig_binder); - let extra_args = &args[fn_sig.inputs().len()..]; - let extra_args = - self.tcx.mk_type_list_from_iter(extra_args.iter().map(|arg| arg.layout().ty)); - - let (fn_val, fn_abi, with_caller_location) = match *func.layout.ty.kind() { - ty::FnPtr(_sig) => { - let fn_ptr = self.read_pointer(&func)?; - let fn_val = self.get_ptr_fn(fn_ptr)?; - (fn_val, self.fn_abi_of_fn_ptr(fn_sig_binder, extra_args)?, false) - } - ty::FnDef(def_id, args) => { - let instance = self.resolve(def_id, args)?; - ( - FnVal::Instance(instance), - self.fn_abi_of_instance(instance, extra_args)?, - instance.def.requires_caller_location(*self.tcx), - ) - } - _ => span_bug!( - terminator.source_info.span, - "invalid callee of type {}", - func.layout.ty - ), - }; - - let destination = self.force_allocation(&self.eval_place(destination)?)?; - self.eval_fn_call( - fn_val, - (fn_sig.abi, fn_abi), - &args, - with_caller_location, - &destination, - target, - if fn_abi.can_unwind { unwind } else { mir::UnwindAction::Unreachable }, - )?; - // Sanity-check that `eval_fn_call` either pushed a new frame or - // did a jump to another block. - if self.frame_idx() == old_stack && self.frame().loc == old_loc { - span_bug!(terminator.source_info.span, "evaluating this call made no progress"); - } - } - - Drop { place, target, unwind, replace: _ } => { - let frame = self.frame(); - let ty = place.ty(&frame.body.local_decls, *self.tcx).ty; - let ty = self.instantiate_from_frame_and_normalize_erasing_regions(frame, ty)?; - let instance = Instance::resolve_drop_in_place(*self.tcx, ty); - if let ty::InstanceDef::DropGlue(_, None) = instance.def { - // This is the branch we enter if and only if the dropped type has no drop glue - // whatsoever. This can happen as a result of monomorphizing a drop of a - // generic. In order to make sure that generic and non-generic code behaves - // roughly the same (and in keeping with Mir semantics) we do nothing here. - self.go_to_block(target); - return Ok(()); - } - let place = self.eval_place(place)?; - trace!("TerminatorKind::drop: {:?}, type {}", place, ty); - self.drop_in_place(&place, instance, target, unwind)?; - } - - Assert { ref cond, expected, ref msg, target, unwind } => { - let ignored = - M::ignore_optional_overflow_checks(self) && msg.is_optional_overflow_check(); - let cond_val = self.read_scalar(&self.eval_operand(cond, None)?)?.to_bool()?; - if ignored || expected == cond_val { - self.go_to_block(target); - } else { - M::assert_panic(self, msg, unwind)?; - } - } - - UnwindTerminate(reason) => { - M::unwind_terminate(self, reason)?; - } - - // When we encounter Resume, we've finished unwinding - // cleanup for the current stack frame. We pop it in order - // to continue unwinding the next frame - UnwindResume => { - trace!("unwinding: resuming from cleanup"); - // By definition, a Resume terminator means - // that we're unwinding - self.pop_stack_frame(/* unwinding */ true)?; - return Ok(()); - } - - // It is UB to ever encounter this. - Unreachable => throw_ub!(Unreachable), - - // These should never occur for MIR we actually run. - FalseEdge { .. } | FalseUnwind { .. } | Yield { .. } | CoroutineDrop => span_bug!( - terminator.source_info.span, - "{:#?} should have been eliminated by MIR pass", - terminator.kind - ), - - InlineAsm { template, ref operands, options, ref targets, .. } => { - M::eval_inline_asm(self, template, operands, options, targets)?; - } - } - - Ok(()) - } - - /// Evaluate the arguments of a function call - pub(super) fn eval_fn_call_arguments( - &self, - ops: &[Spanned>], - ) -> InterpResult<'tcx, Vec>> { - ops.iter() - .map(|op| { - let arg = match &op.node { - mir::Operand::Copy(_) | mir::Operand::Constant(_) => { - // Make a regular copy. - let op = self.eval_operand(&op.node, None)?; - FnArg::Copy(op) - } - mir::Operand::Move(place) => { - // If this place lives in memory, preserve its location. - // We call `place_to_op` which will be an `MPlaceTy` whenever there exists - // an mplace for this place. (This is in contrast to `PlaceTy::as_mplace_or_local` - // which can return a local even if that has an mplace.) - let place = self.eval_place(*place)?; - let op = self.place_to_op(&place)?; - - match op.as_mplace_or_imm() { - Either::Left(mplace) => FnArg::InPlace(mplace), - Either::Right(_imm) => { - // This argument doesn't live in memory, so there's no place - // to make inaccessible during the call. - // We rely on there not being any stray `PlaceTy` that would let the - // caller directly access this local! - // This is also crucial for tail calls, where we want the `FnArg` to - // stay valid when the old stack frame gets popped. - FnArg::Copy(op) - } - } - } - }; - - Ok(arg) - }) - .collect() - } - - /// Find the wrapped inner type of a transparent wrapper. - /// Must not be called on 1-ZST (as they don't have a uniquely defined "wrapped field"). - /// - /// We work with `TyAndLayout` here since that makes it much easier to iterate over all fields. - fn unfold_transparent( - &self, - layout: TyAndLayout<'tcx>, - may_unfold: impl Fn(AdtDef<'tcx>) -> bool, - ) -> TyAndLayout<'tcx> { - match layout.ty.kind() { - ty::Adt(adt_def, _) if adt_def.repr().transparent() && may_unfold(*adt_def) => { - assert!(!adt_def.is_enum()); - // Find the non-1-ZST field, and recurse. - let (_, field) = layout.non_1zst_field(self).unwrap(); - self.unfold_transparent(field, may_unfold) - } - // Not a transparent type, no further unfolding. - _ => layout, - } - } - - /// Unwrap types that are guaranteed a null-pointer-optimization - fn unfold_npo(&self, layout: TyAndLayout<'tcx>) -> InterpResult<'tcx, TyAndLayout<'tcx>> { - // Check if this is `Option` wrapping some type. - let inner = match layout.ty.kind() { - ty::Adt(def, args) if self.tcx.is_diagnostic_item(sym::Option, def.did()) => { - args[0].as_type().unwrap() - } - _ => { - // Not an `Option`. - return Ok(layout); - } - }; - let inner = self.layout_of(inner)?; - // Check if the inner type is one of the NPO-guaranteed ones. - // For that we first unpeel transparent *structs* (but not unions). - let is_npo = |def: AdtDef<'tcx>| { - self.tcx.has_attr(def.did(), sym::rustc_nonnull_optimization_guaranteed) - }; - let inner = self.unfold_transparent(inner, /* may_unfold */ |def| { - // Stop at NPO tpyes so that we don't miss that attribute in the check below! - def.is_struct() && !is_npo(def) - }); - Ok(match inner.ty.kind() { - ty::Ref(..) | ty::FnPtr(..) => { - // Option<&T> behaves like &T, and same for fn() - inner - } - ty::Adt(def, _) if is_npo(*def) => { - // Once we found a `nonnull_optimization_guaranteed` type, further strip off - // newtype structs from it to find the underlying ABI type. - self.unfold_transparent(inner, /* may_unfold */ |def| def.is_struct()) - } - _ => { - // Everything else we do not unfold. - layout - } - }) - } - - /// Check if these two layouts look like they are fn-ABI-compatible. - /// (We also compare the `PassMode`, so this doesn't have to check everything. But it turns out - /// that only checking the `PassMode` is insufficient.) - fn layout_compat( - &self, - caller: TyAndLayout<'tcx>, - callee: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, bool> { - // Fast path: equal types are definitely compatible. - if caller.ty == callee.ty { - return Ok(true); - } - // 1-ZST are compatible with all 1-ZST (and with nothing else). - if caller.is_1zst() || callee.is_1zst() { - return Ok(caller.is_1zst() && callee.is_1zst()); - } - // Unfold newtypes and NPO optimizations. - let unfold = |layout: TyAndLayout<'tcx>| { - self.unfold_npo(self.unfold_transparent(layout, /* may_unfold */ |_def| true)) - }; - let caller = unfold(caller)?; - let callee = unfold(callee)?; - // Now see if these inner types are compatible. - - // Compatible pointer types. For thin pointers, we have to accept even non-`repr(transparent)` - // things as compatible due to `DispatchFromDyn`. For instance, `Rc` and `*mut i32` - // must be compatible. So we just accept everything with Pointer ABI as compatible, - // even if this will accept some code that is not stably guaranteed to work. - // This also handles function pointers. - let thin_pointer = |layout: TyAndLayout<'tcx>| match layout.abi { - abi::Abi::Scalar(s) => match s.primitive() { - abi::Primitive::Pointer(addr_space) => Some(addr_space), - _ => None, - }, - _ => None, - }; - if let (Some(caller), Some(callee)) = (thin_pointer(caller), thin_pointer(callee)) { - return Ok(caller == callee); - } - // For wide pointers we have to get the pointee type. - let pointee_ty = |ty: Ty<'tcx>| -> InterpResult<'tcx, Option>> { - // We cannot use `builtin_deref` here since we need to reject `Box`. - Ok(Some(match ty.kind() { - ty::Ref(_, ty, _) => *ty, - ty::RawPtr(ty, _) => *ty, - // We only accept `Box` with the default allocator. - _ if ty.is_box_global(*self.tcx) => ty.boxed_ty(), - _ => return Ok(None), - })) - }; - if let (Some(caller), Some(callee)) = (pointee_ty(caller.ty)?, pointee_ty(callee.ty)?) { - // This is okay if they have the same metadata type. - let meta_ty = |ty: Ty<'tcx>| { - // Even if `ty` is normalized, the search for the unsized tail will project - // to fields, which can yield non-normalized types. So we need to provide a - // normalization function. - let normalize = |ty| self.tcx.normalize_erasing_regions(self.param_env, ty); - ty.ptr_metadata_ty(*self.tcx, normalize) - }; - return Ok(meta_ty(caller) == meta_ty(callee)); - } - - // Compatible integer types (in particular, usize vs ptr-sized-u32/u64). - // `char` counts as `u32.` - let int_ty = |ty: Ty<'tcx>| { - Some(match ty.kind() { - ty::Int(ity) => (Integer::from_int_ty(&self.tcx, *ity), /* signed */ true), - ty::Uint(uty) => (Integer::from_uint_ty(&self.tcx, *uty), /* signed */ false), - ty::Char => (Integer::I32, /* signed */ false), - _ => return None, - }) - }; - if let (Some(caller), Some(callee)) = (int_ty(caller.ty), int_ty(callee.ty)) { - // This is okay if they are the same integer type. - return Ok(caller == callee); - } - - // Fall back to exact equality. - // FIXME: We are missing the rules for "repr(C) wrapping compatible types". - Ok(caller == callee) - } - - fn check_argument_compat( - &self, - caller_abi: &ArgAbi<'tcx, Ty<'tcx>>, - callee_abi: &ArgAbi<'tcx, Ty<'tcx>>, - ) -> InterpResult<'tcx, bool> { - // We do not want to accept things as ABI-compatible that just "happen to be" compatible on the current target, - // so we implement a type-based check that reflects the guaranteed rules for ABI compatibility. - if self.layout_compat(caller_abi.layout, callee_abi.layout)? { - // Ensure that our checks imply actual ABI compatibility for this concrete call. - assert!(caller_abi.eq_abi(callee_abi)); - return Ok(true); - } else { - trace!( - "check_argument_compat: incompatible ABIs:\ncaller: {:?}\ncallee: {:?}", - caller_abi, - callee_abi - ); - return Ok(false); - } - } - - /// Initialize a single callee argument, checking the types for compatibility. - fn pass_argument<'x, 'y>( - &mut self, - caller_args: &mut impl Iterator< - Item = (&'x FnArg<'tcx, M::Provenance>, &'y ArgAbi<'tcx, Ty<'tcx>>), - >, - callee_abi: &ArgAbi<'tcx, Ty<'tcx>>, - callee_arg: &mir::Place<'tcx>, - callee_ty: Ty<'tcx>, - already_live: bool, - ) -> InterpResult<'tcx> - where - 'tcx: 'x, - 'tcx: 'y, - { - assert_eq!(callee_ty, callee_abi.layout.ty); - if matches!(callee_abi.mode, PassMode::Ignore) { - // This one is skipped. Still must be made live though! - if !already_live { - self.storage_live(callee_arg.as_local().unwrap())?; - } - return Ok(()); - } - // Find next caller arg. - let Some((caller_arg, caller_abi)) = caller_args.next() else { - throw_ub_custom!(fluent::const_eval_not_enough_caller_args); - }; - assert_eq!(caller_arg.layout().layout, caller_abi.layout.layout); - // Sadly we cannot assert that `caller_arg.layout().ty` and `caller_abi.layout.ty` are - // equal; in closures the types sometimes differ. We just hope that `caller_abi` is the - // right type to print to the user. - - // Check compatibility - if !self.check_argument_compat(caller_abi, callee_abi)? { - throw_ub!(AbiMismatchArgument { - caller_ty: caller_abi.layout.ty, - callee_ty: callee_abi.layout.ty - }); - } - // We work with a copy of the argument for now; if this is in-place argument passing, we - // will later protect the source it comes from. This means the callee cannot observe if we - // did in-place of by-copy argument passing, except for pointer equality tests. - let caller_arg_copy = self.copy_fn_arg(caller_arg); - if !already_live { - let local = callee_arg.as_local().unwrap(); - let meta = caller_arg_copy.meta(); - // `check_argument_compat` ensures that if metadata is needed, both have the same type, - // so we know they will use the metadata the same way. - assert!(!meta.has_meta() || caller_arg_copy.layout.ty == callee_ty); - - self.storage_live_dyn(local, meta)?; - } - // Now we can finally actually evaluate the callee place. - let callee_arg = self.eval_place(*callee_arg)?; - // We allow some transmutes here. - // FIXME: Depending on the PassMode, this should reset some padding to uninitialized. (This - // is true for all `copy_op`, but there are a lot of special cases for argument passing - // specifically.) - self.copy_op_allow_transmute(&caller_arg_copy, &callee_arg)?; - // If this was an in-place pass, protect the place it comes from for the duration of the call. - if let FnArg::InPlace(mplace) = caller_arg { - M::protect_in_place_function_argument(self, mplace)?; - } - Ok(()) - } - - /// Call this function -- pushing the stack frame and initializing the arguments. - /// - /// `caller_fn_abi` is used to determine if all the arguments are passed the proper way. - /// However, we also need `caller_abi` to determine if we need to do untupling of arguments. - /// - /// `with_caller_location` indicates whether the caller passed a caller location. Miri - /// implements caller locations without argument passing, but to match `FnAbi` we need to know - /// when those arguments are present. - pub(crate) fn eval_fn_call( - &mut self, - fn_val: FnVal<'tcx, M::ExtraFnVal>, - (caller_abi, caller_fn_abi): (Abi, &FnAbi<'tcx, Ty<'tcx>>), - args: &[FnArg<'tcx, M::Provenance>], - with_caller_location: bool, - destination: &MPlaceTy<'tcx, M::Provenance>, - target: Option, - mut unwind: mir::UnwindAction, - ) -> InterpResult<'tcx> { - trace!("eval_fn_call: {:#?}", fn_val); - - let instance = match fn_val { - FnVal::Instance(instance) => instance, - FnVal::Other(extra) => { - return M::call_extra_fn( - self, - extra, - caller_abi, - args, - destination, - target, - unwind, - ); - } - }; - - match instance.def { - ty::InstanceDef::Intrinsic(def_id) => { - assert!(self.tcx.intrinsic(def_id).is_some()); - // FIXME: Should `InPlace` arguments be reset to uninit? - M::call_intrinsic( - self, - instance, - &self.copy_fn_args(args), - destination, - target, - unwind, - ) - } - ty::InstanceDef::VTableShim(..) - | ty::InstanceDef::ReifyShim(..) - | ty::InstanceDef::ClosureOnceShim { .. } - | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } - | ty::InstanceDef::CoroutineKindShim { .. } - | ty::InstanceDef::FnPtrShim(..) - | ty::InstanceDef::DropGlue(..) - | ty::InstanceDef::CloneShim(..) - | ty::InstanceDef::FnPtrAddrShim(..) - | ty::InstanceDef::ThreadLocalShim(..) - | ty::InstanceDef::Item(_) => { - // We need MIR for this fn - let Some((body, instance)) = M::find_mir_or_eval_fn( - self, - instance, - caller_abi, - args, - destination, - target, - unwind, - )? - else { - return Ok(()); - }; - - // Compute callee information using the `instance` returned by - // `find_mir_or_eval_fn`. - // FIXME: for variadic support, do we have to somehow determine callee's extra_args? - let callee_fn_abi = self.fn_abi_of_instance(instance, ty::List::empty())?; - - if callee_fn_abi.c_variadic || caller_fn_abi.c_variadic { - throw_unsup_format!("calling a c-variadic function is not supported"); - } - - if M::enforce_abi(self) { - if caller_fn_abi.conv != callee_fn_abi.conv { - throw_ub_custom!( - fluent::const_eval_incompatible_calling_conventions, - callee_conv = format!("{:?}", callee_fn_abi.conv), - caller_conv = format!("{:?}", caller_fn_abi.conv), - ) - } - } - - // Check that all target features required by the callee (i.e., from - // the attribute `#[target_feature(enable = ...)]`) are enabled at - // compile time. - self.check_fn_target_features(instance)?; - - if !callee_fn_abi.can_unwind { - // The callee cannot unwind, so force the `Unreachable` unwind handling. - unwind = mir::UnwindAction::Unreachable; - } - - self.push_stack_frame( - instance, - body, - destination, - StackPopCleanup::Goto { ret: target, unwind }, - )?; - - // If an error is raised here, pop the frame again to get an accurate backtrace. - // To this end, we wrap it all in a `try` block. - let res: InterpResult<'tcx> = try { - trace!( - "caller ABI: {:?}, args: {:#?}", - caller_abi, - args.iter() - .map(|arg| ( - arg.layout().ty, - match arg { - FnArg::Copy(op) => format!("copy({op:?})"), - FnArg::InPlace(mplace) => format!("in-place({mplace:?})"), - } - )) - .collect::>() - ); - trace!( - "spread_arg: {:?}, locals: {:#?}", - body.spread_arg, - body.args_iter() - .map(|local| ( - local, - self.layout_of_local(self.frame(), local, None).unwrap().ty, - )) - .collect::>() - ); - - // In principle, we have two iterators: Where the arguments come from, and where - // they go to. - - // For where they come from: If the ABI is RustCall, we untuple the - // last incoming argument. These two iterators do not have the same type, - // so to keep the code paths uniform we accept an allocation - // (for RustCall ABI only). - let caller_args: Cow<'_, [FnArg<'tcx, M::Provenance>]> = - if caller_abi == Abi::RustCall && !args.is_empty() { - // Untuple - let (untuple_arg, args) = args.split_last().unwrap(); - trace!("eval_fn_call: Will pass last argument by untupling"); - Cow::from( - args.iter() - .map(|a| Ok(a.clone())) - .chain( - (0..untuple_arg.layout().fields.count()) - .map(|i| self.fn_arg_field(untuple_arg, i)), - ) - .collect::>>()?, - ) - } else { - // Plain arg passing - Cow::from(args) - }; - // If `with_caller_location` is set we pretend there is an extra argument (that - // we will not pass). - assert_eq!( - caller_args.len() + if with_caller_location { 1 } else { 0 }, - caller_fn_abi.args.len(), - "mismatch between caller ABI and caller arguments", - ); - let mut caller_args = caller_args - .iter() - .zip(caller_fn_abi.args.iter()) - .filter(|arg_and_abi| !matches!(arg_and_abi.1.mode, PassMode::Ignore)); - - // Now we have to spread them out across the callee's locals, - // taking into account the `spread_arg`. If we could write - // this is a single iterator (that handles `spread_arg`), then - // `pass_argument` would be the loop body. It takes care to - // not advance `caller_iter` for ignored arguments. - let mut callee_args_abis = callee_fn_abi.args.iter(); - for local in body.args_iter() { - // Construct the destination place for this argument. At this point all - // locals are still dead, so we cannot construct a `PlaceTy`. - let dest = mir::Place::from(local); - // `layout_of_local` does more than just the instantiation we need to get the - // type, but the result gets cached so this avoids calling the instantiation - // query *again* the next time this local is accessed. - let ty = self.layout_of_local(self.frame(), local, None)?.ty; - if Some(local) == body.spread_arg { - // Make the local live once, then fill in the value field by field. - self.storage_live(local)?; - // Must be a tuple - let ty::Tuple(fields) = ty.kind() else { - span_bug!(self.cur_span(), "non-tuple type for `spread_arg`: {ty}") - }; - for (i, field_ty) in fields.iter().enumerate() { - let dest = dest.project_deeper( - &[mir::ProjectionElem::Field( - FieldIdx::from_usize(i), - field_ty, - )], - *self.tcx, - ); - let callee_abi = callee_args_abis.next().unwrap(); - self.pass_argument( - &mut caller_args, - callee_abi, - &dest, - field_ty, - /* already_live */ true, - )?; - } - } else { - // Normal argument. Cannot mark it as live yet, it might be unsized! - let callee_abi = callee_args_abis.next().unwrap(); - self.pass_argument( - &mut caller_args, - callee_abi, - &dest, - ty, - /* already_live */ false, - )?; - } - } - // If the callee needs a caller location, pretend we consume one more argument from the ABI. - if instance.def.requires_caller_location(*self.tcx) { - callee_args_abis.next().unwrap(); - } - // Now we should have no more caller args or callee arg ABIs - assert!( - callee_args_abis.next().is_none(), - "mismatch between callee ABI and callee body arguments" - ); - if caller_args.next().is_some() { - throw_ub_custom!(fluent::const_eval_too_many_caller_args); - } - // Don't forget to check the return type! - if !self.check_argument_compat(&caller_fn_abi.ret, &callee_fn_abi.ret)? { - throw_ub!(AbiMismatchReturn { - caller_ty: caller_fn_abi.ret.layout.ty, - callee_ty: callee_fn_abi.ret.layout.ty - }); - } - - // Protect return place for in-place return value passing. - M::protect_in_place_function_argument(self, &destination)?; - - // Don't forget to mark "initially live" locals as live. - self.storage_live_for_always_live_locals()?; - }; - match res { - Err(err) => { - self.stack_mut().pop(); - Err(err) - } - Ok(()) => Ok(()), - } - } - // `InstanceDef::Virtual` does not have callable MIR. Calls to `Virtual` instances must be - // codegen'd / interpreted as virtual calls through the vtable. - ty::InstanceDef::Virtual(def_id, idx) => { - let mut args = args.to_vec(); - // We have to implement all "object safe receivers". So we have to go search for a - // pointer or `dyn Trait` type, but it could be wrapped in newtypes. So recursively - // unwrap those newtypes until we are there. - // An `InPlace` does nothing here, we keep the original receiver intact. We can't - // really pass the argument in-place anyway, and we are constructing a new - // `Immediate` receiver. - let mut receiver = self.copy_fn_arg(&args[0]); - let receiver_place = loop { - match receiver.layout.ty.kind() { - ty::Ref(..) | ty::RawPtr(..) => { - // We do *not* use `deref_pointer` here: we don't want to conceptually - // create a place that must be dereferenceable, since the receiver might - // be a raw pointer and (for `*const dyn Trait`) we don't need to - // actually access memory to resolve this method. - // Also see . - let val = self.read_immediate(&receiver)?; - break self.ref_to_mplace(&val)?; - } - ty::Dynamic(.., ty::Dyn) => break receiver.assert_mem_place(), // no immediate unsized values - ty::Dynamic(.., ty::DynStar) => { - // Not clear how to handle this, so far we assume the receiver is always a pointer. - span_bug!( - self.cur_span(), - "by-value calls on a `dyn*`... are those a thing?" - ); - } - _ => { - // Not there yet, search for the only non-ZST field. - // (The rules for `DispatchFromDyn` ensure there's exactly one such field.) - let (idx, _) = receiver.layout.non_1zst_field(self).expect( - "not exactly one non-1-ZST field in a `DispatchFromDyn` type", - ); - receiver = self.project_field(&receiver, idx)?; - } - } - }; - - // Obtain the underlying trait we are working on, and the adjusted receiver argument. - let (vptr, dyn_ty, adjusted_receiver) = if let ty::Dynamic(data, _, ty::DynStar) = - receiver_place.layout.ty.kind() - { - let (recv, vptr) = self.unpack_dyn_star(&receiver_place)?; - let (dyn_ty, dyn_trait) = self.get_ptr_vtable(vptr)?; - if dyn_trait != data.principal() { - throw_ub_custom!(fluent::const_eval_dyn_star_call_vtable_mismatch); - } - - (vptr, dyn_ty, recv.ptr()) - } else { - // Doesn't have to be a `dyn Trait`, but the unsized tail must be `dyn Trait`. - // (For that reason we also cannot use `unpack_dyn_trait`.) - let receiver_tail = self - .tcx - .struct_tail_erasing_lifetimes(receiver_place.layout.ty, self.param_env); - let ty::Dynamic(data, _, ty::Dyn) = receiver_tail.kind() else { - span_bug!( - self.cur_span(), - "dynamic call on non-`dyn` type {}", - receiver_tail - ) - }; - assert!(receiver_place.layout.is_unsized()); - - // Get the required information from the vtable. - let vptr = receiver_place.meta().unwrap_meta().to_pointer(self)?; - let (dyn_ty, dyn_trait) = self.get_ptr_vtable(vptr)?; - if dyn_trait != data.principal() { - throw_ub_custom!(fluent::const_eval_dyn_call_vtable_mismatch); - } - - // It might be surprising that we use a pointer as the receiver even if this - // is a by-val case; this works because by-val passing of an unsized `dyn - // Trait` to a function is actually desugared to a pointer. - (vptr, dyn_ty, receiver_place.ptr()) - }; - - // Now determine the actual method to call. We can do that in two different ways and - // compare them to ensure everything fits. - let Some(ty::VtblEntry::Method(fn_inst)) = - self.get_vtable_entries(vptr)?.get(idx).copied() - else { - // FIXME(fee1-dead) these could be variants of the UB info enum instead of this - throw_ub_custom!(fluent::const_eval_dyn_call_not_a_method); - }; - trace!("Virtual call dispatches to {fn_inst:#?}"); - if cfg!(debug_assertions) { - let tcx = *self.tcx; - - let trait_def_id = tcx.trait_of_item(def_id).unwrap(); - let virtual_trait_ref = - ty::TraitRef::from_method(tcx, trait_def_id, instance.args); - let existential_trait_ref = - ty::ExistentialTraitRef::erase_self_ty(tcx, virtual_trait_ref); - let concrete_trait_ref = existential_trait_ref.with_self_ty(tcx, dyn_ty); - - let concrete_method = Instance::resolve_for_vtable( - tcx, - self.param_env, - def_id, - instance.args.rebase_onto(tcx, trait_def_id, concrete_trait_ref.args), - ) - .unwrap(); - assert_eq!(fn_inst, concrete_method); - } - - // Adjust receiver argument. Layout can be any (thin) ptr. - let receiver_ty = Ty::new_mut_ptr(self.tcx.tcx, dyn_ty); - args[0] = FnArg::Copy( - ImmTy::from_immediate( - Scalar::from_maybe_pointer(adjusted_receiver, self).into(), - self.layout_of(receiver_ty)?, - ) - .into(), - ); - trace!("Patched receiver operand to {:#?}", args[0]); - // Need to also adjust the type in the ABI. Strangely, the layout there is actually - // already fine! Just the type is bogus. This is due to what `force_thin_self_ptr` - // does in `fn_abi_new_uncached`; supposedly, codegen relies on having the bogus - // type, so we just patch this up locally. - let mut caller_fn_abi = caller_fn_abi.clone(); - caller_fn_abi.args[0].layout.ty = receiver_ty; - - // recurse with concrete function - self.eval_fn_call( - FnVal::Instance(fn_inst), - (caller_abi, &caller_fn_abi), - &args, - with_caller_location, - destination, - target, - unwind, - ) - } - } - } - - fn check_fn_target_features(&self, instance: ty::Instance<'tcx>) -> InterpResult<'tcx, ()> { - // Calling functions with `#[target_feature]` is not unsafe on WASM, see #84988 - let attrs = self.tcx.codegen_fn_attrs(instance.def_id()); - if !self.tcx.sess.target.is_like_wasm - && attrs - .target_features - .iter() - .any(|feature| !self.tcx.sess.target_features.contains(feature)) - { - throw_ub_custom!( - fluent::const_eval_unavailable_target_features_for_fn, - unavailable_feats = attrs - .target_features - .iter() - .filter(|&feature| !self.tcx.sess.target_features.contains(feature)) - .fold(String::new(), |mut s, feature| { - if !s.is_empty() { - s.push_str(", "); - } - s.push_str(feature.as_str()); - s - }), - ); - } - Ok(()) - } - - fn drop_in_place( - &mut self, - place: &PlaceTy<'tcx, M::Provenance>, - instance: ty::Instance<'tcx>, - target: mir::BasicBlock, - unwind: mir::UnwindAction, - ) -> InterpResult<'tcx> { - trace!("drop_in_place: {:?},\n instance={:?}", place, instance); - // We take the address of the object. This may well be unaligned, which is fine - // for us here. However, unaligned accesses will probably make the actual drop - // implementation fail -- a problem shared by rustc. - let place = self.force_allocation(place)?; - - let place = match place.layout.ty.kind() { - ty::Dynamic(_, _, ty::Dyn) => { - // Dropping a trait object. Need to find actual drop fn. - self.unpack_dyn_trait(&place)?.0 - } - ty::Dynamic(_, _, ty::DynStar) => { - // Dropping a `dyn*`. Need to find actual drop fn. - self.unpack_dyn_star(&place)?.0 - } - _ => { - debug_assert_eq!( - instance, - ty::Instance::resolve_drop_in_place(*self.tcx, place.layout.ty) - ); - place - } - }; - let instance = ty::Instance::resolve_drop_in_place(*self.tcx, place.layout.ty); - let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty())?; - - let arg = self.mplace_to_ref(&place)?; - let ret = MPlaceTy::fake_alloc_zst(self.layout_of(self.tcx.types.unit)?); - - self.eval_fn_call( - FnVal::Instance(instance), - (Abi::Rust, fn_abi), - &[FnArg::Copy(arg.into())], - false, - &ret.into(), - Some(target), - unwind, - ) - } -} +use std::borrow::Cow;use either::Either ;use rustc_middle::{mir,ty::{self,layout +::{FnAbiOf,IntegerExt,LayoutOf,TyAndLayout},AdtDef,Instance,Ty,},};use//((),()); +rustc_span::{source_map::Spanned,sym};use rustc_target::abi::{self,FieldIdx};//; +use rustc_target::abi::{call::{ArgAbi,FnAbi,PassMode},Integer,};use//let _=||(); +rustc_target::spec::abi::Abi;use super::{CtfeProvenance,FnVal,ImmTy,InterpCx,//; +InterpResult,MPlaceTy,Machine,OpTy,PlaceTy,Projectable,Provenance,Scalar,//({}); +StackPopCleanup,};use crate::fluent_generated as fluent;#[derive(Clone,Debug)]// +pub enum FnArg<'tcx,Prov:Provenance=CtfeProvenance>{Copy(OpTy<'tcx,Prov>),//{;}; +InPlace(MPlaceTy<'tcx,Prov>),}impl<'tcx ,Prov:Provenance>FnArg<'tcx,Prov>{pub fn +layout(&self)->&TyAndLayout<'tcx>{match self{FnArg::Copy(op)=>(&op.layout),FnArg +::InPlace(mplace)=>(&mplace.layout),}}}impl<'mir,'tcx:'mir,M:Machine<'mir,'tcx>> +InterpCx<'mir,'tcx,M>{pub fn copy_fn_arg(&self,arg:&FnArg<'tcx,M::Provenance>)// +->OpTy<'tcx,M::Provenance>{match arg{FnArg:: Copy(op)=>op.clone(),FnArg::InPlace +(mplace)=>mplace.clone().into(),} }pub fn copy_fn_args(&self,args:&[FnArg<'tcx,M +::Provenance>],)->Vec>{ (args.iter()).map(|fn_arg|self. +copy_fn_arg(fn_arg)).collect()}pub fn fn_arg_field(&self,arg:&FnArg<'tcx,M:://3; +Provenance>,field:usize,)->InterpResult<'tcx,FnArg<'tcx,M::Provenance>>{Ok(//(); +match arg{FnArg::Copy(op)=>(FnArg::Copy( self.project_field(op,field)?)),FnArg:: +InPlace(mplace)=>FnArg::InPlace(self.project_field( mplace,field)?),})}pub(super +)fn eval_terminator(&mut self,terminator :&mir::Terminator<'tcx>,)->InterpResult +<'tcx>{;use rustc_middle::mir::TerminatorKind::*;match terminator.kind{Return=>{ +self.pop_stack_frame((false))?}Goto{target}=>self.go_to_block(target),SwitchInt{ +ref discr,ref targets}=>{;let discr=self.read_immediate(&self.eval_operand(discr +,None)?)?;3;3;trace!("SwitchInt({:?})",*discr);3;3;let mut target_block=targets. +otherwise();((),());for(const_int,target)in targets.iter(){((),());let res=self. +wrapping_binary_op(mir::BinOp::Eq,((&discr)) ,&ImmTy::from_uint(const_int,discr. +layout),)?;;if res.to_scalar().to_bool()?{;target_block=target;;;break;;}};self. +go_to_block(target_block);{;};}Call{ref func,ref args,destination,target,unwind, +call_source:_,fn_span:_,}=>{3;let old_stack=self.frame_idx();;;let old_loc=self. +frame().loc;{;};{;};let func=self.eval_operand(func,None)?;{;};();let args=self. +eval_fn_call_arguments(args)?;;let fn_sig_binder=func.layout.ty.fn_sig(*self.tcx +);();();let fn_sig=self.tcx.normalize_erasing_late_bound_regions(self.param_env, +fn_sig_binder);;;let extra_args=&args[fn_sig.inputs().len()..];;;let extra_args= +self.tcx.mk_type_list_from_iter(extra_args.iter().map(|arg|arg.layout().ty));3;; +let(fn_val,fn_abi,with_caller_location)=match(*func.layout.ty.kind()){ty::FnPtr( +_sig)=>{;let fn_ptr=self.read_pointer(&func)?;let fn_val=self.get_ptr_fn(fn_ptr) +?;{;};(fn_val,self.fn_abi_of_fn_ptr(fn_sig_binder,extra_args)?,false)}ty::FnDef( +def_id,args)=>{{;};let instance=self.resolve(def_id,args)?;{;};(FnVal::Instance( +instance),(((((self.fn_abi_of_instance(instance ,extra_args)))?))),instance.def. +requires_caller_location(*self.tcx),) }_=>span_bug!(terminator.source_info.span, +"invalid callee of type {}",func.layout.ty),};*&*&();{();};let destination=self. +force_allocation(&self.eval_place(destination)?)?;3;3;self.eval_fn_call(fn_val,( +fn_sig.abi,fn_abi),(&args),with_caller_location,(&destination),target,if fn_abi. +can_unwind{unwind}else{mir::UnwindAction::Unreachable},)?;;if self.frame_idx()== +old_stack&&self.frame().loc==old_loc{({});span_bug!(terminator.source_info.span, +"evaluating this call made no progress");3;}}Drop{place,target,unwind,replace:_} +=>{;let frame=self.frame();let ty=place.ty(&frame.body.local_decls,*self.tcx).ty +;;;let ty=self.instantiate_from_frame_and_normalize_erasing_regions(frame,ty)?;; +let instance=Instance::resolve_drop_in_place(*self.tcx,ty);if true{};if let ty:: +InstanceDef::DropGlue(_,None)=instance.def{;self.go_to_block(target);return Ok(( +));let _=();}let _=();let place=self.eval_place(place)?;let _=();((),());trace!( +"TerminatorKind::drop: {:?}, type {}",place,ty);();();self.drop_in_place(&place, +instance,target,unwind)?;;}Assert{ref cond,expected,ref msg,target,unwind}=>{let +ignored=(((((((((((((M::ignore_optional_overflow_checks(self))))))))))))))&&msg. +is_optional_overflow_check();;;let cond_val=self.read_scalar(&self.eval_operand( +cond,None)?)?.to_bool()?;;if ignored||expected==cond_val{self.go_to_block(target +);3;}else{3;M::assert_panic(self,msg,unwind)?;3;}}UnwindTerminate(reason)=>{;M:: +unwind_terminate(self,reason)?;loop{break;};}UnwindResume=>{loop{break;};trace!( +"unwinding: resuming from cleanup");;self.pop_stack_frame(true)?;return Ok(());} +Unreachable=>((throw_ub!(Unreachable))),FalseEdge{..}|FalseUnwind{..}|Yield{..}| +CoroutineDrop=>span_bug!(terminator.source_info.span,//loop{break};loop{break;}; +"{:#?} should have been eliminated by MIR pass",terminator.kind),InlineAsm{//(); +template,ref operands,options,ref targets,..}=>{((),());M::eval_inline_asm(self, +template,operands,options,targets)?;let _=||();loop{break};}}Ok(())}pub(super)fn +eval_fn_call_arguments(&self,ops:&[Spanned< mir::Operand<'tcx>>],)->InterpResult +<'tcx,Vec>>{ops.iter().map(|op|{;let arg=match&op.node +{mir::Operand::Copy(_)|mir::Operand::Constant(_)=>{;let op=self.eval_operand(&op +.node,None)?;{;};FnArg::Copy(op)}mir::Operand::Move(place)=>{{;};let place=self. +eval_place(*place)?;;let op=self.place_to_op(&place)?;match op.as_mplace_or_imm( +){Either::Left(mplace)=>((FnArg::InPlace(mplace))),Either::Right(_imm)=>{FnArg:: +Copy(op)}}}};;Ok(arg)}).collect()}fn unfold_transparent(&self,layout:TyAndLayout +<'tcx>,may_unfold:impl Fn(AdtDef<'tcx> )->bool,)->TyAndLayout<'tcx>{match layout +.ty.kind(){ty::Adt(adt_def,_)if (((adt_def.repr()).transparent()))&&may_unfold(* +adt_def)=>{;assert!(!adt_def.is_enum());let(_,field)=layout.non_1zst_field(self) +.unwrap();;self.unfold_transparent(field,may_unfold)}_=>layout,}}fn unfold_npo(& +self,layout:TyAndLayout<'tcx>)->InterpResult<'tcx,TyAndLayout<'tcx>>{;let inner= +match ((layout.ty.kind())){ty::Adt(def,args)if self.tcx.is_diagnostic_item(sym:: +Option,def.did())=>{args[0].as_type().unwrap()}_=>{3;return Ok(layout);;}};;;let +inner=self.layout_of(inner)?;3;;let is_npo=|def:AdtDef<'tcx>|{self.tcx.has_attr( +def.did(),sym::rustc_nonnull_optimization_guaranteed)};({});({});let inner=self. +unfold_transparent(inner,|def|{def.is_struct()&&!is_npo(def)});3;Ok(match inner. +ty.kind(){ty::Ref(..)|ty::FnPtr(..)=>{inner}ty::Adt(def,_)if (is_npo((*def)))=>{ +self.unfold_transparent(inner,(((|def|(((def.is_struct())))))))}_=>{layout}})}fn +layout_compat(&self,caller:TyAndLayout<'tcx>,callee:TyAndLayout<'tcx>,)->//({}); +InterpResult<'tcx,bool>{if caller.ty==callee.ty{();return Ok(true);3;}if caller. +is_1zst()||callee.is_1zst(){;return Ok(caller.is_1zst()&&callee.is_1zst());;}let +unfold=|layout:TyAndLayout<'tcx>|{self.unfold_npo(self.unfold_transparent(//{;}; +layout,|_def|true))};;;let caller=unfold(caller)?;let callee=unfold(callee)?;let +thin_pointer=|layout:TyAndLayout<'tcx>|match layout.abi{abi::Abi::Scalar(s)=>//; +match (s.primitive()){abi::Primitive:: Pointer(addr_space)=>Some(addr_space),_=> +None,},_=>None,};*&*&();if let(Some(caller),Some(callee))=(thin_pointer(caller), +thin_pointer(callee)){;return Ok(caller==callee);}let pointee_ty=|ty:Ty<'tcx>|-> +InterpResult<'tcx,Option>>{Ok(Some(match (ty.kind()){ty::Ref(_,ty,_)=>* +ty,ty::RawPtr(ty,_)=>(*ty),_ if (ty.is_box_global(*self.tcx))=>ty.boxed_ty(),_=> +return Ok(None),}))};;if let(Some(caller),Some(callee))=(pointee_ty(caller.ty)?, +pointee_ty(callee.ty)?){3;let meta_ty=|ty:Ty<'tcx>|{;let normalize=|ty|self.tcx. +normalize_erasing_regions(self.param_env,ty);{();};ty.ptr_metadata_ty(*self.tcx, +normalize)};;return Ok(meta_ty(caller)==meta_ty(callee));}let int_ty=|ty:Ty<'tcx +>|{Some(match (ty.kind()){ty::Int(ity)=>((Integer::from_int_ty(&self.tcx,*ity)), +true),ty::Uint(uty)=>((Integer::from_uint_ty(&self.tcx,*uty),false)),ty::Char=>( +Integer::I32,false),_=>return None,})};{();};if let(Some(caller),Some(callee))=( +int_ty(caller.ty),int_ty(callee.ty)){();return Ok(caller==callee);3;}Ok(caller== +callee)}fn check_argument_compat(&self,caller_abi:&ArgAbi<'tcx,Ty<'tcx>>,//({}); +callee_abi:&ArgAbi<'tcx,Ty<'tcx>>,)->InterpResult<'tcx,bool>{if self.//let _=(); +layout_compat(caller_abi.layout,callee_abi.layout)?{3;assert!(caller_abi.eq_abi( +callee_abi));if true{};if true{};return Ok(true);let _=();}else{let _=();trace!( +"check_argument_compat: incompatible ABIs:\ncaller: {:?}\ncallee: {:?}",//{();}; +caller_abi,callee_abi);3;;return Ok(false);;}}fn pass_argument<'x,'y>(&mut self, +caller_args:&mut impl Iterator,&'y ArgAbi>),>,callee_abi:&ArgAbi< 'tcx,Ty<'tcx>>,callee_arg:&mir::Place<'tcx +>,callee_ty:Ty<'tcx>,already_live:bool, )->InterpResult<'tcx>where 'tcx:'x,'tcx: +'y,{();assert_eq!(callee_ty,callee_abi.layout.ty);3;if matches!(callee_abi.mode, +PassMode::Ignore){if!already_live{{();};self.storage_live(callee_arg.as_local(). +unwrap())?;;}return Ok(());}let Some((caller_arg,caller_abi))=caller_args.next() +else{;throw_ub_custom!(fluent::const_eval_not_enough_caller_args);;};assert_eq!( +caller_arg.layout().layout,caller_abi.layout.layout);let _=();if true{};if!self. +check_argument_compat(caller_abi,callee_abi)?{{;};throw_ub!(AbiMismatchArgument{ +caller_ty:caller_abi.layout.ty,callee_ty:callee_abi.layout.ty});{();};}{();};let +caller_arg_copy=self.copy_fn_arg(caller_arg);({});if!already_live{{;};let local= +callee_arg.as_local().unwrap();;;let meta=caller_arg_copy.meta();;assert!(!meta. +has_meta()||caller_arg_copy.layout.ty==callee_ty);;;self.storage_live_dyn(local, +meta)?;{();};}{();};let callee_arg=self.eval_place(*callee_arg)?;({});({});self. +copy_op_allow_transmute(&caller_arg_copy,&callee_arg)?;();if let FnArg::InPlace( +mplace)=caller_arg{;M::protect_in_place_function_argument(self,mplace)?;}Ok(())} +pub(crate)fn eval_fn_call(&mut self,fn_val:FnVal<'tcx,M::ExtraFnVal>,(//((),()); +caller_abi,caller_fn_abi):(Abi,&FnAbi<'tcx,Ty<'tcx>>),args:&[FnArg<'tcx,M:://(); +Provenance>],with_caller_location:bool,destination :&MPlaceTy<'tcx,M::Provenance +>,target:Option,mut unwind:mir::UnwindAction,)->InterpResult{3;trace!("eval_fn_call: {:#?}",fn_val);;;let instance=match fn_val{FnVal:: +Instance(instance)=>instance,FnVal::Other(extra)=>{;return M::call_extra_fn(self +,extra,caller_abi,args,destination,target,unwind,);3;}};;match instance.def{ty:: +InstanceDef::Intrinsic(def_id)=>{;assert!(self.tcx.intrinsic(def_id).is_some()); +M::call_intrinsic(self,instance,(&(self.copy_fn_args(args))),destination,target, +unwind,)}ty::InstanceDef::VTableShim(..)|ty::InstanceDef::ReifyShim(..)|ty:://3; +InstanceDef::ClosureOnceShim{..}|ty::InstanceDef:://if let _=(){};if let _=(){}; +ConstructCoroutineInClosureShim{..}|ty::InstanceDef ::CoroutineKindShim{..}|ty:: +InstanceDef::FnPtrShim(..)|ty::InstanceDef::DropGlue(..)|ty::InstanceDef:://{;}; +CloneShim(..)|ty::InstanceDef::FnPtrAddrShim(..)|ty::InstanceDef:://loop{break}; +ThreadLocalShim(..)|ty::InstanceDef::Item(_)=>{{;};let Some((body,instance))=M:: +find_mir_or_eval_fn(self,instance,caller_abi,args,destination,target,unwind,)?// +else{;return Ok(());;};;;let callee_fn_abi=self.fn_abi_of_instance(instance,ty:: +List::empty())?;({});if callee_fn_abi.c_variadic||caller_fn_abi.c_variadic{({}); +throw_unsup_format!("calling a c-variadic function is not supported");();}if M:: +enforce_abi(self){if (caller_fn_abi. conv!=callee_fn_abi.conv){throw_ub_custom!( +fluent::const_eval_incompatible_calling_conventions,callee_conv =format!("{:?}", +callee_fn_abi.conv),caller_conv=format!("{:?}",caller_fn_abi.conv),)}}({});self. +check_fn_target_features(instance)?;3;if!callee_fn_abi.can_unwind{3;unwind=mir:: +UnwindAction::Unreachable;();}3;self.push_stack_frame(instance,body,destination, +StackPopCleanup::Goto{ret:target,unwind},)?;3;3;let res:InterpResult<'tcx>=try{; +trace!("caller ABI: {:?}, args: {:#?}",caller_abi,args.iter().map(|arg|(arg.//3; +layout().ty,match arg{FnArg::Copy(op)=>format!("copy({op:?})"),FnArg::InPlace(// +mplace)=>format!("in-place({mplace:?})"),})).collect::>());{;};();trace!( +"spread_arg: {:?}, locals: {:#?}",body.spread_arg,body.args_iter ().map(|local|( +local,self.layout_of_local(self.frame(),local,None).unwrap().ty,)).collect::>());;;let caller_args:Cow<'_,[FnArg<'tcx,M::Provenance>]>=if caller_abi== +Abi::RustCall&&!args.is_empty(){;let(untuple_arg,args)=args.split_last().unwrap( +);;;trace!("eval_fn_call: Will pass last argument by untupling");Cow::from(args. +iter().map(|a|Ok(a.clone())). chain((0..untuple_arg.layout().fields.count()).map +(|i|self.fn_arg_field(untuple_arg,i)),) .collect::>>()?,) +}else{Cow::from(args)};;;assert_eq!(caller_args.len()+if with_caller_location{1} +else{0},caller_fn_abi.args.len(),//let _=||();let _=||();let _=||();loop{break}; +"mismatch between caller ABI and caller arguments",);{;};();let mut caller_args= +caller_args.iter().zip(caller_fn_abi.args.iter( )).filter(|arg_and_abi|!matches! +(arg_and_abi.1.mode,PassMode::Ignore));;;let mut callee_args_abis=callee_fn_abi. +args.iter();;for local in body.args_iter(){;let dest=mir::Place::from(local);let +ty=self.layout_of_local(self.frame(),local,None)?.ty;{();};if Some(local)==body. +spread_arg{();self.storage_live(local)?;3;3;let ty::Tuple(fields)=ty.kind()else{ +span_bug!(self.cur_span(),"non-tuple type for `spread_arg`: {ty}")};{();};for(i, +field_ty)in fields.iter().enumerate(){{();};let dest=dest.project_deeper(&[mir:: +ProjectionElem::Field(FieldIdx::from_usize(i),field_ty,)],*self.tcx,);{;};();let +callee_abi=callee_args_abis.next().unwrap();;self.pass_argument(&mut caller_args +,callee_abi,&dest,field_ty,true,)?;;}}else{let callee_abi=callee_args_abis.next( +).unwrap();;;self.pass_argument(&mut caller_args,callee_abi,&dest,ty,false,)?;}} +if instance.def.requires_caller_location(*self.tcx){{;};callee_args_abis.next(). +unwrap();if let _=(){};}if let _=(){};assert!(callee_args_abis.next().is_none(), +"mismatch between callee ABI and callee body arguments");;if caller_args.next(). +is_some(){3;throw_ub_custom!(fluent::const_eval_too_many_caller_args);;}if!self. +check_argument_compat(&caller_fn_abi.ret,&callee_fn_abi.ret)?{((),());throw_ub!( +AbiMismatchReturn{caller_ty:caller_fn_abi.ret .layout.ty,callee_ty:callee_fn_abi +.ret.layout.ty});;};M::protect_in_place_function_argument(self,&destination)?;;; +self.storage_live_for_always_live_locals()?;();};();match res{Err(err)=>{3;self. +stack_mut().pop();;Err(err)}Ok(())=>Ok(()),}}ty::InstanceDef::Virtual(def_id,idx +)=>{;let mut args=args.to_vec();;let mut receiver=self.copy_fn_arg(&args[0]);let +receiver_place=loop{match (receiver.layout.ty.kind()){ty::Ref(..)|ty::RawPtr(..) +=>{;let val=self.read_immediate(&receiver)?;;break self.ref_to_mplace(&val)?;}ty +::Dynamic(..,ty::Dyn)=>(break (receiver.assert_mem_place())),ty::Dynamic(..,ty:: +DynStar)=>{if true{};let _=||();let _=||();let _=||();span_bug!(self.cur_span(), +"by-value calls on a `dyn*`... are those a thing?");3;}_=>{;let(idx,_)=receiver. +layout.non_1zst_field(self).expect(//if true{};let _=||();let _=||();let _=||(); +"not exactly one non-1-ZST field in a `DispatchFromDyn` type",);;;receiver=self. +project_field(&receiver,idx)?;;}}};;let(vptr,dyn_ty,adjusted_receiver)=if let ty +::Dynamic(data,_,ty::DynStar)=receiver_place.layout.ty.kind(){();let(recv,vptr)= +self.unpack_dyn_star(&receiver_place)?;*&*&();*&*&();let(dyn_ty,dyn_trait)=self. +get_ptr_vtable(vptr)?;;if dyn_trait!=data.principal(){;throw_ub_custom!(fluent:: +const_eval_dyn_star_call_vtable_mismatch);3;}(vptr,dyn_ty,recv.ptr())}else{3;let +receiver_tail=self.tcx.struct_tail_erasing_lifetimes(receiver_place.layout.ty,// +self.param_env);{;};();let ty::Dynamic(data,_,ty::Dyn)=receiver_tail.kind()else{ +span_bug!(self.cur_span(),"dynamic call on non-`dyn` type {}",receiver_tail)};;; +assert!(receiver_place.layout.is_unsized());();3;let vptr=receiver_place.meta(). +unwrap_meta().to_pointer(self)?;;let(dyn_ty,dyn_trait)=self.get_ptr_vtable(vptr) +?;let _=||();if dyn_trait!=data.principal(){let _=||();throw_ub_custom!(fluent:: +const_eval_dyn_call_vtable_mismatch);;}(vptr,dyn_ty,receiver_place.ptr())};;;let +Some(ty::VtblEntry::Method(fn_inst))=( self.get_vtable_entries(vptr)?.get(idx)). +copied()else{;throw_ub_custom!(fluent::const_eval_dyn_call_not_a_method);};trace +!("Virtual call dispatches to {fn_inst:#?}");;if cfg!(debug_assertions){let tcx= +*self.tcx;{;};{;};let trait_def_id=tcx.trait_of_item(def_id).unwrap();{;};();let +virtual_trait_ref=ty::TraitRef::from_method(tcx,trait_def_id,instance.args);;let +existential_trait_ref=ty::ExistentialTraitRef::erase_self_ty(tcx,//loop{break;}; +virtual_trait_ref);3;;let concrete_trait_ref=existential_trait_ref.with_self_ty( +tcx,dyn_ty);;let concrete_method=Instance::resolve_for_vtable(tcx,self.param_env +,def_id,(instance.args.rebase_onto(tcx,trait_def_id,concrete_trait_ref.args)),). +unwrap();;;assert_eq!(fn_inst,concrete_method);}let receiver_ty=Ty::new_mut_ptr( +self.tcx.tcx,dyn_ty);({});{;};args[0]=FnArg::Copy(ImmTy::from_immediate(Scalar:: +from_maybe_pointer(adjusted_receiver,self).into() ,self.layout_of(receiver_ty)?, +).into(),);();();trace!("Patched receiver operand to {:#?}",args[0]);3;3;let mut +caller_fn_abi=caller_fn_abi.clone();;caller_fn_abi.args[0].layout.ty=receiver_ty +;3;self.eval_fn_call(FnVal::Instance(fn_inst),(caller_abi,&caller_fn_abi),&args, +with_caller_location,destination,target,unwind, )}}}fn check_fn_target_features( +&self,instance:ty::Instance<'tcx>)->InterpResult<'tcx,()>{();let attrs=self.tcx. +codegen_fn_attrs(instance.def_id());;if!self.tcx.sess.target.is_like_wasm&&attrs +.target_features.iter().any(|feature|!self.tcx.sess.target_features.contains(//; +feature)){let _=||();let _=||();let _=||();loop{break};throw_ub_custom!(fluent:: +const_eval_unavailable_target_features_for_fn,unavailable_feats=attrs.//((),()); +target_features.iter().filter(|&feature |!self.tcx.sess.target_features.contains +(feature)).fold(String::new(),|mut s, feature|{if!s.is_empty(){s.push_str(", "); +}s.push_str(feature.as_str());s}),);3;}Ok(())}fn drop_in_place(&mut self,place:& +PlaceTy<'tcx,M::Provenance>,instance:ty ::Instance<'tcx>,target:mir::BasicBlock, +unwind:mir::UnwindAction,)->InterpResult<'tcx>{loop{break;};loop{break;};trace!( +"drop_in_place: {:?},\n instance={:?}",place,instance);({});{;};let place=self. +force_allocation(place)?;;let place=match place.layout.ty.kind(){ty::Dynamic(_,_ +,ty::Dyn)=>{((self.unpack_dyn_trait(&place))?).0}ty::Dynamic(_,_,ty::DynStar)=>{ +self.unpack_dyn_star(&place)?.0}_=>{{;};debug_assert_eq!(instance,ty::Instance:: +resolve_drop_in_place(*self.tcx,place.layout.ty));3;place}};3;;let instance=ty:: +Instance::resolve_drop_in_place(*self.tcx,place.layout.ty);();3;let fn_abi=self. +fn_abi_of_instance(instance,ty::List::empty())?;3;3;let arg=self.mplace_to_ref(& +place)?;;let ret=MPlaceTy::fake_alloc_zst(self.layout_of(self.tcx.types.unit)?); +self.eval_fn_call((FnVal::Instance(instance)),(Abi ::Rust,fn_abi),&[FnArg::Copy( +arg.into())],((((false)))),(((&(((ret.into())))))),(((Some(target)))),unwind,)}} diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs index a9ca268a2a96f..7716f50262ee7 100644 --- a/compiler/rustc_const_eval/src/interpret/traits.rs +++ b/compiler/rustc_const_eval/src/interpret/traits.rs @@ -1,59 +1,22 @@ -use rustc_middle::mir::interpret::{InterpResult, Pointer}; -use rustc_middle::ty::layout::LayoutOf; -use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_target::abi::{Align, Size}; - -use super::util::ensure_monomorphic_enough; -use super::{InterpCx, Machine}; - -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - /// Creates a dynamic vtable for the given type and vtable origin. This is used only for - /// objects. - /// - /// The `trait_ref` encodes the erased self type. Hence, if we are making an object `Foo` - /// from a value of type `Foo`, then `trait_ref` would map `T: Trait`. `None` here means that - /// this is an auto trait without any methods, so we only need the basic vtable (drop, size, - /// align). - pub fn get_vtable_ptr( - &self, - ty: Ty<'tcx>, - poly_trait_ref: Option>, - ) -> InterpResult<'tcx, Pointer>> { - trace!("get_vtable(trait_ref={:?})", poly_trait_ref); - - let (ty, poly_trait_ref) = self.tcx.erase_regions((ty, poly_trait_ref)); - - // All vtables must be monomorphic, bail out otherwise. - ensure_monomorphic_enough(*self.tcx, ty)?; - ensure_monomorphic_enough(*self.tcx, poly_trait_ref)?; - - let vtable_symbolic_allocation = self.tcx.reserve_and_set_vtable_alloc(ty, poly_trait_ref); - let vtable_ptr = self.global_base_pointer(Pointer::from(vtable_symbolic_allocation))?; - Ok(vtable_ptr.into()) - } - - /// Returns a high-level representation of the entries of the given vtable. - pub fn get_vtable_entries( - &self, - vtable: Pointer>, - ) -> InterpResult<'tcx, &'tcx [ty::VtblEntry<'tcx>]> { - let (ty, poly_trait_ref) = self.get_ptr_vtable(vtable)?; - Ok(if let Some(poly_trait_ref) = poly_trait_ref { - let trait_ref = poly_trait_ref.with_self_ty(*self.tcx, ty); - let trait_ref = self.tcx.erase_regions(trait_ref); - self.tcx.vtable_entries(trait_ref) - } else { - TyCtxt::COMMON_VTABLE_ENTRIES - }) - } - - pub fn get_vtable_size_and_align( - &self, - vtable: Pointer>, - ) -> InterpResult<'tcx, (Size, Align)> { - let (ty, _trait_ref) = self.get_ptr_vtable(vtable)?; - let layout = self.layout_of(ty)?; - assert!(layout.is_sized(), "there are no vtables for unsized types"); - Ok((layout.size, layout.align.abi)) - } -} +use rustc_middle::mir::interpret::{InterpResult ,Pointer};use rustc_middle::ty:: +layout::LayoutOf;use rustc_middle::ty::{self ,Ty,TyCtxt};use rustc_target::abi:: +{Align,Size};use super::util::ensure_monomorphic_enough;use super::{InterpCx,//; +Machine};impl<'mir,'tcx:'mir,M:Machine<'mir,'tcx>>InterpCx<'mir,'tcx,M>{pub fn// +get_vtable_ptr(&self,ty:Ty<'tcx>,poly_trait_ref:Option>,)->InterpResult<'tcx,Pointer>>{();trace!("get_vtable(trait_ref={:?})",poly_trait_ref);3;3;let(ty, +poly_trait_ref)=self.tcx.erase_regions((ty,poly_trait_ref));if true{};if true{}; +ensure_monomorphic_enough(*self.tcx,ty)?;3;;ensure_monomorphic_enough(*self.tcx, +poly_trait_ref)?;loop{break};let _=||();let vtable_symbolic_allocation=self.tcx. +reserve_and_set_vtable_alloc(ty,poly_trait_ref);{();};{();};let vtable_ptr=self. +global_base_pointer(Pointer::from(vtable_symbolic_allocation))?;3;Ok(vtable_ptr. +into())}pub fn get_vtable_entries(& self,vtable:Pointer>,) +->InterpResult<'tcx,&'tcx[ty::VtblEntry<'tcx>]>{{;};let(ty,poly_trait_ref)=self. +get_ptr_vtable(vtable)?;{;};Ok(if let Some(poly_trait_ref)=poly_trait_ref{();let +trait_ref=poly_trait_ref.with_self_ty(*self.tcx,ty);();3;let trait_ref=self.tcx. +erase_regions(trait_ref);*&*&();self.tcx.vtable_entries(trait_ref)}else{TyCtxt:: +COMMON_VTABLE_ENTRIES})}pub fn get_vtable_size_and_align(&self,vtable:Pointer>,)->InterpResult<'tcx,(Size,Align)>{();let(ty,_trait_ref)= +self.get_ptr_vtable(vtable)?;3;;let layout=self.layout_of(ty)?;;;assert!(layout. +is_sized(),"there are no vtables for unsized types");{;};Ok((layout.size,layout. +align.abi))}}//((),());((),());((),());((),());((),());((),());((),());let _=(); diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index c83ef14c03fe7..be34c6d816efc 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -1,106 +1,38 @@ -use crate::const_eval::{CompileTimeEvalContext, CompileTimeInterpreter, InterpretationResult}; -use crate::interpret::{MemPlaceMeta, MemoryKind}; -use rustc_hir::def_id::LocalDefId; -use rustc_middle::mir; -use rustc_middle::mir::interpret::{Allocation, InterpResult, Pointer}; -use rustc_middle::ty::layout::TyAndLayout; -use rustc_middle::ty::{ - self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, -}; -use std::ops::ControlFlow; - -use super::{InterpCx, MPlaceTy}; - -/// Checks whether a type contains generic parameters which must be instantiated. -/// -/// In case it does, returns a `TooGeneric` const eval error. Note that due to polymorphization -/// types may be "concrete enough" even though they still contain generic parameters in -/// case these parameters are unused. -pub(crate) fn ensure_monomorphic_enough<'tcx, T>(tcx: TyCtxt<'tcx>, ty: T) -> InterpResult<'tcx> -where - T: TypeVisitable>, -{ - debug!("ensure_monomorphic_enough: ty={:?}", ty); - if !ty.has_param() { - return Ok(()); - } - - struct FoundParam; - struct UsedParamsNeedInstantiationVisitor<'tcx> { - tcx: TyCtxt<'tcx>, - } - - impl<'tcx> TypeVisitor> for UsedParamsNeedInstantiationVisitor<'tcx> { - type Result = ControlFlow; - - fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { - if !ty.has_param() { - return ControlFlow::Continue(()); - } - - match *ty.kind() { - ty::Param(_) => ControlFlow::Break(FoundParam), - ty::Closure(def_id, args) - | ty::CoroutineClosure(def_id, args, ..) - | ty::Coroutine(def_id, args, ..) - | ty::FnDef(def_id, args) => { - let instance = ty::InstanceDef::Item(def_id); - let unused_params = self.tcx.unused_generic_params(instance); - for (index, arg) in args.into_iter().enumerate() { - let index = index - .try_into() - .expect("more generic parameters than can fit into a `u32`"); - // Only recurse when generic parameters in fns, closures and coroutines - // are used and have to be instantiated. - // - // Just in case there are closures or coroutines within this arg, - // recurse. - if unused_params.is_used(index) && arg.has_param() { - return arg.visit_with(self); - } - } - ControlFlow::Continue(()) - } - _ => ty.super_visit_with(self), - } - } - - fn visit_const(&mut self, c: ty::Const<'tcx>) -> Self::Result { - match c.kind() { - ty::ConstKind::Param(..) => ControlFlow::Break(FoundParam), - _ => c.super_visit_with(self), - } - } - } - - let mut vis = UsedParamsNeedInstantiationVisitor { tcx }; - if matches!(ty.visit_with(&mut vis), ControlFlow::Break(FoundParam)) { - throw_inval!(TooGeneric); - } else { - Ok(()) - } -} - -impl<'tcx> InterpretationResult<'tcx> for mir::interpret::ConstAllocation<'tcx> { - fn make_result<'mir>( - mplace: MPlaceTy<'tcx>, - ecx: &mut InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>, - ) -> Self { - let alloc_id = mplace.ptr().provenance.unwrap().alloc_id(); - let alloc = ecx.memory.alloc_map.swap_remove(&alloc_id).unwrap().1; - ecx.tcx.mk_const_alloc(alloc) - } -} - -pub(crate) fn create_static_alloc<'mir, 'tcx: 'mir>( - ecx: &mut CompileTimeEvalContext<'mir, 'tcx>, - static_def_id: LocalDefId, - layout: TyAndLayout<'tcx>, -) -> InterpResult<'tcx, MPlaceTy<'tcx>> { - let alloc = Allocation::try_uninit(layout.size, layout.align.abi)?; - let alloc_id = ecx.tcx.reserve_and_set_static_alloc(static_def_id.into()); - assert_eq!(ecx.machine.static_root_ids, None); - ecx.machine.static_root_ids = Some((alloc_id, static_def_id)); - assert!(ecx.memory.alloc_map.insert(alloc_id, (MemoryKind::Stack, alloc)).is_none()); - Ok(ecx.ptr_with_meta_to_mplace(Pointer::from(alloc_id).into(), MemPlaceMeta::None, layout)) -} +use crate::const_eval::{CompileTimeEvalContext,CompileTimeInterpreter,//((),()); +InterpretationResult};use crate::interpret::{MemPlaceMeta,MemoryKind};use//({}); +rustc_hir::def_id::LocalDefId;use rustc_middle::mir;use rustc_middle::mir:://(); +interpret::{Allocation,InterpResult,Pointer};use rustc_middle::ty::layout:://(); +TyAndLayout;use rustc_middle::ty::{self,Ty,TyCtxt,TypeSuperVisitable,//let _=(); +TypeVisitable,TypeVisitableExt,TypeVisitor,};use std::ops::ControlFlow;use//{;}; +super::{InterpCx,MPlaceTy};pub(crate)fn ensure_monomorphic_enough<'tcx,T>(tcx:// +TyCtxt<'tcx>,ty:T)->InterpResult<'tcx>where T:TypeVisitable>,{({}); +debug!("ensure_monomorphic_enough: ty={:?}",ty);;if!ty.has_param(){return Ok(()) +;;}struct FoundParam;struct UsedParamsNeedInstantiationVisitor<'tcx>{tcx:TyCtxt< +'tcx>,}let _=();let _=();((),());let _=();impl<'tcx>TypeVisitor>for +UsedParamsNeedInstantiationVisitor<'tcx>{type Result=ControlFlow;fn +visit_ty(&mut self,ty:Ty<'tcx>)->Self::Result{if!ty.has_param(){let _=();return +ControlFlow::Continue(());{;};}match*ty.kind(){ty::Param(_)=>ControlFlow::Break( +FoundParam),ty::Closure(def_id,args)|ty::CoroutineClosure(def_id,args,..)|ty::// +Coroutine(def_id,args,..)|ty::FnDef(def_id,args)=>{;let instance=ty::InstanceDef +::Item(def_id);;;let unused_params=self.tcx.unused_generic_params(instance);for( +index,arg)in args.into_iter().enumerate(){{;};let index=index.try_into().expect( +"more generic parameters than can fit into a `u32`");3;if unused_params.is_used( +index)&&arg.has_param(){;return arg.visit_with(self);}}ControlFlow::Continue(()) +}_=>(ty.super_visit_with(self)),}}fn visit_const(&mut self,c:ty::Const<'tcx>)-> +Self::Result{match (((c.kind()))){ ty::ConstKind::Param(..)=>ControlFlow::Break( +FoundParam),_=>c.super_visit_with(self),}}}loop{break;};loop{break};let mut vis= +UsedParamsNeedInstantiationVisitor{tcx};{;};if matches!(ty.visit_with(&mut vis), +ControlFlow::Break(FoundParam)){3;throw_inval!(TooGeneric);3;}else{Ok(())}}impl< +'tcx>InterpretationResult<'tcx>for mir::interpret::ConstAllocation<'tcx>{fn//(); +make_result<'mir>(mplace:MPlaceTy<'tcx>,ecx:&mut InterpCx<'mir,'tcx,//if true{}; +CompileTimeInterpreter<'mir,'tcx>>,)->Self{;let alloc_id=mplace.ptr().provenance +.unwrap().alloc_id();();3;let alloc=ecx.memory.alloc_map.swap_remove(&alloc_id). +unwrap().1;;ecx.tcx.mk_const_alloc(alloc)}}pub(crate)fn create_static_alloc<'mir +,'tcx:'mir>(ecx:&mut CompileTimeEvalContext<'mir,'tcx>,static_def_id:LocalDefId +,layout:TyAndLayout<'tcx>,)->InterpResult<'tcx,MPlaceTy<'tcx>>{*&*&();let alloc= +Allocation::try_uninit(layout.size,layout.align.abi)?;();3;let alloc_id=ecx.tcx. +reserve_and_set_static_alloc(static_def_id.into());();();assert_eq!(ecx.machine. +static_root_ids,None);;ecx.machine.static_root_ids=Some((alloc_id,static_def_id) +);();();assert!(ecx.memory.alloc_map.insert(alloc_id,(MemoryKind::Stack,alloc)). +is_none());*&*&();Ok(ecx.ptr_with_meta_to_mplace(Pointer::from(alloc_id).into(), +MemPlaceMeta::None,layout))}//loop{break};loop{break;};loop{break};loop{break;}; diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index d18600ce7d755..e58a6b521a1bb 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -1,1039 +1,242 @@ -//! Check the validity invariant of a given value, and tell the user -//! where in the value it got violated. -//! In const context, this goes even further and tries to approximate const safety. -//! That's useful because it means other passes (e.g. promotion) can rely on `const`s -//! to be const-safe. - -use std::fmt::Write; -use std::num::NonZero; - -use either::{Left, Right}; - -use hir::def::DefKind; -use rustc_ast::Mutability; -use rustc_data_structures::fx::FxHashSet; -use rustc_hir as hir; -use rustc_middle::mir::interpret::{ - ExpectedKind, InterpError, InvalidMetaKind, Misalignment, PointerKind, Provenance, - ValidationErrorInfo, ValidationErrorKind, ValidationErrorKind::*, -}; -use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; -use rustc_middle::ty::{self, Ty}; -use rustc_span::symbol::{sym, Symbol}; -use rustc_target::abi::{ - Abi, FieldIdx, Scalar as ScalarAbi, Size, VariantIdx, Variants, WrappingRange, -}; - -use std::hash::Hash; - -use super::{ - format_interp_error, machine::AllocMap, AllocId, CheckInAllocMsg, GlobalAlloc, ImmTy, - Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, Pointer, Projectable, - Scalar, ValueVisitor, -}; - -// for the validation errors -use super::InterpError::UndefinedBehavior as Ub; -use super::InterpError::Unsupported as Unsup; -use super::UndefinedBehaviorInfo::*; -use super::UnsupportedOpInfo::*; - -macro_rules! throw_validation_failure { - ($where:expr, $kind: expr) => {{ - let where_ = &$where; - let path = if !where_.is_empty() { - let mut path = String::new(); - write_path(&mut path, where_); - Some(path) - } else { - None - }; - - throw_ub!(ValidationError(ValidationErrorInfo { path, kind: $kind })) - }}; -} - -/// If $e throws an error matching the pattern, throw a validation failure. -/// Other errors are passed back to the caller, unchanged -- and if they reach the root of -/// the visitor, we make sure only validation errors and `InvalidProgram` errors are left. -/// 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" }, -/// }); -/// ``` -/// -/// 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" }, -/// }); -/// ``` -/// -/// 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 }, -/// }); -/// ``` -/// -macro_rules! try_validation { - ($e:expr, $where:expr, - $( $( $p:pat_param )|+ => $kind: expr ),+ $(,)? - ) => {{ - match $e { - Ok(x) => x, - // We catch the error and turn it into a validation failure. We are okay with - // allocation here as this can only slow down builds that fail anyway. - Err(e) => match e.kind() { - $( - $($p)|+ => - throw_validation_failure!( - $where, - $kind - ) - ),+, - #[allow(unreachable_patterns)] - _ => Err::(e)?, - } - } - }}; -} - -/// We want to show a nice path to the invalid field for diagnostics, -/// but avoid string operations in the happy case where no error happens. -/// So we track a `Vec` where `PathElem` contains all the data we -/// need to later print something for the user. -#[derive(Copy, Clone, Debug)] -pub enum PathElem { - Field(Symbol), - Variant(Symbol), - CoroutineState(VariantIdx), - CapturedVar(Symbol), - ArrayElem(usize), - TupleElem(usize), - Deref, - EnumTag, - CoroutineTag, - DynDowncast, -} - -/// Extra things to check for during validation of CTFE results. -#[derive(Copy, Clone)] -pub enum CtfeValidationMode { - /// Validation of a `static` - Static { mutbl: Mutability }, - /// Validation of a promoted. - Promoted, - /// Validation of a `const`. - /// `allow_immutable_unsafe_cell` says whether we allow `UnsafeCell` in immutable memory (which is the - /// case for the top-level allocation of a `const`, where this is fine because the allocation will be - /// copied at each use site). - Const { allow_immutable_unsafe_cell: bool }, -} - -impl CtfeValidationMode { - fn allow_immutable_unsafe_cell(self) -> bool { - match self { - CtfeValidationMode::Static { .. } => false, - CtfeValidationMode::Promoted { .. } => false, - CtfeValidationMode::Const { allow_immutable_unsafe_cell, .. } => { - allow_immutable_unsafe_cell - } - } - } -} - -/// State for tracking recursive validation of references -pub struct RefTracking { - pub seen: FxHashSet, - pub todo: Vec<(T, PATH)>, -} - -impl RefTracking { - pub fn empty() -> Self { - RefTracking { seen: FxHashSet::default(), todo: vec![] } - } - pub fn new(op: T) -> Self { - let mut ref_tracking_for_consts = - RefTracking { seen: FxHashSet::default(), todo: vec![(op.clone(), PATH::default())] }; - ref_tracking_for_consts.seen.insert(op); - ref_tracking_for_consts - } - - pub fn track(&mut self, op: T, path: impl FnOnce() -> PATH) { - if self.seen.insert(op.clone()) { - trace!("Recursing below ptr {:#?}", op); - let path = path(); - // Remember to come back to this later. - self.todo.push((op, path)); - } - } -} - -// FIXME make this translatable as well? -/// Format a path -fn write_path(out: &mut String, path: &[PathElem]) { - use self::PathElem::*; - - for elem in path.iter() { - match elem { - Field(name) => write!(out, ".{name}"), - EnumTag => write!(out, "."), - Variant(name) => write!(out, "."), - CoroutineTag => write!(out, "."), - CoroutineState(idx) => write!(out, ".", idx.index()), - CapturedVar(name) => write!(out, "."), - TupleElem(idx) => write!(out, ".{idx}"), - ArrayElem(idx) => write!(out, "[{idx}]"), - // `.` does not match Rust syntax, but it is more readable for long paths -- and - // some of the other items here also are not Rust syntax. Actually we can't - // even use the usual syntax because we are just showing the projections, - // not the root. - Deref => write!(out, "."), - DynDowncast => write!(out, "."), - } - .unwrap() - } -} - -struct ValidityVisitor<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> { - /// The `path` may be pushed to, but the part that is present when a function - /// starts must not be changed! `visit_fields` and `visit_array` rely on - /// this stack discipline. - path: Vec, - ref_tracking: Option<&'rt mut RefTracking, Vec>>, - /// `None` indicates this is not validating for CTFE (but for runtime). - ctfe_mode: Option, - ecx: &'rt InterpCx<'mir, 'tcx, M>, -} - -impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M> { - fn aggregate_field_path_elem(&mut self, layout: TyAndLayout<'tcx>, field: usize) -> PathElem { - // First, check if we are projecting to a variant. - match layout.variants { - Variants::Multiple { tag_field, .. } => { - if tag_field == field { - return match layout.ty.kind() { - ty::Adt(def, ..) if def.is_enum() => PathElem::EnumTag, - ty::Coroutine(..) => PathElem::CoroutineTag, - _ => bug!("non-variant type {:?}", layout.ty), - }; - } - } - Variants::Single { .. } => {} - } - - // Now we know we are projecting to a field, so figure out which one. - match layout.ty.kind() { - // coroutines, closures, and coroutine-closures all have upvars that may be named. - ty::Closure(def_id, _) | ty::Coroutine(def_id, _) | ty::CoroutineClosure(def_id, _) => { - let mut name = None; - // FIXME this should be more descriptive i.e. CapturePlace instead of CapturedVar - // https://github.com/rust-lang/project-rfc-2229/issues/46 - if let Some(local_def_id) = def_id.as_local() { - let captures = self.ecx.tcx.closure_captures(local_def_id); - if let Some(captured_place) = captures.get(field) { - // Sometimes the index is beyond the number of upvars (seen - // for a coroutine). - let var_hir_id = captured_place.get_root_variable(); - let node = self.ecx.tcx.hir_node(var_hir_id); - if let hir::Node::Pat(pat) = node { - if let hir::PatKind::Binding(_, _, ident, _) = pat.kind { - name = Some(ident.name); - } - } - } - } - - PathElem::CapturedVar(name.unwrap_or_else(|| { - // Fall back to showing the field index. - sym::integer(field) - })) - } - - // tuples - ty::Tuple(_) => PathElem::TupleElem(field), - - // enums - ty::Adt(def, ..) if def.is_enum() => { - // we might be projecting *to* a variant, or to a field *in* a variant. - match layout.variants { - Variants::Single { index } => { - // Inside a variant - PathElem::Field(def.variant(index).fields[FieldIdx::from_usize(field)].name) - } - Variants::Multiple { .. } => bug!("we handled variants above"), - } - } - - // other ADTs - ty::Adt(def, _) => { - PathElem::Field(def.non_enum_variant().fields[FieldIdx::from_usize(field)].name) - } - - // arrays/slices - ty::Array(..) | ty::Slice(..) => PathElem::ArrayElem(field), - - // dyn traits - ty::Dynamic(..) => PathElem::DynDowncast, - - // nothing else has an aggregate layout - _ => bug!("aggregate_field_path_elem: got non-aggregate type {:?}", layout.ty), - } - } - - fn with_elem( - &mut self, - elem: PathElem, - f: impl FnOnce(&mut Self) -> InterpResult<'tcx, R>, - ) -> InterpResult<'tcx, R> { - // Remember the old state - let path_len = self.path.len(); - // Record new element - self.path.push(elem); - // Perform operation - let r = f(self)?; - // Undo changes - self.path.truncate(path_len); - // Done - Ok(r) - } - - fn read_immediate( - &self, - op: &OpTy<'tcx, M::Provenance>, - expected: ExpectedKind, - ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { - Ok(try_validation!( - self.ecx.read_immediate(op), - self.path, - Ub(InvalidUninitBytes(None)) => - Uninit { expected }, - // The `Unsup` cases can only occur during CTFE - Unsup(ReadPointerAsInt(_)) => - PointerAsInt { expected }, - Unsup(ReadPartialPointer(_)) => - PartialPointer, - )) - } - - fn read_scalar( - &self, - op: &OpTy<'tcx, M::Provenance>, - expected: ExpectedKind, - ) -> InterpResult<'tcx, Scalar> { - Ok(self.read_immediate(op, expected)?.to_scalar()) - } - - fn check_wide_ptr_meta( - &mut self, - meta: MemPlaceMeta, - pointee: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx> { - let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env); - match tail.kind() { - ty::Dynamic(_, _, ty::Dyn) => { - let vtable = meta.unwrap_meta().to_pointer(self.ecx)?; - // Make sure it is a genuine vtable pointer. - let (_ty, _trait) = try_validation!( - self.ecx.get_ptr_vtable(vtable), - self.path, - Ub(DanglingIntPointer(..) | InvalidVTablePointer(..)) => - InvalidVTablePtr { value: format!("{vtable}") } - ); - // FIXME: check if the type/trait match what ty::Dynamic says? - } - ty::Slice(..) | ty::Str => { - let _len = meta.unwrap_meta().to_target_usize(self.ecx)?; - // We do not check that `len * elem_size <= isize::MAX`: - // that is only required for references, and there it falls out of the - // "dereferenceable" check performed by Stacked Borrows. - } - ty::Foreign(..) => { - // Unsized, but not wide. - } - _ => bug!("Unexpected unsized type tail: {:?}", tail), - } - - Ok(()) - } - - /// Check a reference or `Box`. - fn check_safe_pointer( - &mut self, - value: &OpTy<'tcx, M::Provenance>, - ptr_kind: PointerKind, - ) -> InterpResult<'tcx> { - // Not using `deref_pointer` since we want to use our `read_immediate` wrapper. - let place = self.ecx.ref_to_mplace(&self.read_immediate(value, ptr_kind.into())?)?; - // Handle wide pointers. - // Check metadata early, for better diagnostics - if place.layout.is_unsized() { - self.check_wide_ptr_meta(place.meta(), place.layout)?; - } - // Make sure this is dereferenceable and all. - let size_and_align = try_validation!( - self.ecx.size_and_align_of_mplace(&place), - self.path, - Ub(InvalidMeta(msg)) => match msg { - InvalidMetaKind::SliceTooBig => InvalidMetaSliceTooLarge { ptr_kind }, - InvalidMetaKind::TooBig => InvalidMetaTooLarge { ptr_kind }, - } - ); - let (size, align) = size_and_align - // for the purpose of validity, consider foreign types to have - // alignment and size determined by the layout (size will be 0, - // alignment should take attributes into account). - .unwrap_or_else(|| (place.layout.size, place.layout.align.abi)); - // Direct call to `check_ptr_access_align` checks alignment even on CTFE machines. - try_validation!( - self.ecx.check_ptr_access( - place.ptr(), - size, - CheckInAllocMsg::InboundsTest, // will anyway be replaced by validity message - ), - self.path, - Ub(DanglingIntPointer(0, _)) => NullPtr { ptr_kind }, - Ub(DanglingIntPointer(i, _)) => DanglingPtrNoProvenance { - ptr_kind, - // FIXME this says "null pointer" when null but we need translate - pointer: format!("{}", Pointer::>::from_addr_invalid(*i)) - }, - Ub(PointerOutOfBounds { .. }) => DanglingPtrOutOfBounds { - ptr_kind - }, - // This cannot happen during const-eval (because interning already detects - // dangling pointers), but it can happen in Miri. - Ub(PointerUseAfterFree(..)) => DanglingPtrUseAfterFree { - ptr_kind, - }, - ); - try_validation!( - self.ecx.check_ptr_align( - place.ptr(), - align, - ), - self.path, - Ub(AlignmentCheckFailed(Misalignment { required, has }, _msg)) => UnalignedPtr { - ptr_kind, - required_bytes: required.bytes(), - found_bytes: has.bytes() - }, - ); - // Do not allow pointers to uninhabited types. - if place.layout.abi.is_uninhabited() { - let ty = place.layout.ty; - throw_validation_failure!(self.path, PtrToUninhabited { ptr_kind, ty }) - } - // Recursive checking - if let Some(ref_tracking) = self.ref_tracking.as_deref_mut() { - // Determine whether this pointer expects to be pointing to something mutable. - let ptr_expected_mutbl = match ptr_kind { - PointerKind::Box => Mutability::Mut, - PointerKind::Ref(mutbl) => { - // We do not take into account interior mutability here since we cannot know if - // there really is an `UnsafeCell` inside `Option` -- so we check - // that in the recursive descent behind this reference (controlled by - // `allow_immutable_unsafe_cell`). - mutbl - } - }; - // Proceed recursively even for ZST, no reason to skip them! - // `!` is a ZST and we want to validate it. - if let Ok((alloc_id, _offset, _prov)) = self.ecx.ptr_try_get_alloc_id(place.ptr()) { - let mut skip_recursive_check = false; - // Let's see what kind of memory this points to. - // `unwrap` since dangling pointers have already been handled. - let alloc_kind = self.ecx.tcx.try_get_global_alloc(alloc_id).unwrap(); - let alloc_actual_mutbl = match alloc_kind { - GlobalAlloc::Static(did) => { - // Special handling for pointers to statics (irrespective of their type). - assert!(!self.ecx.tcx.is_thread_local_static(did)); - assert!(self.ecx.tcx.is_static(did)); - // Mode-specific checks - match self.ctfe_mode { - Some( - CtfeValidationMode::Static { .. } - | CtfeValidationMode::Promoted { .. }, - ) => { - // We skip recursively checking other statics. These statics must be sound by - // themselves, and the only way to get broken statics here is by using - // unsafe code. - // The reasons we don't check other statics is twofold. For one, in all - // sound cases, the static was already validated on its own, and second, we - // trigger cycle errors if we try to compute the value of the other static - // and that static refers back to us (potentially through a promoted). - // This could miss some UB, but that's fine. - skip_recursive_check = true; - } - Some(CtfeValidationMode::Const { .. }) => { - // We can't recursively validate `extern static`, so we better reject them. - if self.ecx.tcx.is_foreign_item(did) { - throw_validation_failure!(self.path, ConstRefToExtern); - } - } - None => {} - } - // Return alloc mutability. For "root" statics we look at the type to account for interior - // mutability; for nested statics we have no type and directly use the annotated mutability. - let DefKind::Static { mutability, nested } = self.ecx.tcx.def_kind(did) - else { - bug!() - }; - match (mutability, nested) { - (Mutability::Mut, _) => Mutability::Mut, - (Mutability::Not, true) => Mutability::Not, - (Mutability::Not, false) - if !self - .ecx - .tcx - .type_of(did) - .no_bound_vars() - .expect("statics should not have generic parameters") - .is_freeze(*self.ecx.tcx, ty::ParamEnv::reveal_all()) => - { - Mutability::Mut - } - (Mutability::Not, false) => Mutability::Not, - } - } - GlobalAlloc::Memory(alloc) => alloc.inner().mutability, - GlobalAlloc::Function(..) | GlobalAlloc::VTable(..) => { - // These are immutable, we better don't allow mutable pointers here. - Mutability::Not - } - }; - // Mutability check. - // If this allocation has size zero, there is no actual mutability here. - let (size, _align, _alloc_kind) = self.ecx.get_alloc_info(alloc_id); - if size != Size::ZERO { - // Mutable pointer to immutable memory is no good. - if ptr_expected_mutbl == Mutability::Mut - && alloc_actual_mutbl == Mutability::Not - { - throw_validation_failure!(self.path, MutableRefToImmutable); - } - // In a const, everything must be completely immutable. - if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. })) { - if ptr_expected_mutbl == Mutability::Mut - || alloc_actual_mutbl == Mutability::Mut - { - throw_validation_failure!(self.path, ConstRefToMutable); - } - } - } - // Potentially skip recursive check. - if skip_recursive_check { - return Ok(()); - } - } - let path = &self.path; - ref_tracking.track(place, || { - // We need to clone the path anyway, make sure it gets created - // with enough space for the additional `Deref`. - let mut new_path = Vec::with_capacity(path.len() + 1); - new_path.extend(path); - new_path.push(PathElem::Deref); - new_path - }); - } - Ok(()) - } - - /// Check if this is a value of primitive type, and if yes check the validity of the value - /// at that type. Return `true` if the type is indeed primitive. - /// - /// Note that not all of these have `FieldsShape::Primitive`, e.g. wide references. - fn try_visit_primitive( - &mut self, - value: &OpTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, bool> { - // Go over all the primitive types - let ty = value.layout.ty; - match ty.kind() { - ty::Bool => { - let value = self.read_scalar(value, ExpectedKind::Bool)?; - try_validation!( - value.to_bool(), - self.path, - Ub(InvalidBool(..)) => ValidationErrorKind::InvalidBool { - value: format!("{value:x}"), - } - ); - Ok(true) - } - ty::Char => { - let value = self.read_scalar(value, ExpectedKind::Char)?; - try_validation!( - value.to_char(), - self.path, - Ub(InvalidChar(..)) => ValidationErrorKind::InvalidChar { - value: format!("{value:x}"), - } - ); - Ok(true) - } - ty::Float(_) | ty::Int(_) | ty::Uint(_) => { - // NOTE: Keep this in sync with the array optimization for int/float - // types below! - self.read_scalar( - value, - if matches!(ty.kind(), ty::Float(..)) { - ExpectedKind::Float - } else { - ExpectedKind::Int - }, - )?; - Ok(true) - } - ty::RawPtr(..) => { - let place = - self.ecx.ref_to_mplace(&self.read_immediate(value, ExpectedKind::RawPtr)?)?; - if place.layout.is_unsized() { - self.check_wide_ptr_meta(place.meta(), place.layout)?; - } - Ok(true) - } - ty::Ref(_, _ty, mutbl) => { - self.check_safe_pointer(value, PointerKind::Ref(*mutbl))?; - Ok(true) - } - ty::FnPtr(_sig) => { - let value = self.read_scalar(value, ExpectedKind::FnPtr)?; - - // If we check references recursively, also check that this points to a function. - if let Some(_) = self.ref_tracking { - let ptr = value.to_pointer(self.ecx)?; - let _fn = try_validation!( - self.ecx.get_ptr_fn(ptr), - self.path, - Ub(DanglingIntPointer(..) | InvalidFunctionPointer(..)) => - InvalidFnPtr { value: format!("{ptr}") }, - ); - // FIXME: Check if the signature matches - } else { - // Otherwise (for standalone Miri), we have to still check it to be non-null. - if self.ecx.scalar_may_be_null(value)? { - throw_validation_failure!(self.path, NullFnPtr); - } - } - Ok(true) - } - ty::Never => throw_validation_failure!(self.path, NeverVal), - ty::Foreign(..) | ty::FnDef(..) => { - // Nothing to check. - Ok(true) - } - // The above should be all the primitive types. The rest is compound, we - // check them by visiting their fields/variants. - ty::Adt(..) - | ty::Tuple(..) - | ty::Array(..) - | ty::Slice(..) - | ty::Str - | ty::Dynamic(..) - | ty::Closure(..) - | ty::CoroutineClosure(..) - | ty::Coroutine(..) => Ok(false), - // Some types only occur during typechecking, they have no layout. - // We should not see them here and we could not check them anyway. - ty::Error(_) - | ty::Infer(..) - | ty::Placeholder(..) - | ty::Bound(..) - | ty::Param(..) - | ty::Alias(..) - | ty::CoroutineWitness(..) => bug!("Encountered invalid type {:?}", ty), - } - } - - fn visit_scalar( - &mut self, - scalar: Scalar, - scalar_layout: ScalarAbi, - ) -> InterpResult<'tcx> { - let size = scalar_layout.size(self.ecx); - let valid_range = scalar_layout.valid_range(self.ecx); - let WrappingRange { start, end } = valid_range; - let max_value = size.unsigned_int_max(); - assert!(end <= max_value); - let bits = match scalar.try_to_int() { - Ok(int) => int.assert_bits(size), - Err(_) => { - // So this is a pointer then, and casting to an int failed. - // Can only happen during CTFE. - // We support 2 kinds of ranges here: full range, and excluding zero. - if start == 1 && end == max_value { - // Only null is the niche. So make sure the ptr is NOT null. - if self.ecx.scalar_may_be_null(scalar)? { - throw_validation_failure!( - self.path, - NullablePtrOutOfRange { range: valid_range, max_value } - ) - } else { - return Ok(()); - } - } else if scalar_layout.is_always_valid(self.ecx) { - // Easy. (This is reachable if `enforce_number_validity` is set.) - return Ok(()); - } else { - // Conservatively, we reject, because the pointer *could* have a bad - // value. - throw_validation_failure!( - self.path, - PtrOutOfRange { range: valid_range, max_value } - ) - } - } - }; - // Now compare. - if valid_range.contains(bits) { - Ok(()) - } else { - throw_validation_failure!( - self.path, - OutOfRange { value: format!("{bits}"), range: valid_range, max_value } - ) - } - } - - fn in_mutable_memory(&self, op: &OpTy<'tcx, M::Provenance>) -> bool { - if let Some(mplace) = op.as_mplace_or_imm().left() { - if let Some(alloc_id) = mplace.ptr().provenance.and_then(|p| p.get_alloc_id()) { - let mutability = match self.ecx.tcx.global_alloc(alloc_id) { - GlobalAlloc::Static(_) => { - self.ecx.memory.alloc_map.get(alloc_id).unwrap().1.mutability - } - GlobalAlloc::Memory(alloc) => alloc.inner().mutability, - _ => span_bug!(self.ecx.tcx.span, "not a memory allocation"), - }; - return mutability == Mutability::Mut; - } - } - false - } -} - -impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> - for ValidityVisitor<'rt, 'mir, 'tcx, M> -{ - type V = OpTy<'tcx, M::Provenance>; - - #[inline(always)] - fn ecx(&self) -> &InterpCx<'mir, 'tcx, M> { - self.ecx - } - - fn read_discriminant( - &mut self, - op: &OpTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, VariantIdx> { - self.with_elem(PathElem::EnumTag, move |this| { - Ok(try_validation!( - this.ecx.read_discriminant(op), - this.path, - Ub(InvalidTag(val)) => InvalidEnumTag { - value: format!("{val:x}"), - }, - Ub(UninhabitedEnumVariantRead(_)) => UninhabitedEnumVariant, - // Uninit / bad provenance are not possible since the field was already previously - // checked at its integer type. - )) - }) - } - - #[inline] - fn visit_field( - &mut self, - old_op: &OpTy<'tcx, M::Provenance>, - field: usize, - new_op: &OpTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx> { - let elem = self.aggregate_field_path_elem(old_op.layout, field); - self.with_elem(elem, move |this| this.visit_value(new_op)) - } - - #[inline] - fn visit_variant( - &mut self, - old_op: &OpTy<'tcx, M::Provenance>, - variant_id: VariantIdx, - new_op: &OpTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx> { - let name = match old_op.layout.ty.kind() { - ty::Adt(adt, _) => PathElem::Variant(adt.variant(variant_id).name), - // Coroutines also have variants - ty::Coroutine(..) => PathElem::CoroutineState(variant_id), - _ => bug!("Unexpected type with variant: {:?}", old_op.layout.ty), - }; - self.with_elem(name, move |this| this.visit_value(new_op)) - } - - #[inline(always)] - fn visit_union( - &mut self, - op: &OpTy<'tcx, M::Provenance>, - _fields: NonZero, - ) -> InterpResult<'tcx> { - // Special check for CTFE validation, preventing `UnsafeCell` inside unions in immutable memory. - if self.ctfe_mode.is_some_and(|c| !c.allow_immutable_unsafe_cell()) { - if !op.layout.is_zst() && !op.layout.ty.is_freeze(*self.ecx.tcx, self.ecx.param_env) { - if !self.in_mutable_memory(op) { - throw_validation_failure!(self.path, UnsafeCellInImmutable); - } - } - } - Ok(()) - } - - #[inline] - fn visit_box( - &mut self, - _box_ty: Ty<'tcx>, - op: &OpTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx> { - self.check_safe_pointer(op, PointerKind::Box)?; - Ok(()) - } - - #[inline] - fn visit_value(&mut self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx> { - trace!("visit_value: {:?}, {:?}", *op, op.layout); - - // Check primitive types -- the leaves of our recursive descent. - if self.try_visit_primitive(op)? { - return Ok(()); - } - - // Special check preventing `UnsafeCell` in the inner part of constants - if self.ctfe_mode.is_some_and(|c| !c.allow_immutable_unsafe_cell()) { - if !op.layout.is_zst() - && let Some(def) = op.layout.ty.ty_adt_def() - && def.is_unsafe_cell() - { - if !self.in_mutable_memory(op) { - throw_validation_failure!(self.path, UnsafeCellInImmutable); - } - } - } - - // Recursively walk the value at its type. Apply optimizations for some large types. - match op.layout.ty.kind() { - ty::Str => { - let mplace = op.assert_mem_place(); // strings are unsized and hence never immediate - let len = mplace.len(self.ecx)?; - try_validation!( - self.ecx.read_bytes_ptr_strip_provenance(mplace.ptr(), Size::from_bytes(len)), - self.path, - Ub(InvalidUninitBytes(..)) => Uninit { expected: ExpectedKind::Str }, - Unsup(ReadPointerAsInt(_)) => PointerAsInt { expected: ExpectedKind::Str } - ); - } - ty::Array(tys, ..) | ty::Slice(tys) - // This optimization applies for types that can hold arbitrary bytes (such as - // integer and floating point types) or for structs or tuples with no fields. - // FIXME(wesleywiser) This logic could be extended further to arbitrary structs - // or tuples made up of integer/floating point types or inhabited ZSTs with no - // padding. - if matches!(tys.kind(), ty::Int(..) | ty::Uint(..) | ty::Float(..)) - => - { - let expected = if tys.is_integral() { ExpectedKind::Int } else { ExpectedKind::Float }; - // Optimized handling for arrays of integer/float type. - - // This is the length of the array/slice. - let len = op.len(self.ecx)?; - // This is the element type size. - let layout = self.ecx.layout_of(*tys)?; - // This is the size in bytes of the whole array. (This checks for overflow.) - let size = layout.size * len; - // If the size is 0, there is nothing to check. - // (`size` can only be 0 of `len` is 0, and empty arrays are always valid.) - if size == Size::ZERO { - return Ok(()); - } - // Now that we definitely have a non-ZST array, we know it lives in memory. - let mplace = match op.as_mplace_or_imm() { - Left(mplace) => mplace, - Right(imm) => match *imm { - Immediate::Uninit => - throw_validation_failure!(self.path, Uninit { expected }), - Immediate::Scalar(..) | Immediate::ScalarPair(..) => - bug!("arrays/slices can never have Scalar/ScalarPair layout"), - } - }; - - // Optimization: we just check the entire range at once. - // NOTE: Keep this in sync with the handling of integer and float - // types above, in `visit_primitive`. - // No need for an alignment check here, this is not an actual memory access. - let alloc = self.ecx.get_ptr_alloc(mplace.ptr(), size)?.expect("we already excluded size 0"); - - match alloc.get_bytes_strip_provenance() { - // In the happy case, we needn't check anything else. - Ok(_) => {} - // Some error happened, try to provide a more detailed description. - Err(err) => { - // For some errors we might be able to provide extra information. - // (This custom logic does not fit the `try_validation!` macro.) - match err.kind() { - Ub(InvalidUninitBytes(Some((_alloc_id, access)))) | Unsup(ReadPointerAsInt(Some((_alloc_id, access)))) => { - // Some byte was uninitialized, determine which - // element that byte belongs to so we can - // provide an index. - let i = usize::try_from( - access.bad.start.bytes() / layout.size.bytes(), - ) - .unwrap(); - self.path.push(PathElem::ArrayElem(i)); - - if matches!(err.kind(), Ub(InvalidUninitBytes(_))) { - throw_validation_failure!(self.path, Uninit { expected }) - } else { - throw_validation_failure!(self.path, PointerAsInt { expected }) - } - } - - // Propagate upwards (that will also check for unexpected errors). - _ => return Err(err), - } - } - } - } - // Fast path for arrays and slices of ZSTs. We only need to check a single ZST element - // of an array and not all of them, because there's only a single value of a specific - // ZST type, so either validation fails for all elements or none. - ty::Array(tys, ..) | ty::Slice(tys) if self.ecx.layout_of(*tys)?.is_zst() => { - // Validate just the first element (if any). - if op.len(self.ecx)? > 0 { - self.visit_field(op, 0, &self.ecx.project_index(op, 0)?)?; - } - } - _ => { - self.walk_value(op)?; // default handler - } - } - - // *After* all of this, check the ABI. We need to check the ABI to handle - // types like `NonNull` where the `Scalar` info is more restrictive than what - // the fields say (`rustc_layout_scalar_valid_range_start`). - // But in most cases, this will just propagate what the fields say, - // and then we want the error to point at the field -- so, first recurse, - // then check ABI. - // - // FIXME: We could avoid some redundant checks here. For newtypes wrapping - // scalars, we do the same check on every "level" (e.g., first we check - // MyNewtype and then the scalar in there). - match op.layout.abi { - Abi::Uninhabited => { - let ty = op.layout.ty; - throw_validation_failure!(self.path, UninhabitedVal { ty }); - } - Abi::Scalar(scalar_layout) => { - if !scalar_layout.is_uninit_valid() { - // There is something to check here. - let scalar = self.read_scalar(op, ExpectedKind::InitScalar)?; - self.visit_scalar(scalar, scalar_layout)?; - } - } - Abi::ScalarPair(a_layout, b_layout) => { - // We can only proceed if *both* scalars need to be initialized. - // FIXME: find a way to also check ScalarPair when one side can be uninit but - // the other must be init. - if !a_layout.is_uninit_valid() && !b_layout.is_uninit_valid() { - let (a, b) = - self.read_immediate(op, ExpectedKind::InitScalar)?.to_scalar_pair(); - self.visit_scalar(a, a_layout)?; - self.visit_scalar(b, b_layout)?; - } - } - Abi::Vector { .. } => { - // No checks here, we assume layout computation gets this right. - // (This is harder to check since Miri does not represent these as `Immediate`. We - // also cannot use field projections since this might be a newtype around a vector.) - } - Abi::Aggregate { .. } => { - // Nothing to do. - } - } - - Ok(()) - } -} - -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - fn validate_operand_internal( - &self, - op: &OpTy<'tcx, M::Provenance>, - path: Vec, - ref_tracking: Option<&mut RefTracking, Vec>>, - ctfe_mode: Option, - ) -> InterpResult<'tcx> { - trace!("validate_operand_internal: {:?}, {:?}", *op, op.layout.ty); - - // Construct a visitor - let mut visitor = ValidityVisitor { path, ref_tracking, ctfe_mode, ecx: self }; - - // Run it. - match self.run_for_validation(|| visitor.visit_value(op)) { - Ok(()) => Ok(()), - // Pass through validation failures and "invalid program" issues. - Err(err) - if matches!( - err.kind(), - err_ub!(ValidationError { .. }) | InterpError::InvalidProgram(_) - ) => - { - Err(err) - } - // Complain about any other kind of error -- those are bad because we'd like to - // report them in a way that shows *where* in the value the issue lies. - Err(err) => { - bug!( - "Unexpected error during validation: {}", - format_interp_error(self.tcx.dcx(), err) - ); - } - } - } - - /// This function checks the data at `op` to be const-valid. - /// `op` is assumed to cover valid memory if it is an indirect operand. - /// It will error if the bits at the destination do not match the ones described by the layout. - /// - /// `ref_tracking` is used to record references that we encounter so that they - /// can be checked recursively by an outside driving loop. - /// - /// `constant` controls whether this must satisfy the rules for constants: - /// - no pointers to statics. - /// - no `UnsafeCell` or non-ZST `&mut`. - #[inline(always)] - pub(crate) fn const_validate_operand( - &self, - op: &OpTy<'tcx, M::Provenance>, - path: Vec, - ref_tracking: &mut RefTracking, Vec>, - ctfe_mode: CtfeValidationMode, - ) -> InterpResult<'tcx> { - self.validate_operand_internal(op, path, Some(ref_tracking), Some(ctfe_mode)) - } - - /// This function checks the data at `op` to be runtime-valid. - /// `op` is assumed to cover valid memory if it is an indirect operand. - /// It will error if the bits at the destination do not match the ones described by the layout. - #[inline(always)] - pub fn validate_operand(&self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx> { - // Note that we *could* actually be in CTFE here with `-Zextra-const-ub-checks`, but it's - // still correct to not use `ctfe_mode`: that mode is for validation of the final constant - // value, it rules out things like `UnsafeCell` in awkward places. It also can make checking - // recurse through references which, for now, we don't want here, either. - self.validate_operand_internal(op, vec![], None, None) - } -} +use std::fmt::Write;use std::num::NonZero ;use either::{Left,Right};use hir::def +::DefKind;use rustc_ast::Mutability;use rustc_data_structures::fx::FxHashSet;//; +use rustc_hir as hir;use rustc_middle::mir::interpret::{ExpectedKind,//let _=(); +InterpError,InvalidMetaKind,Misalignment,PointerKind,Provenance,//if let _=(){}; +ValidationErrorInfo,ValidationErrorKind,ValidationErrorKind::*,};use//if true{}; +rustc_middle::ty::layout::{LayoutOf,TyAndLayout} ;use rustc_middle::ty::{self,Ty +};use rustc_span::symbol::{sym,Symbol};use rustc_target::abi::{Abi,FieldIdx,//3; +Scalar as ScalarAbi,Size,VariantIdx,Variants,WrappingRange,};use std::hash:://3; +Hash;use super::{format_interp_error ,machine::AllocMap,AllocId,CheckInAllocMsg, +GlobalAlloc,ImmTy,Immediate,InterpCx ,InterpResult,MPlaceTy,Machine,MemPlaceMeta +,OpTy,Pointer,Projectable,Scalar,ValueVisitor,};use super::InterpError:://{();}; +UndefinedBehavior as Ub;use super::InterpError::Unsupported as Unsup;use super// +::UndefinedBehaviorInfo::*;use super::UnsupportedOpInfo::*;macro_rules!//*&*&(); +throw_validation_failure{($where:expr,$kind:expr)=>{{let where_=&$where;let//(); +path=if!where_.is_empty(){let mut path=String::new();write_path(&mut path,//{;}; +where_);Some(path)}else{None};throw_ub!(ValidationError(ValidationErrorInfo{//3; +path,kind:$kind}))}};}macro_rules!try_validation{($e:expr,$where:expr,$($($p://; +pat_param)|+ =>$kind:expr),+$(,)?)=>{{match $e{Ok(x)=>x,Err(e)=>match e.kind(){$ +($($p)|+ =>throw_validation_failure!($where,$kind)),+,#[allow(//((),());((),()); +unreachable_patterns)]_=>Err::(e)?,}}}};}#[derive(Copy,Clone,Debug)]pub//3; +enum PathElem{Field(Symbol),Variant(Symbol),CoroutineState(VariantIdx),//*&*&(); +CapturedVar(Symbol),ArrayElem(usize),TupleElem(usize),Deref,EnumTag,//if true{}; +CoroutineTag,DynDowncast,}#[derive(Copy,Clone)]pub enum CtfeValidationMode{//(); +Static{mutbl:Mutability},Promoted, Const{allow_immutable_unsafe_cell:bool},}impl +CtfeValidationMode{fn allow_immutable_unsafe_cell(self)->bool{match self{//({}); +CtfeValidationMode::Static{..}=>(false),CtfeValidationMode::Promoted{..}=>false, +CtfeValidationMode::Const{allow_immutable_unsafe_cell,..}=>{//let _=();let _=(); +allow_immutable_unsafe_cell}}}}pub struct RefTracking{pub seen://{;}; +FxHashSet,pub todo:Vec<(T,PATH)>, }implRefTracking{pub fn empty()->Self{RefTracking{seen:FxHashSet:://; +default(),todo:vec![]}}pub fn new(op:T)->Self{3;let mut ref_tracking_for_consts= +RefTracking{seen:FxHashSet::default(),todo:vec![(op.clone(),PATH::default())]};; +ref_tracking_for_consts.seen.insert(op);3;ref_tracking_for_consts}pub fn track(& +mut self,op:T,path:impl FnOnce()->PATH){if self.seen.insert(op.clone()){;trace!( +"Recursing below ptr {:#?}",op);;let path=path();self.todo.push((op,path));}}}fn +write_path(out:&mut String,path:&[PathElem]){;use self::PathElem::*;;for elem in +(path.iter()){match elem{Field(name)=>write!(out,".{name}"),EnumTag=>write!(out, +"."),Variant(name)=>((((((write!(out,"."))))))), +CoroutineTag=>(write!(out,".")) ,CoroutineState(idx)=>write!(out, +".",idx.index()),CapturedVar(name)=>write!(out,//if true{}; +"."),TupleElem(idx)=>(write!(out,".{idx}")),ArrayElem(idx) +=>(write!(out,"[{idx}]")),Deref=>write!(out,"."),DynDowncast=>write!(out, +"."),}.unwrap()}}struct ValidityVisitor<'rt,'mir,'tcx,M:Machine>{path:Vec,ref_tracking:Option<&'rt mut RefTracking,Vec>>,ctfe_mode:Option,ecx:&'rt InterpCx<'mir,'tcx,M>,}impl<'rt,'mir,'tcx:'mir,M:// +Machine<'mir,'tcx>>ValidityVisitor<'rt,'mir,'tcx,M>{fn//loop{break};loop{break}; +aggregate_field_path_elem(&mut self,layout:TyAndLayout<'tcx>,field:usize)->//(); +PathElem{match layout.variants{Variants::Multiple{tag_field,..}=>{if tag_field// +==field{;return match layout.ty.kind(){ty::Adt(def,..)if def.is_enum()=>PathElem +::EnumTag,ty::Coroutine(..)=>PathElem::CoroutineTag,_=>bug!(//let _=();let _=(); +"non-variant type {:?}",layout.ty),};;}}Variants::Single{..}=>{}}match layout.ty +.kind(){ty::Closure(def_id,_)|ty::Coroutine(def_id,_)|ty::CoroutineClosure(//(); +def_id,_)=>{;let mut name=None;;if let Some(local_def_id)=def_id.as_local(){;let +captures=self.ecx.tcx.closure_captures(local_def_id);;if let Some(captured_place +)=captures.get(field){3;let var_hir_id=captured_place.get_root_variable();3;;let +node=self.ecx.tcx.hir_node(var_hir_id);();if let hir::Node::Pat(pat)=node{if let +hir::PatKind::Binding(_,_,ident,_)=pat.kind{;name=Some(ident.name);;}}}}PathElem +::CapturedVar((name.unwrap_or_else((||{(sym::integer(field))}))))}ty::Tuple(_)=> +PathElem::TupleElem(field),ty::Adt(def,..)if (((def.is_enum())))=>{match layout. +variants{Variants::Single{index}=>{PathElem::Field ((def.variant(index)).fields[ +FieldIdx::from_usize(field)].name)}Variants::Multiple{..}=>bug!(//if let _=(){}; +"we handled variants above"),}}ty::Adt(def,_)=>{PathElem::Field(def.//if true{}; +non_enum_variant().fields[FieldIdx::from_usize(field) ].name)}ty::Array(..)|ty:: +Slice(..)=>(PathElem::ArrayElem(field)),ty::Dynamic(..)=>PathElem::DynDowncast,_ +=>bug!("aggregate_field_path_elem: got non-aggregate type {:?}",layout .ty),}}fn +with_elem(&mut self,elem:PathElem,f:impl FnOnce(&mut Self)->InterpResult,)->InterpResult<'tcx,R>{3;let path_len=self.path.len();;;self.path.push( +elem);;let r=f(self)?;self.path.truncate(path_len);Ok(r)}fn read_immediate(&self +,op:&OpTy<'tcx,M::Provenance> ,expected:ExpectedKind,)->InterpResult<'tcx,ImmTy< +'tcx,M::Provenance>>{Ok(try_validation!(self.ecx.read_immediate(op),self.path,// +Ub(InvalidUninitBytes(None))=>Uninit{expected},Unsup(ReadPointerAsInt(_))=>//(); +PointerAsInt{expected},Unsup(ReadPartialPointer(_))=>PartialPointer,))}fn//({}); +read_scalar(&self,op:&OpTy<'tcx,M::Provenance>,expected:ExpectedKind,)->//{();}; +InterpResult<'tcx,Scalar>{Ok((self.read_immediate(op,expected)?). +to_scalar())}fn check_wide_ptr_meta(& mut self,meta:MemPlaceMeta, +pointee:TyAndLayout<'tcx>,)->InterpResult<'tcx>{if true{};let tail=self.ecx.tcx. +struct_tail_erasing_lifetimes(pointee.ty,self.ecx.param_env);;match tail.kind(){ +ty::Dynamic(_,_,ty::Dyn)=>{;let vtable=meta.unwrap_meta().to_pointer(self.ecx)?; +let(_ty,_trait)=try_validation!(self.ecx.get_ptr_vtable(vtable),self.path,Ub(//; +DanglingIntPointer(..)|InvalidVTablePointer(.. ))=>InvalidVTablePtr{value:format +!("{vtable}")});{();};}ty::Slice(..)|ty::Str=>{({});let _len=meta.unwrap_meta(). +to_target_usize(self.ecx)?;loop{break};loop{break;};}ty::Foreign(..)=>{}_=>bug!( +"Unexpected unsized type tail: {:?}",tail),}(Ok( ()))}fn check_safe_pointer(&mut +self,value:&OpTy<'tcx,M::Provenance >,ptr_kind:PointerKind,)->InterpResult<'tcx> +{;let place=self.ecx.ref_to_mplace(&self.read_immediate(value,ptr_kind.into())?) +?;();if place.layout.is_unsized(){3;self.check_wide_ptr_meta(place.meta(),place. +layout)?;;}let size_and_align=try_validation!(self.ecx.size_and_align_of_mplace( +&place),self.path,Ub(InvalidMeta(msg))=>match msg{InvalidMetaKind::SliceTooBig// +=>InvalidMetaSliceTooLarge{ptr_kind},InvalidMetaKind::TooBig=>//((),());((),()); +InvalidMetaTooLarge{ptr_kind},});;let(size,align)=size_and_align.unwrap_or_else( +||(place.layout.size,place.layout.align.abi));({});{;};try_validation!(self.ecx. +check_ptr_access(place.ptr(),size,CheckInAllocMsg ::InboundsTest,),self.path,Ub( +DanglingIntPointer(0,_))=>NullPtr{ptr_kind},Ub(DanglingIntPointer(i,_))=>//({}); +DanglingPtrNoProvenance{ptr_kind,pointer:format!("{}",Pointer::>::from_addr_invalid(*i))}, Ub(PointerOutOfBounds{..})=>DanglingPtrOutOfBounds{ +ptr_kind},Ub(PointerUseAfterFree(..))=>DanglingPtrUseAfterFree{ptr_kind,},);3;3; +try_validation!(self.ecx.check_ptr_align(place.ptr(),align,),self.path,Ub(//{;}; +AlignmentCheckFailed(Misalignment{required,has},_msg))=>UnalignedPtr{ptr_kind,// +required_bytes:required.bytes(),found_bytes:has.bytes()},);;if place.layout.abi. +is_uninhabited(){3;let ty=place.layout.ty;3;throw_validation_failure!(self.path, +PtrToUninhabited{ptr_kind,ty})}if let Some(ref_tracking)=self.ref_tracking.//(); +as_deref_mut(){let _=();let ptr_expected_mutbl=match ptr_kind{PointerKind::Box=> +Mutability::Mut,PointerKind::Ref(mutbl)=>{mutbl}};3;if let Ok((alloc_id,_offset, +_prov))=self.ecx.ptr_try_get_alloc_id(place.ptr()){;let mut skip_recursive_check +=false;;;let alloc_kind=self.ecx.tcx.try_get_global_alloc(alloc_id).unwrap();let +alloc_actual_mutbl=match alloc_kind{GlobalAlloc::Static(did)=>{();assert!(!self. +ecx.tcx.is_thread_local_static(did));;assert!(self.ecx.tcx.is_static(did));match +self.ctfe_mode{Some(CtfeValidationMode::Static{..}|CtfeValidationMode:://*&*&(); +Promoted{..},)=>{;skip_recursive_check=true;}Some(CtfeValidationMode::Const{..}) +=>{if self.ecx.tcx.is_foreign_item(did){{;};throw_validation_failure!(self.path, +ConstRefToExtern);3;}}None=>{}};let DefKind::Static{mutability,nested}=self.ecx. +tcx.def_kind(did)else{bug!()};{;};match(mutability,nested){(Mutability::Mut,_)=> +Mutability::Mut,(Mutability::Not,true) =>Mutability::Not,(Mutability::Not,false) +if!((((((((((((((self.ecx.tcx.type_of(did)))))))).no_bound_vars()))))))).expect( +"statics should not have generic parameters").is_freeze((((*self.ecx.tcx))),ty:: +ParamEnv::reveal_all())=>{Mutability ::Mut}(Mutability::Not,false)=>Mutability:: +Not,}}GlobalAlloc::Memory(alloc)=>((((alloc.inner())))).mutability,GlobalAlloc:: +Function(..)|GlobalAlloc::VTable(..)=>{Mutability::Not}};{;};();let(size,_align, +_alloc_kind)=self.ecx.get_alloc_info(alloc_id);if true{};if size!=Size::ZERO{if +ptr_expected_mutbl==Mutability::Mut&&alloc_actual_mutbl==Mutability::Not{*&*&(); +throw_validation_failure!(self.path,MutableRefToImmutable);();}if matches!(self. +ctfe_mode,Some(CtfeValidationMode::Const{..})){if ptr_expected_mutbl==//((),()); +Mutability::Mut||alloc_actual_mutbl==Mutability::Mut{;throw_validation_failure!( +self.path,ConstRefToMutable);3;}}}if skip_recursive_check{;return Ok(());;}};let +path=&self.path;;ref_tracking.track(place,||{let mut new_path=Vec::with_capacity +(path.len()+1);;new_path.extend(path);new_path.push(PathElem::Deref);new_path}); +}(Ok((())))}fn try_visit_primitive(&mut self,value:&OpTy<'tcx,M::Provenance>,)-> +InterpResult<'tcx,bool>{;let ty=value.layout.ty;;match ty.kind(){ty::Bool=>{;let +value=self.read_scalar(value,ExpectedKind::Bool)?;;try_validation!(value.to_bool +(),self.path,Ub(InvalidBool( ..))=>ValidationErrorKind::InvalidBool{value:format +!("{value:x}"),});({});Ok(true)}ty::Char=>{{;};let value=self.read_scalar(value, +ExpectedKind::Char)?;;;try_validation!(value.to_char(),self.path,Ub(InvalidChar( +..))=>ValidationErrorKind::InvalidChar{value:format!("{value:x}"),});3;Ok(true)} +ty::Float(_)|ty::Int(_)|ty::Uint(_)=>{{;};self.read_scalar(value,if matches!(ty. +kind(),ty::Float(..)){ExpectedKind::Float}else{ExpectedKind::Int},)?;3;Ok(true)} +ty::RawPtr(..)=>{();let place=self.ecx.ref_to_mplace(&self.read_immediate(value, +ExpectedKind::RawPtr)?)?;;if place.layout.is_unsized(){self.check_wide_ptr_meta( +place.meta(),place.layout)?;*&*&();}Ok(true)}ty::Ref(_,_ty,mutbl)=>{*&*&();self. +check_safe_pointer(value,PointerKind::Ref(*mutbl))?;;Ok(true)}ty::FnPtr(_sig)=>{ +let value=self.read_scalar(value,ExpectedKind::FnPtr)?;({});if let Some(_)=self. +ref_tracking{;let ptr=value.to_pointer(self.ecx)?;;let _fn=try_validation!(self. +ecx.get_ptr_fn(ptr),self.path ,Ub(DanglingIntPointer(..)|InvalidFunctionPointer( +..))=>InvalidFnPtr{value:format!("{ptr}")},);((),());let _=();}else{if self.ecx. +scalar_may_be_null(value)?{;throw_validation_failure!(self.path,NullFnPtr);}}Ok( +true)}ty::Never=>throw_validation_failure!(self .path,NeverVal),ty::Foreign(..)| +ty::FnDef(..)=>{Ok(true)}ty::Adt(.. )|ty::Tuple(..)|ty::Array(..)|ty::Slice(..)| +ty::Str|ty::Dynamic(..)|ty::Closure (..)|ty::CoroutineClosure(..)|ty::Coroutine( +..)=>(Ok(false)),ty::Error(_)|ty::Infer(..)|ty::Placeholder(..)|ty::Bound(..)|ty +::Param(..)|ty::Alias(..)|ty::CoroutineWitness(..)=>bug!(//if true{};let _=||(); +"Encountered invalid type {:?}",ty),}}fn visit_scalar (&mut self,scalar:Scalar,scalar_layout:ScalarAbi,)->InterpResult<'tcx>{let _=||();let size= +scalar_layout.size(self.ecx);;let valid_range=scalar_layout.valid_range(self.ecx +);;let WrappingRange{start,end}=valid_range;let max_value=size.unsigned_int_max( +);3;3;assert!(end<=max_value);;;let bits=match scalar.try_to_int(){Ok(int)=>int. +assert_bits(size),Err(_)=>{if ((((start==( 1)))&&(end==max_value))){if self.ecx. +scalar_may_be_null(scalar)?{throw_validation_failure!(self.path,//if let _=(){}; +NullablePtrOutOfRange{range:valid_range,max_value})}else{3;return Ok(());;}}else +if scalar_layout.is_always_valid(self.ecx){let _=();return Ok(());((),());}else{ +throw_validation_failure!(self.path,PtrOutOfRange {range:valid_range,max_value}) +}}};();if valid_range.contains(bits){Ok(())}else{throw_validation_failure!(self. +path,OutOfRange{value:format!("{bits}"),range:valid_range,max_value})}}fn//({}); +in_mutable_memory(&self,op:&OpTy<'tcx,M:: Provenance>)->bool{if let Some(mplace) +=((op.as_mplace_or_imm()).left()){if let Some(alloc_id)=mplace.ptr().provenance. +and_then(|p|p.get_alloc_id()){();let mutability=match self.ecx.tcx.global_alloc( +alloc_id){GlobalAlloc::Static(_)=>{(( self.ecx.memory.alloc_map.get(alloc_id))). +unwrap().1.mutability}GlobalAlloc::Memory(alloc)=>(alloc.inner()).mutability,_=> +span_bug!(self.ecx.tcx.span,"not a memory allocation"),};3;3;return mutability== +Mutability::Mut;if true{};}}false}}impl<'rt,'mir,'tcx:'mir,M:Machine<'mir,'tcx>> +ValueVisitor<'mir,'tcx,M>for ValidityVisitor<'rt, 'mir,'tcx,M>{type V=OpTy<'tcx, +M::Provenance>;#[inline(always)]fn ecx(& self)->&InterpCx<'mir,'tcx,M>{self.ecx} +fn read_discriminant(&mut self,op:&OpTy<'tcx,M::Provenance>,)->InterpResult{self.with_elem(PathElem::EnumTag ,move|this|{Ok(try_validation! +(this.ecx.read_discriminant(op),this.path,Ub(InvalidTag(val))=>InvalidEnumTag{// +value:format!("{val:x}"),},Ub(UninhabitedEnumVariantRead(_))=>//((),());((),()); +UninhabitedEnumVariant,))})}#[inline] fn visit_field(&mut self,old_op:&OpTy<'tcx +,M::Provenance>,field:usize,new_op:&OpTy<'tcx,M::Provenance>,)->InterpResult{{;};let elem=self.aggregate_field_path_elem(old_op.layout,field);{;};self. +with_elem(elem,(move|this|this.visit_value(new_op)))}#[inline]fn visit_variant(& +mut self,old_op:&OpTy<'tcx,M::Provenance>,variant_id:VariantIdx,new_op:&OpTy,)->InterpResult<'tcx>{;let name=match old_op.layout.ty.kind( +){ty::Adt(adt,_)=>PathElem::Variant (adt.variant(variant_id).name),ty::Coroutine +(..)=>((((((((((((((PathElem::CoroutineState( variant_id))))))))))))))),_=>bug!( +"Unexpected type with variant: {:?}",old_op.layout.ty),};();self.with_elem(name, +move|this|(this.visit_value(new_op)))}#[inline(always)]fn visit_union(&mut self, +op:&OpTy<'tcx,M::Provenance>,_fields:NonZero,)->InterpResult<'tcx>{if //; +self.ctfe_mode.is_some_and((|c|!c.allow_immutable_unsafe_cell ())){if!op.layout. +is_zst()&&(!(op.layout.ty.is_freeze(*self.ecx.tcx,self.ecx.param_env))){if!self. +in_mutable_memory(op){;throw_validation_failure!(self.path,UnsafeCellInImmutable +);3;}}}Ok(())}#[inline]fn visit_box(&mut self,_box_ty:Ty<'tcx>,op:&OpTy<'tcx,M:: +Provenance>,)->InterpResult<'tcx>{;self.check_safe_pointer(op,PointerKind::Box)? +;*&*&();Ok(())}#[inline]fn visit_value(&mut self,op:&OpTy<'tcx,M::Provenance>)-> +InterpResult<'tcx>{();trace!("visit_value: {:?}, {:?}",*op,op.layout);3;if self. +try_visit_primitive(op)?{3;return Ok(());3;}if self.ctfe_mode.is_some_and(|c|!c. +allow_immutable_unsafe_cell()){if(!op.layout.is_zst())&&let Some(def)=op.layout. +ty.ty_adt_def()&&def.is_unsafe_cell(){if!self.in_mutable_memory(op){loop{break}; +throw_validation_failure!(self.path,UnsafeCellInImmutable);3;}}}match op.layout. +ty.kind(){ty::Str=>{;let mplace=op.assert_mem_place();;;let len=mplace.len(self. +ecx)?;3;3;try_validation!(self.ecx.read_bytes_ptr_strip_provenance(mplace.ptr(), +Size::from_bytes(len)),self.path,Ub(InvalidUninitBytes(..))=>Uninit{expected://; +ExpectedKind::Str},Unsup(ReadPointerAsInt(_))=>PointerAsInt{expected://let _=(); +ExpectedKind::Str});3;}ty::Array(tys,..)|ty::Slice(tys)if matches!(tys.kind(),ty +::Int(..)|ty::Uint(..)|ty::Float(..))=>{{();};let expected=if tys.is_integral(){ +ExpectedKind::Int}else{ExpectedKind::Float};3;3;let len=op.len(self.ecx)?;3;;let +layout=self.ecx.layout_of(*tys)?;;;let size=layout.size*len;if size==Size::ZERO{ +return Ok(());();}3;let mplace=match op.as_mplace_or_imm(){Left(mplace)=>mplace, +Right(imm)=>match(*imm){ Immediate::Uninit=>throw_validation_failure!(self.path, +Uninit{expected}),Immediate::Scalar(..)|Immediate::ScalarPair(..)=>bug!(//{();}; +"arrays/slices can never have Scalar/ScalarPair layout"),}};;let alloc=self.ecx. +get_ptr_alloc(mplace.ptr(),size)?.expect("we already excluded size 0");();match +alloc.get_bytes_strip_provenance(){Ok(_)=>{}Err( err)=>{match ((err.kind())){Ub( +InvalidUninitBytes(Some((_alloc_id,access))))|Unsup(ReadPointerAsInt(Some((//(); +_alloc_id,access))))=>{();let i=usize::try_from(access.bad.start.bytes()/layout. +size.bytes(),).unwrap();;self.path.push(PathElem::ArrayElem(i));if matches!(err. +kind(),Ub(InvalidUninitBytes(_))){throw_validation_failure!(self.path,Uninit{//; +expected})}else{(throw_validation_failure!(self.path,PointerAsInt{expected}))}}_ +=>(return Err(err)),}}}}ty::Array(tys, ..)|ty::Slice(tys)if self.ecx.layout_of(* +tys)?.is_zst()=>{if op.len(self.ecx)?>0{((),());self.visit_field(op,0,&self.ecx. +project_index(op,0)?)?;;}}_=>{;self.walk_value(op)?;;}}match op.layout.abi{Abi:: +Uninhabited=>{{;};let ty=op.layout.ty;();();throw_validation_failure!(self.path, +UninhabitedVal{ty});loop{break;};}Abi::Scalar(scalar_layout)=>{if!scalar_layout. +is_uninit_valid(){3;let scalar=self.read_scalar(op,ExpectedKind::InitScalar)?;;; +self.visit_scalar(scalar,scalar_layout)?;;}}Abi::ScalarPair(a_layout,b_layout)=> +{if!a_layout.is_uninit_valid()&&!b_layout.is_uninit_valid(){{();};let(a,b)=self. +read_immediate(op,ExpectedKind::InitScalar)?.to_scalar_pair();;self.visit_scalar +(a,a_layout)?;();();self.visit_scalar(b,b_layout)?;();}}Abi::Vector{..}=>{}Abi:: +Aggregate{..}=>{}}(Ok((())))}}impl<'mir,'tcx:'mir,M:Machine<'mir,'tcx>>InterpCx< +'mir,'tcx,M>{fn validate_operand_internal(&self,op:&OpTy<'tcx,M::Provenance>,//; +path:Vec,ref_tracking:Option<&mut RefTracking,Vec>>,ctfe_mode:Option,)->//if true{}; +InterpResult<'tcx>{;trace!("validate_operand_internal: {:?}, {:?}",*op,op.layout +.ty);3;3;let mut visitor=ValidityVisitor{path,ref_tracking,ctfe_mode,ecx:self};; +match self.run_for_validation(||visitor.visit_value(op)) {Ok(())=>Ok(()),Err(err +)if matches!(err.kind(),err_ub!(ValidationError{..})|InterpError:://loop{break}; +InvalidProgram(_))=>{Err(err)}Err(err)=>{((),());let _=();((),());let _=();bug!( +"Unexpected error during validation: {}",format_interp_error(self. tcx.dcx(),err +));;}}}#[inline(always)]pub(crate)fn const_validate_operand(&self,op:&OpTy<'tcx, +M::Provenance>,path:Vec, ref_tracking:&mut RefTracking,Vec>, ctfe_mode:CtfeValidationMode,)->InterpResult<'tcx> +{(self.validate_operand_internal(op,path,Some(ref_tracking),Some(ctfe_mode)))}#[ +inline(always)]pub fn validate_operand(&self,op:&OpTy<'tcx,M::Provenance>)->//3; +InterpResult<'tcx>{((self.validate_operand_internal(op,((vec![])),None,None)))}} diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs index 0e824f3f592d4..6531c18d78736 100644 --- a/compiler/rustc_const_eval/src/interpret/visitor.rs +++ b/compiler/rustc_const_eval/src/interpret/visitor.rs @@ -1,213 +1,44 @@ -//! Visitor for a run-time value with a given layout: Traverse enums, structs and other compound -//! types until we arrive at the leaves, with custom handling for primitive types. - -use rustc_index::IndexVec; -use rustc_middle::mir::interpret::InterpResult; -use rustc_middle::ty::{self, Ty}; -use rustc_target::abi::FieldIdx; -use rustc_target::abi::{FieldsShape, VariantIdx, Variants}; - -use std::num::NonZero; - -use super::{InterpCx, MPlaceTy, Machine, Projectable}; - -/// How to traverse a value and what to do when we are at the leaves. -pub trait ValueVisitor<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>: Sized { - type V: Projectable<'tcx, M::Provenance> + From>; - - /// The visitor must have an `InterpCx` in it. - fn ecx(&self) -> &InterpCx<'mir, 'tcx, M>; - - /// `read_discriminant` can be hooked for better error messages. - #[inline(always)] - fn read_discriminant(&mut self, v: &Self::V) -> InterpResult<'tcx, VariantIdx> { - self.ecx().read_discriminant(&v.to_op(self.ecx())?) - } - - /// This function provides the chance to reorder the order in which fields are visited for - /// `FieldsShape::Aggregate`: The order of fields will be - /// `(0..num_fields).map(aggregate_field_order)`. - /// - /// The default means we iterate in source declaration order; alternative this can do an inverse - /// lookup in `memory_index` to use memory field order instead. - #[inline(always)] - fn aggregate_field_order(_memory_index: &IndexVec, idx: usize) -> usize { - idx - } - - // Recursive actions, ready to be overloaded. - /// Visits the given value, dispatching as appropriate to more specialized visitors. - #[inline(always)] - fn visit_value(&mut self, v: &Self::V) -> InterpResult<'tcx> { - self.walk_value(v) - } - /// Visits the given value as a union. No automatic recursion can happen here. - #[inline(always)] - fn visit_union(&mut self, _v: &Self::V, _fields: NonZero) -> InterpResult<'tcx> { - Ok(()) - } - /// Visits the given value as the pointer of a `Box`. There is nothing to recurse into. - /// The type of `v` will be a raw pointer to `T`, but this is a field of `Box` and the - /// pointee type is the actual `T`. `box_ty` provides the full type of the `Box` itself. - #[inline(always)] - fn visit_box(&mut self, _box_ty: Ty<'tcx>, _v: &Self::V) -> InterpResult<'tcx> { - Ok(()) - } - - /// Called each time we recurse down to a field of a "product-like" aggregate - /// (structs, tuples, arrays and the like, but not enums), passing in old (outer) - /// and new (inner) value. - /// This gives the visitor the chance to track the stack of nested fields that - /// we are descending through. - #[inline(always)] - fn visit_field( - &mut self, - _old_val: &Self::V, - _field: usize, - new_val: &Self::V, - ) -> InterpResult<'tcx> { - self.visit_value(new_val) - } - /// Called when recursing into an enum variant. - /// This gives the visitor the chance to track the stack of nested fields that - /// we are descending through. - #[inline(always)] - fn visit_variant( - &mut self, - _old_val: &Self::V, - _variant: VariantIdx, - new_val: &Self::V, - ) -> InterpResult<'tcx> { - self.visit_value(new_val) - } - - fn walk_value(&mut self, v: &Self::V) -> InterpResult<'tcx> { - let ty = v.layout().ty; - trace!("walk_value: type: {ty}"); - - // Special treatment for special types, where the (static) layout is not sufficient. - match *ty.kind() { - // If it is a trait object, switch to the real type that was used to create it. - ty::Dynamic(_, _, ty::Dyn) => { - // Dyn types. This is unsized, and the actual dynamic type of the data is given by the - // vtable stored in the place metadata. - // unsized values are never immediate, so we can assert_mem_place - let op = v.to_op(self.ecx())?; - let dest = op.assert_mem_place(); - let inner_mplace = self.ecx().unpack_dyn_trait(&dest)?.0; - trace!("walk_value: dyn object layout: {:#?}", inner_mplace.layout); - // recurse with the inner type - return self.visit_field(v, 0, &inner_mplace.into()); - } - ty::Dynamic(_, _, ty::DynStar) => { - // DynStar types. Very different from a dyn type (but strangely part of the - // same variant in `TyKind`): These are pairs where the 2nd component is the - // vtable, and the first component is the data (which must be ptr-sized). - let data = self.ecx().unpack_dyn_star(v)?.0; - return self.visit_field(v, 0, &data); - } - // Slices do not need special handling here: they have `Array` field - // placement with length 0, so we enter the `Array` case below which - // indirectly uses the metadata to determine the actual length. - - // However, `Box`... let's talk about `Box`. - ty::Adt(def, ..) if def.is_box() => { - // `Box` is a hybrid primitive-library-defined type that one the one hand is - // a dereferenceable pointer, on the other hand has *basically arbitrary - // user-defined layout* since the user controls the 'allocator' field. So it - // cannot be treated like a normal pointer, since it does not fit into an - // `Immediate`. Yeah, it is quite terrible. But many visitors want to do - // something with "all boxed pointers", so we handle this mess for them. - // - // When we hit a `Box`, we do not do the usual field recursion; instead, - // we (a) call `visit_box` on the pointer value, and (b) recurse on the - // allocator field. We also assert tons of things to ensure we do not miss - // any other fields. - - // `Box` has two fields: the pointer we care about, and the allocator. - assert_eq!(v.layout().fields.count(), 2, "`Box` must have exactly 2 fields"); - let (unique_ptr, alloc) = - (self.ecx().project_field(v, 0)?, self.ecx().project_field(v, 1)?); - // Unfortunately there is some type junk in the way here: `unique_ptr` is a `Unique`... - // (which means another 2 fields, the second of which is a `PhantomData`) - assert_eq!(unique_ptr.layout().fields.count(), 2); - let (nonnull_ptr, phantom) = ( - self.ecx().project_field(&unique_ptr, 0)?, - self.ecx().project_field(&unique_ptr, 1)?, - ); - assert!( - phantom.layout().ty.ty_adt_def().is_some_and(|adt| adt.is_phantom_data()), - "2nd field of `Unique` should be PhantomData but is {:?}", - phantom.layout().ty, - ); - // ... that contains a `NonNull`... (gladly, only a single field here) - assert_eq!(nonnull_ptr.layout().fields.count(), 1); - let raw_ptr = self.ecx().project_field(&nonnull_ptr, 0)?; // the actual raw ptr - // ... whose only field finally is a raw ptr we can dereference. - self.visit_box(ty, &raw_ptr)?; - - // The second `Box` field is the allocator, which we recursively check for validity - // like in regular structs. - self.visit_field(v, 1, &alloc)?; - - // We visited all parts of this one. - return Ok(()); - } - - // Non-normalized types should never show up here. - ty::Param(..) - | ty::Alias(..) - | ty::Bound(..) - | ty::Placeholder(..) - | ty::Infer(..) - | ty::Error(..) => throw_inval!(TooGeneric), - - // The rest is handled below. - _ => {} - }; - - // Visit the fields of this value. - match &v.layout().fields { - FieldsShape::Primitive => {} - &FieldsShape::Union(fields) => { - self.visit_union(v, fields)?; - } - FieldsShape::Arbitrary { offsets, memory_index } => { - for idx in 0..offsets.len() { - let idx = Self::aggregate_field_order(memory_index, idx); - let field = self.ecx().project_field(v, idx)?; - self.visit_field(v, idx, &field)?; - } - } - FieldsShape::Array { .. } => { - let mut iter = self.ecx().project_array_fields(v)?; - while let Some((idx, field)) = iter.next(self.ecx())? { - self.visit_field(v, idx.try_into().unwrap(), &field)?; - } - } - } - - match v.layout().variants { - // If this is a multi-variant layout, find the right variant and proceed - // with *its* fields. - Variants::Multiple { .. } => { - let idx = self.read_discriminant(v)?; - // There are 3 cases where downcasts can turn a Scalar/ScalarPair into a different ABI which - // could be a problem for `ImmTy` (see layout_sanity_check): - // - variant.size == Size::ZERO: works fine because `ImmTy::offset` has a special case for - // zero-sized layouts. - // - variant.fields.count() == 0: works fine because `ImmTy::offset` has a special case for - // zero-field aggregates. - // - variant.abi.is_uninhabited(): triggers UB in `read_discriminant` so we never get here. - let inner = self.ecx().project_downcast(v, idx)?; - trace!("walk_value: variant layout: {:#?}", inner.layout()); - // recurse with the inner type - self.visit_variant(v, idx, &inner)?; - } - // For single-variant layouts, we already did anything there is to do. - Variants::Single { .. } => {} - } - - Ok(()) - } -} +use rustc_index::IndexVec;use rustc_middle::mir::interpret::InterpResult;use//3; +rustc_middle::ty::{self,Ty};use rustc_target::abi::FieldIdx;use rustc_target::// +abi::{FieldsShape,VariantIdx,Variants};use std::num::NonZero;use super::{//({}); +InterpCx,MPlaceTy,Machine,Projectable};pub trait ValueVisitor<'mir,'tcx:'mir,M: +Machine<'mir,'tcx>>:Sized{type V: Projectable<'tcx,M::Provenance>+From>;fn ecx(&self)->&InterpCx<'mir,'tcx,M>;#[inline(always)]fn// +read_discriminant(&mut self,v:&Self::V )->InterpResult<'tcx,VariantIdx>{self.ecx +().read_discriminant(((&((((v.to_op(((self.ecx ())))))?)))))}#[inline(always)]fn +aggregate_field_order(_memory_index:&IndexVec,idx:usize)->usize{// +idx}#[inline(always)]fn visit_value(&mut self,v:&Self::V)->InterpResult<'tcx>{// +self.walk_value(v)}#[inline(always)]fn visit_union(&mut self,_v:&Self::V,//({}); +_fields:NonZero)->InterpResult<'tcx>{(((Ok(((()))))))}#[inline(always)]fn +visit_box(&mut self,_box_ty:Ty<'tcx>,_v:&Self:: V)->InterpResult<'tcx>{Ok(())}#[ +inline(always)]fn visit_field(&mut self ,_old_val:&Self::V,_field:usize,new_val: +&Self::V,)->InterpResult<'tcx>{((self.visit_value(new_val)))}#[inline(always)]fn +visit_variant(&mut self,_old_val:&Self:: V,_variant:VariantIdx,new_val:&Self::V, +)->InterpResult<'tcx>{self.visit_value(new_val) }fn walk_value(&mut self,v:&Self +::V)->InterpResult<'tcx>{;let ty=v.layout().ty;trace!("walk_value: type: {ty}"); +match*ty.kind(){ty::Dynamic(_,_,ty::Dyn)=>{;let op=v.to_op(self.ecx())?;let dest +=op.assert_mem_place();;;let inner_mplace=self.ecx().unpack_dyn_trait(&dest)?.0; +trace!("walk_value: dyn object layout: {:#?}",inner_mplace.layout);;return self. +visit_field(v,0,&inner_mplace.into());;}ty::Dynamic(_,_,ty::DynStar)=>{let data= +self.ecx().unpack_dyn_star(v)?.0;;;return self.visit_field(v,0,&data);;}ty::Adt( +def,..)if def.is_box()=>{((),());((),());assert_eq!(v.layout().fields.count(),2, +"`Box` must have exactly 2 fields");({});({});let(unique_ptr,alloc)=(self.ecx(). +project_field(v,0)?,self.ecx().project_field(v,1)?);();();assert_eq!(unique_ptr. +layout().fields.count(),2);;let(nonnull_ptr,phantom)=(self.ecx().project_field(& +unique_ptr,0)?,self.ecx().project_field(&unique_ptr,1)?,);();();assert!(phantom. +layout().ty.ty_adt_def().is_some_and(|adt|adt.is_phantom_data()),//loop{break;}; +"2nd field of `Unique` should be PhantomData but is {:?}",phantom.layout ().ty,) +;3;3;assert_eq!(nonnull_ptr.layout().fields.count(),1);;;let raw_ptr=self.ecx(). +project_field(&nonnull_ptr,0)?;;self.visit_box(ty,&raw_ptr)?;self.visit_field(v, +1,&alloc)?;();();return Ok(());3;}ty::Param(..)|ty::Alias(..)|ty::Bound(..)|ty:: +Placeholder(..)|ty::Infer(..)|ty::Error(..)=>throw_inval!(TooGeneric),_=>{}};(); +match&v.layout().fields{ FieldsShape::Primitive=>{}&FieldsShape::Union(fields)=> +{3;self.visit_union(v,fields)?;;}FieldsShape::Arbitrary{offsets,memory_index}=>{ +for idx in 0..offsets.len(){();let idx=Self::aggregate_field_order(memory_index, +idx);;let field=self.ecx().project_field(v,idx)?;self.visit_field(v,idx,&field)? +;;}}FieldsShape::Array{..}=>{;let mut iter=self.ecx().project_array_fields(v)?;; +while let Some((idx,field))=iter.next(self.ecx())?{{();};self.visit_field(v,idx. +try_into().unwrap(),&field)?;;}}}match v.layout().variants{Variants::Multiple{.. +}=>{;let idx=self.read_discriminant(v)?;let inner=self.ecx().project_downcast(v, +idx)?;();();trace!("walk_value: variant layout: {:#?}",inner.layout());3;3;self. +visit_variant(v,idx,&inner)?;((),());let _=();}Variants::Single{..}=>{}}Ok(())}} diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 50420aaec045b..14e507cfa6c01 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -1,67 +1,25 @@ -/*! - -Rust MIR: a lowered representation of Rust. - -*/ - -#![allow(internal_features)] -#![allow(rustc::diagnostic_outside_of_impl)] -#![feature(rustdoc_internals)] -#![doc(rust_logo)] -#![feature(assert_matches)] -#![feature(box_patterns)] -#![feature(decl_macro)] -#![feature(generic_nonzero)] -#![feature(let_chains)] -#![feature(slice_ptr_get)] -#![feature(strict_provenance)] -#![feature(never_type)] -#![feature(trait_alias)] -#![feature(try_blocks)] -#![feature(yeet_expr)] -#![feature(if_let_guard)] - -#[macro_use] -extern crate tracing; -#[macro_use] -extern crate rustc_middle; - -pub mod const_eval; -mod errors; -pub mod interpret; -pub mod transform; -pub mod util; - -use std::sync::atomic::AtomicBool; - -pub use errors::ReportErrorExt; - -use rustc_middle::{ty, util::Providers}; - -rustc_fluent_macro::fluent_messages! { "../messages.ftl" } - -pub fn provide(providers: &mut Providers) { - const_eval::provide(providers); - providers.tag_for_variant = const_eval::tag_for_variant_provider; - providers.eval_to_const_value_raw = const_eval::eval_to_const_value_raw_provider; - providers.eval_to_allocation_raw = const_eval::eval_to_allocation_raw_provider; - providers.eval_static_initializer = const_eval::eval_static_initializer_provider; - providers.hooks.const_caller_location = util::caller_location::const_caller_location_provider; - providers.eval_to_valtree = |tcx, param_env_and_value| { - let (param_env, raw) = param_env_and_value.into_parts(); - const_eval::eval_to_valtree(tcx, param_env, raw) - }; - providers.hooks.try_destructure_mir_constant_for_user_output = - const_eval::try_destructure_mir_constant_for_user_output; - providers.valtree_to_const_val = |tcx, (ty, valtree)| { - const_eval::valtree_to_const_value(tcx, ty::ParamEnv::empty().and(ty), valtree) - }; - providers.check_validity_requirement = |tcx, (init_kind, param_env_and_ty)| { - util::check_validity_requirement(tcx, init_kind, param_env_and_ty) - }; -} - -/// `rustc_driver::main` installs a handler that will set this to `true` if -/// the compiler has been sent a request to shut down, such as by a Ctrl-C. -/// This static lives here because it is only read by the interpreter. -pub static CTRL_C_RECEIVED: AtomicBool = AtomicBool::new(false); +#![allow(internal_features)]#![allow(rustc::diagnostic_outside_of_impl)]#![//(); +feature(rustdoc_internals)]#![doc(rust_logo)]#![feature(assert_matches)]#![//(); +feature(box_patterns)]#![feature(decl_macro)]#![feature(generic_nonzero)]#![//3; +feature(let_chains)]#![feature(slice_ptr_get) ]#![feature(strict_provenance)]#![ +feature(never_type)]#![feature(trait_alias)]#![feature(try_blocks)]#![feature(// +yeet_expr)]#![feature(if_let_guard)]#[macro_use]extern crate tracing;#[//*&*&(); +macro_use]extern crate rustc_middle;pub mod const_eval;mod errors;pub mod//({}); +interpret;pub mod transform;pub mod util;use std::sync::atomic::AtomicBool;pub// +use errors::ReportErrorExt;use rustc_middle::{ty,util::Providers};//loop{break}; +rustc_fluent_macro::fluent_messages!{"../messages.ftl"} pub fn provide(providers +:&mut Providers){3;const_eval::provide(providers);3;3;providers.tag_for_variant= +const_eval::tag_for_variant_provider;({});{;};providers.eval_to_const_value_raw= +const_eval::eval_to_const_value_raw_provider;;;providers.eval_to_allocation_raw= +const_eval::eval_to_allocation_raw_provider;;;providers.eval_static_initializer= +const_eval::eval_static_initializer_provider;if true{};let _=();providers.hooks. +const_caller_location=util::caller_location::const_caller_location_provider;3;3; +providers.eval_to_valtree=|tcx,param_env_and_value|{let _=();let(param_env,raw)= +param_env_and_value.into_parts();;const_eval::eval_to_valtree(tcx,param_env,raw) +};();3;providers.hooks.try_destructure_mir_constant_for_user_output=const_eval:: +try_destructure_mir_constant_for_user_output;3;;providers.valtree_to_const_val=| +tcx,(ty,valtree)|{const_eval::valtree_to_const_value (tcx,ty::ParamEnv::empty(). +and(ty),valtree)};({});{;};providers.check_validity_requirement=|tcx,(init_kind, +param_env_and_ty)|{util::check_validity_requirement(tcx,init_kind,//loop{break}; +param_env_and_ty)};;}pub static CTRL_C_RECEIVED:AtomicBool=AtomicBool::new(false +);//let _=();if true{};let _=();if true{};let _=();if true{};let _=();if true{}; 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 da8e28d02982e..d3ce5ea149a33 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -1,1006 +1,263 @@ -//! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations. - -use rustc_errors::{Diag, ErrorGuaranteed}; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_index::bit_set::BitSet; -use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::traits::ObligationCause; -use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::*; -use rustc_middle::ty::{self, adjustment::PointerCoercion, Ty, TyCtxt}; -use rustc_middle::ty::{Instance, InstanceDef, TypeVisitableExt}; -use rustc_mir_dataflow::Analysis; -use rustc_span::{sym, Span, Symbol}; -use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; -use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt}; -use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitor}; - -use std::mem; -use std::ops::Deref; - -use super::ops::{self, NonConstOp, Status}; -use super::qualifs::{self, HasMutInterior, NeedsDrop, NeedsNonConstDrop}; -use super::resolver::FlowSensitiveAnalysis; -use super::{ConstCx, Qualif}; -use crate::const_eval::is_unstable_const_fn; -use crate::errors::UnstableInStable; - -type QualifResults<'mir, 'tcx, Q> = - rustc_mir_dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'mir, 'mir, 'tcx, Q>>; - -#[derive(Default)] -pub(crate) struct Qualifs<'mir, 'tcx> { - has_mut_interior: Option>, - needs_drop: Option>, - needs_non_const_drop: Option>, -} - -impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { - /// Returns `true` if `local` is `NeedsDrop` at the given `Location`. - /// - /// Only updates the cursor if absolutely necessary - pub fn needs_drop( - &mut self, - ccx: &'mir ConstCx<'mir, 'tcx>, - local: Local, - location: Location, - ) -> bool { - let ty = ccx.body.local_decls[local].ty; - // Peeking into opaque types causes cycles if the current function declares said opaque - // type. Thus we avoid short circuiting on the type and instead run the more expensive - // analysis that looks at the actual usage within this function - if !ty.has_opaque_types() && !NeedsDrop::in_any_value_of_ty(ccx, ty) { - return false; - } - - let needs_drop = self.needs_drop.get_or_insert_with(|| { - let ConstCx { tcx, body, .. } = *ccx; - - FlowSensitiveAnalysis::new(NeedsDrop, ccx) - .into_engine(tcx, body) - .iterate_to_fixpoint() - .into_results_cursor(body) - }); - - needs_drop.seek_before_primary_effect(location); - needs_drop.get().contains(local) - } - - /// Returns `true` if `local` is `NeedsNonConstDrop` at the given `Location`. - /// - /// Only updates the cursor if absolutely necessary - pub fn needs_non_const_drop( - &mut self, - ccx: &'mir ConstCx<'mir, 'tcx>, - local: Local, - location: Location, - ) -> bool { - let ty = ccx.body.local_decls[local].ty; - // Peeking into opaque types causes cycles if the current function declares said opaque - // type. Thus we avoid short circuiting on the type and instead run the more expensive - // analysis that looks at the actual usage within this function - if !ty.has_opaque_types() && !NeedsNonConstDrop::in_any_value_of_ty(ccx, ty) { - return false; - } - - let needs_non_const_drop = self.needs_non_const_drop.get_or_insert_with(|| { - let ConstCx { tcx, body, .. } = *ccx; - - FlowSensitiveAnalysis::new(NeedsNonConstDrop, ccx) - .into_engine(tcx, body) - .iterate_to_fixpoint() - .into_results_cursor(body) - }); - - needs_non_const_drop.seek_before_primary_effect(location); - needs_non_const_drop.get().contains(local) - } - - /// Returns `true` if `local` is `HasMutInterior` at the given `Location`. - /// - /// Only updates the cursor if absolutely necessary. - pub fn has_mut_interior( - &mut self, - ccx: &'mir ConstCx<'mir, 'tcx>, - local: Local, - location: Location, - ) -> bool { - let ty = ccx.body.local_decls[local].ty; - // Peeking into opaque types causes cycles if the current function declares said opaque - // type. Thus we avoid short circuiting on the type and instead run the more expensive - // analysis that looks at the actual usage within this function - if !ty.has_opaque_types() && !HasMutInterior::in_any_value_of_ty(ccx, ty) { - return false; - } - - let has_mut_interior = self.has_mut_interior.get_or_insert_with(|| { - let ConstCx { tcx, body, .. } = *ccx; - - FlowSensitiveAnalysis::new(HasMutInterior, ccx) - .into_engine(tcx, body) - .iterate_to_fixpoint() - .into_results_cursor(body) - }); - - has_mut_interior.seek_before_primary_effect(location); - has_mut_interior.get().contains(local) - } - - fn in_return_place( - &mut self, - ccx: &'mir ConstCx<'mir, 'tcx>, - tainted_by_errors: Option, - ) -> ConstQualifs { - // Find the `Return` terminator if one exists. - // - // If no `Return` terminator exists, this MIR is divergent. Just return the conservative - // qualifs for the return type. - let return_block = ccx - .body - .basic_blocks - .iter_enumerated() - .find(|(_, block)| matches!(block.terminator().kind, TerminatorKind::Return)) - .map(|(bb, _)| bb); - - let Some(return_block) = return_block else { - return qualifs::in_any_value_of_ty(ccx, ccx.body.return_ty(), tainted_by_errors); - }; - - let return_loc = ccx.body.terminator_loc(return_block); - - ConstQualifs { - needs_drop: self.needs_drop(ccx, RETURN_PLACE, return_loc), - needs_non_const_drop: self.needs_non_const_drop(ccx, RETURN_PLACE, return_loc), - has_mut_interior: self.has_mut_interior(ccx, RETURN_PLACE, return_loc), - tainted_by_errors, - } - } -} - -struct LocalReturnTyVisitor<'ck, 'mir, 'tcx> { - kind: LocalKind, - checker: &'ck mut Checker<'mir, 'tcx>, -} - -impl<'ck, 'mir, 'tcx> TypeVisitor> for LocalReturnTyVisitor<'ck, 'mir, 'tcx> { - fn visit_ty(&mut self, t: Ty<'tcx>) { - match t.kind() { - ty::FnPtr(_) => {} - ty::Ref(_, _, hir::Mutability::Mut) => { - self.checker.check_op(ops::ty::MutRef(self.kind)); - t.super_visit_with(self) - } - _ => t.super_visit_with(self), - } - } -} - -pub struct Checker<'mir, 'tcx> { - ccx: &'mir ConstCx<'mir, 'tcx>, - qualifs: Qualifs<'mir, 'tcx>, - - /// The span of the current statement. - span: Span, - - /// A set that stores for each local whether it has a `StorageDead` for it somewhere. - local_has_storage_dead: Option>, - - error_emitted: Option, - secondary_errors: Vec>, -} - -impl<'mir, 'tcx> Deref for Checker<'mir, 'tcx> { - type Target = ConstCx<'mir, 'tcx>; - - fn deref(&self) -> &Self::Target { - self.ccx - } -} - -impl<'mir, 'tcx> Checker<'mir, 'tcx> { - pub fn new(ccx: &'mir ConstCx<'mir, 'tcx>) -> Self { - Checker { - span: ccx.body.span, - ccx, - qualifs: Default::default(), - local_has_storage_dead: None, - error_emitted: None, - secondary_errors: Vec::new(), - } - } - - pub fn check_body(&mut self) { - let ConstCx { tcx, body, .. } = *self.ccx; - let def_id = self.ccx.def_id(); - - // `async` functions cannot be `const fn`. This is checked during AST lowering, so there's - // no need to emit duplicate errors here. - if self.ccx.is_async() || body.coroutine.is_some() { - tcx.dcx().span_delayed_bug(body.span, "`async` functions cannot be `const fn`"); - return; - } - - // The local type and predicate checks are not free and only relevant for `const fn`s. - if self.const_kind() == hir::ConstContext::ConstFn { - for (idx, local) in body.local_decls.iter_enumerated() { - // Handle the return place below. - if idx == RETURN_PLACE { - continue; - } - - self.span = local.source_info.span; - self.check_local_or_return_ty(local.ty, idx); - } - - // impl trait is gone in MIR, so check the return type of a const fn by its signature - // instead of the type of the return place. - self.span = body.local_decls[RETURN_PLACE].source_info.span; - let return_ty = self.ccx.fn_sig().output(); - self.check_local_or_return_ty(return_ty.skip_binder(), RETURN_PLACE); - } - - if !tcx.has_attr(def_id, sym::rustc_do_not_const_check) { - self.visit_body(body); - } - - // If we got through const-checking without emitting any "primary" errors, emit any - // "secondary" errors if they occurred. Otherwise, cancel the "secondary" errors. - let secondary_errors = mem::take(&mut self.secondary_errors); - if self.error_emitted.is_none() { - for error in secondary_errors { - self.error_emitted = Some(error.emit()); - } - } else { - assert!(self.tcx.dcx().has_errors().is_some()); - for error in secondary_errors { - error.cancel(); - } - } - } - - fn local_has_storage_dead(&mut self, local: Local) -> bool { - let ccx = self.ccx; - self.local_has_storage_dead - .get_or_insert_with(|| { - struct StorageDeads { - locals: BitSet, - } - impl<'tcx> Visitor<'tcx> for StorageDeads { - fn visit_statement(&mut self, stmt: &Statement<'tcx>, _: Location) { - if let StatementKind::StorageDead(l) = stmt.kind { - self.locals.insert(l); - } - } - } - let mut v = StorageDeads { locals: BitSet::new_empty(ccx.body.local_decls.len()) }; - v.visit_body(ccx.body); - v.locals - }) - .contains(local) - } - - pub fn qualifs_in_return_place(&mut self) -> ConstQualifs { - self.qualifs.in_return_place(self.ccx, self.error_emitted) - } - - /// Emits an error if an expression cannot be evaluated in the current context. - pub fn check_op(&mut self, op: impl NonConstOp<'tcx>) { - self.check_op_spanned(op, self.span); - } - - /// Emits an error at the given `span` if an expression cannot be evaluated in the current - /// context. - pub fn check_op_spanned>(&mut self, op: O, span: Span) { - let gate = match op.status_in_item(self.ccx) { - Status::Allowed => return, - - Status::Unstable(gate) if self.tcx.features().active(gate) => { - let unstable_in_stable = self.ccx.is_const_stable_const_fn() - && !super::rustc_allow_const_fn_unstable(self.tcx, self.def_id(), gate); - if unstable_in_stable { - emit_unstable_in_stable_error(self.ccx, span, gate); - } - - return; - } - - Status::Unstable(gate) => Some(gate), - Status::Forbidden => None, - }; - - if self.tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you { - self.tcx.sess.miri_unleashed_feature(span, gate); - return; - } - - let err = op.build_error(self.ccx, span); - assert!(err.is_error()); - - match op.importance() { - ops::DiagImportance::Primary => { - let reported = err.emit(); - self.error_emitted = Some(reported); - } - - ops::DiagImportance::Secondary => self.secondary_errors.push(err), - } - } - - fn check_static(&mut self, def_id: DefId, span: Span) { - if self.tcx.is_thread_local_static(def_id) { - self.tcx.dcx().span_bug(span, "tls access is checked in `Rvalue::ThreadLocalRef`"); - } - self.check_op_spanned(ops::StaticAccess, span) - } - - fn check_local_or_return_ty(&mut self, ty: Ty<'tcx>, local: Local) { - let kind = self.body.local_kind(local); - - let mut visitor = LocalReturnTyVisitor { kind, checker: self }; - - visitor.visit_ty(ty); - } - - fn check_mut_borrow(&mut self, place: &Place<'_>, kind: hir::BorrowKind) { - match self.const_kind() { - // In a const fn all borrows are transient or point to the places given via - // references in the arguments (so we already checked them with - // TransientMutBorrow/MutBorrow as appropriate). - // The borrow checker guarantees that no new non-transient borrows are created. - // NOTE: Once we have heap allocations during CTFE we need to figure out - // how to prevent `const fn` to create long-lived allocations that point - // to mutable memory. - hir::ConstContext::ConstFn => self.check_op(ops::TransientMutBorrow(kind)), - _ => { - // For indirect places, we are not creating a new permanent borrow, it's just as - // transient as the already existing one. For reborrowing references this is handled - // at the top of `visit_rvalue`, but for raw pointers we handle it here. - // Pointers/references to `static mut` and cases where the `*` is not the first - // projection also end up here. - // Locals with StorageDead do not live beyond the evaluation and can - // thus safely be borrowed without being able to be leaked to the final - // value of the constant. - // Note: This is only sound if every local that has a `StorageDead` has a - // `StorageDead` in every control flow path leading to a `return` terminator. - // The good news is that interning will detect if any unexpected mutable - // pointer slips through. - if place.is_indirect() || self.local_has_storage_dead(place.local) { - self.check_op(ops::TransientMutBorrow(kind)); - } else { - self.check_op(ops::MutBorrow(kind)); - } - } - } - } -} - -impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { - fn visit_basic_block_data(&mut self, bb: BasicBlock, block: &BasicBlockData<'tcx>) { - trace!("visit_basic_block_data: bb={:?} is_cleanup={:?}", bb, block.is_cleanup); - - // We don't const-check basic blocks on the cleanup path since we never unwind during - // const-eval: a panic causes an immediate compile error. In other words, cleanup blocks - // are unreachable during const-eval. - // - // We can't be more conservative (e.g., by const-checking cleanup blocks anyways) because - // locals that would never be dropped during normal execution are sometimes dropped during - // unwinding, which means backwards-incompatible live-drop errors. - if block.is_cleanup { - return; - } - - self.super_basic_block_data(bb, block); - } - - fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { - trace!("visit_rvalue: rvalue={:?} location={:?}", rvalue, location); - - // Special-case reborrows to be more like a copy of a reference. - // FIXME: this does not actually handle all reborrows. It only detects cases where `*` is the outermost - // projection of the borrowed place, it skips deref'ing raw pointers and it skips `static`. - // All those cases are handled below with shared/mutable borrows. - // Once `const_mut_refs` is stable, we should be able to entirely remove this special case. - // (`const_refs_to_cell` is not needed, we already allow all borrows of indirect places anyway.) - match *rvalue { - Rvalue::Ref(_, kind, place) => { - if let Some(reborrowed_place_ref) = place_as_reborrow(self.tcx, self.body, place) { - let ctx = match kind { - BorrowKind::Shared => { - PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) - } - BorrowKind::Fake => { - PlaceContext::NonMutatingUse(NonMutatingUseContext::FakeBorrow) - } - BorrowKind::Mut { .. } => { - PlaceContext::MutatingUse(MutatingUseContext::Borrow) - } - }; - self.visit_local(reborrowed_place_ref.local, ctx, location); - self.visit_projection(reborrowed_place_ref, ctx, location); - return; - } - } - Rvalue::AddressOf(mutbl, place) => { - if let Some(reborrowed_place_ref) = place_as_reborrow(self.tcx, self.body, place) { - let ctx = match mutbl { - Mutability::Not => { - PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) - } - Mutability::Mut => PlaceContext::MutatingUse(MutatingUseContext::AddressOf), - }; - self.visit_local(reborrowed_place_ref.local, ctx, location); - self.visit_projection(reborrowed_place_ref, ctx, location); - return; - } - } - _ => {} - } - - self.super_rvalue(rvalue, location); - - match rvalue { - Rvalue::ThreadLocalRef(_) => self.check_op(ops::ThreadLocalAccess), - - Rvalue::Use(_) - | Rvalue::CopyForDeref(..) - | Rvalue::Repeat(..) - | Rvalue::Discriminant(..) - | Rvalue::Len(_) => {} - - Rvalue::Aggregate(kind, ..) => { - if let AggregateKind::Coroutine(def_id, ..) = kind.as_ref() - && let Some( - coroutine_kind @ hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, - _, - ), - ) = self.tcx.coroutine_kind(def_id) - { - self.check_op(ops::Coroutine(coroutine_kind)); - } - } - - Rvalue::Ref(_, BorrowKind::Mut { .. }, place) - | Rvalue::AddressOf(Mutability::Mut, place) => { - // Inside mutable statics, we allow arbitrary mutable references. - // We've allowed `static mut FOO = &mut [elements];` for a long time (the exact - // reasons why are lost to history), and there is no reason to restrict that to - // arrays and slices. - let is_allowed = - self.const_kind() == hir::ConstContext::Static(hir::Mutability::Mut); - - if !is_allowed { - self.check_mut_borrow( - place, - if matches!(rvalue, Rvalue::Ref(..)) { - hir::BorrowKind::Ref - } else { - hir::BorrowKind::Raw - }, - ); - } - } - - Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Fake, place) - | Rvalue::AddressOf(Mutability::Not, place) => { - let borrowed_place_has_mut_interior = qualifs::in_place::( - self.ccx, - &mut |local| self.qualifs.has_mut_interior(self.ccx, local, location), - place.as_ref(), - ); - - // If the place is indirect, this is basically a reborrow. We have a reborrow - // special case above, but for raw pointers and pointers/references to `static` and - // when the `*` is not the first projection, `place_as_reborrow` does not recognize - // them as such, so we end up here. This should probably be considered a - // `TransientCellBorrow` (we consider the equivalent mutable case a - // `TransientMutBorrow`), but such reborrows got accidentally stabilized already and - // it is too much of a breaking change to take back. - if borrowed_place_has_mut_interior && !place.is_indirect() { - match self.const_kind() { - // In a const fn all borrows are transient or point to the places given via - // references in the arguments (so we already checked them with - // TransientCellBorrow/CellBorrow as appropriate). - // The borrow checker guarantees that no new non-transient borrows are created. - // NOTE: Once we have heap allocations during CTFE we need to figure out - // how to prevent `const fn` to create long-lived allocations that point - // to (interior) mutable memory. - hir::ConstContext::ConstFn => self.check_op(ops::TransientCellBorrow), - _ => { - // Locals with StorageDead are definitely not part of the final constant value, and - // it is thus inherently safe to permit such locals to have their - // address taken as we can't end up with a reference to them in the - // final value. - // Note: This is only sound if every local that has a `StorageDead` has a - // `StorageDead` in every control flow path leading to a `return` terminator. - // The good news is that interning will detect if any unexpected mutable - // pointer slips through. - if self.local_has_storage_dead(place.local) { - self.check_op(ops::TransientCellBorrow); - } else { - self.check_op(ops::CellBorrow); - } - } - } - } - } - - Rvalue::Cast( - CastKind::PointerCoercion( - PointerCoercion::MutToConstPointer - | PointerCoercion::ArrayToPointer - | PointerCoercion::UnsafeFnPointer - | PointerCoercion::ClosureFnPointer(_) - | PointerCoercion::ReifyFnPointer, - ), - _, - _, - ) => { - // These are all okay; they only change the type, not the data. - } - - Rvalue::Cast(CastKind::PointerCoercion(PointerCoercion::Unsize), _, _) => { - // Unsizing is implemented for CTFE. - } - - Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => { - self.check_op(ops::RawPtrToIntCast); - } - Rvalue::Cast(CastKind::PointerFromExposedAddress, _, _) => { - // Since no pointer can ever get exposed (rejected above), this is easy to support. - } - - Rvalue::Cast(CastKind::DynStar, _, _) => { - // `dyn*` coercion is implemented for CTFE. - } - - Rvalue::Cast(_, _, _) => {} - - Rvalue::NullaryOp( - NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_) | NullOp::UbChecks, - _, - ) => {} - Rvalue::ShallowInitBox(_, _) => {} - - Rvalue::UnaryOp(_, operand) => { - let ty = operand.ty(self.body, self.tcx); - if is_int_bool_or_char(ty) { - // Int, bool, and char operations are fine. - } else if ty.is_floating_point() { - self.check_op(ops::FloatingPointOp); - } else { - span_bug!(self.span, "non-primitive type in `Rvalue::UnaryOp`: {:?}", ty); - } - } - - Rvalue::BinaryOp(op, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(op, box (lhs, rhs)) => { - let lhs_ty = lhs.ty(self.body, self.tcx); - let rhs_ty = rhs.ty(self.body, self.tcx); - - if is_int_bool_or_char(lhs_ty) && is_int_bool_or_char(rhs_ty) { - // Int, bool, and char operations are fine. - } else if lhs_ty.is_fn_ptr() || lhs_ty.is_unsafe_ptr() { - assert!(matches!( - op, - BinOp::Eq - | BinOp::Ne - | BinOp::Le - | BinOp::Lt - | BinOp::Ge - | BinOp::Gt - | BinOp::Offset - )); - - self.check_op(ops::RawPtrComparison); - } else if lhs_ty.is_floating_point() || rhs_ty.is_floating_point() { - self.check_op(ops::FloatingPointOp); - } else { - span_bug!( - self.span, - "non-primitive type in `Rvalue::BinaryOp`: {:?} ⚬ {:?}", - lhs_ty, - rhs_ty - ); - } - } - } - } - - fn visit_operand(&mut self, op: &Operand<'tcx>, location: Location) { - self.super_operand(op, location); - if let Operand::Constant(c) = op { - if let Some(def_id) = c.check_static_ptr(self.tcx) { - self.check_static(def_id, self.span); - } - } - } - fn visit_projection_elem( - &mut self, - place_ref: PlaceRef<'tcx>, - elem: PlaceElem<'tcx>, - context: PlaceContext, - location: Location, - ) { - trace!( - "visit_projection_elem: place_ref={:?} elem={:?} \ - context={:?} location={:?}", - place_ref, - elem, - context, - location, - ); - - self.super_projection_elem(place_ref, elem, context, location); - - match elem { - ProjectionElem::Deref => { - let base_ty = place_ref.ty(self.body, self.tcx).ty; - if base_ty.is_unsafe_ptr() { - if place_ref.projection.is_empty() { - let decl = &self.body.local_decls[place_ref.local]; - // If this is a static, then this is not really dereferencing a pointer, - // just directly accessing a static. That is not subject to any feature - // gates (except for the one about whether statics can even be used, but - // that is checked already by `visit_operand`). - if let LocalInfo::StaticRef { .. } = *decl.local_info() { - return; - } - } - - // `*const T` is stable, `*mut T` is not - if !base_ty.is_mutable_ptr() { - return; - } - - self.check_op(ops::RawMutPtrDeref); - } - - if context.is_mutating_use() { - self.check_op(ops::MutDeref); - } - } - - ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Downcast(..) - | ProjectionElem::OpaqueCast(..) - | ProjectionElem::Subslice { .. } - | ProjectionElem::Subtype(..) - | ProjectionElem::Field(..) - | ProjectionElem::Index(_) => {} - } - } - - fn visit_source_info(&mut self, source_info: &SourceInfo) { - trace!("visit_source_info: source_info={:?}", source_info); - self.span = source_info.span; - } - - fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { - trace!("visit_statement: statement={:?} location={:?}", statement, location); - - self.super_statement(statement, location); - - match statement.kind { - StatementKind::Assign(..) - | StatementKind::SetDiscriminant { .. } - | StatementKind::Deinit(..) - | StatementKind::FakeRead(..) - | StatementKind::StorageLive(_) - | StatementKind::StorageDead(_) - | StatementKind::Retag { .. } - | StatementKind::PlaceMention(..) - | StatementKind::AscribeUserType(..) - | StatementKind::Coverage(..) - | StatementKind::Intrinsic(..) - | StatementKind::ConstEvalCounter - | StatementKind::Nop => {} - } - } - - #[instrument(level = "debug", skip(self))] - fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { - self.super_terminator(terminator, location); - - match &terminator.kind { - TerminatorKind::Call { func, args, fn_span, call_source, .. } => { - let ConstCx { tcx, body, param_env, .. } = *self.ccx; - let caller = self.def_id(); - - let fn_ty = func.ty(body, tcx); - - let (mut callee, mut fn_args) = match *fn_ty.kind() { - ty::FnDef(def_id, fn_args) => (def_id, fn_args), - - ty::FnPtr(_) => { - self.check_op(ops::FnCallIndirect); - return; - } - _ => { - span_bug!(terminator.source_info.span, "invalid callee of type {:?}", fn_ty) - } - }; - - // Check that all trait bounds that are marked as `~const` can be satisfied. - // - // Typeck only does a "non-const" check since it operates on HIR and cannot distinguish - // which path expressions are getting called on and which path expressions are only used - // as function pointers. This is required for correctness. - let infcx = tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(&infcx); - - let predicates = tcx.predicates_of(callee).instantiate(tcx, fn_args); - let cause = ObligationCause::new( - terminator.source_info.span, - self.body.source.def_id().expect_local(), - ObligationCauseCode::ItemObligation(callee), - ); - let normalized_predicates = ocx.normalize(&cause, param_env, predicates); - ocx.register_obligations(traits::predicates_for_generics( - |_, _| cause.clone(), - self.param_env, - normalized_predicates, - )); - - let errors = ocx.select_all_or_error(); - if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(errors); - } - - let mut is_trait = false; - // Attempting to call a trait method? - if tcx.trait_of_item(callee).is_some() { - trace!("attempting to call a trait method"); - // trait method calls are only permitted when `effects` is enabled. - // we don't error, since that is handled by typeck. We try to resolve - // the trait into the concrete method, and uses that for const stability - // checks. - // FIXME(effects) we might consider moving const stability checks to typeck as well. - if tcx.features().effects { - is_trait = true; - - if let Ok(Some(instance)) = - Instance::resolve(tcx, param_env, callee, fn_args) - && let InstanceDef::Item(def) = instance.def - { - // Resolve a trait method call to its concrete implementation, which may be in a - // `const` trait impl. This is only used for the const stability check below, since - // we want to look at the concrete impl's stability. - fn_args = instance.args; - callee = def; - } - } else { - self.check_op(ops::FnCallNonConst { - caller, - callee, - args: fn_args, - span: *fn_span, - call_source: *call_source, - feature: Some(if tcx.features().const_trait_impl { - sym::effects - } else { - sym::const_trait_impl - }), - }); - return; - } - } - - // At this point, we are calling a function, `callee`, whose `DefId` is known... - - // `begin_panic` and `#[rustc_const_panic_str]` functions accept generic - // types other than str. Check to enforce that only str can be used in - // const-eval. - - // const-eval of the `begin_panic` fn assumes the argument is `&str` - if Some(callee) == tcx.lang_items().begin_panic_fn() { - match args[0].node.ty(&self.ccx.body.local_decls, tcx).kind() { - ty::Ref(_, ty, _) if ty.is_str() => return, - _ => self.check_op(ops::PanicNonStr), - } - } - - // const-eval of `#[rustc_const_panic_str]` functions assumes the argument is `&&str` - if tcx.has_attr(callee, sym::rustc_const_panic_str) { - match args[0].node.ty(&self.ccx.body.local_decls, tcx).kind() { - ty::Ref(_, ty, _) if matches!(ty.kind(), ty::Ref(_, ty, _) if ty.is_str()) => - { - return; - } - _ => self.check_op(ops::PanicNonStr), - } - } - - if Some(callee) == tcx.lang_items().exchange_malloc_fn() { - self.check_op(ops::HeapAllocation); - return; - } - - if !tcx.is_const_fn_raw(callee) && !is_trait { - self.check_op(ops::FnCallNonConst { - caller, - callee, - args: fn_args, - span: *fn_span, - call_source: *call_source, - feature: None, - }); - return; - } - - // If the `const fn` we are trying to call is not const-stable, ensure that we have - // the proper feature gate enabled. - if let Some((gate, implied_by)) = is_unstable_const_fn(tcx, callee) { - trace!(?gate, "calling unstable const fn"); - if self.span.allows_unstable(gate) { - return; - } - if let Some(implied_by_gate) = implied_by - && self.span.allows_unstable(implied_by_gate) - { - return; - } - - // Calling an unstable function *always* requires that the corresponding gate - // (or implied gate) be enabled, even if the function has - // `#[rustc_allow_const_fn_unstable(the_gate)]`. - let gate_declared = |gate| { - tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == gate) - }; - let feature_gate_declared = gate_declared(gate); - let implied_gate_declared = implied_by.is_some_and(gate_declared); - if !feature_gate_declared && !implied_gate_declared { - self.check_op(ops::FnCallUnstable(callee, Some(gate))); - return; - } - - // If this crate is not using stability attributes, or the caller is not claiming to be a - // stable `const fn`, that is all that is required. - if !self.ccx.is_const_stable_const_fn() { - trace!("crate not using stability attributes or caller not stably const"); - return; - } - - // Otherwise, we are something const-stable calling a const-unstable fn. - if super::rustc_allow_const_fn_unstable(tcx, caller, gate) { - trace!("rustc_allow_const_fn_unstable gate active"); - return; - } - - self.check_op(ops::FnCallUnstable(callee, Some(gate))); - return; - } - - // FIXME(ecstaticmorse); For compatibility, we consider `unstable` callees that - // have no `rustc_const_stable` attributes to be const-unstable as well. This - // should be fixed later. - let callee_is_unstable_unmarked = tcx.lookup_const_stability(callee).is_none() - && tcx.lookup_stability(callee).is_some_and(|s| s.is_unstable()); - if callee_is_unstable_unmarked { - trace!("callee_is_unstable_unmarked"); - // We do not use `const` modifiers for intrinsic "functions", as intrinsics are - // `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() || tcx.intrinsic(callee).is_some() { - self.check_op(ops::FnCallUnstable(callee, None)); - return; - } - } - trace!("permitting call"); - } - - // Forbid all `Drop` terminators unless the place being dropped is a local with no - // projections that cannot be `NeedsNonConstDrop`. - TerminatorKind::Drop { place: dropped_place, .. } => { - // If we are checking live drops after drop-elaboration, don't emit duplicate - // errors here. - if super::post_drop_elaboration::checking_enabled(self.ccx) { - return; - } - - let mut err_span = self.span; - let ty_of_dropped_place = dropped_place.ty(self.body, self.tcx).ty; - - let ty_needs_non_const_drop = - qualifs::NeedsNonConstDrop::in_any_value_of_ty(self.ccx, ty_of_dropped_place); - - debug!(?ty_of_dropped_place, ?ty_needs_non_const_drop); - - if !ty_needs_non_const_drop { - return; - } - - let needs_non_const_drop = if let Some(local) = dropped_place.as_local() { - // Use the span where the local was declared as the span of the drop error. - err_span = self.body.local_decls[local].source_info.span; - self.qualifs.needs_non_const_drop(self.ccx, local, location) - } else { - true - }; - - if needs_non_const_drop { - self.check_op_spanned( - ops::LiveDrop { - dropped_at: Some(terminator.source_info.span), - dropped_ty: ty_of_dropped_place, - }, - err_span, - ); - } - } - - TerminatorKind::InlineAsm { .. } => self.check_op(ops::InlineAsm), - - TerminatorKind::Yield { .. } => self.check_op(ops::Coroutine( - self.tcx - .coroutine_kind(self.body.source.def_id()) - .expect("Only expected to have a yield in a coroutine"), - )), - - TerminatorKind::CoroutineDrop => { - span_bug!( - self.body.source_info(location).span, - "We should not encounter TerminatorKind::CoroutineDrop after coroutine transform" - ); - } - - TerminatorKind::UnwindTerminate(_) => { - // Cleanup blocks are skipped for const checking (see `visit_basic_block_data`). - span_bug!(self.span, "`Terminate` terminator outside of cleanup block") - } - - TerminatorKind::Assert { .. } - | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::Goto { .. } - | TerminatorKind::UnwindResume - | TerminatorKind::Return - | TerminatorKind::SwitchInt { .. } - | TerminatorKind::Unreachable => {} - } - } -} - -fn place_as_reborrow<'tcx>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - place: Place<'tcx>, -) -> Option> { - match place.as_ref().last_projection() { - Some((place_base, ProjectionElem::Deref)) => { - // FIXME: why do statics and raw pointers get excluded here? This makes - // some code involving mutable pointers unstable, but it is unclear - // why that code is treated differently from mutable references. - // Once TransientMutBorrow and TransientCellBorrow are stable, - // this can probably be cleaned up without any behavioral changes. - - // A borrow of a `static` also looks like `&(*_1)` in the MIR, but `_1` is a `const` - // that points to the allocation for the static. Don't treat these as reborrows. - if body.local_decls[place_base.local].is_ref_to_static() { - None - } else { - // Ensure the type being derefed is a reference and not a raw pointer. - // This is sufficient to prevent an access to a `static mut` from being marked as a - // reborrow, even if the check above were to disappear. - let inner_ty = place_base.ty(body, tcx).ty; - - if let ty::Ref(..) = inner_ty.kind() { - return Some(place_base); - } else { - return None; - } - } - } - _ => None, - } -} - -fn is_int_bool_or_char(ty: Ty<'_>) -> bool { - ty.is_bool() || ty.is_integral() || ty.is_char() -} - -fn emit_unstable_in_stable_error(ccx: &ConstCx<'_, '_>, span: Span, gate: Symbol) { - let attr_span = ccx.tcx.def_span(ccx.def_id()).shrink_to_lo(); - - ccx.dcx().emit_err(UnstableInStable { gate: gate.to_string(), span, attr_span }); -} +use rustc_errors::{Diag,ErrorGuaranteed};use rustc_hir as hir;use rustc_hir:://; +def_id::DefId;use rustc_index::bit_set::BitSet;use rustc_infer::infer:://*&*&(); +TyCtxtInferExt;use rustc_infer::traits:: ObligationCause;use rustc_middle::mir:: +visit::{MutatingUseContext,NonMutatingUseContext,PlaceContext,Visitor};use//{;}; +rustc_middle::mir::*;use rustc_middle:: ty::{self,adjustment::PointerCoercion,Ty +,TyCtxt};use rustc_middle::ty::{Instance,InstanceDef,TypeVisitableExt};use//{;}; +rustc_mir_dataflow::Analysis;use rustc_span::{sym,Span,Symbol};use//loop{break}; +rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;use//*&*&(); +rustc_trait_selection::traits::{self,ObligationCauseCode,ObligationCtxt};use//3; +rustc_type_ir::visit::{TypeSuperVisitable,TypeVisitor};use std::mem;use std:://; +ops::Deref;use super::ops::{self,NonConstOp,Status};use super::qualifs::{self,// +HasMutInterior,NeedsDrop,NeedsNonConstDrop};use super::resolver:://loop{break;}; +FlowSensitiveAnalysis;use super::{ConstCx,Qualif};use crate::const_eval:://({}); +is_unstable_const_fn;use crate::errors::UnstableInStable;type QualifResults=rustc_mir_dataflow ::ResultsCursor<'mir,'tcx,FlowSensitiveAnalysis< +'mir,'mir,'tcx,Q>>;#[derive(Default)]pub(crate)struct Qualifs<'mir,'tcx>{//({}); +has_mut_interior:Option>,needs_drop://3; +Option>,needs_non_const_drop:Option>,}impl <'mir,'tcx>Qualifs<'mir,'tcx>{ +pub fn needs_drop(&mut self,ccx:&'mir ConstCx<'mir,'tcx>,local:Local,location:// +Location,)->bool{;let ty=ccx.body.local_decls[local].ty;if!ty.has_opaque_types() +&&!NeedsDrop::in_any_value_of_ty(ccx,ty){3;return false;3;};let needs_drop=self. +needs_drop.get_or_insert_with(||{let _=();let ConstCx{tcx,body,..}=*ccx;((),()); +FlowSensitiveAnalysis::new(NeedsDrop,ccx).into_engine(tcx,body).//if let _=(){}; +iterate_to_fixpoint().into_results_cursor(body)});if true{};let _=();needs_drop. +seek_before_primary_effect(location);{;};needs_drop.get().contains(local)}pub fn +needs_non_const_drop(&mut self,ccx:&'mir ConstCx<'mir,'tcx>,local:Local,//{();}; +location:Location,)->bool{({});let ty=ccx.body.local_decls[local].ty;({});if!ty. +has_opaque_types()&&!NeedsNonConstDrop::in_any_value_of_ty(ccx,ty){;return false +;;};let needs_non_const_drop=self.needs_non_const_drop.get_or_insert_with(||{let +ConstCx{tcx,body,..}=*ccx;{;};FlowSensitiveAnalysis::new(NeedsNonConstDrop,ccx). +into_engine(tcx,body).iterate_to_fixpoint().into_results_cursor(body)});{;};{;}; +needs_non_const_drop.seek_before_primary_effect(location);;needs_non_const_drop. +get().contains(local)}pub fn has_mut_interior(&mut self,ccx:&'mir ConstCx<'mir, +'tcx>,local:Local,location:Location,)->bool{;let ty=ccx.body.local_decls[local]. +ty;;if!ty.has_opaque_types()&&!HasMutInterior::in_any_value_of_ty(ccx,ty){return +false;3;}3;let has_mut_interior=self.has_mut_interior.get_or_insert_with(||{;let +ConstCx{tcx,body,..}=*ccx;*&*&();FlowSensitiveAnalysis::new(HasMutInterior,ccx). +into_engine(tcx,body).iterate_to_fixpoint().into_results_cursor(body)});{;};{;}; +has_mut_interior.seek_before_primary_effect(location);();has_mut_interior.get(). +contains(local)}fn in_return_place(&mut self,ccx:&'mir ConstCx<'mir,'tcx>,//{;}; +tainted_by_errors:Option,)->ConstQualifs{;let return_block=ccx. +body.basic_blocks.iter_enumerated().find(|( _,block)|matches!(block.terminator() +.kind,TerminatorKind::Return)).map(|(bb,_)|bb);({});({});let Some(return_block)= +return_block else{3;return qualifs::in_any_value_of_ty(ccx,ccx.body.return_ty(), +tainted_by_errors);3;};3;;let return_loc=ccx.body.terminator_loc(return_block);; +ConstQualifs{needs_drop:(((((self.needs_drop (ccx,RETURN_PLACE,return_loc)))))), +needs_non_const_drop:((self.needs_non_const_drop(ccx,RETURN_PLACE,return_loc))), +has_mut_interior:((((((self.has_mut_interior(ccx,RETURN_PLACE,return_loc))))))), +tainted_by_errors,}}}struct LocalReturnTyVisitor< 'ck,'mir,'tcx>{kind:LocalKind, +checker:&'ck mut Checker<'mir,'tcx>, }impl<'ck,'mir,'tcx>TypeVisitor>for LocalReturnTyVisitor<'ck,'mir,'tcx>{fn visit_ty(&mut self,t:Ty<'tcx>){//3; +match t.kind(){ty::FnPtr(_)=>{}ty::Ref(_,_,hir::Mutability::Mut)=>{;self.checker +.check_op(ops::ty::MutRef(self.kind));loop{break};t.super_visit_with(self)}_=>t. +super_visit_with(self),}}}pub struct Checker <'mir,'tcx>{ccx:&'mir ConstCx<'mir, +'tcx>,qualifs:Qualifs<'mir,'tcx >,span:Span,local_has_storage_dead:Option>,error_emitted:Option,secondary_errors:Vec> +,}impl<'mir,'tcx>Deref for Checker<'mir ,'tcx>{type Target=ConstCx<'mir,'tcx>;fn +deref(&self)->&Self::Target{self.ccx}}impl<'mir,'tcx>Checker<'mir,'tcx>{pub fn// +new(ccx:&'mir ConstCx<'mir,'tcx>)->Self{Checker{span:ccx.body.span,ccx,qualifs// +:((((((Default::default())))))) ,local_has_storage_dead:None,error_emitted:None, +secondary_errors:Vec::new(),}}pub fn check_body(&mut self){;let ConstCx{tcx,body +,..}=*self.ccx;();3;let def_id=self.ccx.def_id();3;if self.ccx.is_async()||body. +coroutine.is_some(){let _=||();loop{break};tcx.dcx().span_delayed_bug(body.span, +"`async` functions cannot be `const fn`");;;return;;}if self.const_kind()==hir:: +ConstContext::ConstFn{for(idx,local)in (body.local_decls.iter_enumerated()){if +idx==RETURN_PLACE{();continue;();}();self.span=local.source_info.span;();3;self. +check_local_or_return_ty(local.ty,idx);;}self.span=body.local_decls[RETURN_PLACE +].source_info.span;{;};{;};let return_ty=self.ccx.fn_sig().output();{;};();self. +check_local_or_return_ty(return_ty.skip_binder(),RETURN_PLACE);;}if!tcx.has_attr +(def_id,sym::rustc_do_not_const_check){({});self.visit_body(body);({});}({});let +secondary_errors=mem::take(&mut self.secondary_errors);();if self.error_emitted. +is_none(){for error in secondary_errors{;self.error_emitted=Some(error.emit());} +}else{((),());assert!(self.tcx.dcx().has_errors().is_some());*&*&();for error in +secondary_errors{3;error.cancel();;}}}fn local_has_storage_dead(&mut self,local: +Local)->bool{;let ccx=self.ccx;self.local_has_storage_dead.get_or_insert_with(|| +{{;};struct StorageDeads{locals:BitSet,}{;};();impl<'tcx>Visitor<'tcx>for +StorageDeads{fn visit_statement(&mut self,stmt:&Statement<'tcx>,_:Location){if// +let StatementKind::StorageDead(l)=stmt.kind{;self.locals.insert(l);}}}let mut v= +StorageDeads{locals:BitSet::new_empty(ccx.body.local_decls.len())};;v.visit_body +(ccx.body);;v.locals}).contains(local)}pub fn qualifs_in_return_place(&mut self) +->ConstQualifs{self.qualifs.in_return_place(self .ccx,self.error_emitted)}pub fn +check_op(&mut self,op:impl NonConstOp<'tcx>){({});self.check_op_spanned(op,self. +span);3;}pub fn check_op_spanned>(&mut self,op:O,span:Span){; +let gate=match (op.status_in_item(self. ccx)){Status::Allowed=>(return),Status:: +Unstable(gate)if self.tcx.features().active(gate)=>{;let unstable_in_stable=self +.ccx.is_const_stable_const_fn()&& !super::rustc_allow_const_fn_unstable(self.tcx +,self.def_id(),gate);;if unstable_in_stable{;emit_unstable_in_stable_error(self. +ccx,span,gate);;};return;}Status::Unstable(gate)=>Some(gate),Status::Forbidden=> +None,};;if self.tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you{self. +tcx.sess.miri_unleashed_feature(span,gate);;return;}let err=op.build_error(self. +ccx,span);;;assert!(err.is_error());;match op.importance(){ops::DiagImportance:: +Primary=>{3;let reported=err.emit();3;;self.error_emitted=Some(reported);;}ops:: +DiagImportance::Secondary=>(self.secondary_errors.push(err)),}}fn check_static(& +mut self,def_id:DefId,span:Span){if self.tcx.is_thread_local_static(def_id){{;}; +self.tcx.dcx().span_bug(span,//loop{break};loop{break};loop{break};loop{break;}; +"tls access is checked in `Rvalue::ThreadLocalRef`");;}self.check_op_spanned(ops +::StaticAccess,span)}fn check_local_or_return_ty(&mut self,ty:Ty<'tcx>,local://; +Local){*&*&();let kind=self.body.local_kind(local);*&*&();{();};let mut visitor= +LocalReturnTyVisitor{kind,checker:self};{();};({});visitor.visit_ty(ty);({});}fn +check_mut_borrow(&mut self,place:&Place<'_>,kind:hir::BorrowKind){match self.//; +const_kind(){hir::ConstContext::ConstFn =>self.check_op(ops::TransientMutBorrow( +kind)),_=>{if place.is_indirect()||self.local_has_storage_dead(place.local){{;}; +self.check_op(ops::TransientMutBorrow(kind));;}else{self.check_op(ops::MutBorrow +(kind));if true{};let _=||();}}}}}impl<'tcx>Visitor<'tcx>for Checker<'_,'tcx>{fn +visit_basic_block_data(&mut self,bb:BasicBlock,block:&BasicBlockData<'tcx>){{;}; +trace!("visit_basic_block_data: bb={:?} is_cleanup={:?}",bb,block.is_cleanup);3; +if block.is_cleanup{();return;();}();self.super_basic_block_data(bb,block);3;}fn +visit_rvalue(&mut self,rvalue:&Rvalue<'tcx>,location:Location){if true{};trace!( +"visit_rvalue: rvalue={:?} location={:?}",rvalue,location);3;match*rvalue{Rvalue +::Ref(_,kind,place)=>{if let Some(reborrowed_place_ref)=place_as_reborrow(self. +tcx,self.body,place){({});let ctx=match kind{BorrowKind::Shared=>{PlaceContext:: +NonMutatingUse(NonMutatingUseContext::SharedBorrow)}BorrowKind::Fake=>{//*&*&(); +PlaceContext::NonMutatingUse(NonMutatingUseContext:: FakeBorrow)}BorrowKind::Mut +{..}=>{PlaceContext::MutatingUse(MutatingUseContext::Borrow)}};;self.visit_local +(reborrowed_place_ref.local,ctx,location);((),());((),());self.visit_projection( +reborrowed_place_ref,ctx,location);;return;}}Rvalue::AddressOf(mutbl,place)=>{if +let Some(reborrowed_place_ref)=place_as_reborrow(self.tcx,self.body,place){3;let +ctx=match mutbl{Mutability::Not=>{PlaceContext::NonMutatingUse(//*&*&();((),()); +NonMutatingUseContext::AddressOf)}Mutability::Mut=>PlaceContext::MutatingUse(//; +MutatingUseContext::AddressOf),};3;;self.visit_local(reborrowed_place_ref.local, +ctx,location);;self.visit_projection(reborrowed_place_ref,ctx,location);return;} +}_=>{}};self.super_rvalue(rvalue,location);match rvalue{Rvalue::ThreadLocalRef(_ +)=>self.check_op(ops::ThreadLocalAccess) ,Rvalue::Use(_)|Rvalue::CopyForDeref(.. +)|Rvalue::Repeat(..)|Rvalue::Discriminant(..)|Rvalue::Len(_)=>{}Rvalue:://{();}; +Aggregate(kind,..)=>{if let AggregateKind:: Coroutine(def_id,..)=kind.as_ref()&& +let Some(coroutine_kind@hir::CoroutineKind::Desugared(hir::CoroutineDesugaring// +::Async,_,),)=self.tcx.coroutine_kind(def_id){({});self.check_op(ops::Coroutine( +coroutine_kind));3;}}Rvalue::Ref(_,BorrowKind::Mut{..},place)|Rvalue::AddressOf( +Mutability::Mut,place)=>{3;let is_allowed=self.const_kind()==hir::ConstContext:: +Static(hir::Mutability::Mut);();if!is_allowed{();self.check_mut_borrow(place,if +matches!(rvalue,Rvalue::Ref(..)) {hir::BorrowKind::Ref}else{hir::BorrowKind::Raw +},);let _=();}}Rvalue::Ref(_,BorrowKind::Shared|BorrowKind::Fake,place)|Rvalue:: +AddressOf(Mutability::Not,place)=>{3;let borrowed_place_has_mut_interior=qualifs +::in_place::(self.ccx,&mut|local|self.qualifs.//if let _=(){}; +has_mut_interior(self.ccx,local,location),place.as_ref(),);let _=();let _=();if +borrowed_place_has_mut_interior&&(!place.is_indirect()){match self.const_kind(){ +hir::ConstContext::ConstFn=>self.check_op(ops ::TransientCellBorrow),_=>{if self +.local_has_storage_dead(place.local){;self.check_op(ops::TransientCellBorrow);;} +else{;self.check_op(ops::CellBorrow);}}}}}Rvalue::Cast(CastKind::PointerCoercion +(PointerCoercion::MutToConstPointer|PointerCoercion::ArrayToPointer|//if true{}; +PointerCoercion::UnsafeFnPointer|PointerCoercion::ClosureFnPointer(_)|//((),()); +PointerCoercion::ReifyFnPointer,),_,_,)=>{}Rvalue::Cast(CastKind:://loop{break}; +PointerCoercion(PointerCoercion::Unsize),_,_)=>{}Rvalue::Cast(CastKind:://{();}; +PointerExposeAddress,_,_)=>{;self.check_op(ops::RawPtrToIntCast);;}Rvalue::Cast( +CastKind::PointerFromExposedAddress,_,_)=>{} Rvalue::Cast(CastKind::DynStar,_,_) +=>{}Rvalue::Cast(_,_,_)=>{}Rvalue::NullaryOp(NullOp::SizeOf|NullOp::AlignOf|//3; +NullOp::OffsetOf(_)|NullOp::UbChecks,_,)=>{}Rvalue::ShallowInitBox(_,_)=>{}//(); +Rvalue::UnaryOp(_,operand)=>{({});let ty=operand.ty(self.body,self.tcx);({});if +is_int_bool_or_char(ty){}else if ty.is_floating_point(){({});self.check_op(ops:: +FloatingPointOp);let _=();if true{};}else{let _=();let _=();span_bug!(self.span, +"non-primitive type in `Rvalue::UnaryOp`: {:?}",ty);3;}}Rvalue::BinaryOp(op,box( +lhs,rhs))|Rvalue::CheckedBinaryOp(op,box(lhs,rhs))=>{{;};let lhs_ty=lhs.ty(self. +body,self.tcx);3;;let rhs_ty=rhs.ty(self.body,self.tcx);;if is_int_bool_or_char( +lhs_ty)&&((is_int_bool_or_char(rhs_ty))){}else if (lhs_ty.is_fn_ptr())||lhs_ty. +is_unsafe_ptr(){{;};assert!(matches!(op,BinOp::Eq|BinOp::Ne|BinOp::Le|BinOp::Lt| +BinOp::Ge|BinOp::Gt|BinOp::Offset));;;self.check_op(ops::RawPtrComparison);}else +if lhs_ty.is_floating_point()||rhs_ty.is_floating_point(){();self.check_op(ops:: +FloatingPointOp);let _=();if true{};}else{let _=();let _=();span_bug!(self.span, +"non-primitive type in `Rvalue::BinaryOp`: {:?} ⚬ {:?}",lhs_ty,rhs_ty);();}}}}fn +visit_operand(&mut self,op:&Operand<'tcx>,location:Location){;self.super_operand +(op,location);loop{break;};if let Operand::Constant(c)=op{if let Some(def_id)=c. +check_static_ptr(self.tcx){{();};self.check_static(def_id,self.span);{();};}}}fn +visit_projection_elem(&mut self,place_ref:PlaceRef<'tcx>,elem:PlaceElem<'tcx>,// +context:PlaceContext,location:Location,){((),());((),());((),());((),());trace!( +"visit_projection_elem: place_ref={:?} elem={:?} \ + context={:?} location={:?}" +,place_ref,elem,context,location,);3;;self.super_projection_elem(place_ref,elem, +context,location);;match elem{ProjectionElem::Deref=>{;let base_ty=place_ref.ty( +self.body,self.tcx).ty;{();};if base_ty.is_unsafe_ptr(){if place_ref.projection. +is_empty(){;let decl=&self.body.local_decls[place_ref.local];;if let LocalInfo:: +StaticRef{..}=*decl.local_info(){;return;;}}if!base_ty.is_mutable_ptr(){return;} +self.check_op(ops::RawMutPtrDeref);;}if context.is_mutating_use(){self.check_op( +ops::MutDeref);;}}ProjectionElem::ConstantIndex{..}|ProjectionElem::Downcast(..) +|ProjectionElem::OpaqueCast(..)|ProjectionElem::Subslice{..}|ProjectionElem:://; +Subtype(..)|ProjectionElem::Field(..)|ProjectionElem::Index(_)=>{}}}fn//((),()); +visit_source_info(&mut self,source_info:&SourceInfo){if true{};if true{};trace!( +"visit_source_info: source_info={:?}",source_info);;self.span=source_info.span;} +fn visit_statement(&mut self,statement:&Statement<'tcx>,location:Location){({}); +trace!("visit_statement: statement={:?} location={:?}",statement,location);;self +.super_statement(statement,location);;match statement.kind{StatementKind::Assign +(..)|StatementKind::SetDiscriminant{.. }|StatementKind::Deinit(..)|StatementKind +::FakeRead(..)|StatementKind::StorageLive(_)|StatementKind::StorageDead(_)|//(); +StatementKind::Retag{..}|StatementKind::PlaceMention(..)|StatementKind:://{();}; +AscribeUserType(..)|StatementKind::Coverage(..)|StatementKind::Intrinsic(..)|//; +StatementKind::ConstEvalCounter|StatementKind::Nop=>{}}}#[instrument(level=//(); +"debug",skip(self))]fn visit_terminator( &mut self,terminator:&Terminator<'tcx>, +location:Location){;self.super_terminator(terminator,location);match&terminator. +kind{TerminatorKind::Call{func,args,fn_span,call_source,..}=>{3;let ConstCx{tcx, +body,param_env,..}=*self.ccx;;;let caller=self.def_id();;let fn_ty=func.ty(body, +tcx);;let(mut callee,mut fn_args)=match*fn_ty.kind(){ty::FnDef(def_id,fn_args)=> +(def_id,fn_args),ty::FnPtr(_)=>{;self.check_op(ops::FnCallIndirect);return;}_=>{ +span_bug!(terminator.source_info.span,"invalid callee of type {:?}",fn_ty)}};3;; +let infcx=tcx.infer_ctxt().build();3;3;let ocx=ObligationCtxt::new(&infcx);;;let +predicates=tcx.predicates_of(callee).instantiate(tcx,fn_args);{;};{;};let cause= +ObligationCause::new(terminator.source_info.span, ((self.body.source.def_id())). +expect_local(),ObligationCauseCode::ItemObligation(callee),);((),());((),());let +normalized_predicates=ocx.normalize(&cause,param_env,predicates);{();};({});ocx. +register_obligations(traits::predicates_for_generics((|_,_ |cause.clone()),self. +param_env,normalized_predicates,));3;3;let errors=ocx.select_all_or_error();;if! +errors.is_empty(){;infcx.err_ctxt().report_fulfillment_errors(errors);;};let mut +is_trait=false;if true{};if tcx.trait_of_item(callee).is_some(){let _=();trace!( +"attempting to call a trait method");;if tcx.features().effects{is_trait=true;if +let Ok(Some(instance))=((Instance ::resolve(tcx,param_env,callee,fn_args)))&&let +InstanceDef::Item(def)=instance.def{;fn_args=instance.args;;;callee=def;;}}else{ +self.check_op(ops::FnCallNonConst{caller,callee ,args:fn_args,span:((*fn_span)), +call_source:(*call_source),feature:Some(if tcx.features().const_trait_impl{sym:: +effects}else{sym::const_trait_impl}),});{;};();return;();}}if Some(callee)==tcx. +lang_items().begin_panic_fn(){match args[ 0].node.ty(&self.ccx.body.local_decls, +tcx).kind(){ty::Ref(_,ty,_)if ((ty.is_str()))=>((return)),_=>self.check_op(ops:: +PanicNonStr),}}if tcx.has_attr(callee,sym ::rustc_const_panic_str){match args[0] +.node.ty((&self.ccx.body.local_decls),tcx).kind(){ty::Ref(_,ty,_)if matches!(ty. +kind(),ty::Ref(_,ty,_)if ty.is_str())=>{({});return;({});}_=>self.check_op(ops:: +PanicNonStr),}}if Some(callee)==tcx.lang_items().exchange_malloc_fn(){({});self. +check_op(ops::HeapAllocation);;return;}if!tcx.is_const_fn_raw(callee)&&!is_trait +{{;};self.check_op(ops::FnCallNonConst{caller,callee,args:fn_args,span:*fn_span, +call_source:*call_source,feature:None,});;return;}if let Some((gate,implied_by)) +=is_unstable_const_fn(tcx,callee){;trace!(?gate,"calling unstable const fn");if +self.span.allows_unstable(gate){;return;}if let Some(implied_by_gate)=implied_by +&&self.span.allows_unstable(implied_by_gate){;return;;}let gate_declared=|gate|{ +tcx.features().declared_lib_features.iter().any(|&(sym,_)|sym==gate)};{;};();let +feature_gate_declared=gate_declared(gate);;let implied_gate_declared=implied_by. +is_some_and(gate_declared);3;if!feature_gate_declared&&!implied_gate_declared{3; +self.check_op(ops::FnCallUnstable(callee,Some(gate)));3;3;return;3;}if!self.ccx. +is_const_stable_const_fn(){let _=||();loop{break};let _=||();loop{break};trace!( +"crate not using stability attributes or caller not stably const");;;return;}if +super::rustc_allow_const_fn_unstable(tcx,caller,gate){let _=();if true{};trace!( +"rustc_allow_const_fn_unstable gate active");3;3;return;3;}3;self.check_op(ops:: +FnCallUnstable(callee,Some(gate)));;return;}let callee_is_unstable_unmarked=tcx. +lookup_const_stability(callee).is_none() &&((((tcx.lookup_stability(callee))))). +is_some_and(|s|s.is_unstable());({});if callee_is_unstable_unmarked{({});trace!( +"callee_is_unstable_unmarked");({});if self.ccx.is_const_stable_const_fn()||tcx. +intrinsic(callee).is_some(){3;self.check_op(ops::FnCallUnstable(callee,None));;; +return;;}}trace!("permitting call");}TerminatorKind::Drop{place:dropped_place,.. +}=>{if super::post_drop_elaboration::checking_enabled(self.ccx){;return;}let mut +err_span=self.span;;;let ty_of_dropped_place=dropped_place.ty(self.body,self.tcx +).ty;;let ty_needs_non_const_drop=qualifs::NeedsNonConstDrop::in_any_value_of_ty +(self.ccx,ty_of_dropped_place);if true{};if true{};debug!(?ty_of_dropped_place,? +ty_needs_non_const_drop);({});if!ty_needs_non_const_drop{{;};return;{;};}{;};let +needs_non_const_drop=if let Some(local)=dropped_place.as_local(){;err_span=self. +body.local_decls[local].source_info.span;;self.qualifs.needs_non_const_drop(self +.ccx,local,location)}else{true};;if needs_non_const_drop{;self.check_op_spanned( +ops::LiveDrop{dropped_at:(((((Some(terminator.source_info.span)))))),dropped_ty: +ty_of_dropped_place,},err_span,);;}}TerminatorKind::InlineAsm{..}=>self.check_op +(ops::InlineAsm),TerminatorKind::Yield{..}=>self.check_op(ops::Coroutine(self.// +tcx.coroutine_kind((((((((((((((self.body.source .def_id())))))))))))))).expect( +"Only expected to have a yield in a coroutine"),)),TerminatorKind:://let _=||(); +CoroutineDrop=>{((),());let _=();span_bug!(self.body.source_info(location).span, +"We should not encounter TerminatorKind::CoroutineDrop after coroutine transform" +);if true{};if true{};}TerminatorKind::UnwindTerminate(_)=>{span_bug!(self.span, +"`Terminate` terminator outside of cleanup block")}TerminatorKind::Assert{..}|// +TerminatorKind::FalseEdge{..}|TerminatorKind::FalseUnwind{..}|TerminatorKind::// +Goto{..}|TerminatorKind::UnwindResume|TerminatorKind::Return|TerminatorKind:://; +SwitchInt{..}|TerminatorKind::Unreachable=>{} }}}fn place_as_reborrow<'tcx>(tcx: +TyCtxt<'tcx>,body:&Body<'tcx>,place: Place<'tcx>,)->Option>{match +(place.as_ref().last_projection()){Some((place_base,ProjectionElem::Deref))=>{if +body.local_decls[place_base.local].is_ref_to_static(){None}else{();let inner_ty= +place_base.ty(body,tcx).ty;();if let ty::Ref(..)=inner_ty.kind(){();return Some( +place_base);;}else{;return None;}}}_=>None,}}fn is_int_bool_or_char(ty:Ty<'_>)-> +bool{(((((((((ty.is_bool())))||(((ty.is_integral()))))))||((ty.is_char())))))}fn +emit_unstable_in_stable_error(ccx:&ConstCx<'_,'_>,span:Span,gate:Symbol){{;};let +attr_span=ccx.tcx.def_span(ccx.def_id()).shrink_to_lo();();3;ccx.dcx().emit_err( +UnstableInStable{gate:gate.to_string(),span,attr_span});let _=||();loop{break};} diff --git a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs index 12e7ec15e3292..8a4bdea948304 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs @@ -1,140 +1,38 @@ -//! Check the bodies of `const`s, `static`s and `const fn`s for illegal operations. -//! -//! This module will eventually replace the parts of `qualify_consts.rs` that check whether a local -//! has interior mutability or needs to be dropped, as well as the visitor that emits errors when -//! it finds operations that are invalid in a certain context. - -use rustc_attr as attr; -use rustc_errors::DiagCtxt; -use rustc_hir as hir; -use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_middle::mir; -use rustc_middle::ty::{self, PolyFnSig, TyCtxt}; -use rustc_span::Symbol; - -pub use self::qualifs::Qualif; - -pub mod check; -mod ops; -pub mod post_drop_elaboration; -pub mod qualifs; -mod resolver; - -/// Information about the item currently being const-checked, as well as a reference to the global -/// context. -pub struct ConstCx<'mir, 'tcx> { - pub body: &'mir mir::Body<'tcx>, - pub tcx: TyCtxt<'tcx>, - pub param_env: ty::ParamEnv<'tcx>, - pub const_kind: Option, -} - -impl<'mir, 'tcx> ConstCx<'mir, 'tcx> { - pub fn new(tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>) -> Self { - let def_id = body.source.def_id().expect_local(); - let param_env = tcx.param_env(def_id); - Self::new_with_param_env(tcx, body, param_env) - } - - pub fn new_with_param_env( - tcx: TyCtxt<'tcx>, - body: &'mir mir::Body<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> Self { - let const_kind = tcx.hir().body_const_context(body.source.def_id().expect_local()); - ConstCx { body, tcx, param_env, const_kind } - } - - pub(crate) fn dcx(&self) -> &'tcx DiagCtxt { - self.tcx.dcx() - } - - pub fn def_id(&self) -> LocalDefId { - self.body.source.def_id().expect_local() - } - - /// Returns the kind of const context this `Item` represents (`const`, `static`, etc.). - /// - /// Panics if this `Item` is not const. - pub fn const_kind(&self) -> hir::ConstContext { - self.const_kind.expect("`const_kind` must not be called on a non-const fn") - } - - pub fn is_const_stable_const_fn(&self) -> bool { - self.const_kind == Some(hir::ConstContext::ConstFn) - && self.tcx.features().staged_api - && is_const_stable_const_fn(self.tcx, self.def_id().to_def_id()) - } - - fn is_async(&self) -> bool { - self.tcx.asyncness(self.def_id()).is_async() - } - - pub fn fn_sig(&self) -> PolyFnSig<'tcx> { - let did = self.def_id().to_def_id(); - if self.tcx.is_closure_like(did) { - let ty = self.tcx.type_of(did).instantiate_identity(); - let ty::Closure(_, args) = ty.kind() else { bug!("type_of closure not ty::Closure") }; - args.as_closure().sig() - } else { - self.tcx.fn_sig(did).instantiate_identity() - } - } -} - -pub fn rustc_allow_const_fn_unstable( - tcx: TyCtxt<'_>, - def_id: LocalDefId, - feature_gate: Symbol, -) -> bool { - let attrs = tcx.hir().attrs(tcx.local_def_id_to_hir_id(def_id)); - attr::rustc_allow_const_fn_unstable(tcx.sess, attrs).any(|name| name == feature_gate) -} - -/// Returns `true` if the given `const fn` is "const-stable". -/// -/// Panics if the given `DefId` does not refer to a `const fn`. -/// -/// Const-stability is only relevant for `const fn` within a `staged_api` crate. Only "const-stable" -/// functions can be called in a const-context by users of the stable compiler. "const-stable" -/// functions are subject to more stringent restrictions than "const-unstable" functions: They -/// cannot use unstable features and can only call other "const-stable" functions. -pub fn is_const_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - // A default body in a `#[const_trait]` is not const-stable because const - // trait fns currently cannot be const-stable. We shouldn't - // restrict default bodies to only call const-stable functions. - if tcx.is_const_default_method(def_id) { - return false; - } - - // Const-stability is only relevant for `const fn`. - assert!(tcx.is_const_fn_raw(def_id)); - - // A function is only const-stable if it has `#[rustc_const_stable]` or it the trait it belongs - // to is const-stable. - match tcx.lookup_const_stability(def_id) { - Some(stab) => stab.is_const_stable(), - None if is_parent_const_stable_trait(tcx, def_id) => { - // Remove this when `#![feature(const_trait_impl)]` is stabilized, - // returning `true` unconditionally. - tcx.dcx().span_delayed_bug( - tcx.def_span(def_id), - "trait implementations cannot be const stable yet", - ); - true - } - None => false, // By default, items are not const stable. - } -} - -fn is_parent_const_stable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - let local_def_id = def_id.expect_local(); - let hir_id = tcx.local_def_id_to_hir_id(local_def_id); - - let parent_owner_id = tcx.parent_hir_id(hir_id).owner; - if !tcx.is_const_trait_impl_raw(parent_owner_id.to_def_id()) { - return false; - } - - tcx.lookup_const_stability(parent_owner_id).is_some_and(|stab| stab.is_const_stable()) -} +use rustc_attr as attr;use rustc_errors::DiagCtxt;use rustc_hir as hir;use//{;}; +rustc_hir::def_id::{DefId,LocalDefId};use rustc_middle::mir;use rustc_middle::// +ty::{self,PolyFnSig,TyCtxt};use rustc_span::Symbol;pub use self::qualifs:://{;}; +Qualif;pub mod check;mod ops;pub mod post_drop_elaboration;pub mod qualifs;mod// +resolver;pub struct ConstCx<'mir,'tcx>{pub body:&'mir mir::Body<'tcx>,pub tcx:// +TyCtxt<'tcx>,pub param_env:ty::ParamEnv<'tcx>,pub const_kind:Option,}impl<'mir,'tcx>ConstCx<'mir,'tcx>{pub fn new(tcx:TyCtxt<'tcx>,//; +body:&'mir mir::Body<'tcx>)->Self{;let def_id=body.source.def_id().expect_local( +);();();let param_env=tcx.param_env(def_id);3;Self::new_with_param_env(tcx,body, +param_env)}pub fn new_with_param_env(tcx:TyCtxt <'tcx>,body:&'mir mir::Body<'tcx +>,param_env:ty::ParamEnv<'tcx>,)->Self{((),());((),());let const_kind=tcx.hir(). +body_const_context(body.source.def_id().expect_local());*&*&();ConstCx{body,tcx, +param_env,const_kind}}pub(crate)fn dcx(&self )->&'tcx DiagCtxt{(self.tcx.dcx())} +pub fn def_id(&self)->LocalDefId{(self .body.source.def_id().expect_local())}pub +fn const_kind(&self)->hir::ConstContext{self.const_kind.expect(//*&*&();((),()); +"`const_kind` must not be called on a non-const fn")}pub fn//let _=();if true{}; +is_const_stable_const_fn(&self)->bool{ self.const_kind==Some(hir::ConstContext:: +ConstFn)&&((self.tcx.features())).staged_api&&is_const_stable_const_fn(self.tcx, +self.def_id().to_def_id())}fn is_async(&self)->bool{self.tcx.asyncness(self.//3; +def_id()).is_async()}pub fn fn_sig(&self)->PolyFnSig<'tcx>{;let did=self.def_id( +).to_def_id();3;if self.tcx.is_closure_like(did){3;let ty=self.tcx.type_of(did). +instantiate_identity();*&*&();*&*&();let ty::Closure(_,args)=ty.kind()else{bug!( +"type_of closure not ty::Closure")};{();};args.as_closure().sig()}else{self.tcx. +fn_sig(did).instantiate_identity()}}}pub fn rustc_allow_const_fn_unstable(tcx:// +TyCtxt<'_>,def_id:LocalDefId,feature_gate:Symbol,)->bool{();let attrs=tcx.hir(). +attrs(tcx.local_def_id_to_hir_id(def_id));3;attr::rustc_allow_const_fn_unstable( +tcx.sess,attrs).any((|name|name==feature_gate))}pub fn is_const_stable_const_fn( +tcx:TyCtxt<'_>,def_id:DefId)->bool{if tcx.is_const_default_method(def_id){{();}; +return false;*&*&();}{();};assert!(tcx.is_const_fn_raw(def_id));{();};match tcx. +lookup_const_stability(def_id){Some(stab)=>(((stab.is_const_stable()))),None if +is_parent_const_stable_trait(tcx,def_id)=>{{();};tcx.dcx().span_delayed_bug(tcx. +def_span(def_id),"trait implementations cannot be const stable yet",);;true}None +=>false,}}fn is_parent_const_stable_trait(tcx:TyCtxt<'_>,def_id:DefId)->bool{(); +let local_def_id=def_id.expect_local();3;;let hir_id=tcx.local_def_id_to_hir_id( +local_def_id);();3;let parent_owner_id=tcx.parent_hir_id(hir_id).owner;3;if!tcx. +is_const_trait_impl_raw(parent_owner_id.to_def_id()){({});return false;{;};}tcx. +lookup_const_stability(parent_owner_id).is_some_and( |stab|stab.is_const_stable( +))}//let _=();let _=();let _=();if true{};let _=();if true{};let _=();if true{}; 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 e87e60f62dc88..08df2ea26aba8 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -1,650 +1,190 @@ -//! Concrete error types for all operations which may be invalid in a certain const context. - -use hir::def_id::LocalDefId; -use hir::{ConstContext, LangItem}; -use rustc_errors::{codes::*, Diag}; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::traits::{ImplSource, Obligation, ObligationCause}; -use rustc_middle::mir::{self, CallSource}; -use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::TraitRef; -use rustc_middle::ty::{suggest_constraining_type_param, Adt, Closure, FnDef, FnPtr, Param, Ty}; -use rustc_middle::ty::{GenericArgKind, GenericArgsRef}; -use rustc_middle::util::{call_kind, CallDesugaringKind, CallKind}; -use rustc_session::parse::feature_err; -use rustc_span::symbol::sym; -use rustc_span::{BytePos, Pos, Span, Symbol}; -use rustc_trait_selection::traits::SelectionContext; - -use super::ConstCx; -use crate::errors; - -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum Status { - Allowed, - Unstable(Symbol), - Forbidden, -} - -#[derive(Clone, Copy)] -pub enum DiagImportance { - /// An operation that must be removed for const-checking to pass. - Primary, - - /// An operation that causes const-checking to fail, but is usually a side-effect of a `Primary` operation elsewhere. - Secondary, -} - -/// An operation that is not *always* allowed in a const context. -pub trait NonConstOp<'tcx>: std::fmt::Debug { - /// Returns an enum indicating whether this operation is allowed within the given item. - fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status { - Status::Forbidden - } - - fn importance(&self) -> DiagImportance { - DiagImportance::Primary - } - - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx>; -} - -#[derive(Debug)] -pub struct FloatingPointOp; -impl<'tcx> NonConstOp<'tcx> for FloatingPointOp { - fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status { - if ccx.const_kind() == hir::ConstContext::ConstFn { - Status::Unstable(sym::const_fn_floating_point_arithmetic) - } else { - Status::Allowed - } - } - - #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - feature_err( - &ccx.tcx.sess, - sym::const_fn_floating_point_arithmetic, - span, - format!("floating point arithmetic is not allowed in {}s", ccx.const_kind()), - ) - } -} - -/// A function call where the callee is a pointer. -#[derive(Debug)] -pub struct FnCallIndirect; -impl<'tcx> NonConstOp<'tcx> for FnCallIndirect { - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - ccx.dcx().create_err(errors::UnallowedFnPointerCall { span, kind: ccx.const_kind() }) - } -} - -/// A function call where the callee is not marked as `const`. -#[derive(Debug, Clone, Copy)] -pub struct FnCallNonConst<'tcx> { - pub caller: LocalDefId, - pub callee: DefId, - pub args: GenericArgsRef<'tcx>, - pub span: Span, - pub call_source: CallSource, - pub feature: Option, -} - -impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { - // FIXME: make this translatable - #[allow(rustc::diagnostic_outside_of_impl)] - #[allow(rustc::untranslatable_diagnostic)] - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> Diag<'tcx> { - let FnCallNonConst { caller, callee, args, span, call_source, feature } = *self; - let ConstCx { tcx, param_env, body, .. } = *ccx; - - let diag_trait = |err, self_ty: Ty<'_>, trait_id| { - let trait_ref = TraitRef::from_method(tcx, trait_id, args); - - match self_ty.kind() { - Param(param_ty) => { - debug!(?param_ty); - if let Some(generics) = tcx.hir_node_by_def_id(caller).generics() { - let constraint = with_no_trimmed_paths!(format!( - "~const {}", - trait_ref.print_only_trait_path() - )); - suggest_constraining_type_param( - tcx, - generics, - err, - param_ty.name.as_str(), - &constraint, - None, - None, - ); - } - } - Adt(..) => { - let obligation = - Obligation::new(tcx, ObligationCause::dummy(), param_env, trait_ref); - - 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 { - // FIXME(effects) revisit this - if !tcx.is_const_trait_impl_raw(data.impl_def_id) { - let span = tcx.def_span(data.impl_def_id); - err.subdiagnostic(tcx.dcx(), errors::NonConstImplNote { span }); - } - } - } - _ => {} - } - }; - - let call_kind = - call_kind(tcx, ccx.param_env, callee, args, span, call_source.from_hir_call(), None); - - debug!(?call_kind); - - let mut err = match call_kind { - CallKind::Normal { desugaring: Some((kind, self_ty)), .. } => { - macro_rules! error { - ($err:ident) => { - tcx.dcx().create_err(errors::$err { - span, - ty: self_ty, - kind: ccx.const_kind(), - }) - }; - } - - let mut err = match kind { - CallDesugaringKind::ForLoopIntoIter => { - error!(NonConstForLoopIntoIter) - } - CallDesugaringKind::QuestionBranch => { - error!(NonConstQuestionBranch) - } - CallDesugaringKind::QuestionFromResidual => { - error!(NonConstQuestionFromResidual) - } - CallDesugaringKind::TryBlockFromOutput => { - error!(NonConstTryBlockFromOutput) - } - CallDesugaringKind::Await => { - error!(NonConstAwait) - } - }; - - diag_trait(&mut err, self_ty, kind.trait_def_id(tcx)); - err - } - CallKind::FnCall { fn_trait_id, self_ty } => { - let note = match self_ty.kind() { - FnDef(def_id, ..) => { - let span = tcx.def_span(*def_id); - if ccx.tcx.is_const_fn_raw(*def_id) { - span_bug!(span, "calling const FnDef errored when it shouldn't"); - } - - Some(errors::NonConstClosureNote::FnDef { span }) - } - FnPtr(..) => Some(errors::NonConstClosureNote::FnPtr), - Closure(..) => Some(errors::NonConstClosureNote::Closure), - _ => None, - }; - - let mut err = tcx.dcx().create_err(errors::NonConstClosure { - span, - kind: ccx.const_kind(), - note, - }); - - diag_trait(&mut err, self_ty, fn_trait_id); - err - } - CallKind::Operator { trait_id, self_ty, .. } => { - let mut err = if let CallSource::MatchCmp = call_source { - tcx.dcx().create_err(errors::NonConstMatchEq { - span, - kind: ccx.const_kind(), - ty: self_ty, - }) - } else { - let mut sugg = None; - - if Some(trait_id) == ccx.tcx.lang_items().eq_trait() { - match (args[0].unpack(), args[1].unpack()) { - (GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty)) - if self_ty == rhs_ty - && self_ty.is_ref() - && self_ty.peel_refs().is_primitive() => - { - let mut num_refs = 0; - let mut tmp_ty = self_ty; - while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() { - num_refs += 1; - tmp_ty = *inner_ty; - } - let deref = "*".repeat(num_refs); - - if let Ok(call_str) = - ccx.tcx.sess.source_map().span_to_snippet(span) - { - if let Some(eq_idx) = call_str.find("==") { - if let Some(rhs_idx) = call_str[(eq_idx + 2)..] - .find(|c: char| !c.is_whitespace()) - { - let rhs_pos = span.lo() - + BytePos::from_usize(eq_idx + 2 + rhs_idx); - let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos); - sugg = Some(errors::ConsiderDereferencing { - deref, - span: span.shrink_to_lo(), - rhs_span, - }); - } - } - } - } - _ => {} - } - } - tcx.dcx().create_err(errors::NonConstOperator { - span, - kind: ccx.const_kind(), - sugg, - }) - }; - - diag_trait(&mut err, self_ty, trait_id); - err - } - CallKind::DerefCoercion { deref_target, deref_target_ty, self_ty } => { - // Check first whether the source is accessible (issue #87060) - let target = if tcx.sess.source_map().is_span_accessible(deref_target) { - Some(deref_target) - } else { - None - }; - - let mut err = tcx.dcx().create_err(errors::NonConstDerefCoercion { - span, - ty: self_ty, - kind: ccx.const_kind(), - target_ty: deref_target_ty, - deref_target: target, - }); - - diag_trait(&mut err, self_ty, tcx.require_lang_item(LangItem::Deref, Some(span))); - err - } - _ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::ArgumentMethods) => { - ccx.dcx().create_err(errors::NonConstFmtMacroCall { span, kind: ccx.const_kind() }) - } - _ => ccx.dcx().create_err(errors::NonConstFnCall { - span, - def_path_str: ccx.tcx.def_path_str_with_args(callee, args), - kind: ccx.const_kind(), - }), - }; - - err.note(format!( - "calls in {}s are limited to constant functions, \ - tuple structs and tuple variants", - ccx.const_kind(), - )); - - if let Some(feature) = feature { - ccx.tcx.disabled_nightly_features( - &mut err, - body.source.def_id().as_local().map(|local| ccx.tcx.local_def_id_to_hir_id(local)), - [(String::new(), feature)], - ); - } - - if let ConstContext::Static(_) = ccx.const_kind() { - err.note("consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell"); - } - - err - } -} - -/// A call to an `#[unstable]` const fn or `#[rustc_const_unstable]` function. -/// -/// Contains the name of the feature that would allow the use of this function. -#[derive(Debug)] -pub struct FnCallUnstable(pub DefId, pub Option); - -impl<'tcx> NonConstOp<'tcx> for FnCallUnstable { - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - let FnCallUnstable(def_id, feature) = *self; - - let mut err = ccx - .dcx() - .create_err(errors::UnstableConstFn { span, def_path: ccx.tcx.def_path_str(def_id) }); - - // FIXME: make this translatable - #[allow(rustc::untranslatable_diagnostic)] - if ccx.is_const_stable_const_fn() { - err.help("const-stable functions can only call other const-stable functions"); - } else if ccx.tcx.sess.is_nightly_build() { - if let Some(feature) = feature { - err.help(format!("add `#![feature({feature})]` to the crate attributes to enable")); - } - } - - err - } -} - -#[derive(Debug)] -pub struct Coroutine(pub hir::CoroutineKind); -impl<'tcx> NonConstOp<'tcx> for Coroutine { - fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status { - if let hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, - hir::CoroutineSource::Block, - ) = self.0 - { - Status::Unstable(sym::const_async_blocks) - } else { - Status::Forbidden - } - } - - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - let msg = format!("{:#}s are not allowed in {}s", self.0, ccx.const_kind()); - if let hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, - hir::CoroutineSource::Block, - ) = self.0 - { - ccx.tcx.sess.create_feature_err( - errors::UnallowedOpInConstContext { span, msg }, - sym::const_async_blocks, - ) - } else { - ccx.dcx().create_err(errors::UnallowedOpInConstContext { span, msg }) - } - } -} - -#[derive(Debug)] -pub struct HeapAllocation; -impl<'tcx> NonConstOp<'tcx> for HeapAllocation { - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - ccx.dcx().create_err(errors::UnallowedHeapAllocations { - span, - kind: ccx.const_kind(), - teach: ccx.tcx.sess.teach(E0010).then_some(()), - }) - } -} - -#[derive(Debug)] -pub struct InlineAsm; -impl<'tcx> NonConstOp<'tcx> for InlineAsm { - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - ccx.dcx().create_err(errors::UnallowedInlineAsm { span, kind: ccx.const_kind() }) - } -} - -#[derive(Debug)] -pub struct LiveDrop<'tcx> { - pub dropped_at: Option, - pub dropped_ty: Ty<'tcx>, -} -impl<'tcx> NonConstOp<'tcx> for LiveDrop<'tcx> { - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - ccx.dcx().create_err(errors::LiveDrop { - span, - dropped_ty: self.dropped_ty, - kind: ccx.const_kind(), - dropped_at: self.dropped_at, - }) - } -} - -#[derive(Debug)] -/// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow never escapes to -/// the final value of the constant. -pub struct TransientCellBorrow; -impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow { - fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status { - Status::Unstable(sym::const_refs_to_cell) - } - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - ccx.tcx - .sess - .create_feature_err(errors::InteriorMutabilityBorrow { span }, sym::const_refs_to_cell) - } -} - -#[derive(Debug)] -/// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow might escape to -/// the final value of the constant, and thus we cannot allow this (for now). We may allow -/// it in the future for static items. -pub struct CellBorrow; -impl<'tcx> NonConstOp<'tcx> for CellBorrow { - fn importance(&self) -> DiagImportance { - // Most likely the code will try to do mutation with these borrows, which - // triggers its own errors. Only show this one if that does not happen. - DiagImportance::Secondary - } - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - // FIXME: Maybe a more elegant solution to this if else case - if let hir::ConstContext::Static(_) = ccx.const_kind() { - ccx.dcx().create_err(errors::InteriorMutableDataRefer { - span, - opt_help: Some(()), - kind: ccx.const_kind(), - teach: ccx.tcx.sess.teach(E0492).then_some(()), - }) - } else { - ccx.dcx().create_err(errors::InteriorMutableDataRefer { - span, - opt_help: None, - kind: ccx.const_kind(), - teach: ccx.tcx.sess.teach(E0492).then_some(()), - }) - } - } -} - -#[derive(Debug)] -/// This op is for `&mut` borrows in the trailing expression of a constant -/// which uses the "enclosing scopes rule" to leak its locals into anonymous -/// static or const items. -pub struct MutBorrow(pub hir::BorrowKind); - -impl<'tcx> NonConstOp<'tcx> for MutBorrow { - fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status { - Status::Forbidden - } - - fn importance(&self) -> DiagImportance { - // Most likely the code will try to do mutation with these borrows, which - // triggers its own errors. Only show this one if that does not happen. - DiagImportance::Secondary - } - - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - match self.0 { - hir::BorrowKind::Raw => ccx.tcx.dcx().create_err(errors::UnallowedMutableRaw { - span, - kind: ccx.const_kind(), - teach: ccx.tcx.sess.teach(E0764).then_some(()), - }), - hir::BorrowKind::Ref => ccx.dcx().create_err(errors::UnallowedMutableRefs { - span, - kind: ccx.const_kind(), - teach: ccx.tcx.sess.teach(E0764).then_some(()), - }), - } - } -} - -#[derive(Debug)] -pub struct TransientMutBorrow(pub hir::BorrowKind); - -impl<'tcx> NonConstOp<'tcx> for TransientMutBorrow { - fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status { - Status::Unstable(sym::const_mut_refs) - } - - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - let kind = ccx.const_kind(); - match self.0 { - hir::BorrowKind::Raw => ccx - .tcx - .sess - .create_feature_err(errors::TransientMutRawErr { span, kind }, sym::const_mut_refs), - hir::BorrowKind::Ref => ccx.tcx.sess.create_feature_err( - errors::TransientMutBorrowErr { span, kind }, - sym::const_mut_refs, - ), - } - } -} - -#[derive(Debug)] -pub struct MutDeref; -impl<'tcx> NonConstOp<'tcx> for MutDeref { - fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status { - Status::Unstable(sym::const_mut_refs) - } - - fn importance(&self) -> DiagImportance { - // Usually a side-effect of a `TransientMutBorrow` somewhere. - DiagImportance::Secondary - } - - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - ccx.tcx.sess.create_feature_err( - errors::MutDerefErr { span, kind: ccx.const_kind() }, - sym::const_mut_refs, - ) - } -} - -/// A call to a `panic()` lang item where the first argument is _not_ a `&str`. -#[derive(Debug)] -pub struct PanicNonStr; -impl<'tcx> NonConstOp<'tcx> for PanicNonStr { - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - ccx.dcx().create_err(errors::PanicNonStrErr { span }) - } -} - -/// Comparing raw pointers for equality. -/// Not currently intended to ever be allowed, even behind a feature gate: operation depends on -/// allocation base addresses that are not known at compile-time. -#[derive(Debug)] -pub struct RawPtrComparison; -impl<'tcx> NonConstOp<'tcx> for RawPtrComparison { - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - // FIXME(const_trait_impl): revert to span_bug? - ccx.dcx().create_err(errors::RawPtrComparisonErr { span }) - } -} - -#[derive(Debug)] -pub struct RawMutPtrDeref; -impl<'tcx> NonConstOp<'tcx> for RawMutPtrDeref { - fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { - Status::Unstable(sym::const_mut_refs) - } - - #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - feature_err( - &ccx.tcx.sess, - sym::const_mut_refs, - span, - format!("dereferencing raw mutable pointers in {}s is unstable", ccx.const_kind(),), - ) - } -} - -/// Casting raw pointer or function pointer to an integer. -/// Not currently intended to ever be allowed, even behind a feature gate: operation depends on -/// allocation base addresses that are not known at compile-time. -#[derive(Debug)] -pub struct RawPtrToIntCast; -impl<'tcx> NonConstOp<'tcx> for RawPtrToIntCast { - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - ccx.dcx().create_err(errors::RawPtrToIntErr { span }) - } -} - -/// An access to a (non-thread-local) `static`. -#[derive(Debug)] -pub struct StaticAccess; -impl<'tcx> NonConstOp<'tcx> for StaticAccess { - fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status { - if let hir::ConstContext::Static(_) = ccx.const_kind() { - Status::Allowed - } else { - Status::Unstable(sym::const_refs_to_static) - } - } - - #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - let mut err = feature_err( - &ccx.tcx.sess, - sym::const_refs_to_static, - span, - format!("referencing statics in {}s is unstable", ccx.const_kind(),), - ); - // FIXME: make this translatable - #[allow(rustc::untranslatable_diagnostic)] - err - .note("`static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable.") - .help("to fix this, the value can be extracted to a `const` and then used."); - err - } -} - -/// An access to a thread-local `static`. -#[derive(Debug)] -pub struct ThreadLocalAccess; -impl<'tcx> NonConstOp<'tcx> for ThreadLocalAccess { - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - ccx.dcx().create_err(errors::ThreadLocalAccessErr { span }) - } -} - -/// Types that cannot appear in the signature or locals of a `const fn`. -pub mod ty { - use super::*; - - #[derive(Debug)] - pub struct MutRef(pub mir::LocalKind); - impl<'tcx> NonConstOp<'tcx> for MutRef { - fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status { - Status::Unstable(sym::const_mut_refs) - } - - fn importance(&self) -> DiagImportance { - match self.0 { - mir::LocalKind::Temp => DiagImportance::Secondary, - mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => DiagImportance::Primary, - } - } - - #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - feature_err( - &ccx.tcx.sess, - sym::const_mut_refs, - span, - format!("mutable references are not allowed in {}s", ccx.const_kind()), - ) - } - } -} +use hir::def_id::LocalDefId;use hir ::{ConstContext,LangItem};use rustc_errors:: +{codes::*,Diag};use rustc_hir as hir;use rustc_hir::def_id::DefId;use//let _=(); +rustc_infer::infer::TyCtxtInferExt;use rustc_infer::traits::{ImplSource,//{();}; +Obligation,ObligationCause};use rustc_middle::mir::{self,CallSource};use//{();}; +rustc_middle::ty::print::with_no_trimmed_paths;use rustc_middle::ty::TraitRef;// +use rustc_middle::ty::{suggest_constraining_type_param ,Adt,Closure,FnDef,FnPtr, +Param,Ty};use rustc_middle::ty::{GenericArgKind,GenericArgsRef};use//let _=||(); +rustc_middle::util::{call_kind,CallDesugaringKind ,CallKind};use rustc_session:: +parse::feature_err;use rustc_span::symbol::sym;use rustc_span::{BytePos,Pos,//3; +Span,Symbol};use rustc_trait_selection::traits::SelectionContext;use super:://3; +ConstCx;use crate::errors;#[derive(Clone,Copy,Debug,PartialEq,Eq)]pub enum//{;}; +Status{Allowed,Unstable(Symbol),Forbidden,}#[derive(Clone,Copy)]pub enum//{();}; +DiagImportance{Primary,Secondary,}pub trait NonConstOp<'tcx>:std::fmt::Debug{fn +status_in_item(&self,_ccx:&ConstCx<'_,'tcx>)->Status{Status::Forbidden}fn//({}); +importance(&self)->DiagImportance{DiagImportance ::Primary}fn build_error(&self, +ccx:&ConstCx<'_,'tcx>,span:Span)->Diag<'tcx>;}#[derive(Debug)]pub struct//{();}; +FloatingPointOp;impl<'tcx>NonConstOp< 'tcx>for FloatingPointOp{fn status_in_item +(&self,ccx:&ConstCx<'_,'tcx>)->Status{if (ccx.const_kind())==hir::ConstContext:: +ConstFn{Status::Unstable(sym ::const_fn_floating_point_arithmetic)}else{Status:: +Allowed}}#[allow(rustc::untranslatable_diagnostic)]fn build_error(&self,ccx:&//; +ConstCx<'_,'tcx>,span:Span)->Diag<'tcx >{feature_err(((((&ccx.tcx.sess)))),sym:: +const_fn_floating_point_arithmetic,span,format!(//*&*&();((),());*&*&();((),()); +"floating point arithmetic is not allowed in {}s",ccx.const_kind()) ,)}}#[derive +(Debug)]pub struct FnCallIndirect;impl <'tcx>NonConstOp<'tcx>for FnCallIndirect{ +fn build_error(&self,ccx:&ConstCx<'_,'tcx>,span:Span)->Diag<'tcx>{((ccx.dcx())). +create_err(((errors::UnallowedFnPointerCall{span,kind:(ccx.const_kind())})))}}#[ +derive(Debug,Clone,Copy)]pub struct FnCallNonConst<'tcx>{pub caller:LocalDefId, +pub callee:DefId,pub args:GenericArgsRef<'tcx>,pub span:Span,pub call_source://; +CallSource,pub feature:Option,}impl<'tcx>NonConstOp<'tcx>for//if true{}; +FnCallNonConst<'tcx>{#[allow(rustc ::diagnostic_outside_of_impl)]#[allow(rustc:: +untranslatable_diagnostic)]fn build_error(&self,ccx: &ConstCx<'_,'tcx>,_:Span)-> +Diag<'tcx>{{;};let FnCallNonConst{caller,callee,args,span,call_source,feature}=* +self;;let ConstCx{tcx,param_env,body,..}=*ccx;let diag_trait=|err,self_ty:Ty<'_> +,trait_id|{;let trait_ref=TraitRef::from_method(tcx,trait_id,args);match self_ty +.kind(){Param(param_ty)=>{({});debug!(?param_ty);({});if let Some(generics)=tcx. +hir_node_by_def_id(caller).generics(){{;};let constraint=with_no_trimmed_paths!( +format!("~const {}",trait_ref.print_only_trait_path()));loop{break};loop{break}; +suggest_constraining_type_param(tcx,generics,err,(((param_ty .name.as_str()))),& +constraint,None,None,);({});}}Adt(..)=>{({});let obligation=Obligation::new(tcx, +ObligationCause::dummy(),param_env,trait_ref);;let infcx=tcx.infer_ctxt().build( +);3;3;let mut selcx=SelectionContext::new(&infcx);3;3;let implsrc=selcx.select(& +obligation);{();};if let Ok(Some(ImplSource::UserDefined(data)))=implsrc{if!tcx. +is_const_trait_impl_raw(data.impl_def_id){let _=||();let span=tcx.def_span(data. +impl_def_id);;err.subdiagnostic(tcx.dcx(),errors::NonConstImplNote{span});}}}_=> +{}}};3;3;let call_kind=call_kind(tcx,ccx.param_env,callee,args,span,call_source. +from_hir_call(),None);;debug!(?call_kind);let mut err=match call_kind{CallKind:: +Normal{desugaring:Some((kind,self_ty)),..}=>{3;macro_rules!error{($err:ident)=>{ +tcx.dcx().create_err(errors::$err{span,ty:self_ty,kind:ccx.const_kind(),})};}3;; +let mut err=match kind{CallDesugaringKind::ForLoopIntoIter=>{error!(//if true{}; +NonConstForLoopIntoIter)}CallDesugaringKind::QuestionBranch=>{error!(//let _=(); +NonConstQuestionBranch)}CallDesugaringKind::QuestionFromResidual=>{error!(//{;}; +NonConstQuestionFromResidual)}CallDesugaringKind::TryBlockFromOutput=>{error!(// +NonConstTryBlockFromOutput)}CallDesugaringKind::Await=>{ error!(NonConstAwait)}} +;3;3;diag_trait(&mut err,self_ty,kind.trait_def_id(tcx));3;err}CallKind::FnCall{ +fn_trait_id,self_ty}=>{();let note=match self_ty.kind(){FnDef(def_id,..)=>{3;let +span=tcx.def_span(*def_id);;if ccx.tcx.is_const_fn_raw(*def_id){;span_bug!(span, +"calling const FnDef errored when it shouldn't");((),());let _=();}Some(errors:: +NonConstClosureNote::FnDef{span})}FnPtr (..)=>Some(errors::NonConstClosureNote:: +FnPtr),Closure(..)=>Some(errors::NonConstClosureNote::Closure),_=>None,};3;3;let +mut err=tcx.dcx().create_err( errors::NonConstClosure{span,kind:ccx.const_kind() +,note,});();3;diag_trait(&mut err,self_ty,fn_trait_id);3;err}CallKind::Operator{ +trait_id,self_ty,..}=>{;let mut err=if let CallSource::MatchCmp=call_source{tcx. +dcx().create_err(errors::NonConstMatchEq{span, kind:ccx.const_kind(),ty:self_ty, +})}else{3;let mut sugg=None;;if Some(trait_id)==ccx.tcx.lang_items().eq_trait(){ +match((((args[(0)]).unpack()),args[1].unpack())){(GenericArgKind::Type(self_ty), +GenericArgKind::Type(rhs_ty))if ((self_ty==rhs_ty )&&self_ty.is_ref())&&self_ty. +peel_refs().is_primitive()=>{;let mut num_refs=0;;;let mut tmp_ty=self_ty;;while +let rustc_middle::ty::Ref(_,inner_ty,_)=tmp_ty.kind(){3;num_refs+=1;3;3;tmp_ty=* +inner_ty;3;}3;let deref="*".repeat(num_refs);3;if let Ok(call_str)=ccx.tcx.sess. +source_map().span_to_snippet(span){if let Some (eq_idx)=(call_str.find("==")){if +let Some(rhs_idx)=call_str[(eq_idx+2)..].find(|c:char|!c.is_whitespace()){();let +rhs_pos=span.lo()+BytePos::from_usize(eq_idx+2+rhs_idx);();();let rhs_span=span. +with_lo(rhs_pos).with_hi(rhs_pos);;sugg=Some(errors::ConsiderDereferencing{deref +,span:span.shrink_to_lo(),rhs_span,});3;}}}}_=>{}}}tcx.dcx().create_err(errors:: +NonConstOperator{span,kind:ccx.const_kind(),sugg,})};{;};();diag_trait(&mut err, +self_ty,trait_id);({});err}CallKind::DerefCoercion{deref_target,deref_target_ty, +self_ty}=>{;let target=if tcx.sess.source_map().is_span_accessible(deref_target) +{Some(deref_target)}else{None};{;};{;};let mut err=tcx.dcx().create_err(errors:: +NonConstDerefCoercion{span,ty:self_ty,kind:(((((ccx.const_kind()))))),target_ty: +deref_target_ty,deref_target:target,});({});{;};diag_trait(&mut err,self_ty,tcx. +require_lang_item(LangItem::Deref,Some(span)));3;err}_ if tcx.opt_parent(callee) +==tcx.get_diagnostic_item(sym::ArgumentMethods)=>{ ccx.dcx().create_err(errors:: +NonConstFmtMacroCall{span,kind:((ccx.const_kind()))})}_=>(ccx.dcx()).create_err( +errors::NonConstFnCall{span,def_path_str: ccx.tcx.def_path_str_with_args(callee, +args),kind:ccx.const_kind(),}),};*&*&();((),());*&*&();((),());err.note(format!( +"calls in {}s are limited to constant functions, \ + tuple structs and tuple variants" +,ccx.const_kind(),));let _=||();if let Some(feature)=feature{let _=||();ccx.tcx. +disabled_nightly_features((&mut err),body.source.def_id().as_local().map(|local| +ccx.tcx.local_def_id_to_hir_id(local)),[(String::new(),feature)],);{();};}if let +ConstContext::Static(_)=ccx.const_kind(){*&*&();((),());*&*&();((),());err.note( +"consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell" +);;}err}}#[derive(Debug)]pub struct FnCallUnstable(pub DefId,pub Option) +;impl<'tcx>NonConstOp<'tcx>for FnCallUnstable {fn build_error(&self,ccx:&ConstCx +<'_,'tcx>,span:Span)->Diag<'tcx>{;let FnCallUnstable(def_id,feature)=*self;;;let +mut err=((ccx.dcx())).create_err (errors::UnstableConstFn{span,def_path:ccx.tcx. +def_path_str(def_id)});((),());#[allow(rustc::untranslatable_diagnostic)]if ccx. +is_const_stable_const_fn(){let _=||();let _=||();let _=||();let _=||();err.help( +"const-stable functions can only call other const-stable functions");3;}else if +ccx.tcx.sess.is_nightly_build(){if let Some(feature)=feature{3;err.help(format!( +"add `#![feature({feature})]` to the crate attributes to enable"));{;};}}err}}#[ +derive(Debug)]pub struct Coroutine( pub hir::CoroutineKind);impl<'tcx>NonConstOp +<'tcx>for Coroutine{fn status_in_item(&self,_ :&ConstCx<'_,'tcx>)->Status{if let +hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async,hir:://let _=||(); +CoroutineSource::Block,)=self.0{ Status::Unstable(sym::const_async_blocks)}else{ +Status::Forbidden}}fn build_error(&self,ccx: &ConstCx<'_,'tcx>,span:Span)->Diag< +'tcx>{;let msg=format!("{:#}s are not allowed in {}s",self.0,ccx.const_kind());; +if let hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async,hir:://{;}; +CoroutineSource::Block,)=self.0{ccx.tcx.sess.create_feature_err(errors:://{();}; +UnallowedOpInConstContext{span,msg},sym::const_async_blocks,) }else{(ccx.dcx()). +create_err((errors::UnallowedOpInConstContext{span,msg}) )}}}#[derive(Debug)]pub +struct HeapAllocation;impl<'tcx>NonConstOp<'tcx>for HeapAllocation{fn//let _=(); +build_error(&self,ccx:&ConstCx<'_,'tcx>,span: Span)->Diag<'tcx>{(((ccx.dcx()))). +create_err(errors::UnallowedHeapAllocations{span,kind: (ccx.const_kind()),teach: +ccx.tcx.sess.teach(E0010).then_some((((((())))))),})}}#[derive(Debug)]pub struct +InlineAsm;impl<'tcx>NonConstOp<'tcx>for InlineAsm{fn build_error(&self,ccx:&//3; +ConstCx<'_,'tcx>,span:Span)->Diag<'tcx >{(((((ccx.dcx()))))).create_err(errors:: +UnallowedInlineAsm{span,kind:((ccx.const_kind()))} )}}#[derive(Debug)]pub struct +LiveDrop<'tcx>{pub dropped_at:Option,pub dropped_ty:Ty<'tcx>,}impl<'tcx>// +NonConstOp<'tcx>for LiveDrop<'tcx>{fn build_error(&self,ccx:&ConstCx<'_,'tcx>,// +span:Span)->Diag<'tcx>{(ccx.dcx ()).create_err(errors::LiveDrop{span,dropped_ty: +self.dropped_ty,kind:(ccx.const_kind()),dropped_at:self.dropped_at,})}}#[derive( +Debug)]pub struct TransientCellBorrow;impl<'tcx>NonConstOp<'tcx>for//let _=||(); +TransientCellBorrow{fn status_in_item(&self,_:& ConstCx<'_,'tcx>)->Status{Status +::Unstable(sym::const_refs_to_cell)}fn build_error( &self,ccx:&ConstCx<'_,'tcx>, +span:Span)->Diag<'tcx>{ccx.tcx.sess.create_feature_err(errors:://*&*&();((),()); +InteriorMutabilityBorrow{span},sym::const_refs_to_cell)}}#[derive(Debug)]pub//3; +struct CellBorrow;impl<'tcx>NonConstOp<'tcx >for CellBorrow{fn importance(&self) +->DiagImportance{DiagImportance::Secondary}fn build_error (&self,ccx:&ConstCx<'_ +,'tcx>,span:Span)->Diag<'tcx>{if let hir::ConstContext::Static(_)=ccx.//((),()); +const_kind(){((((ccx.dcx())))).create_err(errors::InteriorMutableDataRefer{span, +opt_help:(Some((()))),kind:(ccx.const_kind()),teach:(ccx.tcx.sess.teach(E0492)). +then_some((())),})}else{(ccx.dcx()).create_err(errors::InteriorMutableDataRefer{ +span,opt_help:None,kind:((ccx.const_kind())), teach:(ccx.tcx.sess.teach(E0492)). +then_some((())),})}}}#[ derive(Debug)]pub struct MutBorrow(pub hir::BorrowKind); +impl<'tcx>NonConstOp<'tcx>for MutBorrow{fn status_in_item(&self,_ccx:&ConstCx)->Status{Status::Forbidden}fn importance(&self)->DiagImportance{//({}); +DiagImportance::Secondary}fn build_error(&self,ccx :&ConstCx<'_,'tcx>,span:Span) +->Diag<'tcx>{match self.0{hir::BorrowKind:: Raw=>ccx.tcx.dcx().create_err(errors +::UnallowedMutableRaw{span,kind:ccx.const_kind() ,teach:ccx.tcx.sess.teach(E0764 +).then_some((((())))),}),hir::BorrowKind::Ref=>((ccx.dcx())).create_err(errors:: +UnallowedMutableRefs{span,kind:ccx.const_kind(), teach:ccx.tcx.sess.teach(E0764) +.then_some(((()))),}),}}}#[derive(Debug)]pub struct TransientMutBorrow(pub hir:: +BorrowKind);impl<'tcx>NonConstOp< 'tcx>for TransientMutBorrow{fn status_in_item( +&self,_:&ConstCx<'_,'tcx>)-> Status{((Status::Unstable(sym::const_mut_refs)))}fn +build_error(&self,ccx:&ConstCx<'_,'tcx>,span:Span)->Diag<'tcx>{{;};let kind=ccx. +const_kind();;match self.0{hir::BorrowKind::Raw=>ccx.tcx.sess.create_feature_err +((errors::TransientMutRawErr{span,kind}) ,sym::const_mut_refs),hir::BorrowKind:: +Ref=>ccx.tcx.sess.create_feature_err((errors::TransientMutBorrowErr{span,kind}), +sym::const_mut_refs,),}}}#[derive(Debug)]pub struct MutDeref;impl<'tcx>//*&*&(); +NonConstOp<'tcx>for MutDeref{fn status_in_item(&self,_:&ConstCx<'_,'tcx>)->//(); +Status{((((((Status::Unstable(sym::const_mut_refs )))))))}fn importance(&self)-> +DiagImportance{DiagImportance::Secondary}fn build_error(&self,ccx:&ConstCx<'_,// +'tcx>,span:Span)->Diag<'tcx>{ccx.tcx.sess.create_feature_err(errors:://let _=(); +MutDerefErr{span,kind:ccx.const_kind()} ,sym::const_mut_refs,)}}#[derive(Debug)] +pub struct PanicNonStr;impl<'tcx> NonConstOp<'tcx>for PanicNonStr{fn build_error +(&self,ccx:&ConstCx<'_,'tcx>,span:Span) ->Diag<'tcx>{ccx.dcx().create_err(errors +::PanicNonStrErr{span})}}#[derive (Debug)]pub struct RawPtrComparison;impl<'tcx> +NonConstOp<'tcx>for RawPtrComparison{fn build_error( &self,ccx:&ConstCx<'_,'tcx> +,span:Span)->Diag<'tcx>{ccx.dcx ().create_err(errors::RawPtrComparisonErr{span}) +}}#[derive(Debug)]pub struct RawMutPtrDeref;impl<'tcx>NonConstOp<'tcx>for//({}); +RawMutPtrDeref{fn status_in_item(&self,_:&ConstCx<'_,'_>)->Status{Status:://{;}; +Unstable(sym::const_mut_refs)}#[allow(rustc::untranslatable_diagnostic)]fn//{;}; +build_error(&self,ccx:&ConstCx<'_,'tcx>, span:Span)->Diag<'tcx>{feature_err(&ccx +.tcx.sess,sym::const_mut_refs,span,format!(//((),());let _=();let _=();let _=(); +"dereferencing raw mutable pointers in {}s is unstable",ccx.const_kind(), ),)}}# +[derive(Debug)]pub struct RawPtrToIntCast;impl<'tcx>NonConstOp<'tcx>for//*&*&(); +RawPtrToIntCast{fn build_error(&self,ccx:&ConstCx<'_,'tcx>,span:Span)->Diag{(ccx.dcx().create_err(errors:: RawPtrToIntErr{span}))}}#[derive(Debug)]pub +struct StaticAccess;impl<'tcx>NonConstOp<'tcx>for StaticAccess{fn//loop{break;}; +status_in_item(&self,ccx:&ConstCx<'_,'tcx>)->Status{if let hir::ConstContext::// +Static(_)=(((((ccx.const_kind()))))){Status::Allowed}else{Status::Unstable(sym:: +const_refs_to_static)}}#[allow (rustc::untranslatable_diagnostic)]fn build_error +(&self,ccx:&ConstCx<'_,'tcx>,span:Span)->Diag<'tcx>{();let mut err=feature_err(& +ccx.tcx.sess,sym::const_refs_to_static,span,format!(//loop{break;};loop{break;}; +"referencing statics in {}s is unstable",ccx.const_kind(),),);3;;#[allow(rustc:: +untranslatable_diagnostic)]err.note(//if true{};let _=||();if true{};let _=||(); +"`static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable." +).help("to fix this, the value can be extracted to a `const` and then used.");3; +err}}#[derive(Debug)]pub struct ThreadLocalAccess;impl<'tcx>NonConstOp<'tcx>for +ThreadLocalAccess{fn build_error(&self,ccx:&ConstCx<'_,'tcx>,span:Span)->Diag{(ccx.dcx().create_err(errors::ThreadLocalAccessErr{span}))}}pub mod ty{use +super::*;#[derive(Debug)]pub struct MutRef(pub mir::LocalKind);impl<'tcx>//({}); +NonConstOp<'tcx>for MutRef{fn status_in_item(&self,_ccx:&ConstCx<'_,'tcx>)->//3; +Status{((((((Status::Unstable(sym::const_mut_refs )))))))}fn importance(&self)-> +DiagImportance{match self.0{mir ::LocalKind::Temp=>DiagImportance::Secondary,mir +::LocalKind::ReturnPointer|mir::LocalKind::Arg=>DiagImportance::Primary,}}#[//3; +allow(rustc::untranslatable_diagnostic)]fn build_error(&self,ccx:&ConstCx<'_,//; +'tcx>,span:Span)->Diag<'tcx>{feature_err (&ccx.tcx.sess,sym::const_mut_refs,span +,((format!("mutable references are not allowed in {}s",ccx.const_kind ()))),)}}} 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 5cd13783c2318..b1bcfed19573e 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,123 +1,35 @@ -use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{self, BasicBlock, Location}; -use rustc_middle::ty::{Ty, TyCtxt}; -use rustc_span::{symbol::sym, Span}; - -use super::check::Qualifs; -use super::ops::{self, NonConstOp}; -use super::qualifs::{NeedsNonConstDrop, Qualif}; -use super::ConstCx; - -/// Returns `true` if we should use the more precise live drop checker that runs after drop -/// elaboration. -pub fn checking_enabled(ccx: &ConstCx<'_, '_>) -> bool { - // Const-stable functions must always use the stable live drop checker. - if ccx.is_const_stable_const_fn() { - return false; - } - - ccx.tcx.features().const_precise_live_drops -} - -/// Look for live drops in a const context. -/// -/// This is separate from the rest of the const checking logic because it must run after drop -/// elaboration. -pub fn check_live_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>) { - let def_id = body.source.def_id().expect_local(); - let const_kind = tcx.hir().body_const_context(def_id); - if const_kind.is_none() { - return; - } - - if tcx.has_attr(def_id, sym::rustc_do_not_const_check) { - return; - } - - let ccx = ConstCx { body, tcx, const_kind, param_env: tcx.param_env(def_id) }; - if !checking_enabled(&ccx) { - return; - } - - let mut visitor = CheckLiveDrops { ccx: &ccx, qualifs: Qualifs::default() }; - - visitor.visit_body(body); -} - -struct CheckLiveDrops<'mir, 'tcx> { - ccx: &'mir ConstCx<'mir, 'tcx>, - qualifs: Qualifs<'mir, 'tcx>, -} - -// So we can access `body` and `tcx`. -impl<'mir, 'tcx> std::ops::Deref for CheckLiveDrops<'mir, 'tcx> { - type Target = ConstCx<'mir, 'tcx>; - - fn deref(&self) -> &Self::Target { - self.ccx - } -} - -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(); - } -} - -impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> { - fn visit_basic_block_data(&mut self, bb: BasicBlock, block: &mir::BasicBlockData<'tcx>) { - trace!("visit_basic_block_data: bb={:?} is_cleanup={:?}", bb, block.is_cleanup); - - // Ignore drop terminators in cleanup blocks. - if block.is_cleanup { - return; - } - - self.super_basic_block_data(bb, block); - } - - fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) { - trace!("visit_terminator: terminator={:?} location={:?}", terminator, location); - - match &terminator.kind { - mir::TerminatorKind::Drop { place: dropped_place, .. } => { - let dropped_ty = dropped_place.ty(self.body, self.tcx).ty; - - if !NeedsNonConstDrop::in_any_value_of_ty(self.ccx, dropped_ty) { - // Instead of throwing a bug, we just return here. This is because we have to - // run custom `const Drop` impls. - return; - } - - if dropped_place.is_indirect() { - self.check_live_drop(terminator.source_info.span, dropped_ty); - return; - } - - // Drop elaboration is not precise enough to accept code like - // `tests/ui/consts/control-flow/drop-pass.rs`; e.g., when an `Option>` is - // initialized with `None` and never changed, it still emits drop glue. - // Hence we additionally check the qualifs here to allow more code to pass. - 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, dropped_ty); - } - } - - mir::TerminatorKind::UnwindTerminate(_) - | mir::TerminatorKind::Call { .. } - | mir::TerminatorKind::Assert { .. } - | mir::TerminatorKind::FalseEdge { .. } - | mir::TerminatorKind::FalseUnwind { .. } - | mir::TerminatorKind::CoroutineDrop - | mir::TerminatorKind::Goto { .. } - | mir::TerminatorKind::InlineAsm { .. } - | mir::TerminatorKind::UnwindResume - | mir::TerminatorKind::Return - | mir::TerminatorKind::SwitchInt { .. } - | mir::TerminatorKind::Unreachable - | mir::TerminatorKind::Yield { .. } => {} - } - } -} +use rustc_middle::mir::visit::Visitor;use rustc_middle::mir::{self,BasicBlock,// +Location};use rustc_middle::ty::{Ty,TyCtxt };use rustc_span::{symbol::sym,Span}; +use super::check::Qualifs;use super::ops::{self,NonConstOp};use super::qualifs// +::{NeedsNonConstDrop,Qualif};use super::ConstCx;pub fn checking_enabled(ccx:&//; +ConstCx<'_,'_>)->bool{if ccx.is_const_stable_const_fn(){;return false;;}ccx.tcx. +features().const_precise_live_drops}pub fn check_live_drops<'tcx>(tcx:TyCtxt,body:&mir::Body<'tcx>){;let def_id=body.source.def_id().expect_local();let +const_kind=tcx.hir().body_const_context(def_id);;if const_kind.is_none(){;return +;;}if tcx.has_attr(def_id,sym::rustc_do_not_const_check){return;}let ccx=ConstCx +{body,tcx,const_kind,param_env:tcx.param_env(def_id)};;if!checking_enabled(&ccx) +{;return;;};let mut visitor=CheckLiveDrops{ccx:&ccx,qualifs:Qualifs::default()}; +visitor.visit_body(body);();}struct CheckLiveDrops<'mir,'tcx>{ccx:&'mir ConstCx< +'mir,'tcx>,qualifs:Qualifs<'mir,'tcx>,}impl<'mir,'tcx>std::ops::Deref for//({}); +CheckLiveDrops<'mir,'tcx>{type Target=ConstCx<'mir ,'tcx>;fn deref(&self)->&Self +::Target{self.ccx}}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();3;}}impl<'tcx>Visitor<'tcx>for CheckLiveDrops< +'_,'tcx>{fn visit_basic_block_data(&mut self,bb:BasicBlock,block:&mir:://*&*&(); +BasicBlockData<'tcx>){;trace!("visit_basic_block_data: bb={:?} is_cleanup={:?}", +bb,block.is_cleanup);;if block.is_cleanup{return;}self.super_basic_block_data(bb +,block);*&*&();}fn visit_terminator(&mut self,terminator:&mir::Terminator<'tcx>, +location:Location){{;};trace!("visit_terminator: terminator={:?} location={:?}", +terminator,location);({});match&terminator.kind{mir::TerminatorKind::Drop{place: +dropped_place,..}=>{;let dropped_ty=dropped_place.ty(self.body,self.tcx).ty;;if! +NeedsNonConstDrop::in_any_value_of_ty(self.ccx,dropped_ty){({});return;({});}if +dropped_place.is_indirect(){();self.check_live_drop(terminator.source_info.span, +dropped_ty);;return;}if self.qualifs.needs_non_const_drop(self.ccx,dropped_place +.local,location){let _=||();let span=self.body.local_decls[dropped_place.local]. +source_info.span;;;self.check_live_drop(span,dropped_ty);}}mir::TerminatorKind:: +UnwindTerminate(_)|mir::TerminatorKind::Call {..}|mir::TerminatorKind::Assert{.. +}|mir::TerminatorKind::FalseEdge{..}| mir::TerminatorKind::FalseUnwind{..}|mir:: +TerminatorKind::CoroutineDrop|mir::TerminatorKind:: Goto{..}|mir::TerminatorKind +::InlineAsm{..}|mir::TerminatorKind::UnwindResume|mir::TerminatorKind::Return|// +mir::TerminatorKind::SwitchInt{..}|mir::TerminatorKind::Unreachable|mir:://({}); +TerminatorKind::Yield{..}=>{}}}}//let _=||();loop{break};let _=||();loop{break}; 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 1847847d9d2ae..c61b7df7a9b0c 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -1,395 +1,90 @@ -//! Structural const qualification. -//! -//! See the `Qualif` trait for more info. - -use rustc_errors::ErrorGuaranteed; -use rustc_hir::LangItem; -use rustc_infer::infer::TyCtxtInferExt; -use rustc_middle::mir; -use rustc_middle::mir::*; -use rustc_middle::traits::BuiltinImplSource; -use rustc_middle::ty::{self, AdtDef, GenericArgsRef, Ty}; -use rustc_trait_selection::traits::{ - ImplSource, Obligation, ObligationCause, ObligationCtxt, SelectionContext, -}; - -use super::ConstCx; - -pub fn in_any_value_of_ty<'tcx>( - cx: &ConstCx<'_, 'tcx>, - ty: Ty<'tcx>, - tainted_by_errors: Option, -) -> ConstQualifs { - ConstQualifs { - has_mut_interior: HasMutInterior::in_any_value_of_ty(cx, ty), - needs_drop: NeedsDrop::in_any_value_of_ty(cx, ty), - needs_non_const_drop: NeedsNonConstDrop::in_any_value_of_ty(cx, ty), - tainted_by_errors, - } -} - -/// A "qualif"(-ication) is a way to look for something "bad" in the MIR that would disqualify some -/// code for promotion or prevent it from evaluating at compile time. -/// -/// Normally, we would determine what qualifications apply to each type and error when an illegal -/// operation is performed on such a type. However, this was found to be too imprecise, especially -/// in the presence of `enum`s. If only a single variant of an enum has a certain qualification, we -/// needn't reject code unless it actually constructs and operates on the qualified variant. -/// -/// To accomplish this, const-checking and promotion use a value-based analysis (as opposed to a -/// type-based one). Qualifications propagate structurally across variables: If a local (or a -/// projection of a local) is assigned a qualified value, that local itself becomes qualified. -pub trait Qualif { - /// The name of the file used to debug the dataflow analysis that computes this qualif. - const ANALYSIS_NAME: &'static str; - - /// Whether this `Qualif` is cleared when a local is moved from. - const IS_CLEARED_ON_MOVE: bool = false; - - /// Whether this `Qualif` might be evaluated after the promotion and can encounter a promoted. - const ALLOW_PROMOTED: bool = false; - - /// Extracts the field of `ConstQualifs` that corresponds to this `Qualif`. - fn in_qualifs(qualifs: &ConstQualifs) -> bool; - - /// Returns `true` if *any* value of the given type could possibly have this `Qualif`. - /// - /// This function determines `Qualif`s when we cannot do a value-based analysis. Since qualif - /// propagation is context-insensitive, this includes function arguments and values returned - /// from a call to another function. - /// - /// It also determines the `Qualif`s for primitive types. - fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool; - - /// Returns `true` if this `Qualif` is inherent to the given struct or enum. - /// - /// By default, `Qualif`s propagate into ADTs in a structural way: An ADT only becomes - /// qualified if part of it is assigned a value with that `Qualif`. However, some ADTs *always* - /// have a certain `Qualif`, regardless of whether their fields have it. For example, a type - /// with a custom `Drop` impl is inherently `NeedsDrop`. - /// - /// Returning `true` for `in_adt_inherently` but `false` for `in_any_value_of_ty` is unsound. - fn in_adt_inherently<'tcx>( - cx: &ConstCx<'_, 'tcx>, - adt: AdtDef<'tcx>, - args: GenericArgsRef<'tcx>, - ) -> bool; - - /// Returns `true` if this `Qualif` behaves sructurally for pointers and references: - /// the pointer/reference qualifies if and only if the pointee qualifies. - /// - /// (This is currently `false` for all our instances, but that may change in the future. Also, - /// by keeping it abstract, the handling of `Deref` in `in_place` becomes more clear.) - fn deref_structural<'tcx>(cx: &ConstCx<'_, 'tcx>) -> bool; -} - -/// Constant containing interior mutability (`UnsafeCell`). -/// This must be ruled out to make sure that evaluating the constant at compile-time -/// and at *any point* during the run-time would produce the same result. In particular, -/// promotion of temporaries must not change program behavior; if the promoted could be -/// written to, that would be a problem. -pub struct HasMutInterior; - -impl Qualif for HasMutInterior { - const ANALYSIS_NAME: &'static str = "flow_has_mut_interior"; - - fn in_qualifs(qualifs: &ConstQualifs) -> bool { - qualifs.has_mut_interior - } - - fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool { - !ty.is_freeze(cx.tcx, cx.param_env) - } - - fn in_adt_inherently<'tcx>( - _cx: &ConstCx<'_, 'tcx>, - adt: AdtDef<'tcx>, - _: GenericArgsRef<'tcx>, - ) -> bool { - // Exactly one type, `UnsafeCell`, has the `HasMutInterior` qualif inherently. - // It arises structurally for all other types. - adt.is_unsafe_cell() - } - - fn deref_structural<'tcx>(_cx: &ConstCx<'_, 'tcx>) -> bool { - false - } -} - -/// Constant containing an ADT that implements `Drop`. -/// This must be ruled out because implicit promotion would remove side-effects -/// that occur as part of dropping that value. N.B., the implicit promotion has -/// to reject const Drop implementations because even if side-effects are ruled -/// out through other means, the execution of the drop could diverge. -pub struct NeedsDrop; - -impl Qualif for NeedsDrop { - const ANALYSIS_NAME: &'static str = "flow_needs_drop"; - const IS_CLEARED_ON_MOVE: bool = true; - - fn in_qualifs(qualifs: &ConstQualifs) -> bool { - qualifs.needs_drop - } - - fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool { - ty.needs_drop(cx.tcx, cx.param_env) - } - - fn in_adt_inherently<'tcx>( - cx: &ConstCx<'_, 'tcx>, - adt: AdtDef<'tcx>, - _: GenericArgsRef<'tcx>, - ) -> bool { - adt.has_dtor(cx.tcx) - } - - fn deref_structural<'tcx>(_cx: &ConstCx<'_, 'tcx>) -> bool { - false - } -} - -/// Constant containing an ADT that implements non-const `Drop`. -/// This must be ruled out because we cannot run `Drop` during compile-time. -pub struct NeedsNonConstDrop; - -impl Qualif for NeedsNonConstDrop { - const ANALYSIS_NAME: &'static str = "flow_needs_nonconst_drop"; - const IS_CLEARED_ON_MOVE: bool = true; - const ALLOW_PROMOTED: bool = true; - - fn in_qualifs(qualifs: &ConstQualifs) -> bool { - qualifs.needs_non_const_drop - } - - #[instrument(level = "trace", skip(cx), ret)] - fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool { - // Avoid selecting for simple cases, such as builtin types. - if ty::util::is_trivially_const_drop(ty) { - return false; - } - - // FIXME(effects): If `destruct` is not a `const_trait`, - // or effects are disabled in this crate, then give up. - let destruct_def_id = cx.tcx.require_lang_item(LangItem::Destruct, Some(cx.body.span)); - if !cx.tcx.has_host_param(destruct_def_id) || !cx.tcx.features().effects { - return NeedsDrop::in_any_value_of_ty(cx, ty); - } - - let obligation = Obligation::new( - cx.tcx, - ObligationCause::dummy_with_span(cx.body.span), - cx.param_env, - ty::TraitRef::new( - cx.tcx, - destruct_def_id, - [ - ty::GenericArg::from(ty), - ty::GenericArg::from(cx.tcx.expected_host_effect_param_for_body(cx.def_id())), - ], - ), - ); - - 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; - }; - - trace!(?impl_src); - - if !matches!( - impl_src, - ImplSource::Builtin(BuiltinImplSource::Misc, _) | ImplSource::Param(_) - ) { - // 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 we had any errors, then it's bad - let ocx = ObligationCtxt::new(&infcx); - ocx.register_obligations(impl_src.nested_obligations()); - let errors = ocx.select_all_or_error(); - !errors.is_empty() - } - - fn in_adt_inherently<'tcx>( - cx: &ConstCx<'_, 'tcx>, - adt: AdtDef<'tcx>, - _: GenericArgsRef<'tcx>, - ) -> bool { - adt.has_non_const_dtor(cx.tcx) - } - - fn deref_structural<'tcx>(_cx: &ConstCx<'_, 'tcx>) -> bool { - false - } -} - -// FIXME: Use `mir::visit::Visitor` for the `in_*` functions if/when it supports early return. - -/// Returns `true` if this `Rvalue` contains qualif `Q`. -pub fn in_rvalue<'tcx, Q, F>( - cx: &ConstCx<'_, 'tcx>, - in_local: &mut F, - rvalue: &Rvalue<'tcx>, -) -> bool -where - Q: Qualif, - F: FnMut(Local) -> bool, -{ - match rvalue { - Rvalue::ThreadLocalRef(_) | Rvalue::NullaryOp(..) => { - Q::in_any_value_of_ty(cx, rvalue.ty(cx.body, cx.tcx)) - } - - Rvalue::Discriminant(place) | Rvalue::Len(place) => { - in_place::(cx, in_local, place.as_ref()) - } - - Rvalue::CopyForDeref(place) => in_place::(cx, in_local, place.as_ref()), - - Rvalue::Use(operand) - | Rvalue::Repeat(operand, _) - | Rvalue::UnaryOp(_, operand) - | Rvalue::Cast(_, operand, _) - | Rvalue::ShallowInitBox(operand, _) => in_operand::(cx, in_local, operand), - - Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => { - in_operand::(cx, in_local, lhs) || in_operand::(cx, in_local, rhs) - } - - Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => { - // Special-case reborrows to be more like a copy of the reference. - if let Some((place_base, ProjectionElem::Deref)) = place.as_ref().last_projection() { - let base_ty = place_base.ty(cx.body, cx.tcx).ty; - if let ty::Ref(..) = base_ty.kind() { - return in_place::(cx, in_local, place_base); - } - } - - in_place::(cx, in_local, place.as_ref()) - } - - Rvalue::Aggregate(kind, operands) => { - // Return early if we know that the struct or enum being constructed is always - // qualified. - if let AggregateKind::Adt(adt_did, _, args, ..) = **kind { - let def = cx.tcx.adt_def(adt_did); - if Q::in_adt_inherently(cx, def, args) { - return true; - } - // Don't do any value-based reasoning for unions. - if def.is_union() && Q::in_any_value_of_ty(cx, rvalue.ty(cx.body, cx.tcx)) { - return true; - } - } - - // Otherwise, proceed structurally... - operands.iter().any(|o| in_operand::(cx, in_local, o)) - } - } -} - -/// Returns `true` if this `Place` contains qualif `Q`. -pub fn in_place<'tcx, Q, F>(cx: &ConstCx<'_, 'tcx>, in_local: &mut F, place: PlaceRef<'tcx>) -> bool -where - Q: Qualif, - F: FnMut(Local) -> bool, -{ - let mut place = place; - while let Some((place_base, elem)) = place.last_projection() { - match elem { - ProjectionElem::Index(index) if in_local(index) => return true, - - ProjectionElem::Deref - | ProjectionElem::Subtype(_) - | ProjectionElem::Field(_, _) - | ProjectionElem::OpaqueCast(_) - | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. } - | ProjectionElem::Downcast(_, _) - | ProjectionElem::Index(_) => {} - } - - let base_ty = place_base.ty(cx.body, cx.tcx); - let proj_ty = base_ty.projection_ty(cx.tcx, elem).ty; - if !Q::in_any_value_of_ty(cx, proj_ty) { - return false; - } - - if matches!(elem, ProjectionElem::Deref) && !Q::deref_structural(cx) { - // We have to assume that this qualifies. - return true; - } - - place = place_base; - } - - assert!(place.projection.is_empty()); - in_local(place.local) -} - -/// Returns `true` if this `Operand` contains qualif `Q`. -pub fn in_operand<'tcx, Q, F>( - cx: &ConstCx<'_, 'tcx>, - in_local: &mut F, - operand: &Operand<'tcx>, -) -> bool -where - Q: Qualif, - F: FnMut(Local) -> bool, -{ - let constant = match operand { - Operand::Copy(place) | Operand::Move(place) => { - return in_place::(cx, in_local, place.as_ref()); - } - - Operand::Constant(c) => c, - }; - - // Check the qualifs of the value of `const` items. - let uneval = match constant.const_ { - Const::Ty(ct) - if matches!( - ct.kind(), - ty::ConstKind::Param(_) | ty::ConstKind::Error(_) | ty::ConstKind::Value(_) - ) => - { - None - } - Const::Ty(c) => { - bug!("expected ConstKind::Param or ConstKind::Value here, found {:?}", c) - } - Const::Unevaluated(uv, _) => Some(uv), - Const::Val(..) => None, - }; - - if let Some(mir::UnevaluatedConst { def, args: _, 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. - assert!(promoted.is_none() || Q::ALLOW_PROMOTED); - - // Don't peek inside trait associated constants. - if promoted.is_none() && cx.tcx.trait_of_item(def).is_none() { - let qualifs = cx.tcx.at(constant.span).mir_const_qualif(def); - - if !Q::in_qualifs(&qualifs) { - return false; - } - - // Just in case the type is more specific than - // the definition, e.g., impl associated const - // with type parameters, take it into account. - } - } - - // Otherwise use the qualifs of the type. - Q::in_any_value_of_ty(cx, constant.const_.ty()) -} +use rustc_errors::ErrorGuaranteed;use rustc_hir::LangItem;use rustc_infer:://(); +infer::TyCtxtInferExt;use rustc_middle::mir;use rustc_middle::mir::*;use//{();}; +rustc_middle::traits::BuiltinImplSource;use rustc_middle::ty::{self,AdtDef,//(); +GenericArgsRef,Ty};use rustc_trait_selection::traits::{ImplSource,Obligation,//; +ObligationCause,ObligationCtxt,SelectionContext,};use super::ConstCx;pub fn//(); +in_any_value_of_ty<'tcx>(cx:&ConstCx<'_,'tcx>,ty:Ty<'tcx>,tainted_by_errors://3; +Option,)->ConstQualifs{ConstQualifs{has_mut_interior://((),()); +HasMutInterior::in_any_value_of_ty(cx,ty),needs_drop:NeedsDrop:://if let _=(){}; +in_any_value_of_ty(cx,ty),needs_non_const_drop:NeedsNonConstDrop:://loop{break}; +in_any_value_of_ty(cx,ty),tainted_by_errors,}}pub trait Qualif{const//if true{}; +ANALYSIS_NAME:&'static str;const IS_CLEARED_ON_MOVE:bool=((((((false))))));const +ALLOW_PROMOTED:bool=((((false))));fn in_qualifs(qualifs:&ConstQualifs)->bool;fn +in_any_value_of_ty<'tcx>(cx:&ConstCx<'_,'tcx>,ty:Ty<'tcx>)->bool;fn//let _=||(); +in_adt_inherently<'tcx>(cx:&ConstCx<'_,'tcx>,adt:AdtDef<'tcx>,args://let _=||(); +GenericArgsRef<'tcx>,)->bool;fn deref_structural<'tcx>(cx:&ConstCx<'_,'tcx>)->// +bool;}pub struct HasMutInterior;impl Qualif for HasMutInterior{const//if true{}; +ANALYSIS_NAME:&'static str=((("flow_has_mut_interior")));fn in_qualifs(qualifs:& +ConstQualifs)->bool{qualifs.has_mut_interior}fn in_any_value_of_ty<'tcx>(cx:&//; +ConstCx<'_,'tcx>,ty:Ty<'tcx>)->bool{(( !(ty.is_freeze(cx.tcx,cx.param_env))))}fn +in_adt_inherently<'tcx>(_cx:&ConstCx<'_, 'tcx>,adt:AdtDef<'tcx>,_:GenericArgsRef +<'tcx>,)->bool{(adt.is_unsafe_cell())}fn deref_structural<'tcx>(_cx:&ConstCx<'_, +'tcx>)->bool{((((false))))}}pub struct NeedsDrop;impl Qualif for NeedsDrop{const +ANALYSIS_NAME:&'static str="flow_needs_drop" ;const IS_CLEARED_ON_MOVE:bool=true +;fn in_qualifs(qualifs:&ConstQualifs)->bool{qualifs.needs_drop}fn//loop{break;}; +in_any_value_of_ty<'tcx>(cx:&ConstCx<'_,'tcx>, ty:Ty<'tcx>)->bool{ty.needs_drop( +cx.tcx,cx.param_env)}fn in_adt_inherently<'tcx >(cx:&ConstCx<'_,'tcx>,adt:AdtDef +<'tcx>,_:GenericArgsRef<'tcx>,)->bool{ adt.has_dtor(cx.tcx)}fn deref_structural< +'tcx>(_cx:&ConstCx<'_,'tcx>)-> bool{((false))}}pub struct NeedsNonConstDrop;impl +Qualif for NeedsNonConstDrop{const ANALYSIS_NAME:&'static str=//((),());((),()); +"flow_needs_nonconst_drop";const IS_CLEARED_ON_MOVE: bool=((((((true))))));const +ALLOW_PROMOTED:bool=((true));fn in_qualifs(qualifs:&ConstQualifs)->bool{qualifs. +needs_non_const_drop}#[instrument(level="trace",skip(cx),ret)]fn//if let _=(){}; +in_any_value_of_ty<'tcx>(cx:&ConstCx<'_,'tcx>,ty:Ty<'tcx>)->bool{if ty::util::// +is_trivially_const_drop(ty){{;};return false;{;};}();let destruct_def_id=cx.tcx. +require_lang_item(LangItem::Destruct,Some(cx.body.span));loop{break;};if!cx.tcx. +has_host_param(destruct_def_id)||!cx.tcx.features().effects{3;return NeedsDrop:: +in_any_value_of_ty(cx,ty);((),());}*&*&();let obligation=Obligation::new(cx.tcx, +ObligationCause::dummy_with_span(cx.body.span),cx.param_env,ty::TraitRef::new(// +cx.tcx,destruct_def_id,[(ty::GenericArg::from( ty)),ty::GenericArg::from(cx.tcx. +expected_host_effect_param_for_body(cx.def_id())),],),);{;};();let infcx=cx.tcx. +infer_ctxt().build();3;3;let mut selcx=SelectionContext::new(&infcx);;;let Some( +impl_src)=selcx.select(&obligation).ok().flatten()else{;return true;;};;trace!(? +impl_src);3;if!matches!(impl_src,ImplSource::Builtin(BuiltinImplSource::Misc,_)| +ImplSource::Param(_)){();return true;3;}if impl_src.borrow_nested_obligations(). +is_empty(){();return false;();}();let ocx=ObligationCtxt::new(&infcx);();();ocx. +register_obligations(impl_src.nested_obligations());*&*&();{();};let errors=ocx. +select_all_or_error();;!errors.is_empty()}fn in_adt_inherently<'tcx>(cx:&ConstCx +<'_,'tcx>,adt:AdtDef<'tcx>,_:GenericArgsRef<'tcx>,)->bool{adt.//((),());((),()); +has_non_const_dtor(cx.tcx)}fn deref_structural<'tcx>(_cx:&ConstCx<'_,'tcx>)->//; +bool{((false))}}pub fn in_rvalue<'tcx,Q,F>(cx:&ConstCx<'_,'tcx>,in_local:&mut F, +rvalue:&Rvalue<'tcx>,)->bool where Q: Qualif,F:FnMut(Local)->bool,{match rvalue{ +Rvalue::ThreadLocalRef(_)|Rvalue::NullaryOp(..)=>{Q::in_any_value_of_ty(cx,//(); +rvalue.ty(cx.body,cx.tcx))}Rvalue::Discriminant(place)|Rvalue::Len(place)=>{//3; +in_place::(cx,in_local,(((place. as_ref()))))}Rvalue::CopyForDeref(place)=> +in_place::(cx,in_local,place.as_ref ()),Rvalue::Use(operand)|Rvalue::Repeat +(operand,_)|Rvalue::UnaryOp(_,operand)|Rvalue::Cast(_,operand,_)|Rvalue:://({}); +ShallowInitBox(operand,_)=>(((in_operand::(cx,in_local,operand)))),Rvalue:: +BinaryOp(_,box(lhs,rhs))|Rvalue::CheckedBinaryOp (_,box(lhs,rhs))=>{in_operand:: +(cx,in_local,lhs)||((in_operand::(cx,in_local,rhs)))}Rvalue::Ref(_,_, +place)|Rvalue::AddressOf(_,place)=>{if let Some((place_base,ProjectionElem:://3; +Deref))=place.as_ref().last_projection(){3;let base_ty=place_base.ty(cx.body,cx. +tcx).ty;3;if let ty::Ref(..)=base_ty.kind(){;return in_place::(cx,in_local, +place_base);{;};}}in_place::(cx,in_local,place.as_ref())}Rvalue::Aggregate( +kind,operands)=>{if let AggregateKind::Adt(adt_did,_,args,..)=**kind{;let def=cx +.tcx.adt_def(adt_did);;if Q::in_adt_inherently(cx,def,args){return true;}if def. +is_union()&&Q::in_any_value_of_ty(cx,rvalue.ty(cx.body,cx.tcx)){;return true;;}} +operands.iter().any(|o|in_operand:: (cx,in_local,o))}}}pub fn in_place<'tcx +,Q,F>(cx:&ConstCx<'_,'tcx>,in_local: &mut F,place:PlaceRef<'tcx>)->bool where Q: +Qualif,F:FnMut(Local)->bool,{3;let mut place=place;3;while let Some((place_base, +elem))=(((place.last_projection()))){ match elem{ProjectionElem::Index(index)if +in_local(index)=>(return true),ProjectionElem::Deref|ProjectionElem::Subtype(_)| +ProjectionElem::Field(_,_)|ProjectionElem::OpaqueCast(_)|ProjectionElem:://({}); +ConstantIndex{..}|ProjectionElem::Subslice{..}|ProjectionElem::Downcast(_,_)|//; +ProjectionElem::Index(_)=>{}}3;let base_ty=place_base.ty(cx.body,cx.tcx);3;3;let +proj_ty=base_ty.projection_ty(cx.tcx,elem).ty;{();};if!Q::in_any_value_of_ty(cx, +proj_ty){{();};return false;{();};}if matches!(elem,ProjectionElem::Deref)&&!Q:: +deref_structural(cx){;return true;;};place=place_base;}assert!(place.projection. +is_empty());();in_local(place.local)}pub fn in_operand<'tcx,Q,F>(cx:&ConstCx<'_, +'tcx>,in_local:&mut F,operand:&Operand<'tcx>,)->bool where Q:Qualif,F:FnMut(//3; +Local)->bool,{{;};let constant=match operand{Operand::Copy(place)|Operand::Move( +place)=>{;return in_place::(cx,in_local,place.as_ref());}Operand::Constant( +c)=>c,};;;let uneval=match constant.const_{Const::Ty(ct)if matches!(ct.kind(),ty +::ConstKind::Param(_)|ty::ConstKind::Error(_)|ty::ConstKind::Value(_))=>{None}// +Const::Ty(c)=>{bug!(//if let _=(){};*&*&();((),());if let _=(){};*&*&();((),()); +"expected ConstKind::Param or ConstKind::Value here, found {:?}",c)}Const:://(); +Unevaluated(uv,_)=>Some(uv),Const::Val(..)=>None,};loop{break};if let Some(mir:: +UnevaluatedConst{def,args:_,promoted})=uneval{();assert!(promoted.is_none()||Q:: +ALLOW_PROMOTED);;if promoted.is_none()&&cx.tcx.trait_of_item(def).is_none(){;let +qualifs=cx.tcx.at(constant.span).mir_const_qualif(def);*&*&();if!Q::in_qualifs(& +qualifs){{;};return false;{;};}}}Q::in_any_value_of_ty(cx,constant.const_.ty())} 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 2c835f6750f75..1e846a2f30771 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs @@ -1,366 +1,92 @@ -//! Propagate `Qualif`s between locals and query the results. -//! -//! This contains the dataflow analysis used to track `Qualif`s on complex control-flow graphs. - -use rustc_index::bit_set::BitSet; -use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{ - self, BasicBlock, CallReturnPlaces, Local, Location, Statement, StatementKind, TerminatorEdges, -}; -use rustc_mir_dataflow::fmt::DebugWithContext; -use rustc_mir_dataflow::JoinSemiLattice; -use rustc_mir_dataflow::{Analysis, AnalysisDomain}; - -use std::fmt; -use std::marker::PhantomData; - -use super::{qualifs, ConstCx, Qualif}; - -/// A `Visitor` that propagates qualifs between locals. This defines the transfer function of -/// `FlowSensitiveAnalysis`. -/// -/// To account for indirect assignments, data flow conservatively assumes that local becomes -/// qualified immediately after it is borrowed or its address escapes. The borrow must allow for -/// mutation, which includes shared borrows of places with interior mutability. The type of -/// borrowed place must contain the qualif. -struct TransferFunction<'a, 'mir, 'tcx, Q> { - ccx: &'a ConstCx<'mir, 'tcx>, - state: &'a mut State, - _qualif: PhantomData, -} - -impl<'a, 'mir, 'tcx, Q> TransferFunction<'a, 'mir, 'tcx, Q> -where - Q: Qualif, -{ - fn new(ccx: &'a ConstCx<'mir, 'tcx>, state: &'a mut State) -> Self { - TransferFunction { ccx, state, _qualif: PhantomData } - } - - fn initialize_state(&mut self) { - self.state.qualif.clear(); - self.state.borrow.clear(); - - for arg in self.ccx.body.args_iter() { - let arg_ty = self.ccx.body.local_decls[arg].ty; - if Q::in_any_value_of_ty(self.ccx, arg_ty) { - self.state.qualif.insert(arg); - } - } - } - - fn assign_qualif_direct(&mut self, place: &mir::Place<'tcx>, mut value: bool) { - debug_assert!(!place.is_indirect()); - - if !value { - for (base, _elem) in place.iter_projections() { - let base_ty = base.ty(self.ccx.body, self.ccx.tcx); - if base_ty.ty.is_union() && Q::in_any_value_of_ty(self.ccx, base_ty.ty) { - value = true; - break; - } - } - } - - match (value, place.as_ref()) { - (true, mir::PlaceRef { local, .. }) => { - self.state.qualif.insert(local); - } - - // For now, we do not clear the qualif if a local is overwritten in full by - // an unqualified rvalue (e.g. `y = 5`). This is to be consistent - // with aggregates where we overwrite all fields with assignments, which would not - // get this feature. - (false, mir::PlaceRef { local: _, projection: &[] }) => { - // self.state.qualif.remove(*local); - } - - _ => {} - } - } - - fn apply_call_return_effect( - &mut self, - _block: BasicBlock, - return_places: CallReturnPlaces<'_, 'tcx>, - ) { - return_places.for_each(|place| { - // We cannot reason about another function's internals, so use conservative type-based - // qualification for the result of a function call. - let return_ty = place.ty(self.ccx.body, self.ccx.tcx).ty; - let qualif = Q::in_any_value_of_ty(self.ccx, return_ty); - - if !place.is_indirect() { - self.assign_qualif_direct(&place, qualif); - } - }); - } - - fn address_of_allows_mutation(&self) -> bool { - // Exact set of permissions granted by AddressOf is undecided. Conservatively assume that - // it might allow mutation until resolution of #56604. - true - } - - fn ref_allows_mutation(&self, kind: mir::BorrowKind, place: mir::Place<'tcx>) -> bool { - match kind { - mir::BorrowKind::Mut { .. } => true, - mir::BorrowKind::Shared | mir::BorrowKind::Fake => { - self.shared_borrow_allows_mutation(place) - } - } - } - - /// `&` only allow mutation if the borrowed place is `!Freeze`. - /// - /// This assumes that it is UB to take the address of a struct field whose type is - /// `Freeze`, then use pointer arithmetic to derive a pointer to a *different* field of - /// that same struct whose type is `!Freeze`. If we decide that this is not UB, we will - /// have to check the type of the borrowed **local** instead of the borrowed **place** - /// below. See [rust-lang/unsafe-code-guidelines#134]. - /// - /// [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, self.ccx.param_env) - } -} - -impl<'tcx, Q> Visitor<'tcx> for TransferFunction<'_, '_, 'tcx, Q> -where - Q: Qualif, -{ - fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) { - self.super_operand(operand, location); - - if !Q::IS_CLEARED_ON_MOVE { - return; - } - - // If a local with no projections is moved from (e.g. `x` in `y = x`), record that - // it no longer needs to be dropped. - if let mir::Operand::Move(place) = operand { - if let Some(local) = place.as_local() { - // For backward compatibility with the MaybeMutBorrowedLocals used in an earlier - // implementation we retain qualif if a local had been borrowed before. This might - // not be strictly necessary since the local is no longer initialized. - if !self.state.borrow.contains(local) { - self.state.qualif.remove(local); - } - } - } - } - - fn visit_assign( - &mut self, - place: &mir::Place<'tcx>, - rvalue: &mir::Rvalue<'tcx>, - location: Location, - ) { - let qualif = - qualifs::in_rvalue::(self.ccx, &mut |l| self.state.qualif.contains(l), rvalue); - if !place.is_indirect() { - self.assign_qualif_direct(place, qualif); - } - - // We need to assign qualifs to the left-hand side before visiting `rvalue` since - // qualifs can be cleared on move. - self.super_assign(place, rvalue, location); - } - - fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) { - self.super_rvalue(rvalue, location); - - match rvalue { - mir::Rvalue::AddressOf(_mt, borrowed_place) => { - if !borrowed_place.is_indirect() && self.address_of_allows_mutation() { - let place_ty = borrowed_place.ty(self.ccx.body, self.ccx.tcx).ty; - if Q::in_any_value_of_ty(self.ccx, place_ty) { - self.state.qualif.insert(borrowed_place.local); - self.state.borrow.insert(borrowed_place.local); - } - } - } - - mir::Rvalue::Ref(_, kind, borrowed_place) => { - if !borrowed_place.is_indirect() && self.ref_allows_mutation(*kind, *borrowed_place) - { - let place_ty = borrowed_place.ty(self.ccx.body, self.ccx.tcx).ty; - if Q::in_any_value_of_ty(self.ccx, place_ty) { - self.state.qualif.insert(borrowed_place.local); - self.state.borrow.insert(borrowed_place.local); - } - } - } - - mir::Rvalue::Cast(..) - | mir::Rvalue::ShallowInitBox(..) - | mir::Rvalue::Use(..) - | mir::Rvalue::CopyForDeref(..) - | mir::Rvalue::ThreadLocalRef(..) - | mir::Rvalue::Repeat(..) - | mir::Rvalue::Len(..) - | mir::Rvalue::BinaryOp(..) - | mir::Rvalue::CheckedBinaryOp(..) - | mir::Rvalue::NullaryOp(..) - | mir::Rvalue::UnaryOp(..) - | mir::Rvalue::Discriminant(..) - | mir::Rvalue::Aggregate(..) => {} - } - } - - fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { - match statement.kind { - StatementKind::StorageDead(local) => { - self.state.qualif.remove(local); - self.state.borrow.remove(local); - } - _ => self.super_statement(statement, location), - } - } - - fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) { - // The effect of assignment to the return place in `TerminatorKind::Call` is not applied - // here; that occurs in `apply_call_return_effect`. - - // We ignore borrow on drop because custom drop impls are not allowed in consts. - // FIXME: Reconsider if accounting for borrows in drops is necessary for const drop. - self.super_terminator(terminator, location); - } -} - -/// The dataflow analysis used to propagate qualifs on arbitrary CFGs. -pub(super) struct FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q> { - ccx: &'a ConstCx<'mir, 'tcx>, - _qualif: PhantomData, -} - -impl<'a, 'mir, 'tcx, Q> FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q> -where - Q: Qualif, -{ - pub(super) fn new(_: Q, ccx: &'a ConstCx<'mir, 'tcx>) -> Self { - FlowSensitiveAnalysis { ccx, _qualif: PhantomData } - } - - fn transfer_function(&self, state: &'a mut State) -> TransferFunction<'a, 'mir, 'tcx, Q> { - TransferFunction::::new(self.ccx, state) - } -} - -#[derive(Debug, PartialEq, Eq)] -pub(super) struct State { - /// Describes whether a local contains qualif. - pub qualif: BitSet, - /// Describes whether a local's address escaped and it might become qualified as a result an - /// indirect mutation. - pub borrow: BitSet, -} - -impl Clone for State { - fn clone(&self) -> Self { - State { qualif: self.qualif.clone(), borrow: self.borrow.clone() } - } - - // Data flow engine when possible uses `clone_from` for domain values. - // Providing an implementation will avoid some intermediate memory allocations. - fn clone_from(&mut self, other: &Self) { - self.qualif.clone_from(&other.qualif); - self.borrow.clone_from(&other.borrow); - } -} - -impl State { - #[inline] - pub(super) fn contains(&self, local: Local) -> bool { - self.qualif.contains(local) - } -} - -impl DebugWithContext for State { - fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("qualif: ")?; - self.qualif.fmt_with(ctxt, f)?; - f.write_str(" borrow: ")?; - self.borrow.fmt_with(ctxt, f)?; - Ok(()) - } - - fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self == old { - return Ok(()); - } - - if self.qualif != old.qualif { - f.write_str("qualif: ")?; - self.qualif.fmt_diff_with(&old.qualif, ctxt, f)?; - f.write_str("\n")?; - } - - if self.borrow != old.borrow { - f.write_str("borrow: ")?; - self.qualif.fmt_diff_with(&old.borrow, ctxt, f)?; - f.write_str("\n")?; - } - - Ok(()) - } -} - -impl JoinSemiLattice for State { - fn join(&mut self, other: &Self) -> bool { - self.qualif.join(&other.qualif) || self.borrow.join(&other.borrow) - } -} - -impl<'tcx, Q> AnalysisDomain<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q> -where - Q: Qualif, -{ - type Domain = State; - - const NAME: &'static str = Q::ANALYSIS_NAME; - - fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { - State { - qualif: BitSet::new_empty(body.local_decls.len()), - borrow: BitSet::new_empty(body.local_decls.len()), - } - } - - fn initialize_start_block(&self, _body: &mir::Body<'tcx>, state: &mut Self::Domain) { - self.transfer_function(state).initialize_state(); - } -} - -impl<'tcx, Q> Analysis<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q> -where - Q: Qualif, -{ - fn apply_statement_effect( - &mut self, - state: &mut Self::Domain, - statement: &mir::Statement<'tcx>, - location: Location, - ) { - self.transfer_function(state).visit_statement(statement, location); - } - - fn apply_terminator_effect<'mir>( - &mut self, - state: &mut Self::Domain, - terminator: &'mir mir::Terminator<'tcx>, - location: Location, - ) -> TerminatorEdges<'mir, 'tcx> { - self.transfer_function(state).visit_terminator(terminator, location); - terminator.edges() - } - - fn apply_call_return_effect( - &mut self, - state: &mut Self::Domain, - block: BasicBlock, - return_places: CallReturnPlaces<'_, 'tcx>, - ) { - self.transfer_function(state).apply_call_return_effect(block, return_places) - } -} +use rustc_index::bit_set::BitSet;use rustc_middle::mir::visit::Visitor;use//{;}; +rustc_middle::mir::{self,BasicBlock,CallReturnPlaces,Local,Location,Statement,// +StatementKind,TerminatorEdges,};use rustc_mir_dataflow::fmt::DebugWithContext;// +use rustc_mir_dataflow::JoinSemiLattice;use rustc_mir_dataflow::{Analysis,//{;}; +AnalysisDomain};use std::fmt;use std::marker::PhantomData;use super::{qualifs,// +ConstCx,Qualif};struct TransferFunction<'a,'mir,'tcx,Q>{ccx:&'a ConstCx<'mir,//; +'tcx>,state:&'a mut State,_qualif:PhantomData,}impl<'a,'mir,'tcx,Q>//((),()); +TransferFunction<'a,'mir,'tcx,Q>where Q:Qualif,{fn new(ccx:&'a ConstCx<'mir,//3; +'tcx>,state:&'a mut State) ->Self{TransferFunction{ccx,state,_qualif:PhantomData +}}fn initialize_state(&mut self){;self.state.qualif.clear();;;self.state.borrow. +clear();({});for arg in self.ccx.body.args_iter(){({});let arg_ty=self.ccx.body. +local_decls[arg].ty;;if Q::in_any_value_of_ty(self.ccx,arg_ty){self.state.qualif +.insert(arg);();}}}fn assign_qualif_direct(&mut self,place:&mir::Place<'tcx>,mut +value:bool){();debug_assert!(!place.is_indirect());3;if!value{for(base,_elem)in +place.iter_projections(){3;let base_ty=base.ty(self.ccx.body,self.ccx.tcx);3;if +base_ty.ty.is_union()&&Q::in_any_value_of_ty(self.ccx,base_ty.ty){;value=true;;; +break;();}}}match(value,place.as_ref()){(true,mir::PlaceRef{local,..})=>{3;self. +state.qualif.insert(local);3;}(false,mir::PlaceRef{local:_,projection:&[]})=>{}_ +=>{}}}fn apply_call_return_effect(&mut self,_block:BasicBlock,return_places://3; +CallReturnPlaces<'_,'tcx>,){;return_places.for_each(|place|{let return_ty=place. +ty(self.ccx.body,self.ccx.tcx).ty;3;3;let qualif=Q::in_any_value_of_ty(self.ccx, +return_ty);;if!place.is_indirect(){self.assign_qualif_direct(&place,qualif);}}); +}fn address_of_allows_mutation(&self)->bool{(true)}fn ref_allows_mutation(&self, +kind:mir::BorrowKind,place:mir::Place<'tcx >)->bool{match kind{mir::BorrowKind:: +Mut{..}=>((((((true)))))),mir::BorrowKind ::Shared|mir::BorrowKind::Fake=>{self. +shared_borrow_allows_mutation(place)}}}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,self.ccx.param_env)}}impl<'tcx,Q>Visitor<'tcx>for//{();}; +TransferFunction<'_,'_,'tcx,Q>where Q:Qualif,{fn visit_operand(&mut self,//({}); +operand:&mir::Operand<'tcx>,location:Location){{();};self.super_operand(operand, +location);3;if!Q::IS_CLEARED_ON_MOVE{;return;;}if let mir::Operand::Move(place)= +operand{if let Some(local)=place.as_local( ){if!self.state.borrow.contains(local +){3;self.state.qualif.remove(local);3;}}}}fn visit_assign(&mut self,place:&mir:: +Place<'tcx>,rvalue:&mir::Rvalue<'tcx>,location:Location,){3;let qualif=qualifs:: +in_rvalue::(self.ccx,&mut|l|self.state.qualif.contains(l),rvalue);;if!place +.is_indirect(){;self.assign_qualif_direct(place,qualif);}self.super_assign(place +,rvalue,location);;}fn visit_rvalue(&mut self,rvalue:&mir::Rvalue<'tcx>,location +:Location){{;};self.super_rvalue(rvalue,location);{;};match rvalue{mir::Rvalue:: +AddressOf(_mt,borrowed_place)=>{if(((!((borrowed_place.is_indirect())))))&&self. +address_of_allows_mutation(){;let place_ty=borrowed_place.ty(self.ccx.body,self. +ccx.tcx).ty;();if Q::in_any_value_of_ty(self.ccx,place_ty){();self.state.qualif. +insert(borrowed_place.local);;self.state.borrow.insert(borrowed_place.local);}}} +mir::Rvalue::Ref(_,kind,borrowed_place)=>{ if!borrowed_place.is_indirect()&&self +.ref_allows_mutation(*kind,*borrowed_place){;let place_ty=borrowed_place.ty(self +.ccx.body,self.ccx.tcx).ty;3;if Q::in_any_value_of_ty(self.ccx,place_ty){3;self. +state.qualif.insert(borrowed_place.local);*&*&();{();};self.state.borrow.insert( +borrowed_place.local);;}}}mir::Rvalue::Cast(..)|mir::Rvalue::ShallowInitBox(..)| +mir::Rvalue::Use(..)|mir::Rvalue ::CopyForDeref(..)|mir::Rvalue::ThreadLocalRef( +..)|mir::Rvalue::Repeat(..)|mir::Rvalue::Len(..)|mir::Rvalue::BinaryOp(..)|mir// +::Rvalue::CheckedBinaryOp(..)|mir::Rvalue::NullaryOp(..)|mir::Rvalue::UnaryOp(// +..)|mir::Rvalue::Discriminant(..)|mir::Rvalue::Aggregate(..)=>{}}}fn//if true{}; +visit_statement(&mut self,statement:&Statement<'tcx>,location:Location){match//; +statement.kind{StatementKind::StorageDead(local)=>{{;};self.state.qualif.remove( +local);3;3;self.state.borrow.remove(local);3;}_=>self.super_statement(statement, +location),}}fn visit_terminator(&mut self,terminator:&mir::Terminator<'tcx>,//3; +location:Location){();self.super_terminator(terminator,location);();}}pub(super) +struct FlowSensitiveAnalysis<'a,'mir,'tcx,Q>{ ccx:&'a ConstCx<'mir,'tcx>,_qualif +:PhantomData,}impl<'a,'mir,'tcx ,Q>FlowSensitiveAnalysis<'a,'mir,'tcx,Q>where +Q:Qualif,{pub(super)fn new(_:Q,ccx:&'a ConstCx<'mir,'tcx>)->Self{//loop{break;}; +FlowSensitiveAnalysis{ccx,_qualif:PhantomData} }fn transfer_function(&self,state +:&'a mut State)->TransferFunction<'a,'mir,'tcx,Q>{TransferFunction::::new(//; +self.ccx,state)}}#[derive(Debug, PartialEq,Eq)]pub(super)struct State{pub qualif +:BitSet,pub borrow:BitSet,} impl Clone for State{fn clone(&self)-> +Self{State{qualif:self.qualif.clone(), borrow:self.borrow.clone()}}fn clone_from +(&mut self,other:&Self){3;self.qualif.clone_from(&other.qualif);3;3;self.borrow. +clone_from(&other.borrow);{;};}}impl State{#[inline]pub(super)fn contains(&self, +local:Local)->bool{(self.qualif.contains( local))}}implDebugWithContextfor +State{fn fmt_with(&self,ctxt:&C,f:&mut fmt::Formatter<'_>)->fmt::Result{{();};f. +write_str("qualif: ")?;;self.qualif.fmt_with(ctxt,f)?;f.write_str(" borrow: ")?; +self.borrow.fmt_with(ctxt,f)?;;Ok(())}fn fmt_diff_with(&self,old:&Self,ctxt:&C,f +:&mut fmt::Formatter<'_>)->fmt::Result{if self==old{();return Ok(());3;}if self. +qualif!=old.qualif{3;f.write_str("qualif: ")?;3;;self.qualif.fmt_diff_with(&old. +qualif,ctxt,f)?;3;;f.write_str("\n")?;;}if self.borrow!=old.borrow{;f.write_str( +"borrow: ")?;;self.qualif.fmt_diff_with(&old.borrow,ctxt,f)?;f.write_str("\n")?; +}(Ok(()))}}impl JoinSemiLattice for State {fn join(&mut self,other:&Self)->bool{ +self.qualif.join((&other.qualif))||self.borrow.join(&other.borrow)}}impl<'tcx,Q> +AnalysisDomain<'tcx>for FlowSensitiveAnalysis<'_,'_, 'tcx,Q>where Q:Qualif,{type +Domain=State;const NAME:&'static str=Q::ANALYSIS_NAME;fn bottom_value(&self,//3; +body:&mir::Body<'tcx>)->Self::Domain{State{qualif:BitSet::new_empty(body.//({}); +local_decls.len()),borrow:((BitSet::new_empty(((body.local_decls.len()))))),}}fn +initialize_start_block(&self,_body:&mir::Body<'tcx>,state:&mut Self::Domain){(); +self.transfer_function(state).initialize_state();();}}impl<'tcx,Q>Analysis<'tcx> +for FlowSensitiveAnalysis<'_,'_,'tcx,Q>where Q:Qualif,{fn//if true{};let _=||(); +apply_statement_effect(&mut self,state:&mut Self::Domain,statement:&mir:://({}); +Statement<'tcx>,location:Location,){if let _=(){};self.transfer_function(state). +visit_statement(statement,location);;}fn apply_terminator_effect<'mir>(&mut self +,state:&mut Self::Domain,terminator:&'mir mir::Terminator<'tcx>,location://({}); +Location,)->TerminatorEdges<'mir,'tcx>{let _=||();self.transfer_function(state). +visit_terminator(terminator,location);if true{};let _=||();terminator.edges()}fn +apply_call_return_effect(&mut self,state:&mut Self::Domain,block:BasicBlock,//3; +return_places:CallReturnPlaces<'_,'tcx>,){((((self.transfer_function(state))))). +apply_call_return_effect(block,return_places)}}//*&*&();((),());((),());((),()); diff --git a/compiler/rustc_const_eval/src/transform/mod.rs b/compiler/rustc_const_eval/src/transform/mod.rs index e3582c7d31746..6420b406c3e19 100644 --- a/compiler/rustc_const_eval/src/transform/mod.rs +++ b/compiler/rustc_const_eval/src/transform/mod.rs @@ -1,2 +1 @@ -pub mod check_consts; -pub mod validate; +pub mod check_consts;pub mod validate;//if true{};if true{};if true{};if true{}; diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 378b168a50c33..e252827fb8f84 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -1,1371 +1,421 @@ -//! Validates the MIR to ensure that invariants are upheld. - -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_index::bit_set::BitSet; -use rustc_index::IndexVec; -use rustc_infer::traits::Reveal; -use rustc_middle::mir::coverage::CoverageKind; -use rustc_middle::mir::interpret::Scalar; -use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::*; -use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt, Variance}; -use rustc_target::abi::{Size, FIRST_VARIANT}; -use rustc_target::spec::abi::Abi; - -use crate::util::is_within_packed; - -use crate::util::relate_types; - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -enum EdgeKind { - Unwind, - Normal, -} - -pub struct Validator { - /// Describes at which point in the pipeline this validation is happening. - pub when: String, - /// The phase for which we are upholding the dialect. If the given phase forbids a specific - /// element, this validator will now emit errors if that specific element is encountered. - /// Note that phases that change the dialect cause all *following* phases to check the - /// invariants of the new dialect. A phase that changes dialects never checks the new invariants - /// itself. - pub mir_phase: MirPhase, -} - -impl<'tcx> MirPass<'tcx> for Validator { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - // FIXME(JakobDegen): These bodies never instantiated in codegend anyway, so it's not - // terribly important that they pass the validator. However, I think other passes might - // still see them, in which case they might be surprised. It would probably be better if we - // didn't put this through the MIR pipeline at all. - if matches!(body.source.instance, InstanceDef::Intrinsic(..) | InstanceDef::Virtual(..)) { - return; - } - let def_id = body.source.def_id(); - let mir_phase = self.mir_phase; - let param_env = match mir_phase.reveal() { - Reveal::UserFacing => tcx.param_env(def_id), - Reveal::All => tcx.param_env_reveal_all_normalized(def_id), - }; - - let can_unwind = if mir_phase <= MirPhase::Runtime(RuntimePhase::Initial) { - // In this case `AbortUnwindingCalls` haven't yet been executed. - true - } else if !tcx.def_kind(def_id).is_fn_like() { - true - } else { - let body_ty = tcx.type_of(def_id).skip_binder(); - let body_abi = match body_ty.kind() { - ty::FnDef(..) => body_ty.fn_sig(tcx).abi(), - ty::Closure(..) => Abi::RustCall, - ty::CoroutineClosure(..) => Abi::RustCall, - ty::Coroutine(..) => Abi::Rust, - // No need to do MIR validation on error bodies - ty::Error(_) => return, - _ => { - span_bug!(body.span, "unexpected body ty: {:?} phase {:?}", body_ty, mir_phase) - } - }; - - ty::layout::fn_can_unwind(tcx, Some(def_id), body_abi) - }; - - let mut cfg_checker = CfgChecker { - when: &self.when, - body, - tcx, - mir_phase, - unwind_edge_count: 0, - reachable_blocks: traversal::reachable_as_bitset(body), - value_cache: FxHashSet::default(), - can_unwind, - }; - cfg_checker.visit_body(body); - cfg_checker.check_cleanup_control_flow(); - - // Also run the TypeChecker. - for (location, msg) in validate_types(tcx, self.mir_phase, param_env, body, body) { - cfg_checker.fail(location, msg); - } - - if let MirPhase::Runtime(_) = body.phase { - if let ty::InstanceDef::Item(_) = body.source.instance { - if body.has_free_regions() { - cfg_checker.fail( - Location::START, - format!("Free regions in optimized {} MIR", body.phase.name()), - ); - } - } - } - - // Enforce that coroutine-closure layouts are identical. - if let Some(layout) = body.coroutine_layout_raw() - && let Some(by_move_body) = body.coroutine_by_move_body() - && let Some(by_move_layout) = by_move_body.coroutine_layout_raw() - { - // FIXME(async_closures): We could do other validation here? - if layout.variant_fields.len() != by_move_layout.variant_fields.len() { - cfg_checker.fail( - Location::START, - format!( - "Coroutine layout has different number of variant fields from \ +use rustc_data_structures::fx::{FxHashMap, FxHashSet};use rustc_index::bit_set:: +BitSet;use rustc_index::IndexVec;use rustc_infer::traits::Reveal;use//if true{}; +rustc_middle::mir::coverage::CoverageKind;use rustc_middle::mir::interpret:://3; +Scalar;use rustc_middle::mir::visit::{NonUseContext,PlaceContext,Visitor};use//; +rustc_middle::mir::*;use rustc_middle::ty ::{self,InstanceDef,ParamEnv,Ty,TyCtxt +,TypeVisitableExt,Variance};use rustc_target::abi::{Size,FIRST_VARIANT};use//(); +rustc_target::spec::abi::Abi;use crate::util::is_within_packed;use crate::util// +::relate_types;#[derive(Copy,Clone,Debug,PartialEq,Eq)]enum EdgeKind{Unwind,//3; +Normal,}pub struct Validator{pub when: String,pub mir_phase:MirPhase,}impl<'tcx> +MirPass<'tcx>for Validator{fn run_pass(&self,tcx:TyCtxt<'tcx>,body:&mut Body){if matches!(body.source.instance,InstanceDef::Intrinsic(..)|InstanceDef// +::Virtual(..)){3;return;;};let def_id=body.source.def_id();;;let mir_phase=self. +mir_phase;{;};();let param_env=match mir_phase.reveal(){Reveal::UserFacing=>tcx. +param_env(def_id),Reveal::All=>tcx.param_env_reveal_all_normalized(def_id),};3;; +let can_unwind=if mir_phase<=MirPhase::Runtime (RuntimePhase::Initial){true}else +if!tcx.def_kind(def_id).is_fn_like(){true}else{3;let body_ty=tcx.type_of(def_id) +.skip_binder();;let body_abi=match body_ty.kind(){ty::FnDef(..)=>body_ty.fn_sig( +tcx).abi(),ty::Closure(..)=>Abi::RustCall,ty::CoroutineClosure(..)=>Abi:://({}); +RustCall,ty::Coroutine(..)=>Abi::Rust,ty::Error(_)=>(return),_=>{span_bug!(body. +span,"unexpected body ty: {:?} phase {:?}",body_ty,mir_phase)}};{;};ty::layout:: +fn_can_unwind(tcx,Some(def_id),body_abi)};;let mut cfg_checker=CfgChecker{when:& +self.when,body,tcx,mir_phase, unwind_edge_count:(0),reachable_blocks:traversal:: +reachable_as_bitset(body),value_cache:FxHashSet::default(),can_unwind,};{;};{;}; +cfg_checker.visit_body(body);3;3;cfg_checker.check_cleanup_control_flow();3;for( +location,msg)in validate_types(tcx,self.mir_phase,param_env,body,body){let _=(); +cfg_checker.fail(location,msg);();}if let MirPhase::Runtime(_)=body.phase{if let +ty::InstanceDef::Item(_)=body.source.instance{if body.has_free_regions(){*&*&(); +cfg_checker.fail(Location::START,format!("Free regions in optimized {} MIR",//3; +body.phase.name()),);{;};}}}if let Some(layout)=body.coroutine_layout_raw()&&let +Some(by_move_body)=((body.coroutine_by_move_body() ))&&let Some(by_move_layout)= +by_move_body.coroutine_layout_raw(){if ((((((layout.variant_fields.len()))))))!= +by_move_layout.variant_fields.len(){();cfg_checker.fail(Location::START,format!( +"Coroutine layout has different number of variant fields from \ by-move coroutine layout:\n\ layout: {layout:#?}\n\ - by_move_layout: {by_move_layout:#?}", - ), - ); - } - } - } -} - -struct CfgChecker<'a, 'tcx> { - when: &'a str, - body: &'a Body<'tcx>, - tcx: TyCtxt<'tcx>, - mir_phase: MirPhase, - unwind_edge_count: usize, - reachable_blocks: BitSet, - value_cache: FxHashSet, - // If `false`, then the MIR must not contain `UnwindAction::Continue` or - // `TerminatorKind::Resume`. - can_unwind: bool, -} - -impl<'a, 'tcx> CfgChecker<'a, 'tcx> { - #[track_caller] - fn fail(&self, location: Location, msg: impl AsRef) { - // We might see broken MIR when other errors have already occurred. - assert!( - self.tcx.dcx().has_errors().is_some(), - "broken MIR in {:?} ({}) at {:?}:\n{}", - self.body.source.instance, - self.when, - location, - msg.as_ref(), - ); - } - - fn check_edge(&mut self, location: Location, bb: BasicBlock, edge_kind: EdgeKind) { - if bb == START_BLOCK { - self.fail(location, "start block must not have predecessors") - } - if let Some(bb) = self.body.basic_blocks.get(bb) { - let src = self.body.basic_blocks.get(location.block).unwrap(); - match (src.is_cleanup, bb.is_cleanup, edge_kind) { - // Non-cleanup blocks can jump to non-cleanup blocks along non-unwind edges - (false, false, EdgeKind::Normal) - // Cleanup blocks can jump to cleanup blocks along non-unwind edges - | (true, true, EdgeKind::Normal) => {} - // Non-cleanup blocks can jump to cleanup blocks along unwind edges - (false, true, EdgeKind::Unwind) => { - self.unwind_edge_count += 1; - } - // All other jumps are invalid - _ => { - self.fail( - location, - format!( - "{:?} edge to {:?} violates unwind invariants (cleanup {:?} -> {:?})", - edge_kind, - bb, - src.is_cleanup, - bb.is_cleanup, - ) - ) - } - } - } else { - self.fail(location, format!("encountered jump to invalid basic block {bb:?}")) - } - } - - fn check_cleanup_control_flow(&self) { - if self.unwind_edge_count <= 1 { - return; - } - let doms = self.body.basic_blocks.dominators(); - let mut post_contract_node = FxHashMap::default(); - // Reusing the allocation across invocations of the closure - let mut dom_path = vec![]; - let mut get_post_contract_node = |mut bb| { - let root = loop { - if let Some(root) = post_contract_node.get(&bb) { - break *root; - } - let parent = doms.immediate_dominator(bb).unwrap(); - dom_path.push(bb); - if !self.body.basic_blocks[parent].is_cleanup { - break bb; - } - bb = parent; - }; - for bb in dom_path.drain(..) { - post_contract_node.insert(bb, root); - } - root - }; - - let mut parent = IndexVec::from_elem(None, &self.body.basic_blocks); - for (bb, bb_data) in self.body.basic_blocks.iter_enumerated() { - if !bb_data.is_cleanup || !self.reachable_blocks.contains(bb) { - continue; - } - let bb = get_post_contract_node(bb); - for s in bb_data.terminator().successors() { - let s = get_post_contract_node(s); - if s == bb { - continue; - } - let parent = &mut parent[bb]; - match parent { - None => { - *parent = Some(s); - } - Some(e) if *e == s => (), - Some(e) => self.fail( - Location { block: bb, statement_index: 0 }, - format!( - "Cleanup control flow violation: The blocks dominated by {:?} have edges to both {:?} and {:?}", - bb, - s, - *e - ) - ), - } - } - } - - // Check for cycles - let mut stack = FxHashSet::default(); - for i in 0..parent.len() { - let mut bb = BasicBlock::from_usize(i); - stack.clear(); - stack.insert(bb); - loop { - let Some(parent) = parent[bb].take() else { break }; - let no_cycle = stack.insert(parent); - if !no_cycle { - self.fail( - Location { block: bb, statement_index: 0 }, - format!( - "Cleanup control flow violation: Cycle involving edge {bb:?} -> {parent:?}", - ), - ); - break; - } - bb = parent; - } - } - } - - fn check_unwind_edge(&mut self, location: Location, unwind: UnwindAction) { - let is_cleanup = self.body.basic_blocks[location.block].is_cleanup; - match unwind { - UnwindAction::Cleanup(unwind) => { - if is_cleanup { - self.fail(location, "`UnwindAction::Cleanup` in cleanup block"); - } - self.check_edge(location, unwind, EdgeKind::Unwind); - } - UnwindAction::Continue => { - if is_cleanup { - self.fail(location, "`UnwindAction::Continue` in cleanup block"); - } - - if !self.can_unwind { - self.fail(location, "`UnwindAction::Continue` in no-unwind function"); - } - } - UnwindAction::Terminate(UnwindTerminateReason::InCleanup) => { - if !is_cleanup { - self.fail( - location, - "`UnwindAction::Terminate(InCleanup)` in a non-cleanup block", - ); - } - } - // These are allowed everywhere. - UnwindAction::Unreachable | UnwindAction::Terminate(UnwindTerminateReason::Abi) => (), - } - } - - fn is_critical_call_edge(&self, target: Option, unwind: UnwindAction) -> bool { - let Some(target) = target else { return false }; - matches!(unwind, UnwindAction::Cleanup(_) | UnwindAction::Terminate(_)) - && self.body.basic_blocks.predecessors()[target].len() > 1 - } -} - -impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { - fn visit_local(&mut self, local: Local, _context: PlaceContext, location: Location) { - if self.body.local_decls.get(local).is_none() { - self.fail( - location, - format!("local {local:?} has no corresponding declaration in `body.local_decls`"), - ); - } - } - - fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { - match &statement.kind { - StatementKind::AscribeUserType(..) => { - if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { - self.fail( - location, - "`AscribeUserType` should have been removed after drop lowering phase", - ); - } - } - StatementKind::FakeRead(..) => { - if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { - self.fail( - location, - "`FakeRead` should have been removed after drop lowering phase", - ); - } - } - StatementKind::SetDiscriminant { .. } => { - if self.mir_phase < MirPhase::Runtime(RuntimePhase::Initial) { - self.fail(location, "`SetDiscriminant`is not allowed until deaggregation"); - } - } - StatementKind::Deinit(..) => { - if self.mir_phase < MirPhase::Runtime(RuntimePhase::Initial) { - self.fail(location, "`Deinit`is not allowed until deaggregation"); - } - } - StatementKind::Retag(kind, _) => { - // FIXME(JakobDegen) The validator should check that `self.mir_phase < - // DropsLowered`. However, this causes ICEs with generation of drop shims, which - // seem to fail to set their `MirPhase` correctly. - if matches!(kind, RetagKind::TwoPhase) { - self.fail(location, format!("explicit `{kind:?}` is forbidden")); - } - } - StatementKind::Coverage(kind) => { - if self.mir_phase >= MirPhase::Analysis(AnalysisPhase::PostCleanup) - && let CoverageKind::BlockMarker { .. } | CoverageKind::SpanMarker { .. } = kind - { - self.fail( - location, - format!("{kind:?} should have been removed after analysis"), - ); - } - } - StatementKind::Assign(..) - | StatementKind::StorageLive(_) - | StatementKind::StorageDead(_) - | StatementKind::Intrinsic(_) - | StatementKind::ConstEvalCounter - | StatementKind::PlaceMention(..) - | StatementKind::Nop => {} - } - - self.super_statement(statement, location); - } - - fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { - match &terminator.kind { - TerminatorKind::Goto { target } => { - self.check_edge(location, *target, EdgeKind::Normal); - } - TerminatorKind::SwitchInt { targets, discr: _ } => { - for (_, target) in targets.iter() { - self.check_edge(location, target, EdgeKind::Normal); - } - self.check_edge(location, targets.otherwise(), EdgeKind::Normal); - - self.value_cache.clear(); - self.value_cache.extend(targets.iter().map(|(value, _)| value)); - let has_duplicates = targets.iter().len() != self.value_cache.len(); - if has_duplicates { - self.fail( - location, - format!( - "duplicated values in `SwitchInt` terminator: {:?}", - terminator.kind, - ), - ); - } - } - TerminatorKind::Drop { target, unwind, .. } => { - self.check_edge(location, *target, EdgeKind::Normal); - self.check_unwind_edge(location, *unwind); - } - TerminatorKind::Call { args, destination, target, unwind, .. } => { - if let Some(target) = target { - self.check_edge(location, *target, EdgeKind::Normal); - } - self.check_unwind_edge(location, *unwind); - - // The code generation assumes that there are no critical call edges. The assumption - // is used to simplify inserting code that should be executed along the return edge - // from the call. FIXME(tmiasko): Since this is a strictly code generation concern, - // the code generation should be responsible for handling it. - if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Optimized) - && self.is_critical_call_edge(*target, *unwind) - { - self.fail( - location, - format!( - "encountered critical edge in `Call` terminator {:?}", - terminator.kind, - ), - ); - } - - // The call destination place and Operand::Move place used as an argument might be - // passed by a reference to the callee. Consequently they cannot be packed. - if is_within_packed(self.tcx, &self.body.local_decls, *destination).is_some() { - // This is bad! The callee will expect the memory to be aligned. - self.fail( - location, - format!( - "encountered packed place in `Call` terminator destination: {:?}", - terminator.kind, - ), - ); - } - for arg in args { - if let Operand::Move(place) = &arg.node { - if is_within_packed(self.tcx, &self.body.local_decls, *place).is_some() { - // This is bad! The callee will expect the memory to be aligned. - self.fail( - location, - format!( - "encountered `Move` of a packed place in `Call` terminator: {:?}", - terminator.kind, - ), - ); - } - } - } - } - TerminatorKind::Assert { target, unwind, .. } => { - self.check_edge(location, *target, EdgeKind::Normal); - self.check_unwind_edge(location, *unwind); - } - TerminatorKind::Yield { resume, drop, .. } => { - if self.body.coroutine.is_none() { - self.fail(location, "`Yield` cannot appear outside coroutine bodies"); - } - if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { - self.fail(location, "`Yield` should have been replaced by coroutine lowering"); - } - self.check_edge(location, *resume, EdgeKind::Normal); - if let Some(drop) = drop { - self.check_edge(location, *drop, EdgeKind::Normal); - } - } - TerminatorKind::FalseEdge { real_target, imaginary_target } => { - if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { - self.fail( - location, - "`FalseEdge` should have been removed after drop elaboration", - ); - } - self.check_edge(location, *real_target, EdgeKind::Normal); - self.check_edge(location, *imaginary_target, EdgeKind::Normal); - } - TerminatorKind::FalseUnwind { real_target, unwind } => { - if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { - self.fail( - location, - "`FalseUnwind` should have been removed after drop elaboration", - ); - } - self.check_edge(location, *real_target, EdgeKind::Normal); - self.check_unwind_edge(location, *unwind); - } - TerminatorKind::InlineAsm { targets, unwind, .. } => { - for &target in targets { - self.check_edge(location, target, EdgeKind::Normal); - } - self.check_unwind_edge(location, *unwind); - } - TerminatorKind::CoroutineDrop => { - if self.body.coroutine.is_none() { - self.fail(location, "`CoroutineDrop` cannot appear outside coroutine bodies"); - } - if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { - self.fail( - location, - "`CoroutineDrop` should have been replaced by coroutine lowering", - ); - } - } - TerminatorKind::UnwindResume => { - let bb = location.block; - if !self.body.basic_blocks[bb].is_cleanup { - self.fail(location, "Cannot `UnwindResume` from non-cleanup basic block") - } - if !self.can_unwind { - self.fail(location, "Cannot `UnwindResume` in a function that cannot unwind") - } - } - TerminatorKind::UnwindTerminate(_) => { - let bb = location.block; - if !self.body.basic_blocks[bb].is_cleanup { - self.fail(location, "Cannot `UnwindTerminate` from non-cleanup basic block") - } - } - TerminatorKind::Return => { - let bb = location.block; - if self.body.basic_blocks[bb].is_cleanup { - self.fail(location, "Cannot `Return` from cleanup basic block") - } - } - TerminatorKind::Unreachable => {} - } - - self.super_terminator(terminator, location); - } - - fn visit_source_scope(&mut self, scope: SourceScope) { - if self.body.source_scopes.get(scope).is_none() { - self.tcx.dcx().span_bug( - self.body.span, - format!( - "broken MIR in {:?} ({}):\ninvalid source scope {:?}", - self.body.source.instance, self.when, scope, - ), - ); - } - } -} - -/// A faster version of the validation pass that only checks those things which may break when -/// instantiating any generic parameters. -/// -/// `caller_body` is used to detect cycles in MIR inlining and MIR validation before -/// `optimized_mir` is available. -pub fn validate_types<'tcx>( - tcx: TyCtxt<'tcx>, - mir_phase: MirPhase, - param_env: ty::ParamEnv<'tcx>, - body: &Body<'tcx>, - caller_body: &Body<'tcx>, -) -> Vec<(Location, String)> { - let mut type_checker = - TypeChecker { body, caller_body, tcx, param_env, mir_phase, failures: Vec::new() }; - type_checker.visit_body(body); - type_checker.failures -} - -struct TypeChecker<'a, 'tcx> { - body: &'a Body<'tcx>, - caller_body: &'a Body<'tcx>, - tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - mir_phase: MirPhase, - failures: Vec<(Location, String)>, -} - -impl<'a, 'tcx> TypeChecker<'a, 'tcx> { - fn fail(&mut self, location: Location, msg: impl Into) { - self.failures.push((location, msg.into())); - } - - /// Check if src can be assigned into dest. - /// This is not precise, it will accept some incorrect assignments. - fn mir_assign_valid_types(&self, src: Ty<'tcx>, dest: Ty<'tcx>) -> bool { - // Fast path before we normalize. - if src == dest { - // Equal types, all is good. - return true; - } - - // We sometimes have to use `defining_opaque_types` for subtyping - // to succeed here and figuring out how exactly that should work - // is annoying. It is harmless enough to just not validate anything - // in that case. We still check this after analysis as all opaque - // types have been revealed at this point. - if (src, dest).has_opaque_types() { - return true; - } - - // After borrowck subtyping should be fully explicit via - // `Subtype` projections. - let variance = if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { - Variance::Invariant - } else { - Variance::Covariant - }; - - crate::util::relate_types(self.tcx, self.param_env, variance, src, dest) - } -} - -impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { - fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { - // This check is somewhat expensive, so only run it when -Zvalidate-mir is passed. - if self.tcx.sess.opts.unstable_opts.validate_mir - && self.mir_phase < MirPhase::Runtime(RuntimePhase::Initial) - { - // `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; - - if !ty.is_copy_modulo_regions(self.tcx, self.param_env) { - self.fail(location, format!("`Operand::Copy` with non-`Copy` type {ty}")); - } - } - } - - self.super_operand(operand, location); - } - - fn visit_projection_elem( - &mut self, - place_ref: PlaceRef<'tcx>, - elem: PlaceElem<'tcx>, - context: PlaceContext, - location: Location, - ) { - match elem { - ProjectionElem::OpaqueCast(ty) - if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) => - { - self.fail( - location, - format!("explicit opaque type cast to `{ty}` after `RevealAll`"), - ) - } - ProjectionElem::Index(index) => { - let index_ty = self.body.local_decls[index].ty; - if index_ty != self.tcx.types.usize { - self.fail(location, format!("bad index ({index_ty:?} != usize)")) - } - } - ProjectionElem::Deref - if self.mir_phase >= MirPhase::Runtime(RuntimePhase::PostCleanup) => - { - let base_ty = place_ref.ty(&self.body.local_decls, self.tcx).ty; - - if base_ty.is_box() { - self.fail( - location, - format!("{base_ty:?} dereferenced after ElaborateBoxDerefs"), - ) - } - } - ProjectionElem::Field(f, ty) => { - let parent_ty = place_ref.ty(&self.body.local_decls, self.tcx); - let fail_out_of_bounds = |this: &mut Self, location| { - this.fail(location, format!("Out of bounds field {f:?} for {parent_ty:?}")); - }; - let check_equal = |this: &mut Self, location, f_ty| { - if !this.mir_assign_valid_types(ty, f_ty) { - this.fail( - location, - format!( - "Field projection `{place_ref:?}.{f:?}` specified type `{ty:?}`, but actual type is `{f_ty:?}`" - ) - ) - } - }; - - let kind = match parent_ty.ty.kind() { - &ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => { - self.tcx.type_of(def_id).instantiate(self.tcx, args).kind() - } - kind => kind, - }; - - match kind { - ty::Tuple(fields) => { - let Some(f_ty) = fields.get(f.as_usize()) else { - fail_out_of_bounds(self, location); - return; - }; - check_equal(self, location, *f_ty); - } - ty::Adt(adt_def, args) => { - let var = parent_ty.variant_index.unwrap_or(FIRST_VARIANT); - let Some(field) = adt_def.variant(var).fields.get(f) else { - fail_out_of_bounds(self, location); - return; - }; - check_equal(self, location, field.ty(self.tcx, args)); - } - ty::Closure(_, args) => { - let args = args.as_closure(); - let Some(&f_ty) = args.upvar_tys().get(f.as_usize()) else { - fail_out_of_bounds(self, location); - return; - }; - check_equal(self, location, f_ty); - } - ty::CoroutineClosure(_, args) => { - let args = args.as_coroutine_closure(); - let Some(&f_ty) = args.upvar_tys().get(f.as_usize()) else { - fail_out_of_bounds(self, location); - return; - }; - check_equal(self, location, f_ty); - } - &ty::Coroutine(def_id, args) => { - let f_ty = if let Some(var) = parent_ty.variant_index { - // If we're currently validating an inlined copy of this body, - // then it will no longer be parameterized over the original - // args of the coroutine. Otherwise, we prefer to use this body - // since we may be in the process of computing this MIR in the - // first place. - let layout = if def_id == self.caller_body.source.def_id() { - // FIXME: This is not right for async closures. - self.caller_body.coroutine_layout_raw() - } else { - self.tcx.coroutine_layout(def_id, args.as_coroutine().kind_ty()) - }; - - let Some(layout) = layout else { - self.fail( - location, - format!("No coroutine layout for {parent_ty:?}"), - ); - return; - }; - - let Some(&local) = layout.variant_fields[var].get(f) else { - fail_out_of_bounds(self, location); - return; - }; - - let Some(f_ty) = layout.field_tys.get(local) else { - self.fail( - location, - format!("Out of bounds local {local:?} for {parent_ty:?}"), - ); - return; - }; - - ty::EarlyBinder::bind(f_ty.ty).instantiate(self.tcx, args) - } else { - let Some(&f_ty) = args.as_coroutine().prefix_tys().get(f.index()) - else { - fail_out_of_bounds(self, location); - return; - }; - - f_ty - }; - - check_equal(self, location, f_ty); - } - _ => { - self.fail(location, format!("{:?} does not have fields", parent_ty.ty)); - } - } - } - ProjectionElem::Subtype(ty) => { - if !relate_types( - self.tcx, - self.param_env, - Variance::Covariant, - ty, - place_ref.ty(&self.body.local_decls, self.tcx).ty, - ) { - self.fail( - location, - format!( - "Failed subtyping {ty:#?} and {:#?}", - place_ref.ty(&self.body.local_decls, self.tcx).ty - ), - ) - } - } - _ => {} - } - self.super_projection_elem(place_ref, elem, context, location); - } - - fn visit_var_debug_info(&mut self, debuginfo: &VarDebugInfo<'tcx>) { - if let Some(box VarDebugInfoFragment { ty, ref projection }) = debuginfo.composite { - if ty.is_union() || ty.is_enum() { - self.fail( - START_BLOCK.start_location(), - format!("invalid type {ty:?} in debuginfo for {:?}", debuginfo.name), - ); - } - if projection.is_empty() { - self.fail( - START_BLOCK.start_location(), - format!("invalid empty projection in debuginfo for {:?}", debuginfo.name), - ); - } - if projection.iter().any(|p| !matches!(p, PlaceElem::Field(..))) { - self.fail( - START_BLOCK.start_location(), - format!( - "illegal projection {:?} in debuginfo for {:?}", - projection, debuginfo.name - ), - ); - } - } - match debuginfo.value { - VarDebugInfoContents::Const(_) => {} - VarDebugInfoContents::Place(place) => { - if place.projection.iter().any(|p| !p.can_use_in_debuginfo()) { - self.fail( - START_BLOCK.start_location(), - format!("illegal place {:?} in debuginfo for {:?}", place, debuginfo.name), - ); - } - } - } - self.super_var_debug_info(debuginfo); - } - - fn visit_place(&mut self, place: &Place<'tcx>, cntxt: PlaceContext, location: Location) { - // Set off any `bug!`s in the type computation code - let _ = place.ty(&self.body.local_decls, self.tcx); - - if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) - && place.projection.len() > 1 - && cntxt != PlaceContext::NonUse(NonUseContext::VarDebugInfo) - && place.projection[1..].contains(&ProjectionElem::Deref) - { - self.fail(location, format!("{place:?}, has deref at the wrong place")); - } - - self.super_place(place, cntxt, location); - } - - fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { - macro_rules! check_kinds { - ($t:expr, $text:literal, $typat:pat) => { - if !matches!(($t).kind(), $typat) { - self.fail(location, format!($text, $t)); - } - }; - } - match rvalue { - Rvalue::Use(_) | Rvalue::CopyForDeref(_) => {} - Rvalue::Aggregate(kind, fields) => match **kind { - AggregateKind::Tuple => {} - AggregateKind::Array(dest) => { - for src in fields { - if !self.mir_assign_valid_types(src.ty(self.body, self.tcx), dest) { - self.fail(location, "array field has the wrong type"); - } - } - } - AggregateKind::Adt(def_id, idx, args, _, Some(field)) => { - let adt_def = self.tcx.adt_def(def_id); - assert!(adt_def.is_union()); - assert_eq!(idx, FIRST_VARIANT); - let dest_ty = self.tcx.normalize_erasing_regions( - self.param_env, - adt_def.non_enum_variant().fields[field].ty(self.tcx, args), - ); - if fields.len() == 1 { - let src_ty = fields.raw[0].ty(self.body, self.tcx); - if !self.mir_assign_valid_types(src_ty, dest_ty) { - self.fail(location, "union field has the wrong type"); - } - } else { - self.fail(location, "unions should have one initialized field"); - } - } - AggregateKind::Adt(def_id, idx, args, _, None) => { - let adt_def = self.tcx.adt_def(def_id); - assert!(!adt_def.is_union()); - let variant = &adt_def.variants()[idx]; - if variant.fields.len() != fields.len() { - self.fail(location, "adt has the wrong number of initialized fields"); - } - for (src, dest) in std::iter::zip(fields, &variant.fields) { - let dest_ty = self - .tcx - .normalize_erasing_regions(self.param_env, dest.ty(self.tcx, args)); - if !self.mir_assign_valid_types(src.ty(self.body, self.tcx), dest_ty) { - self.fail(location, "adt field has the wrong type"); - } - } - } - AggregateKind::Closure(_, args) => { - let upvars = args.as_closure().upvar_tys(); - if upvars.len() != fields.len() { - self.fail(location, "closure has the wrong number of initialized fields"); - } - for (src, dest) in std::iter::zip(fields, upvars) { - if !self.mir_assign_valid_types(src.ty(self.body, self.tcx), dest) { - self.fail(location, "closure field has the wrong type"); - } - } - } - AggregateKind::Coroutine(_, args) => { - let upvars = args.as_coroutine().upvar_tys(); - if upvars.len() != fields.len() { - self.fail(location, "coroutine has the wrong number of initialized fields"); - } - for (src, dest) in std::iter::zip(fields, upvars) { - if !self.mir_assign_valid_types(src.ty(self.body, self.tcx), dest) { - self.fail(location, "coroutine field has the wrong type"); - } - } - } - AggregateKind::CoroutineClosure(_, args) => { - let upvars = args.as_coroutine_closure().upvar_tys(); - if upvars.len() != fields.len() { - self.fail( - location, - "coroutine-closure has the wrong number of initialized fields", - ); - } - for (src, dest) in std::iter::zip(fields, upvars) { - if !self.mir_assign_valid_types(src.ty(self.body, self.tcx), dest) { - self.fail(location, "coroutine-closure field has the wrong type"); - } - } - } - }, - Rvalue::Ref(_, BorrowKind::Fake, _) => { - if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { - self.fail( - location, - "`Assign` statement with a `Fake` borrow should have been removed in runtime MIR", - ); - } - } - Rvalue::Ref(..) => {} - Rvalue::Len(p) => { - let pty = p.ty(&self.body.local_decls, self.tcx).ty; - check_kinds!( - pty, - "Cannot compute length of non-array type {:?}", - ty::Array(..) | ty::Slice(..) - ); - } - Rvalue::BinaryOp(op, vals) => { - use BinOp::*; - let a = vals.0.ty(&self.body.local_decls, self.tcx); - let b = vals.1.ty(&self.body.local_decls, self.tcx); - if crate::util::binop_right_homogeneous(*op) { - if let Eq | Lt | Le | Ne | Ge | Gt = op { - // The function pointer types can have lifetimes - if !self.mir_assign_valid_types(a, b) { - self.fail( - location, - format!("Cannot {op:?} compare incompatible types {a:?} and {b:?}"), - ); - } - } else if a != b { - self.fail( - location, - format!( - "Cannot perform binary op {op:?} on unequal types {a:?} and {b:?}" - ), - ); - } - } - - match op { - Offset => { - check_kinds!(a, "Cannot offset non-pointer type {:?}", ty::RawPtr(..)); - if b != self.tcx.types.isize && b != self.tcx.types.usize { - self.fail(location, format!("Cannot offset by non-isize type {b:?}")); - } - } - Eq | Lt | Le | Ne | Ge | Gt => { - for x in [a, b] { - check_kinds!( - x, - "Cannot {op:?} compare type {:?}", - ty::Bool - | ty::Char - | ty::Int(..) - | ty::Uint(..) - | ty::Float(..) - | ty::RawPtr(..) - | ty::FnPtr(..) - ) - } - } - AddUnchecked | SubUnchecked | MulUnchecked | Shl | ShlUnchecked | Shr - | ShrUnchecked => { - for x in [a, b] { - check_kinds!( - x, - "Cannot {op:?} non-integer type {:?}", - ty::Uint(..) | ty::Int(..) - ) - } - } - BitAnd | BitOr | BitXor => { - for x in [a, b] { - check_kinds!( - x, - "Cannot perform bitwise op {op:?} on type {:?}", - ty::Uint(..) | ty::Int(..) | ty::Bool - ) - } - } - Add | Sub | Mul | Div | Rem => { - for x in [a, b] { - check_kinds!( - x, - "Cannot perform arithmetic {op:?} on type {:?}", - ty::Uint(..) | ty::Int(..) | ty::Float(..) - ) - } - } - } - } - Rvalue::CheckedBinaryOp(op, vals) => { - use BinOp::*; - let a = vals.0.ty(&self.body.local_decls, self.tcx); - let b = vals.1.ty(&self.body.local_decls, self.tcx); - match op { - Add | Sub | Mul => { - for x in [a, b] { - check_kinds!( - x, - "Cannot perform checked arithmetic on type {:?}", - ty::Uint(..) | ty::Int(..) - ) - } - if a != b { - self.fail( - location, - format!( - "Cannot perform checked arithmetic on unequal types {a:?} and {b:?}" - ), - ); - } - } - _ => self.fail(location, format!("There is no checked version of {op:?}")), - } - } - Rvalue::UnaryOp(op, operand) => { - let a = operand.ty(&self.body.local_decls, self.tcx); - match op { - UnOp::Neg => { - check_kinds!(a, "Cannot negate type {:?}", ty::Int(..) | ty::Float(..)) - } - UnOp::Not => { - check_kinds!( - a, - "Cannot binary not type {:?}", - ty::Int(..) | ty::Uint(..) | ty::Bool - ); - } - } - } - Rvalue::ShallowInitBox(operand, _) => { - let a = operand.ty(&self.body.local_decls, self.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::DynStar => { - // FIXME(dyn-star): make sure nothing needs to be done here. - } - // FIXME: Add Checks for these - CastKind::PointerFromExposedAddress - | CastKind::PointerExposeAddress - | CastKind::PointerCoercion(_) => {} - 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!( - "Trying to cast non 'Float' as {kind:?} into {target_type:?}" - ), - ); - } - } - CastKind::Transmute => { - if let MirPhase::Runtime(..) = self.mir_phase { - // Unlike `mem::transmute`, a MIR `Transmute` is well-formed - // for any two `Sized` types, just potentially UB to run. - - if !self - .tcx - .normalize_erasing_regions(self.param_env, op_ty) - .is_sized(self.tcx, self.param_env) - { - self.fail( - location, - format!("Cannot transmute from non-`Sized` type {op_ty:?}"), - ); - } - if !self - .tcx - .normalize_erasing_regions(self.param_env, *target_type) - .is_sized(self.tcx, self.param_env) - { - self.fail( - location, - format!("Cannot transmute to non-`Sized` type {target_type:?}"), - ); - } - } else { - self.fail( - location, - format!( - "Transmute is not supported in non-runtime phase {:?}.", - self.mir_phase - ), - ); - } - } - } - } - Rvalue::NullaryOp(NullOp::OffsetOf(indices), container) => { - let fail_out_of_bounds = |this: &mut Self, location, field, ty| { - this.fail(location, format!("Out of bounds field {field:?} for {ty:?}")); - }; - - let mut current_ty = *container; - - for (variant, field) in indices.iter() { - match current_ty.kind() { - ty::Tuple(fields) => { - if variant != FIRST_VARIANT { - self.fail( - location, - format!("tried to get variant {variant:?} of tuple"), - ); - return; - } - let Some(&f_ty) = fields.get(field.as_usize()) else { - fail_out_of_bounds(self, location, field, current_ty); - return; - }; - - current_ty = self.tcx.normalize_erasing_regions(self.param_env, f_ty); - } - ty::Adt(adt_def, args) => { - let Some(field) = adt_def.variant(variant).fields.get(field) else { - fail_out_of_bounds(self, location, field, current_ty); - return; - }; - - let f_ty = field.ty(self.tcx, args); - current_ty = self.tcx.normalize_erasing_regions(self.param_env, f_ty); - } - _ => { - self.fail( - location, - format!("Cannot get offset ({variant:?}, {field:?}) from type {current_ty:?}"), - ); - return; - } - } - } - } - Rvalue::Repeat(_, _) - | Rvalue::ThreadLocalRef(_) - | Rvalue::AddressOf(_, _) - | Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::UbChecks, _) - | Rvalue::Discriminant(_) => {} - } - self.super_rvalue(rvalue, location); - } - - fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { - match &statement.kind { - StatementKind::Assign(box (dest, rvalue)) => { - // LHS and RHS of the assignment must have the same type. - let left_ty = dest.ty(&self.body.local_decls, self.tcx).ty; - let right_ty = rvalue.ty(&self.body.local_decls, self.tcx); - - if !self.mir_assign_valid_types(right_ty, left_ty) { - self.fail( - location, - format!( - "encountered `{:?}` with incompatible types:\n\ + by_move_layout: {by_move_layout:#?}" +,),);;}}}}struct CfgChecker<'a,'tcx>{when:&'a str,body:&'a Body<'tcx>,tcx:TyCtxt +<'tcx>,mir_phase:MirPhase,unwind_edge_count:usize,reachable_blocks:BitSet,value_cache:FxHashSet,can_unwind:bool,}impl<'a,'tcx>//((),()); +CfgChecker<'a,'tcx>{#[track_caller]fn fail(&self,location:Location,msg:impl//(); +AsRef){let _=||();let _=||();assert!(self.tcx.dcx().has_errors().is_some(), +"broken MIR in {:?} ({}) at {:?}:\n{}",self.body.source.instance,self.when,//(); +location,msg.as_ref(),);if true{};}fn check_edge(&mut self,location:Location,bb: +BasicBlock,edge_kind:EdgeKind){if (((((bb ==START_BLOCK))))){self.fail(location, +"start block must not have predecessors")}if let Some(bb)=self.body.//if true{}; +basic_blocks.get(bb){;let src=self.body.basic_blocks.get(location.block).unwrap( +);;match(src.is_cleanup,bb.is_cleanup,edge_kind){(false,false,EdgeKind::Normal)| +(true,true,EdgeKind::Normal)=>{}(false,true,EdgeKind::Unwind)=>{let _=||();self. +unwind_edge_count+=1;loop{break;};if let _=(){};}_=>{self.fail(location,format!( +"{:?} edge to {:?} violates unwind invariants (cleanup {:?} -> {:?})" ,edge_kind +,bb,src.is_cleanup,bb.is_cleanup,))}}}else{self.fail(location,format!(//((),()); +"encountered jump to invalid basic block {bb:?}"))}}fn//loop{break};loop{break}; +check_cleanup_control_flow(&self){if self.unwind_edge_count<=1{;return;}let doms +=self.body.basic_blocks.dominators();();3;let mut post_contract_node=FxHashMap:: +default();;;let mut dom_path=vec![];;let mut get_post_contract_node=|mut bb|{let +root=loop{if let Some(root)=post_contract_node.get(&bb){;break*root;}let parent= +doms.immediate_dominator(bb).unwrap();{;};{;};dom_path.push(bb);();if!self.body. +basic_blocks[parent].is_cleanup{;break bb;}bb=parent;};for bb in dom_path.drain( +..){();post_contract_node.insert(bb,root);3;}root};3;3;let mut parent=IndexVec:: +from_elem(None,&self.body.basic_blocks);loop{break};for(bb,bb_data)in self.body. +basic_blocks.iter_enumerated(){if(! bb_data.is_cleanup)||!self.reachable_blocks. +contains(bb){3;continue;3;};let bb=get_post_contract_node(bb);;for s in bb_data. +terminator().successors(){;let s=get_post_contract_node(s);;if s==bb{;continue;} +let parent=&mut parent[bb];;match parent{None=>{;*parent=Some(s);}Some(e)if*e==s +=>((())),Some(e)=>self.fail((( Location{block:bb,statement_index:(0)})),format!( +"Cleanup control flow violation: The blocks dominated by {:?} have edges to both {:?} and {:?}" +,bb,s,*e)),}}};let mut stack=FxHashSet::default();;for i in 0..parent.len(){;let +mut bb=BasicBlock::from_usize(i);;;stack.clear();stack.insert(bb);loop{let Some( +parent)=parent[bb].take()else{break};3;3;let no_cycle=stack.insert(parent);3;if! +no_cycle{((),());((),());self.fail(Location{block:bb,statement_index:0},format!( +"Cleanup control flow violation: Cycle involving edge {bb:?} -> {parent:?}",) ,) +;;;break;;}bb=parent;}}}fn check_unwind_edge(&mut self,location:Location,unwind: +UnwindAction){;let is_cleanup=self.body.basic_blocks[location.block].is_cleanup; +match unwind{UnwindAction::Cleanup(unwind)=>{if is_cleanup{3;self.fail(location, +"`UnwindAction::Cleanup` in cleanup block");3;};self.check_edge(location,unwind, +EdgeKind::Unwind);3;}UnwindAction::Continue=>{if is_cleanup{;self.fail(location, +"`UnwindAction::Continue` in cleanup block");();}if!self.can_unwind{3;self.fail( +location,"`UnwindAction::Continue` in no-unwind function");({});}}UnwindAction:: +Terminate(UnwindTerminateReason::InCleanup)=>{if!is_cleanup{;self.fail(location, +"`UnwindAction::Terminate(InCleanup)` in a non-cleanup block",);3;}}UnwindAction +::Unreachable|UnwindAction::Terminate(UnwindTerminateReason::Abi)=>(((()))),}}fn +is_critical_call_edge(&self,target:Option,unwind:UnwindAction)->//3; +bool{;let Some(target)=target else{return false};;matches!(unwind,UnwindAction:: +Cleanup(_)|UnwindAction::Terminate(_))&&(self.body.basic_blocks.predecessors())[ +target].len()>(((((1)))))}}impl< 'a,'tcx>Visitor<'tcx>for CfgChecker<'a,'tcx>{fn +visit_local(&mut self,local:Local,_context:PlaceContext,location:Location){if // +self.body.local_decls.get(local).is_none(){if true{};self.fail(location,format!( +"local {local:?} has no corresponding declaration in `body.local_decls`"),);3;}} +fn visit_statement(&mut self,statement:&Statement<'tcx>,location:Location){//(); +match(&statement.kind){StatementKind::AscribeUserType( ..)=>{if self.mir_phase>= +MirPhase::Runtime(RuntimePhase::Initial){if true{};if true{};self.fail(location, +"`AscribeUserType` should have been removed after drop lowering phase",);({});}} +StatementKind::FakeRead(..)=>{if self.mir_phase>=MirPhase::Runtime(RuntimePhase +::Initial){loop{break};loop{break;};loop{break};loop{break;};self.fail(location, +"`FakeRead` should have been removed after drop lowering phase",);loop{break};}} +StatementKind::SetDiscriminant{..}=>{if self.mir_phase{if self.mir_phase{if matches!(kind,RetagKind::TwoPhase){({});self.fail(location,format!( +"explicit `{kind:?}` is forbidden"));;}}StatementKind::Coverage(kind)=>{if self. +mir_phase>=(MirPhase::Analysis(AnalysisPhase:: PostCleanup))&&let CoverageKind:: +BlockMarker{..}|CoverageKind::SpanMarker{..}=kind{();self.fail(location,format!( +"{kind:?} should have been removed after analysis"),);3;}}StatementKind::Assign( +..)|StatementKind::StorageLive(_) |StatementKind::StorageDead(_)|StatementKind:: +Intrinsic(_)|StatementKind::ConstEvalCounter|StatementKind::PlaceMention(..)|//; +StatementKind::Nop=>{}}*&*&();self.super_statement(statement,location);{();};}fn +visit_terminator(&mut self,terminator:&Terminator<'tcx>,location:Location){//(); +match&terminator.kind{TerminatorKind::Goto{target}=>{;self.check_edge(location,* +target,EdgeKind::Normal);();}TerminatorKind::SwitchInt{targets,discr:_}=>{for(_, +target)in targets.iter(){3;self.check_edge(location,target,EdgeKind::Normal);;}; +self.check_edge(location,targets.otherwise(),EdgeKind::Normal);;self.value_cache +.clear();3;3;self.value_cache.extend(targets.iter().map(|(value,_)|value));;;let +has_duplicates=targets.iter().len()!=self.value_cache.len();;if has_duplicates{; +self.fail(location, format!("duplicated values in `SwitchInt` terminator: {:?}", +terminator.kind,),);;}}TerminatorKind::Drop{target,unwind,..}=>{self.check_edge( +location,*target,EdgeKind::Normal);;;self.check_unwind_edge(location,*unwind);;} +TerminatorKind::Call{args,destination,target,unwind,..}=>{if let Some(target)=// +target{{();};self.check_edge(location,*target,EdgeKind::Normal);({});}({});self. +check_unwind_edge(location,*unwind);*&*&();if self.mir_phase>=MirPhase::Runtime( +RuntimePhase::Optimized)&&self.is_critical_call_edge(*target,*unwind){;self.fail +(location,format!("encountered critical edge in `Call` terminator {:?}",//{();}; +terminator.kind,),);{();};}if is_within_packed(self.tcx,&self.body.local_decls,* +destination).is_some(){*&*&();((),());*&*&();((),());self.fail(location,format!( +"encountered packed place in `Call` terminator destination: {:?}",terminator.//; +kind,),);loop{break;};}for arg in args{if let Operand::Move(place)=&arg.node{if +is_within_packed(self.tcx,&self.body.local_decls,*place).is_some(){();self.fail( +location,format!(//*&*&();((),());*&*&();((),());*&*&();((),());((),());((),()); +"encountered `Move` of a packed place in `Call` terminator: {:?}",terminator.//; +kind,),);{;};}}}}TerminatorKind::Assert{target,unwind,..}=>{{;};self.check_edge( +location,*target,EdgeKind::Normal);;;self.check_unwind_edge(location,*unwind);;} +TerminatorKind::Yield{resume,drop,..}=>{if self.body.coroutine.is_none(){3;self. +fail(location,"`Yield` cannot appear outside coroutine bodies");*&*&();}if self. +mir_phase>=MirPhase::Runtime(RuntimePhase::Initial){let _=();self.fail(location, +"`Yield` should have been replaced by coroutine lowering");3;}3;self.check_edge( +location,*resume,EdgeKind::Normal);();if let Some(drop)=drop{();self.check_edge( +location,*drop,EdgeKind::Normal);*&*&();}}TerminatorKind::FalseEdge{real_target, +imaginary_target}=>{if self.mir_phase>= MirPhase::Runtime(RuntimePhase::Initial) +{*&*&();((),());*&*&();((),());*&*&();((),());*&*&();((),());self.fail(location, +"`FalseEdge` should have been removed after drop elaboration",);({});}({});self. +check_edge(location,*real_target,EdgeKind::Normal);3;;self.check_edge(location,* +imaginary_target,EdgeKind::Normal);{;};}TerminatorKind::FalseUnwind{real_target, +unwind}=>{if self.mir_phase>=MirPhase::Runtime(RuntimePhase::Initial){;self.fail +(location,"`FalseUnwind` should have been removed after drop elaboration",);3;}; +self.check_edge(location,*real_target,EdgeKind::Normal);;self.check_unwind_edge( +location,*unwind);;}TerminatorKind::InlineAsm{targets,unwind,..}=>{for&target in +targets{{();};self.check_edge(location,target,EdgeKind::Normal);({});}({});self. +check_unwind_edge(location,*unwind);();}TerminatorKind::CoroutineDrop=>{if self. +body.coroutine.is_none(){let _=();let _=();let _=();let _=();self.fail(location, +"`CoroutineDrop` cannot appear outside coroutine bodies");3;}if self.mir_phase>= +MirPhase::Runtime(RuntimePhase::Initial){if true{};if true{};self.fail(location, +"`CoroutineDrop` should have been replaced by coroutine lowering",);if true{};}} +TerminatorKind::UnwindResume=>{;let bb=location.block;if!self.body.basic_blocks[ +bb].is_cleanup{self.fail(location,//let _=||();let _=||();let _=||();let _=||(); +"Cannot `UnwindResume` from non-cleanup basic block")}if(!self.can_unwind){self. +fail(location,((( "Cannot `UnwindResume` in a function that cannot unwind"))))}} +TerminatorKind::UnwindTerminate(_)=>{{;};let bb=location.block;{;};if!self.body. +basic_blocks[bb].is_cleanup{self.fail(location,//*&*&();((),());((),());((),()); +"Cannot `UnwindTerminate` from non-cleanup basic block")}}TerminatorKind:://{;}; +Return=>{3;let bb=location.block;;if self.body.basic_blocks[bb].is_cleanup{self. +fail(location,(("Cannot `Return` from cleanup basic block" )))}}TerminatorKind:: +Unreachable=>{}}let _=();self.super_terminator(terminator,location);let _=();}fn +visit_source_scope(&mut self,scope:SourceScope){ if self.body.source_scopes.get( +scope).is_none(){((),());((),());self.tcx.dcx().span_bug(self.body.span,format!( +"broken MIR in {:?} ({}):\ninvalid source scope {:?}",self. body.source.instance +,self.when,scope,),);;}}}pub fn validate_types<'tcx>(tcx:TyCtxt<'tcx>,mir_phase: +MirPhase,param_env:ty::ParamEnv<'tcx>,body: &Body<'tcx>,caller_body:&Body<'tcx>, +)->Vec<(Location,String)>{;let mut type_checker=TypeChecker{body,caller_body,tcx +,param_env,mir_phase,failures:Vec::new()};();();type_checker.visit_body(body);3; +type_checker.failures}struct TypeChecker<'a,'tcx>{body:&'a Body<'tcx>,//((),()); +caller_body:&'a Body<'tcx>,tcx:TyCtxt <'tcx>,param_env:ParamEnv<'tcx>,mir_phase: +MirPhase,failures:Vec<(Location,String)>,}impl<'a,'tcx>TypeChecker<'a,'tcx>{fn// +fail(&mut self,location:Location,msg:impl Into){{;};self.failures.push(( +location,msg.into()));{;};}fn mir_assign_valid_types(&self,src:Ty<'tcx>,dest:Ty< +'tcx>)->bool{if src==dest{;return true;;}if(src,dest).has_opaque_types(){return +true;;}let variance=if self.mir_phase>=MirPhase::Runtime(RuntimePhase::Initial){ +Variance::Invariant}else{Variance::Covariant};();crate::util::relate_types(self. +tcx,self.param_env,variance,src,dest)}}impl<'a,'tcx>Visitor<'tcx>for//if true{}; +TypeChecker<'a,'tcx>{fn visit_operand(& mut self,operand:&Operand<'tcx>,location +:Location){if self.tcx.sess.opts.unstable_opts.validate_mir&&self.mir_phase,elem: +PlaceElem<'tcx>,context:PlaceContext,location:Location,){match elem{//if true{}; +ProjectionElem::OpaqueCast(ty)if self.mir_phase>=MirPhase::Runtime(RuntimePhase +::Initial)=>{self.fail(location,format!(//let _=();if true{};let _=();if true{}; +"explicit opaque type cast to `{ty}` after `RevealAll`"),)}ProjectionElem:://(); +Index(index)=>{;let index_ty=self.body.local_decls[index].ty;;if index_ty!=self. +tcx.types.usize{self. fail(location,format!("bad index ({index_ty:?} != usize)") +)}}ProjectionElem::Deref if self.mir_phase>=MirPhase::Runtime(RuntimePhase:://3; +PostCleanup)=>{;let base_ty=place_ref.ty(&self.body.local_decls,self.tcx).ty;if +base_ty.is_box(){self.fail(location,format!(//((),());let _=();((),());let _=(); +"{base_ty:?} dereferenced after ElaborateBoxDerefs"),) }}ProjectionElem::Field(f +,ty)=>{{;};let parent_ty=place_ref.ty(&self.body.local_decls,self.tcx);();();let +fail_out_of_bounds=|this:&mut Self,location|{((),());this.fail(location,format!( +"Out of bounds field {f:?} for {parent_ty:?}"));3;};;;let check_equal=|this:&mut +Self,location,f_ty|{if!this.mir_assign_valid_types( ty,f_ty){this.fail(location, +format!(//((),());let _=();let _=();let _=();((),());let _=();let _=();let _=(); +"Field projection `{place_ref:?}.{f:?}` specified type `{ty:?}`, but actual type is `{f_ty:?}`" +))}};();();let kind=match parent_ty.ty.kind(){&ty::Alias(ty::Opaque,ty::AliasTy{ +def_id,args,..})=>{(self.tcx.type_of(def_id).instantiate(self.tcx,args).kind())} +kind=>kind,};{;};match kind{ty::Tuple(fields)=>{{;};let Some(f_ty)=fields.get(f. +as_usize())else{;fail_out_of_bounds(self,location);;;return;;};check_equal(self, +location,*f_ty);{;};}ty::Adt(adt_def,args)=>{();let var=parent_ty.variant_index. +unwrap_or(FIRST_VARIANT);;let Some(field)=adt_def.variant(var).fields.get(f)else +{;fail_out_of_bounds(self,location);return;};check_equal(self,location,field.ty( +self.tcx,args));;}ty::Closure(_,args)=>{;let args=args.as_closure();;;let Some(& +f_ty)=args.upvar_tys().get(f.as_usize())else{;fail_out_of_bounds(self,location); +return;;};;;check_equal(self,location,f_ty);;}ty::CoroutineClosure(_,args)=>{let +args=args.as_coroutine_closure();{;};{;};let Some(&f_ty)=args.upvar_tys().get(f. +as_usize())else{;fail_out_of_bounds(self,location);;;return;;};check_equal(self, +location,f_ty);{;};}&ty::Coroutine(def_id,args)=>{{;};let f_ty=if let Some(var)= +parent_ty.variant_index{;let layout=if def_id==self.caller_body.source.def_id(){ +self.caller_body.coroutine_layout_raw()}else{self.tcx.coroutine_layout(def_id,// +args.as_coroutine().kind_ty())};;let Some(layout)=layout else{self.fail(location +,format!("No coroutine layout for {parent_ty:?}"),);;;return;};let Some(&local)= +layout.variant_fields[var].get(f)else{;fail_out_of_bounds(self,location);return; +};3;;let Some(f_ty)=layout.field_tys.get(local)else{;self.fail(location,format!( +"Out of bounds local {local:?} for {parent_ty:?}"),);;return;};ty::EarlyBinder:: +bind(f_ty.ty).instantiate(self.tcx,args)}else{;let Some(&f_ty)=args.as_coroutine +().prefix_tys().get(f.index())else{;fail_out_of_bounds(self,location);;return;}; +f_ty};();();check_equal(self,location,f_ty);3;}_=>{3;self.fail(location,format!( +"{:?} does not have fields",parent_ty.ty));;}}}ProjectionElem::Subtype(ty)=>{if! +relate_types(self.tcx,self.param_env,Variance:: Covariant,ty,place_ref.ty(&self. +body.local_decls,self.tcx).ty,){self.fail(location,format!(//let _=();if true{}; +"Failed subtyping {ty:#?} and {:#?}",place_ref.ty(&self.body.local_decls,self.// +tcx).ty),)}}_=>{}};self.super_projection_elem(place_ref,elem,context,location);} +fn visit_var_debug_info(&mut self,debuginfo:&VarDebugInfo<'tcx>){if let Some(//; +box VarDebugInfoFragment{ty,ref projection}) =debuginfo.composite{if ty.is_union +()||ty.is_enum(){((),());((),());self.fail(START_BLOCK.start_location(),format!( +"invalid type {ty:?} in debuginfo for {:?}",debuginfo.name),);();}if projection. +is_empty(){let _=||();let _=||();self.fail(START_BLOCK.start_location(),format!( +"invalid empty projection in debuginfo for {:?}",debuginfo.name),);let _=();}if +projection.iter().any(|p|!matches!(p,PlaceElem::Field(..))){if true{};self.fail( +START_BLOCK.start_location(),format!(//if true{};if true{};if true{};let _=||(); +"illegal projection {:?} in debuginfo for {:?}",projection,debuginfo.name),);;}} +match debuginfo.value{VarDebugInfoContents::Const(_)=>{}VarDebugInfoContents::// +Place(place)=>{if place.projection.iter().any(|p|!p.can_use_in_debuginfo()){{;}; +self.fail(((((((((((((((((START_BLOCK.start_location ())))))))))))))))),format!( +"illegal place {:?} in debuginfo for {:?}",place,debuginfo.name),);();}}}3;self. +super_var_debug_info(debuginfo);();}fn visit_place(&mut self,place:&Place<'tcx>, +cntxt:PlaceContext,location:Location){{;};let _=place.ty(&self.body.local_decls, +self.tcx);();if self.mir_phase>=MirPhase::Runtime(RuntimePhase::Initial)&&place. +projection.len()>(1)&&cntxt!=PlaceContext::NonUse(NonUseContext::VarDebugInfo)&& +place.projection[1..].contains(&ProjectionElem::Deref){{();};self.fail(location, +format!("{place:?}, has deref at the wrong place"));3;}3;self.super_place(place, +cntxt,location);*&*&();}fn visit_rvalue(&mut self,rvalue:&Rvalue<'tcx>,location: +Location){{();};macro_rules!check_kinds{($t:expr,$text:literal,$typat:pat)=>{if! +matches!(($t).kind(),$typat){self.fail(location,format!($text,$t));}};}{;};match +rvalue{Rvalue::Use(_)|Rvalue::CopyForDeref( _)=>{}Rvalue::Aggregate(kind,fields) +=>match(**kind){AggregateKind::Tuple=> {}AggregateKind::Array(dest)=>{for src in +fields{if!self.mir_assign_valid_types(src.ty(self.body,self.tcx),dest){{;};self. +fail(location,"array field has the wrong type");();}}}AggregateKind::Adt(def_id, +idx,args,_,Some(field))=>{;let adt_def=self.tcx.adt_def(def_id);assert!(adt_def. +is_union());({});{;};assert_eq!(idx,FIRST_VARIANT);{;};{;};let dest_ty=self.tcx. +normalize_erasing_regions(self.param_env,(( adt_def.non_enum_variant())).fields[ +field].ty(self.tcx,args),);;if fields.len()==1{let src_ty=fields.raw[0].ty(self. +body,self.tcx);{;};if!self.mir_assign_valid_types(src_ty,dest_ty){{;};self.fail( +location,"union field has the wrong type");{();};}}else{({});self.fail(location, +"unions should have one initialized field");{;};}}AggregateKind::Adt(def_id,idx, +args,_,None)=>{;let adt_def=self.tcx.adt_def(def_id);assert!(!adt_def.is_union() +);;;let variant=&adt_def.variants()[idx];;if variant.fields.len()!=fields.len(){ +self.fail(location,"adt has the wrong number of initialized fields");3;}for(src, +dest)in std::iter::zip(fields,&variant.fields){loop{break};let dest_ty=self.tcx. +normalize_erasing_regions(self.param_env,dest.ty(self.tcx,args));*&*&();if!self. +mir_assign_valid_types(src.ty(self.body,self.tcx),dest_ty){3;self.fail(location, +"adt field has the wrong type");;}}}AggregateKind::Closure(_,args)=>{let upvars= +args.as_closure().upvar_tys();;if upvars.len()!=fields.len(){self.fail(location, +"closure has the wrong number of initialized fields");{;};}for(src,dest)in std:: +iter::zip(fields,upvars){if!self.mir_assign_valid_types(src.ty(self.body,self.// +tcx),dest){{();};self.fail(location,"closure field has the wrong type");({});}}} +AggregateKind::Coroutine(_,args)=>{;let upvars=args.as_coroutine().upvar_tys();; +if upvars.len()!=fields.len(){*&*&();((),());((),());((),());self.fail(location, +"coroutine has the wrong number of initialized fields");3;}for(src,dest)in std:: +iter::zip(fields,upvars){if!self.mir_assign_valid_types(src.ty(self.body,self.// +tcx),dest){({});self.fail(location,"coroutine field has the wrong type");{;};}}} +AggregateKind::CoroutineClosure(_,args)=>{;let upvars=args.as_coroutine_closure( +).upvar_tys();let _=();if upvars.len()!=fields.len(){((),());self.fail(location, +"coroutine-closure has the wrong number of initialized fields",);;}for(src,dest) +in ((std::iter::zip(fields,upvars))){if!self.mir_assign_valid_types(src.ty(self. +body,self.tcx),dest){if true{};if true{};if true{};if true{};self.fail(location, +"coroutine-closure field has the wrong type");();}}}},Rvalue::Ref(_,BorrowKind:: +Fake,_)=>{if self.mir_phase>=MirPhase::Runtime(RuntimePhase::Initial){;self.fail +(location,//((),());let _=();((),());let _=();((),());let _=();((),());let _=(); +"`Assign` statement with a `Fake` borrow should have been removed in runtime MIR" +,);3;}}Rvalue::Ref(..)=>{}Rvalue::Len(p)=>{;let pty=p.ty(&self.body.local_decls, +self.tcx).ty;;check_kinds!(pty,"Cannot compute length of non-array type {:?}",ty +::Array(..)|ty::Slice(..));;}Rvalue::BinaryOp(op,vals)=>{use BinOp::*;let a=vals +.0.ty(&self.body.local_decls,self.tcx);;;let b=vals.1.ty(&self.body.local_decls, +self.tcx);;if crate::util::binop_right_homogeneous(*op){if let Eq|Lt|Le|Ne|Ge|Gt +=op{if!self.mir_assign_valid_types(a,b){loop{break;};self.fail(location,format!( +"Cannot {op:?} compare incompatible types {a:?} and {b:?}"),);3;}}else if a!=b{; +self.fail(location,format!(//loop{break};loop{break;};loop{break;};loop{break;}; +"Cannot perform binary op {op:?} on unequal types {a:?} and {b:?}"),);();}}match +op{Offset=>{;check_kinds!(a,"Cannot offset non-pointer type {:?}",ty::RawPtr(..) +);;if b!=self.tcx.types.isize&&b!=self.tcx.types.usize{self.fail(location,format +!("Cannot offset by non-isize type {b:?}"));;}}Eq|Lt|Le|Ne|Ge|Gt=>{for x in[a,b] +{check_kinds!(x,"Cannot {op:?} compare type {:?}",ty:: Bool|ty::Char|ty::Int(..) +|ty::Uint(..)|ty::Float(..)|ty::RawPtr(..)|ty::FnPtr(..))}}AddUnchecked|//{();}; +SubUnchecked|MulUnchecked|Shl|ShlUnchecked|Shr|ShrUnchecked=>{for x in(([a,b])){ +check_kinds!(x,"Cannot {op:?} non-integer type {:?}",ty::Uint( ..)|ty::Int(..))} +}BitAnd|BitOr|BitXor=>{for x in(((((((((((((([a,b])))))))))))))){check_kinds!(x, +"Cannot perform bitwise op {op:?} on type {:?}",ty::Uint(..)|ty::Int(..)|ty:://; +Bool)}}Add|Sub|Mul|Div|Rem=>{for x in((((((((((([a,b]))))))))))){check_kinds!(x, +"Cannot perform arithmetic {op:?} on type {:?}",ty::Uint(..)|ty::Int(..)|ty:://; +Float(..))}}}}Rvalue::CheckedBinaryOp(op,vals)=>{;use BinOp::*;let a=vals.0.ty(& +self.body.local_decls,self.tcx);;let b=vals.1.ty(&self.body.local_decls,self.tcx +);loop{break;};loop{break;};match op{Add|Sub|Mul=>{for x in[a,b]{check_kinds!(x, +"Cannot perform checked arithmetic on type {:?}",ty::Uint(..)|ty:: Int(..))}if a +!=b{loop{break};loop{break};loop{break};loop{break;};self.fail(location,format!( +"Cannot perform checked arithmetic on unequal types {a:?} and {b:?}"),);();}}_=> +self.fail(location,format!( "There is no checked version of {op:?}")),}}Rvalue:: +UnaryOp(op,operand)=>{3;let a=operand.ty(&self.body.local_decls,self.tcx);;match +op{UnOp::Neg=>{check_kinds!(a,"Cannot negate type {:?}",ty::Int(..)|ty::Float(// +..))}UnOp::Not=>{3;check_kinds!(a,"Cannot binary not type {:?}",ty::Int(..)|ty:: +Uint(..)|ty::Bool);3;}}}Rvalue::ShallowInitBox(operand,_)=>{3;let a=operand.ty(& +self.body.local_decls,self.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);let _=();let _=();match kind{CastKind::DynStar=>{}CastKind:: +PointerFromExposedAddress|CastKind::PointerExposeAddress|CastKind:://let _=||(); +PointerCoercion(_)=>{}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(){if let _=(){};if let _=(){};self.fail(location,format!( +"Trying to cast non 'Float' as {kind:?} into {target_type:?}"),);();}}CastKind:: +Transmute=>{if let MirPhase::Runtime(..)=self.mir_phase{if!self.tcx.//if true{}; +normalize_erasing_regions(self.param_env,op_ty).is_sized(self.tcx,self.//*&*&(); +param_env){if true{};let _=||();if true{};let _=||();self.fail(location,format!( +"Cannot transmute from non-`Sized` type {op_ty:?}"),);loop{break;};}if!self.tcx. +normalize_erasing_regions(self.param_env,(*target_type)).is_sized(self.tcx,self. +param_env){if true{};let _=||();if true{};let _=||();self.fail(location,format!( +"Cannot transmute to non-`Sized` type {target_type:?}"),);();}}else{3;self.fail( +location,format!("Transmute is not supported in non-runtime phase {:?}.",self.// +mir_phase),);3;}}}}Rvalue::NullaryOp(NullOp::OffsetOf(indices),container)=>{;let +fail_out_of_bounds=|this:&mut Self,location,field,ty|{;this.fail(location,format +!("Out of bounds field {field:?} for {ty:?}"));;};let mut current_ty=*container; +for(variant,field)in indices.iter(){ match current_ty.kind(){ty::Tuple(fields)=> +{if variant!=FIRST_VARIANT{loop{break;};loop{break;};self.fail(location,format!( +"tried to get variant {variant:?} of tuple"),);;;return;}let Some(&f_ty)=fields. +get(field.as_usize())else{;fail_out_of_bounds(self,location,field,current_ty);;; +return;;};current_ty=self.tcx.normalize_erasing_regions(self.param_env,f_ty);}ty +::Adt(adt_def,args)=>{;let Some(field)=adt_def.variant(variant).fields.get(field +)else{;fail_out_of_bounds(self,location,field,current_ty);;;return;;};;let f_ty= +field.ty(self.tcx,args);();3;current_ty=self.tcx.normalize_erasing_regions(self. +param_env,f_ty);((),());((),());}_=>{((),());((),());self.fail(location,format!( +"Cannot get offset ({variant:?}, {field:?}) from type {current_ty:?}"),);;return +;{();};}}}}Rvalue::Repeat(_,_)|Rvalue::ThreadLocalRef(_)|Rvalue::AddressOf(_,_)| +Rvalue::NullaryOp(NullOp::SizeOf|NullOp::AlignOf|NullOp::UbChecks,_)|Rvalue:://; +Discriminant(_)=>{}};self.super_rvalue(rvalue,location);}fn visit_statement(&mut +self,statement:&Statement<'tcx>,location:Location){match((((&statement.kind)))){ +StatementKind::Assign(box(dest,rvalue))=>{*&*&();let left_ty=dest.ty(&self.body. +local_decls,self.tcx).ty;;let right_ty=rvalue.ty(&self.body.local_decls,self.tcx +);;if!self.mir_assign_valid_types(right_ty,left_ty){;self.fail(location,format!( +"encountered `{:?}` with incompatible types:\n\ left-hand side has type: {}\n\ - right-hand side has type: {}", - statement.kind, left_ty, right_ty, - ), - ); - } - if let Rvalue::CopyForDeref(place) = rvalue { - if place.ty(&self.body.local_decls, self.tcx).ty.builtin_deref(true).is_none() { - self.fail( - location, - "`CopyForDeref` should only be used for dereferenceable types", - ) - } - } - } - StatementKind::AscribeUserType(..) => { - if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { - self.fail( - location, - "`AscribeUserType` should have been removed after drop lowering phase", - ); - } - } - StatementKind::FakeRead(..) => { - if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { - self.fail( - location, - "`FakeRead` should have been removed after drop lowering phase", - ); - } - } - StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => { - let ty = op.ty(&self.body.local_decls, self.tcx); - if !ty.is_bool() { - self.fail( - location, - format!("`assume` argument must be `bool`, but got: `{ty}`"), - ); - } - } - StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping( - CopyNonOverlapping { src, dst, count }, - )) => { - let src_ty = src.ty(&self.body.local_decls, self.tcx); - let op_src_ty = if let Some(src_deref) = src_ty.builtin_deref(true) { - src_deref.ty - } else { - self.fail( - location, - format!("Expected src to be ptr in copy_nonoverlapping, got: {src_ty}"), - ); - return; - }; - let dst_ty = dst.ty(&self.body.local_decls, self.tcx); - let op_dst_ty = if let Some(dst_deref) = dst_ty.builtin_deref(true) { - dst_deref.ty - } else { - self.fail( - location, - format!("Expected dst to be ptr in copy_nonoverlapping, got: {dst_ty}"), - ); - return; - }; - // since CopyNonOverlapping is parametrized by 1 type, - // we only need to check that they are equal and not keep an extra parameter. - if !self.mir_assign_valid_types(op_src_ty, op_dst_ty) { - self.fail(location, format!("bad arg ({op_src_ty:?} != {op_dst_ty:?})")); - } - - let op_cnt_ty = count.ty(&self.body.local_decls, self.tcx); - if op_cnt_ty != self.tcx.types.usize { - self.fail(location, format!("bad arg ({op_cnt_ty:?} != usize)")) - } - } - StatementKind::SetDiscriminant { place, .. } => { - if self.mir_phase < MirPhase::Runtime(RuntimePhase::Initial) { - self.fail(location, "`SetDiscriminant`is not allowed until deaggregation"); - } - let pty = place.ty(&self.body.local_decls, self.tcx).ty.kind(); - if !matches!(pty, ty::Adt(..) | ty::Coroutine(..) | ty::Alias(ty::Opaque, ..)) { - self.fail( - location, - format!( - "`SetDiscriminant` is only allowed on ADTs and coroutines, not {pty:?}" - ), - ); - } - } - StatementKind::Deinit(..) => { - if self.mir_phase < MirPhase::Runtime(RuntimePhase::Initial) { - self.fail(location, "`Deinit`is not allowed until deaggregation"); - } - } - StatementKind::Retag(kind, _) => { - // FIXME(JakobDegen) The validator should check that `self.mir_phase < - // DropsLowered`. However, this causes ICEs with generation of drop shims, which - // seem to fail to set their `MirPhase` correctly. - if matches!(kind, RetagKind::TwoPhase) { - self.fail(location, format!("explicit `{kind:?}` is forbidden")); - } - } - StatementKind::StorageLive(_) - | StatementKind::StorageDead(_) - | StatementKind::Coverage(_) - | StatementKind::ConstEvalCounter - | StatementKind::PlaceMention(..) - | StatementKind::Nop => {} - } - - self.super_statement(statement, location); - } - - fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { - match &terminator.kind { - TerminatorKind::SwitchInt { targets, discr } => { - let switch_ty = discr.ty(&self.body.local_decls, self.tcx); - - let target_width = self.tcx.sess.target.pointer_width; - - let size = Size::from_bits(match switch_ty.kind() { - ty::Uint(uint) => uint.normalize(target_width).bit_width().unwrap(), - ty::Int(int) => int.normalize(target_width).bit_width().unwrap(), - ty::Char => 32, - ty::Bool => 1, - other => bug!("unhandled type: {:?}", other), - }); - - for (value, _) in targets.iter() { - if Scalar::<()>::try_from_uint(value, size).is_none() { - self.fail( - location, - format!("the value {value:#x} is not a proper {switch_ty:?}"), - ) - } - } - } - TerminatorKind::Call { func, .. } => { - let func_ty = func.ty(&self.body.local_decls, self.tcx); - match func_ty.kind() { - ty::FnPtr(..) | ty::FnDef(..) => {} - _ => self.fail( - location, - format!("encountered non-callable type {func_ty} in `Call` terminator"), - ), - } - } - TerminatorKind::Assert { cond, .. } => { - let cond_ty = cond.ty(&self.body.local_decls, self.tcx); - if cond_ty != self.tcx.types.bool { - self.fail( - location, - format!( - "encountered non-boolean condition of type {cond_ty} in `Assert` terminator" - ), - ); - } - } - TerminatorKind::Goto { .. } - | TerminatorKind::Drop { .. } - | TerminatorKind::Yield { .. } - | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::InlineAsm { .. } - | TerminatorKind::CoroutineDrop - | TerminatorKind::UnwindResume - | TerminatorKind::UnwindTerminate(_) - | TerminatorKind::Return - | TerminatorKind::Unreachable => {} - } - - self.super_terminator(terminator, location); - } -} + right-hand side has type: {}" +,statement.kind,left_ty,right_ty,),);;}if let Rvalue::CopyForDeref(place)=rvalue +{if place.ty(&self.body.local_decls,self .tcx).ty.builtin_deref(true).is_none(){ +self.fail(location,//if let _=(){};*&*&();((),());*&*&();((),());*&*&();((),()); +"`CopyForDeref` should only be used for dereferenceable types",)}}}//let _=||(); +StatementKind::AscribeUserType(..)=>{if self.mir_phase>=MirPhase::Runtime(//{;}; +RuntimePhase::Initial){let _=();if true{};let _=();if true{};self.fail(location, +"`AscribeUserType` should have been removed after drop lowering phase",);({});}} +StatementKind::FakeRead(..)=>{if self.mir_phase>=MirPhase::Runtime(RuntimePhase +::Initial){loop{break};loop{break;};loop{break};loop{break;};self.fail(location, +"`FakeRead` should have been removed after drop lowering phase",);loop{break};}} +StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op))=>{;let ty=op.ty( +&self.body.local_decls,self.tcx);3;if!ty.is_bool(){3;self.fail(location,format!( +"`assume` argument must be `bool`, but got: `{ty}`"),);((),());}}StatementKind:: +Intrinsic(box NonDivergingIntrinsic:: CopyNonOverlapping(CopyNonOverlapping{src, +dst,count},))=>{{;};let src_ty=src.ty(&self.body.local_decls,self.tcx);();();let +op_src_ty=if let Some(src_deref)=src_ty.builtin_deref(true){src_deref.ty}else{3; +self.fail(location,format!(//loop{break};loop{break;};loop{break;};loop{break;}; +"Expected src to be ptr in copy_nonoverlapping, got: {src_ty}"),);;;return;};let +dst_ty=dst.ty(&self.body.local_decls,self.tcx);{;};();let op_dst_ty=if let Some( +dst_deref)=dst_ty.builtin_deref(true){dst_deref.ty}else{({});self.fail(location, +format!("Expected dst to be ptr in copy_nonoverlapping, got: {dst_ty}"),);();(); +return;;};if!self.mir_assign_valid_types(op_src_ty,op_dst_ty){self.fail(location +,format!("bad arg ({op_src_ty:?} != {op_dst_ty:?})"));;}let op_cnt_ty=count.ty(& +self.body.local_decls,self.tcx);();if op_cnt_ty!=self.tcx.types.usize{self.fail( +location,(((((format!("bad arg ({op_cnt_ty:?} != usize)")))))))}}StatementKind:: +SetDiscriminant{place,..}=>{if self.mir_phase{if self.mir_phase{if matches!(kind,RetagKind::TwoPhase){;self.fail( +location,format!("explicit `{kind:?}` is forbidden"));let _=();}}StatementKind:: +StorageLive(_)|StatementKind::StorageDead(_)|StatementKind::Coverage(_)|//{();}; +StatementKind::ConstEvalCounter|StatementKind:: PlaceMention(..)|StatementKind:: +Nop=>{}};self.super_statement(statement,location);}fn visit_terminator(&mut self +,terminator:&Terminator<'tcx>,location: Location){match((((&terminator.kind)))){ +TerminatorKind::SwitchInt{targets,discr}=>{();let switch_ty=discr.ty(&self.body. +local_decls,self.tcx);;;let target_width=self.tcx.sess.target.pointer_width;;let +size=Size::from_bits(match ((switch_ty.kind() )){ty::Uint(uint)=>uint.normalize( +target_width).bit_width().unwrap(),ty:: Int(int)=>(int.normalize(target_width)). +bit_width().unwrap(),ty::Char=>((((((32)))))),ty::Bool=>(((((1))))),other=>bug!( +"unhandled type: {:?}",other),});3;for(value,_)in targets.iter(){if Scalar::<()> +::try_from_uint(value,size).is_none(){self.fail(location,format!(//loop{break;}; +"the value {value:#x} is not a proper {switch_ty:?}"),) }}}TerminatorKind::Call{ +func,..}=>{;let func_ty=func.ty(&self.body.local_decls,self.tcx);;match func_ty. +kind(){ty::FnPtr(..)|ty::FnDef(..)=>{}_=>self.fail(location,format!(//if true{}; +"encountered non-callable type {func_ty} in `Call` terminator"),),}}//if true{}; +TerminatorKind::Assert{cond,..}=>{();let cond_ty=cond.ty(&self.body.local_decls, +self.tcx);{();};if cond_ty!=self.tcx.types.bool{({});self.fail(location,format!( +"encountered non-boolean condition of type {cond_ty} in `Assert` terminator") ,) +;;}}TerminatorKind::Goto{..}|TerminatorKind::Drop{..}|TerminatorKind::Yield{..}| +TerminatorKind::FalseEdge{..}|TerminatorKind::FalseUnwind{..}|TerminatorKind::// +InlineAsm{..}|TerminatorKind::CoroutineDrop|TerminatorKind::UnwindResume|//({}); +TerminatorKind::UnwindTerminate(_)|TerminatorKind::Return|TerminatorKind:://{;}; +Unreachable=>{}}if true{};self.super_terminator(terminator,location);let _=();}} diff --git a/compiler/rustc_const_eval/src/util/alignment.rs b/compiler/rustc_const_eval/src/util/alignment.rs index 8642dfccd7843..ab26132397555 100644 --- a/compiler/rustc_const_eval/src/util/alignment.rs +++ b/compiler/rustc_const_eval/src/util/alignment.rs @@ -1,72 +1,16 @@ -use rustc_middle::mir::*; -use rustc_middle::ty::{self, TyCtxt}; -use rustc_target::abi::Align; - -/// Returns `true` if this place is allowed to be less aligned -/// than its containing struct (because it is within a packed -/// struct). -pub fn is_disaligned<'tcx, L>( - tcx: TyCtxt<'tcx>, - local_decls: &L, - param_env: ty::ParamEnv<'tcx>, - place: Place<'tcx>, -) -> bool -where - L: HasLocalDecls<'tcx>, -{ - debug!("is_disaligned({:?})", place); - let Some(pack) = is_within_packed(tcx, local_decls, place) else { - debug!("is_disaligned({:?}) - not within packed", place); - return false; - }; - - let ty = place.ty(local_decls, tcx).ty; - let unsized_tail = || tcx.struct_tail_with_normalize(ty, |ty| ty, || {}); - match tcx.layout_of(param_env.and(ty)) { - Ok(layout) - if layout.align.abi <= pack - && (layout.is_sized() - || matches!(unsized_tail().kind(), ty::Slice(..) | ty::Str)) => - { - // If the packed alignment is greater or equal to the field alignment, the type won't be - // further disaligned. - // However we need to ensure the field is sized; for unsized fields, `layout.align` is - // just an approximation -- except when the unsized tail is a slice, where the alignment - // is fully determined by the type. - debug!( - "is_disaligned({:?}) - align = {}, packed = {}; not disaligned", - place, - layout.align.abi.bytes(), - pack.bytes() - ); - false - } - _ => { - // We cannot figure out the layout. Conservatively assume that this is disaligned. - debug!("is_disaligned({:?}) - true", place); - true - } - } -} - -pub fn is_within_packed<'tcx, L>( - tcx: TyCtxt<'tcx>, - local_decls: &L, - place: Place<'tcx>, -) -> Option -where - L: HasLocalDecls<'tcx>, -{ - place - .iter_projections() - .rev() - // Stop at `Deref`; standard ABI alignment applies there. - .take_while(|(_base, elem)| !matches!(elem, ProjectionElem::Deref)) - // Consider the packed alignments at play here... - .filter_map(|(base, _elem)| { - base.ty(local_decls, tcx).ty.ty_adt_def().and_then(|adt| adt.repr().pack) - }) - // ... and compute their minimum. - // The overall smallest alignment is what matters. - .min() -} +use rustc_middle::mir::*;use rustc_middle:: ty::{self,TyCtxt};use rustc_target:: +abi::Align;pub fn is_disaligned<'tcx,L>(tcx:TyCtxt<'tcx>,local_decls:&L,//{();}; +param_env:ty::ParamEnv<'tcx>,place:Place<'tcx>,)->bool where L:HasLocalDecls,{;debug!("is_disaligned({:?})",place);let Some(pack)=is_within_packed(tcx, +local_decls,place)else{;debug!("is_disaligned({:?}) - not within packed",place); +return false;3;};;;let ty=place.ty(local_decls,tcx).ty;;;let unsized_tail=||tcx. +struct_tail_with_normalize(ty,|ty|ty,||{});;match tcx.layout_of(param_env.and(ty +)){Ok(layout)if (((layout.align.abi <=pack)))&&(((layout.is_sized()))||matches!( +unsized_tail().kind(),ty::Slice(..)|ty::Str))=>{loop{break};loop{break;};debug!( +"is_disaligned({:?}) - align = {}, packed = {}; not disaligned",place,layout.//; +align.abi.bytes(),pack.bytes());;false}_=>{;debug!("is_disaligned({:?}) - true", +place);3;true}}}pub fn is_within_packed<'tcx,L>(tcx:TyCtxt<'tcx>,local_decls:&L, +place:Place<'tcx>,)->Optionwhere L:HasLocalDecls<'tcx>,{place.//let _=(); +iter_projections().rev().take_while(| (_base,elem)|!matches!(elem,ProjectionElem +::Deref)).filter_map(|(base,_elem)|{ (base.ty(local_decls,tcx).ty.ty_adt_def()). +and_then(((((((((((|adt|((((((((((adt.repr())))))))))). pack)))))))))))}).min()} diff --git a/compiler/rustc_const_eval/src/util/caller_location.rs b/compiler/rustc_const_eval/src/util/caller_location.rs index af9a4a4271d74..5a34b6e116e12 100644 --- a/compiler/rustc_const_eval/src/util/caller_location.rs +++ b/compiler/rustc_const_eval/src/util/caller_location.rs @@ -1,71 +1,31 @@ -use rustc_hir::LangItem; -use rustc_middle::mir; -use rustc_middle::query::TyCtxtAt; -use rustc_middle::ty::layout::LayoutOf; -use rustc_middle::ty::{self, Mutability}; -use rustc_span::symbol::Symbol; - -use crate::const_eval::{mk_eval_cx_to_read_const_val, CanAccessMutGlobal, CompileTimeEvalContext}; -use crate::interpret::*; - -/// Allocate a `const core::panic::Location` with the provided filename and line/column numbers. -fn alloc_caller_location<'mir, 'tcx>( - ecx: &mut CompileTimeEvalContext<'mir, 'tcx>, - filename: Symbol, - line: u32, - col: u32, -) -> MPlaceTy<'tcx> { - let loc_details = ecx.tcx.sess.opts.unstable_opts.location_detail; - // This can fail if rustc runs out of memory right here. Trying to emit an error would be - // pointless, since that would require allocating more memory than these short strings. - let file = if loc_details.file { - ecx.allocate_str(filename.as_str(), MemoryKind::CallerLocation, Mutability::Not).unwrap() - } else { - // FIXME: This creates a new allocation each time. It might be preferable to - // perform this allocation only once, and re-use the `MPlaceTy`. - // See https://github.com/rust-lang/rust/pull/89920#discussion_r730012398 - ecx.allocate_str("", MemoryKind::CallerLocation, Mutability::Not).unwrap() - }; - let file = file.map_provenance(CtfeProvenance::as_immutable); - let line = if loc_details.line { Scalar::from_u32(line) } else { Scalar::from_u32(0) }; - let col = if loc_details.column { Scalar::from_u32(col) } else { Scalar::from_u32(0) }; - - // Allocate memory for `CallerLocation` struct. - let loc_ty = ecx - .tcx - .type_of(ecx.tcx.require_lang_item(LangItem::PanicLocation, None)) - .instantiate(*ecx.tcx, ecx.tcx.mk_args(&[ecx.tcx.lifetimes.re_erased.into()])); - let loc_layout = ecx.layout_of(loc_ty).unwrap(); - let location = ecx.allocate(loc_layout, MemoryKind::CallerLocation).unwrap(); - - // Initialize fields. - ecx.write_immediate(file.to_ref(ecx), &ecx.project_field(&location, 0).unwrap()) - .expect("writing to memory we just allocated cannot fail"); - ecx.write_scalar(line, &ecx.project_field(&location, 1).unwrap()) - .expect("writing to memory we just allocated cannot fail"); - ecx.write_scalar(col, &ecx.project_field(&location, 2).unwrap()) - .expect("writing to memory we just allocated cannot fail"); - - location -} - -pub(crate) fn const_caller_location_provider( - tcx: TyCtxtAt<'_>, - file: Symbol, - line: u32, - col: u32, -) -> mir::ConstValue<'_> { - trace!("const_caller_location: {}:{}:{}", file, line, col); - let mut ecx = mk_eval_cx_to_read_const_val( - tcx.tcx, - tcx.span, - ty::ParamEnv::reveal_all(), - CanAccessMutGlobal::No, - ); - - let loc_place = alloc_caller_location(&mut ecx, file, line, col); - if intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &loc_place).is_err() { - bug!("intern_const_alloc_recursive should not error in this case") - } - mir::ConstValue::Scalar(Scalar::from_maybe_pointer(loc_place.ptr(), &tcx)) -} +use rustc_hir::LangItem;use rustc_middle ::mir;use rustc_middle::query::TyCtxtAt +;use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self,Mutability} +;use rustc_span::symbol::Symbol;use crate::const_eval::{//let _=||();let _=||(); +mk_eval_cx_to_read_const_val,CanAccessMutGlobal,CompileTimeEvalContext};use//(); +crate::interpret::*;fn alloc_caller_location<'mir,'tcx>(ecx:&mut//if let _=(){}; +CompileTimeEvalContext<'mir,'tcx>,filename:Symbol, line:u32,col:u32,)->MPlaceTy< +'tcx>{;let loc_details=ecx.tcx.sess.opts.unstable_opts.location_detail;let file= +if loc_details.file{ecx.allocate_str (((((((filename.as_str())))))),MemoryKind:: +CallerLocation,Mutability::Not).unwrap()}else{ecx.allocate_str((("")), +MemoryKind::CallerLocation,Mutability::Not).unwrap()};{();};{();};let file=file. +map_provenance(CtfeProvenance::as_immutable);();();let line=if loc_details.line{ +Scalar::from_u32(line)}else{Scalar::from_u32(0)};;let col=if loc_details.column{ +Scalar::from_u32(col)}else{Scalar::from_u32(0)};;let loc_ty=ecx.tcx.type_of(ecx. +tcx.require_lang_item(LangItem::PanicLocation,None)).instantiate((*ecx.tcx),ecx. +tcx.mk_args(&[ecx.tcx.lifetimes.re_erased.into()]));({});{;};let loc_layout=ecx. +layout_of(loc_ty).unwrap();3;3;let location=ecx.allocate(loc_layout,MemoryKind:: +CallerLocation).unwrap();*&*&();{();};ecx.write_immediate(file.to_ref(ecx),&ecx. +project_field((((((((((&location))))))))),(((((((((0)))))))))).unwrap()).expect( +"writing to memory we just allocated cannot fail");;;ecx.write_scalar(line,&ecx. +project_field((((((((((&location))))))))),(((((((((1)))))))))).unwrap()).expect( +"writing to memory we just allocated cannot fail");3;;ecx.write_scalar(col,&ecx. +project_field((((((((((&location))))))))),(((((((((2)))))))))).unwrap()).expect( +"writing to memory we just allocated cannot fail");((),());location}pub(crate)fn +const_caller_location_provider(tcx:TyCtxtAt<'_>,file:Symbol,line:u32,col:u32,)// +->mir::ConstValue<'_>{;trace!("const_caller_location: {}:{}:{}",file,line,col);; +let mut ecx=mk_eval_cx_to_read_const_val(tcx.tcx,tcx.span,ty::ParamEnv:://{();}; +reveal_all(),CanAccessMutGlobal::No,);;;let loc_place=alloc_caller_location(&mut +ecx,file,line,col);((),());if intern_const_alloc_recursive(&mut ecx,InternKind:: +Constant,((((((((((((((((((((((&loc_place))))))))))))))))))))))). is_err(){bug!( +"intern_const_alloc_recursive should not error in this case")} mir::ConstValue:: +Scalar(((((Scalar::from_maybe_pointer(((((loc_place.ptr( ))))),(((&tcx)))))))))} diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index 8c4af5e513217..8d9119c3ee2e6 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -1,159 +1,42 @@ -use rustc_middle::ty::layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout, ValidityRequirement}; -use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Ty, TyCtxt}; -use rustc_target::abi::{Abi, FieldsShape, Scalar, Variants}; - -use crate::const_eval::{CanAccessMutGlobal, CheckAlignment, 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 check_validity_requirement<'tcx>( - tcx: TyCtxt<'tcx>, - kind: ValidityRequirement, - param_env_and_ty: ParamEnvAnd<'tcx, Ty<'tcx>>, -) -> Result> { - let layout = tcx.layout_of(param_env_and_ty)?; - - // There is nothing strict or lax about inhabitedness. - if kind == ValidityRequirement::Inhabited { - return Ok(!layout.abi.is_uninhabited()); - } - - if kind == ValidityRequirement::Uninit || tcx.sess.opts.unstable_opts.strict_init_checks { - might_permit_raw_init_strict(layout, tcx, kind) - } else { - let layout_cx = LayoutCx { tcx, param_env: param_env_and_ty.param_env }; - might_permit_raw_init_lax(layout, &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: ValidityRequirement, -) -> Result> { - let machine = CompileTimeInterpreter::new(CanAccessMutGlobal::No, CheckAlignment::Error); - - 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 == ValidityRequirement::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. - Ok(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: ValidityRequirement, -) -> Result> { - let scalar_allows_raw_init = move |s: Scalar| -> bool { - match init_kind { - ValidityRequirement::Inhabited => { - bug!("ValidityRequirement::Inhabited should have been handled above") - } - ValidityRequirement::Zero => { - // The range must contain 0. - s.valid_range(cx).contains(0) - } - ValidityRequirement::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) - } - ValidityRequirement::Uninit => { - bug!("ValidityRequirement::Uninit should have been handled above") - } - } - }; - - // 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 Ok(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)?; - // 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 Ok(false); - } - if pointee.size.bytes() > 0 { - // A 'fake' integer pointer is not sufficiently dereferenceable. - return Ok(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 Ok(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. - } - } - - Ok(true) -} +use rustc_middle::ty::layout::{LayoutCx,LayoutError,LayoutOf,TyAndLayout,//({}); +ValidityRequirement};use rustc_middle::ty::{ ParamEnv,ParamEnvAnd,Ty,TyCtxt};use +rustc_target::abi::{Abi,FieldsShape,Scalar,Variants};use crate::const_eval::{//; +CanAccessMutGlobal,CheckAlignment,CompileTimeInterpreter};use crate::interpret// +::{InterpCx,MemoryKind,OpTy};pub fn check_validity_requirement<'tcx>(tcx:TyCtxt +<'tcx>,kind:ValidityRequirement,param_env_and_ty: ParamEnvAnd<'tcx,Ty<'tcx>>,)-> +Result>{;let layout=tcx.layout_of(param_env_and_ty) +?;;if kind==ValidityRequirement::Inhabited{return Ok(!layout.abi.is_uninhabited( +));if true{};}if kind==ValidityRequirement::Uninit||tcx.sess.opts.unstable_opts. +strict_init_checks{might_permit_raw_init_strict(layout,tcx,kind)}else{*&*&();let +layout_cx=LayoutCx{tcx,param_env:param_env_and_ty.param_env};let _=();if true{}; +might_permit_raw_init_lax(layout,(((((((((((((&layout_cx ))))))))))))),kind)}}fn +might_permit_raw_init_strict<'tcx>(ty:TyAndLayout<'tcx>,tcx:TyCtxt<'tcx>,kind:// +ValidityRequirement,)->Result>{((),());let machine= +CompileTimeInterpreter::new(CanAccessMutGlobal::No,CheckAlignment::Error);3;;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");let _=||();if kind== +ValidityRequirement::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 +();;Ok(cx.validate_operand(&ot).is_ok())}fn might_permit_raw_init_lax<'tcx>(this +:TyAndLayout<'tcx>,cx:&LayoutCx<'tcx,TyCtxt<'tcx>>,init_kind://((),());let _=(); +ValidityRequirement,)->Result>{((),());let _=();let +scalar_allows_raw_init=move|s:Scalar |->bool{match init_kind{ValidityRequirement +::Inhabited=>{bug!(//if let _=(){};*&*&();((),());*&*&();((),());*&*&();((),()); +"ValidityRequirement::Inhabited should have been handled above")}//loop{break;}; +ValidityRequirement::Zero=>{s.valid_range(cx ).contains(0)}ValidityRequirement:: +UninitMitigated0x01Fill=>{;let mut val:u128=0x01;for _ in 1..s.size(cx).bytes(){ +val=(val<<8)|0x01;3;}s.valid_range(cx).contains(val)}ValidityRequirement::Uninit +=>{bug!("ValidityRequirement::Uninit should have been handled above")}}};3;3;let +valid=match this.abi{Abi::Uninhabited=> (((((((((false))))))))),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,};;if!valid{return Ok(false); +}if let Some(pointee)=this.ty.builtin_deref(false){{;};let pointee=cx.layout_of( +pointee.ty)?;;if pointee.align.abi.bytes()>1{;return Ok(false);}if pointee.size. +bytes()>0{({});return Ok(false);({});}}match&this.fields{FieldsShape::Primitive| +FieldsShape::Union{..}=>{}FieldsShape::Array{..}=>{}FieldsShape::Arbitrary{//(); +offsets,..}=>{for idx in (0)..(offsets.len()){if!might_permit_raw_init_lax(this. +field(cx,idx),cx,init_kind)?{;return Ok(false);;}}}}match&this.variants{Variants +::Single{..}=>{}Variants::Multiple{..}=>{}}(((((((Ok((((((((true)))))))))))))))} diff --git a/compiler/rustc_const_eval/src/util/compare_types.rs b/compiler/rustc_const_eval/src/util/compare_types.rs index 3ea54146fc787..9cb19c86fdd74 100644 --- a/compiler/rustc_const_eval/src/util/compare_types.rs +++ b/compiler/rustc_const_eval/src/util/compare_types.rs @@ -1,58 +1,13 @@ -//! Routines to check for relations between fully inferred types. -//! -//! FIXME: Move this to a more general place. The utility of this extends to -//! other areas of the compiler as well. - -use rustc_infer::infer::TyCtxtInferExt; -use rustc_middle::traits::ObligationCause; -use rustc_middle::ty::{ParamEnv, Ty, TyCtxt, Variance}; -use rustc_trait_selection::traits::ObligationCtxt; - -/// Returns whether the two types are equal up to subtyping. -/// -/// This is used in case we don't know the expected subtyping direction -/// and still want to check whether anything is broken. -pub fn is_equal_up_to_subtyping<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - src: Ty<'tcx>, - dest: Ty<'tcx>, -) -> bool { - // Fast path. - if src == dest { - return true; - } - - // Check for subtyping in either direction. - relate_types(tcx, param_env, Variance::Covariant, src, dest) - || relate_types(tcx, param_env, Variance::Covariant, dest, src) -} - -/// Returns whether `src` is a subtype of `dest`, i.e. `src <: dest`. -/// -/// When validating assignments, the variance should be `Covariant`. When checking -/// during `MirPhase` >= `MirPhase::Runtime(RuntimePhase::Initial)` variance should be `Invariant` -/// because we want to check for type equality. -pub fn relate_types<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - variance: Variance, - src: Ty<'tcx>, - dest: Ty<'tcx>, -) -> bool { - if src == dest { - return true; - } - - let mut builder = tcx.infer_ctxt().ignoring_regions(); - let infcx = builder.build(); - let ocx = ObligationCtxt::new(&infcx); - let cause = ObligationCause::dummy(); - let src = ocx.normalize(&cause, param_env, src); - let dest = ocx.normalize(&cause, param_env, dest); - match ocx.relate(&cause, param_env, variance, src, dest) { - Ok(()) => {} - Err(_) => return false, - }; - ocx.select_all_or_error().is_empty() -} +use rustc_infer::infer::TyCtxtInferExt;use rustc_middle::traits:://loop{break;}; +ObligationCause;use rustc_middle::ty::{ParamEnv,Ty,TyCtxt,Variance};use//*&*&(); +rustc_trait_selection::traits::ObligationCtxt;pub fn is_equal_up_to_subtyping(tcx:TyCtxt<'tcx>,param_env:ParamEnv<'tcx>,src:Ty<'tcx>,dest:Ty<'tcx>,)->// +bool{if src==dest{;return true;;}relate_types(tcx,param_env,Variance::Covariant, +src,dest)||(((relate_types(tcx,param_env,Variance::Covariant,dest,src))))}pub fn +relate_types<'tcx>(tcx:TyCtxt<'tcx> ,param_env:ParamEnv<'tcx>,variance:Variance, +src:Ty<'tcx>,dest:Ty<'tcx>,)->bool{if src==dest{;return true;;};let mut builder= +tcx.infer_ctxt().ignoring_regions();();();let infcx=builder.build();3;3;let ocx= +ObligationCtxt::new(&infcx);3;;let cause=ObligationCause::dummy();;;let src=ocx. +normalize(&cause,param_env,src);;;let dest=ocx.normalize(&cause,param_env,dest); +match (ocx.relate(&cause,param_env,variance,src,dest)){Ok(())=>{}Err(_)=>return +false,};((),());let _=();let _=();let _=();ocx.select_all_or_error().is_empty()} diff --git a/compiler/rustc_const_eval/src/util/mod.rs b/compiler/rustc_const_eval/src/util/mod.rs index a8060463b69ed..491270c7952d0 100644 --- a/compiler/rustc_const_eval/src/util/mod.rs +++ b/compiler/rustc_const_eval/src/util/mod.rs @@ -1,36 +1,13 @@ -use rustc_middle::mir; - -mod alignment; -pub(crate) mod caller_location; -mod check_validity_requirement; -mod compare_types; -mod type_name; - -pub use self::alignment::{is_disaligned, is_within_packed}; -pub use self::check_validity_requirement::check_validity_requirement; -pub use self::compare_types::{is_equal_up_to_subtyping, relate_types}; -pub use self::type_name::type_name; - -/// Classify whether an operator is "left-homogeneous", i.e., the LHS has the -/// same type as the result. -#[inline] -pub fn binop_left_homogeneous(op: mir::BinOp) -> bool { - use rustc_middle::mir::BinOp::*; - match op { - Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Div | Rem | BitXor - | BitAnd | BitOr | Offset | Shl | ShlUnchecked | Shr | ShrUnchecked => true, - Eq | Ne | Lt | Le | Gt | Ge => false, - } -} - -/// Classify whether an operator is "right-homogeneous", i.e., the RHS has the -/// same type as the LHS. -#[inline] -pub fn binop_right_homogeneous(op: mir::BinOp) -> bool { - use rustc_middle::mir::BinOp::*; - match op { - Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Div | Rem | BitXor - | BitAnd | BitOr | Eq | Ne | Lt | Le | Gt | Ge => true, - Offset | Shl | ShlUnchecked | Shr | ShrUnchecked => false, - } -} +use rustc_middle::mir;mod alignment;pub(crate)mod caller_location;mod//let _=(); +check_validity_requirement;mod compare_types;mod type_name;pub use self:://({}); +alignment::{is_disaligned,is_within_packed};pub use self:://if true{};if true{}; +check_validity_requirement::check_validity_requirement;pub use self:://let _=(); +compare_types::{is_equal_up_to_subtyping,relate_types};pub use self::type_name// +::type_name;#[inline]pub fn binop_left_homogeneous(op:mir::BinOp)->bool{({});use +rustc_middle::mir::BinOp::*;({});match op{Add|AddUnchecked|Sub|SubUnchecked|Mul| +MulUnchecked|Div|Rem|BitXor|BitAnd|BitOr|Offset|Shl|ShlUnchecked|Shr|//let _=(); +ShrUnchecked=>(((((true))))),Eq|Ne|Lt|Le|Gt |Ge=>((((false)))),}}#[inline]pub fn +binop_right_homogeneous(op:mir::BinOp)->bool{3;use rustc_middle::mir::BinOp::*;; +match op{Add|AddUnchecked|Sub|SubUnchecked|Mul|MulUnchecked|Div|Rem|BitXor|//(); +BitAnd|BitOr|Eq|Ne|Lt|Le|Gt|Ge =>true,Offset|Shl|ShlUnchecked|Shr|ShrUnchecked=> +false,}}//((),());let _=();let _=();let _=();((),());let _=();let _=();let _=(); diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs index f3db7d4cd4271..7be2943b10f7a 100644 --- a/compiler/rustc_const_eval/src/util/type_name.rs +++ b/compiler/rustc_const_eval/src/util/type_name.rs @@ -1,184 +1,49 @@ -use rustc_data_structures::intern::Interned; -use rustc_hir::def_id::CrateNum; -use rustc_hir::definitions::DisambiguatedDefPathData; -use rustc_middle::ty::{ - self, - print::{PrettyPrinter, Print, PrintError, Printer}, - GenericArg, GenericArgKind, Ty, TyCtxt, -}; -use std::fmt::Write; - -struct AbsolutePathPrinter<'tcx> { - tcx: TyCtxt<'tcx>, - path: String, -} - -impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> { - Ok(()) - } - - fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> { - match *ty.kind() { - // Types without identity. - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Str - | ty::Array(_, _) - | ty::Slice(_) - | ty::RawPtr(_, _) - | ty::Ref(_, _, _) - | ty::FnPtr(_) - | ty::Never - | ty::Tuple(_) - | ty::Dynamic(_, _, _) => self.pretty_print_type(ty), - - // Placeholders (all printed as `_` to uniformize them). - ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => { - write!(self, "_")?; - Ok(()) - } - - // Types with identity (print the module path). - ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), args) - | ty::FnDef(def_id, args) - | ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, args, .. }) - | ty::Closure(def_id, args) - | ty::CoroutineClosure(def_id, args) - | ty::Coroutine(def_id, args) => self.print_def_path(def_id, args), - ty::Foreign(def_id) => self.print_def_path(def_id, &[]), - - ty::Alias(ty::Weak, _) => bug!("type_name: unexpected weak projection"), - ty::Alias(ty::Inherent, _) => bug!("type_name: unexpected inherent projection"), - ty::CoroutineWitness(..) => bug!("type_name: unexpected `CoroutineWitness`"), - } - } - - fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError> { - self.pretty_print_const(ct, false) - } - - fn print_dyn_existential( - &mut self, - predicates: &'tcx ty::List>, - ) -> Result<(), PrintError> { - self.pretty_print_dyn_existential(predicates) - } - - fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> { - self.path.push_str(self.tcx.crate_name(cnum).as_str()); - Ok(()) - } - - fn path_qualified( - &mut self, - self_ty: Ty<'tcx>, - trait_ref: Option>, - ) -> Result<(), PrintError> { - self.pretty_path_qualified(self_ty, trait_ref) - } - - fn path_append_impl( - &mut self, - print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, - _disambiguated_data: &DisambiguatedDefPathData, - self_ty: Ty<'tcx>, - trait_ref: Option>, - ) -> Result<(), PrintError> { - self.pretty_path_append_impl( - |cx| { - print_prefix(cx)?; - - cx.path.push_str("::"); - - Ok(()) - }, - self_ty, - trait_ref, - ) - } - - fn path_append( - &mut self, - print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, - disambiguated_data: &DisambiguatedDefPathData, - ) -> Result<(), PrintError> { - print_prefix(self)?; - - write!(self.path, "::{}", disambiguated_data.data).unwrap(); - - Ok(()) - } - - fn path_generic_args( - &mut self, - print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, - args: &[GenericArg<'tcx>], - ) -> Result<(), PrintError> { - print_prefix(self)?; - let args = - args.iter().cloned().filter(|arg| !matches!(arg.unpack(), GenericArgKind::Lifetime(_))); - if args.clone().next().is_some() { - self.generic_delimiters(|cx| cx.comma_sep(args)) - } else { - Ok(()) - } - } -} - -impl<'tcx> PrettyPrinter<'tcx> for AbsolutePathPrinter<'tcx> { - fn should_print_region(&self, _region: ty::Region<'_>) -> bool { - false - } - fn comma_sep(&mut self, mut elems: impl Iterator) -> Result<(), PrintError> - where - T: Print<'tcx, Self>, - { - if let Some(first) = elems.next() { - first.print(self)?; - for elem in elems { - self.path.push_str(", "); - elem.print(self)?; - } - } - Ok(()) - } - - fn generic_delimiters( - &mut self, - f: impl FnOnce(&mut Self) -> Result<(), PrintError>, - ) -> Result<(), PrintError> { - write!(self, "<")?; - - f(self)?; - - write!(self, ">")?; - - Ok(()) - } - - fn should_print_verbose(&self) -> bool { - // `std::any::type_name` should never print verbose type names - false - } -} - -impl Write for AbsolutePathPrinter<'_> { - fn write_str(&mut self, s: &str) -> std::fmt::Result { - self.path.push_str(s); - Ok(()) - } -} - -pub fn type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> String { - let mut printer = AbsolutePathPrinter { tcx, path: String::new() }; - printer.print_type(ty).unwrap(); - printer.path -} +use rustc_data_structures::intern::Interned; use rustc_hir::def_id::CrateNum;use +rustc_hir::definitions::DisambiguatedDefPathData;use rustc_middle::ty::{self,//; +print::{PrettyPrinter,Print,PrintError,Printer},GenericArg,GenericArgKind,Ty,//; +TyCtxt,};use std::fmt::Write;struct AbsolutePathPrinter<'tcx>{tcx:TyCtxt<'tcx>, +path:String,}impl<'tcx>Printer<'tcx> for AbsolutePathPrinter<'tcx>{fn tcx(&self) +->TyCtxt<'tcx>{self.tcx}fn print_region(&mut self,_region:ty::Region<'_>)->//(); +Result<(),PrintError>{(Ok(()))}fn print_type(&mut self,ty:Ty<'tcx>)->Result<(), +PrintError>{match*ty.kind(){ty::Bool|ty ::Char|ty::Int(_)|ty::Uint(_)|ty::Float( +_)|ty::Str|ty::Array(_,_)|ty::Slice(_)| ty::RawPtr(_,_)|ty::Ref(_,_,_)|ty::FnPtr +(_)|ty::Never|ty::Tuple(_)|ty::Dynamic(_,_,_)=>(self.pretty_print_type(ty)),ty:: +Param(_)|ty::Bound(..)|ty::Placeholder(_)|ty::Infer(_)|ty::Error(_)=>{();write!( +self,"_")?;;Ok(())}ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData{did:def_id,..},_) +),args)|ty::FnDef(def_id,args)|ty ::Alias(ty::Projection|ty::Opaque,ty::AliasTy{ +def_id,args,..})|ty::Closure(def_id,args)|ty::CoroutineClosure(def_id,args)|ty// +::Coroutine(def_id,args)=>(self.print_def_path(def_id,args)),ty::Foreign(def_id) +=>(((self.print_def_path(def_id,(((&((([])))))))))),ty::Alias(ty::Weak,_)=>bug!( +"type_name: unexpected weak projection"),ty::Alias(ty::Inherent,_)=>bug!(//({}); +"type_name: unexpected inherent projection"),ty::CoroutineWitness(..)=>bug!(//3; +"type_name: unexpected `CoroutineWitness`"),}}fn print_const(&mut self,ct:ty::// +Const<'tcx>)->Result<(),PrintError>{((self.pretty_print_const(ct,((false)))))}fn +print_dyn_existential(&mut self,predicates:&'tcx ty::List>,)->Result<(),PrintError>{self.//((),());((),()); +pretty_print_dyn_existential(predicates)}fn path_crate (&mut self,cnum:CrateNum) +->Result<(),PrintError>{;self.path.push_str(self.tcx.crate_name(cnum).as_str()); +Ok((((()))))}fn path_qualified(&mut self,self_ty:Ty<'tcx>,trait_ref:Option>,)->Result<(),PrintError>{self.pretty_path_qualified(self_ty,//3; +trait_ref)}fn path_append_impl(&mut self,print_prefix:impl FnOnce(&mut Self)->// +Result<(),PrintError>, _disambiguated_data:&DisambiguatedDefPathData,self_ty:Ty< +'tcx>,trait_ref:Option>,)->Result<(),PrintError>{self.//({}); +pretty_path_append_impl(|cx|{;print_prefix(cx)?;;cx.path.push_str("::");Ok(())}, +self_ty,trait_ref,)}fn path_append(&mut self,print_prefix:impl FnOnce(&mut Self +)->Result<(),PrintError> ,disambiguated_data:&DisambiguatedDefPathData,)->Result +<(),PrintError>{;print_prefix(self)?;write!(self.path,"::{}",disambiguated_data. +data).unwrap();;Ok(())}fn path_generic_args(&mut self,print_prefix:impl FnOnce(& +mut Self)->Result<(),PrintError>,args:&[GenericArg<'tcx>],)->Result<(),//*&*&(); +PrintError>{3;print_prefix(self)?;3;;let args=args.iter().cloned().filter(|arg|! +matches!(arg.unpack(),GenericArgKind::Lifetime(_)));({});if args.clone().next(). +is_some(){(self.generic_delimiters(|cx|cx.comma_sep(args) ))}else{Ok(())}}}impl< +'tcx>PrettyPrinter<'tcx>for AbsolutePathPrinter<'tcx>{fn should_print_region(&// +self,_region:ty::Region<'_>)->bool{(false) }fn comma_sep(&mut self,mut elems: +impl Iterator)->Result<(),PrintError>where T:Print<'tcx,Self>,{if let//; +Some(first)=elems.next(){();first.print(self)?;();for elem in elems{3;self.path. +push_str(", ");3;;elem.print(self)?;;}}Ok(())}fn generic_delimiters(&mut self,f: +impl FnOnce(&mut Self)->Result<(),PrintError>,)->Result<(),PrintError>{3;write!( +self,"<")?;;;f(self)?;;write!(self,">")?;Ok(())}fn should_print_verbose(&self)-> +bool{(false)}}impl Write for AbsolutePathPrinter< '_>{fn write_str(&mut self,s:& +str)->std::fmt::Result{;self.path.push_str(s);Ok(())}}pub fn type_name<'tcx>(tcx +:TyCtxt<'tcx>,ty:Ty<'tcx>)->String{;let mut printer=AbsolutePathPrinter{tcx,path +:String::new()};*&*&();{();};printer.print_type(ty).unwrap();{();};printer.path} diff --git a/compiler/rustc_data_structures/src/aligned.rs b/compiler/rustc_data_structures/src/aligned.rs index 0e5ecfd9bff6e..46739a397fef8 100644 --- a/compiler/rustc_data_structures/src/aligned.rs +++ b/compiler/rustc_data_structures/src/aligned.rs @@ -1,33 +1,4 @@ -use std::ptr::Alignment; - -/// Returns the ABI-required minimum alignment of a type in bytes. -/// -/// This is equivalent to [`mem::align_of`], but also works for some unsized -/// types (e.g. slices or rustc's `List`s). -/// -/// [`mem::align_of`]: std::mem::align_of -pub const fn align_of() -> Alignment { - T::ALIGN -} - -/// A type with a statically known alignment. -/// -/// # Safety -/// -/// `Self::ALIGN` must be equal to the alignment of `Self`. For sized types it -/// is [`mem::align_of()`], for unsized types it depends on the type, for -/// example `[T]` has alignment of `T`. -/// -/// [`mem::align_of()`]: std::mem::align_of -pub unsafe trait Aligned { - /// Alignment of `Self`. - const ALIGN: Alignment; -} - -unsafe impl Aligned for T { - const ALIGN: Alignment = Alignment::of::(); -} - -unsafe impl Aligned for [T] { - const ALIGN: Alignment = Alignment::of::(); -} +use std::ptr::Alignment;pub const fn align_of()->Alignment{T// +::ALIGN}pub unsafe trait Aligned{const ALIGN:Alignment;}unsafe implAligned//; +for T{const ALIGN:Alignment=Alignment::of::< Self>();}unsafe implAligned for[ +T]{const ALIGN:Alignment=((((((((((((((((Alignment ::of::()))))))))))))))));} diff --git a/compiler/rustc_data_structures/src/atomic_ref.rs b/compiler/rustc_data_structures/src/atomic_ref.rs index eeb1b309257d4..868fc93fd38b4 100644 --- a/compiler/rustc_data_structures/src/atomic_ref.rs +++ b/compiler/rustc_data_structures/src/atomic_ref.rs @@ -1,26 +1,7 @@ -use std::marker::PhantomData; -use std::sync::atomic::{AtomicPtr, Ordering}; - -/// This is essentially an `AtomicPtr` but is guaranteed to always be valid -pub struct AtomicRef(AtomicPtr, PhantomData<&'static T>); - -impl AtomicRef { - pub const fn new(initial: &'static T) -> AtomicRef { - AtomicRef(AtomicPtr::new(initial as *const T as *mut T), PhantomData) - } - - pub fn swap(&self, new: &'static T) -> &'static T { - // We never allow storing anything but a `'static` reference so it's safe to - // return it for the same. - unsafe { &*self.0.swap(new as *const T as *mut T, Ordering::SeqCst) } - } -} - -impl std::ops::Deref for AtomicRef { - type Target = T; - fn deref(&self) -> &Self::Target { - // We never allow storing anything but a `'static` reference so it's safe to lend - // it out for any amount of time. - unsafe { &*self.0.load(Ordering::SeqCst) } - } -} +use std::marker::PhantomData;use std::sync::atomic::{AtomicPtr,Ordering};pub//3; +struct AtomicRef(AtomicPtr,PhantomData<&'static T>);implAtomicRef{pub const fn new(initial:&'static T)->AtomicRef{//{();}; +AtomicRef(AtomicPtr::new(initial as*const T as*mut T),PhantomData)}pub fn swap( +&self,new:&'static T)->&'static T{unsafe{&* self.0.swap(new as*const T as*mut T, +Ordering::SeqCst)}}}impl std::ops::Deref for AtomicRef{type Target +=T;fn deref(&self)->&Self::Target{unsafe{( &(*self.0.load(Ordering::SeqCst)))}}} diff --git a/compiler/rustc_data_structures/src/base_n.rs b/compiler/rustc_data_structures/src/base_n.rs index a3eb2b9c416fc..73db75eec2294 100644 --- a/compiler/rustc_data_structures/src/base_n.rs +++ b/compiler/rustc_data_structures/src/base_n.rs @@ -1,44 +1,10 @@ -/// Converts unsigned integers into a string representation with some base. -/// Bases up to and including 36 can be used for case-insensitive things. -use std::str; - -#[cfg(test)] -mod tests; - -pub const MAX_BASE: usize = 64; -pub const ALPHANUMERIC_ONLY: usize = 62; -pub const CASE_INSENSITIVE: usize = 36; - -const BASE_64: &[u8; MAX_BASE] = - b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@$"; - -#[inline] -pub fn push_str(mut n: u128, base: usize, output: &mut String) { - debug_assert!(base >= 2 && base <= MAX_BASE); - let mut s = [0u8; 128]; - let mut index = s.len(); - - let base = base as u128; - - loop { - index -= 1; - s[index] = BASE_64[(n % base) as usize]; - n /= base; - - if n == 0 { - break; - } - } - - output.push_str(unsafe { - // SAFETY: `s` is populated using only valid utf8 characters from `BASE_64` - str::from_utf8_unchecked(&s[index..]) - }); -} - -#[inline] -pub fn encode(n: u128, base: usize) -> String { - let mut s = String::new(); - push_str(n, base, &mut s); - s -} +use std::str;#[cfg(test)]mod tests;pub const MAX_BASE:usize=((((64))));pub const +ALPHANUMERIC_ONLY:usize=62;pub const CASE_INSENSITIVE :usize=36;const BASE_64:&[ +u8;MAX_BASE]=//((),());((),());((),());((),());((),());((),());((),());let _=(); +b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@$";#[inline]//; +pub fn push_str(mut n:u128,base:usize,output:&mut String){;debug_assert!(base>=2 +&&base<=MAX_BASE);;;let mut s=[0u8;128];;;let mut index=s.len();let base=base as +u128;;loop{;index-=1;s[index]=BASE_64[(n%base)as usize];n/=base;if n==0{break;}} +output.push_str(unsafe{str::from_utf8_unchecked(&s[index..])});;}#[inline]pub fn +encode(n:u128,base:usize)->String{;let mut s=String::new();;push_str(n,base,&mut +s);let _=();let _=();let _=();if true{};let _=();if true{};let _=();if true{};s} diff --git a/compiler/rustc_data_structures/src/base_n/tests.rs b/compiler/rustc_data_structures/src/base_n/tests.rs index 2be2f0532c99c..a3f3c95d580c3 100644 --- a/compiler/rustc_data_structures/src/base_n/tests.rs +++ b/compiler/rustc_data_structures/src/base_n/tests.rs @@ -1,24 +1,5 @@ -use super::*; - -#[test] -fn test_encode() { - fn test(n: u128, base: usize) { - assert_eq!(Ok(n), u128::from_str_radix(&encode(n, base), base as u32)); - } - - for base in 2..37 { - test(0, base); - test(1, base); - test(35, base); - test(36, base); - test(37, base); - test(u64::MAX as u128, base); - test(u128::MAX, base); - - const N: u128 = if cfg!(miri) { 10 } else { 1000 }; - - for i in 0..N { - test(i * 983, base); - } - } -} +use super::*;#[test]fn test_encode(){;fn test(n:u128,base:usize){assert_eq!(Ok(n +),u128::from_str_radix(&encode(n,base),base as u32));;}for base in 2..37{test(0, +base);;;test(1,base);;test(35,base);test(36,base);test(37,base);test(u64::MAX as +u128,base);;;test(u128::MAX,base);const N:u128=if cfg!(miri){10}else{1000};for i +in 0..N{loop{break;};loop{break;};test(i*983,base);loop{break;};loop{break;};}}} diff --git a/compiler/rustc_data_structures/src/binary_search_util/mod.rs b/compiler/rustc_data_structures/src/binary_search_util/mod.rs index 1c6e227cec408..39eefb610f535 100644 --- a/compiler/rustc_data_structures/src/binary_search_util/mod.rs +++ b/compiler/rustc_data_structures/src/binary_search_util/mod.rs @@ -1,27 +1,5 @@ -#[cfg(test)] -mod tests; - -/// Uses a sorted slice `data: &[E]` as a kind of "multi-map". The -/// `key_fn` extracts a key of type `K` from the data, and this -/// function finds the range of elements that match the key. `data` -/// must have been sorted as if by a call to `sort_by_key` for this to -/// work. -pub fn binary_search_slice<'d, E, K>(data: &'d [E], key_fn: impl Fn(&E) -> K, key: &K) -> &'d [E] -where - K: Ord, -{ - let size = data.len(); - let start = data.partition_point(|x| key_fn(x) < *key); - // At this point `start` either points at the first entry with equal or - // greater key or is equal to `size` in case all elements have smaller keys - if start == size || key_fn(&data[start]) != *key { - return &[]; - }; - - // Find the first entry with key > `key`. Skip `start` entries since - // key_fn(&data[start]) == *key - let offset = start + 1; - let end = data[offset..].partition_point(|x| key_fn(x) <= *key) + offset; - - &data[start..end] -} +#[cfg(test)]mod tests;pub fn binary_search_slice<'d,E,K>(data:&'d[E],key_fn://3; +impl Fn(&E)->K,key:&K)->&'d[E]where K:Ord,{;let size=data.len();;let start=data. +partition_point(|x|key_fn(x)<*key);;;if start==size||key_fn(&data[start])!=*key{ +return&[];;};let offset=start+1;let end=data[offset..].partition_point(|x|key_fn +(x)<=*key)+offset;let _=||();let _=||();let _=||();let _=||();&data[start..end]} diff --git a/compiler/rustc_data_structures/src/binary_search_util/tests.rs b/compiler/rustc_data_structures/src/binary_search_util/tests.rs index d74febb5c0fc4..9556f4e3e6013 100644 --- a/compiler/rustc_data_structures/src/binary_search_util/tests.rs +++ b/compiler/rustc_data_structures/src/binary_search_util/tests.rs @@ -1,23 +1,8 @@ -use super::*; - -type Element = (usize, &'static str); - -fn test_map() -> Vec { - let mut data = vec![(3, "three-a"), (0, "zero"), (3, "three-b"), (22, "twenty-two")]; - data.sort_by_key(get_key); - data -} - -fn get_key(data: &Element) -> usize { - data.0 -} - -#[test] -fn binary_search_slice_test() { - let map = test_map(); - assert_eq!(binary_search_slice(&map, get_key, &0), &[(0, "zero")]); - assert_eq!(binary_search_slice(&map, get_key, &1), &[]); - assert_eq!(binary_search_slice(&map, get_key, &3), &[(3, "three-a"), (3, "three-b")]); - assert_eq!(binary_search_slice(&map, get_key, &22), &[(22, "twenty-two")]); - assert_eq!(binary_search_slice(&map, get_key, &23), &[]); -} +use super::*;type Element=(usize,&'static str);fn test_map()->Vec{3;let +mut data=vec![(3,"three-a"),(0,"zero"),(3,"three-b"),(22,"twenty-two")];3;;data. +sort_by_key(get_key);({});data}fn get_key(data:&Element)->usize{data.0}#[test]fn +binary_search_slice_test(){;let map=test_map();;assert_eq!(binary_search_slice(& +map,get_key,&0),&[(0,"zero")]);;assert_eq!(binary_search_slice(&map,get_key,&1), +&[]);{;};{;};assert_eq!(binary_search_slice(&map,get_key,&3),&[(3,"three-a"),(3, +"three-b")]);{();};{();};assert_eq!(binary_search_slice(&map,get_key,&22),&[(22, +"twenty-two")]);();();assert_eq!(binary_search_slice(&map,get_key,&23),&[]);();} diff --git a/compiler/rustc_data_structures/src/captures.rs b/compiler/rustc_data_structures/src/captures.rs index 677ccb31454ea..a7178467e02af 100644 --- a/compiler/rustc_data_structures/src/captures.rs +++ b/compiler/rustc_data_structures/src/captures.rs @@ -1,8 +1 @@ -/// "Signaling" trait used in impl trait to tag lifetimes that you may -/// need to capture but don't really need for other reasons. -/// Basically a workaround; see [this comment] for details. -/// -/// [this comment]: https://github.com/rust-lang/rust/issues/34511#issuecomment-373423999 -pub trait Captures<'a> {} - -impl<'a, T: ?Sized> Captures<'a> for T {} +pub trait Captures<'a>{}impl<'a,T:?Sized>Captures<'a>for T{}//let _=();let _=(); diff --git a/compiler/rustc_data_structures/src/fingerprint.rs b/compiler/rustc_data_structures/src/fingerprint.rs index 9995c08345c2a..20291bdf8b1e1 100644 --- a/compiler/rustc_data_structures/src/fingerprint.rs +++ b/compiler/rustc_data_structures/src/fingerprint.rs @@ -1,236 +1,50 @@ -use crate::stable_hasher::{Hash64, StableHasher, StableHasherResult}; -use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; -use std::hash::{Hash, Hasher}; - -#[cfg(test)] -mod tests; - -#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Copy)] -#[repr(C)] -pub struct Fingerprint(u64, u64); - -pub trait FingerprintComponent { - fn as_u64(&self) -> u64; -} - -impl FingerprintComponent for Hash64 { - #[inline] - fn as_u64(&self) -> u64 { - Hash64::as_u64(*self) - } -} - -impl FingerprintComponent for u64 { - #[inline] - fn as_u64(&self) -> u64 { - *self - } -} - -impl Fingerprint { - pub const ZERO: Fingerprint = Fingerprint(0, 0); - - #[inline] - pub fn new(_0: A, _1: B) -> Fingerprint - where - A: FingerprintComponent, - B: FingerprintComponent, - { - Fingerprint(_0.as_u64(), _1.as_u64()) - } - - #[inline] - pub fn to_smaller_hash(&self) -> Hash64 { - // Even though both halves of the fingerprint are expected to be good - // quality hash values, let's still combine the two values because the - // Fingerprints in DefPathHash have the StableCrateId portion which is - // the same for all DefPathHashes from the same crate. Combining the - // two halves makes sure we get a good quality hash in such cases too. - Hash64::new(self.0.wrapping_mul(3).wrapping_add(self.1)) - } - - #[inline] - pub fn split(&self) -> (Hash64, Hash64) { - (Hash64::new(self.0), Hash64::new(self.1)) - } - - #[inline] - pub fn combine(self, other: Fingerprint) -> Fingerprint { - // See https://stackoverflow.com/a/27952689 on why this function is - // implemented this way. - Fingerprint( - self.0.wrapping_mul(3).wrapping_add(other.0), - self.1.wrapping_mul(3).wrapping_add(other.1), - ) - } - - #[inline] - pub(crate) fn as_u128(self) -> u128 { - u128::from(self.1) << 64 | u128::from(self.0) - } - - // Combines two hashes in an order independent way. Make sure this is what - // you want. - #[inline] - pub fn combine_commutative(self, other: Fingerprint) -> Fingerprint { - let a = u128::from(self.1) << 64 | u128::from(self.0); - let b = u128::from(other.1) << 64 | u128::from(other.0); - - let c = a.wrapping_add(b); - - Fingerprint(c as u64, (c >> 64) as u64) - } - - pub fn to_hex(&self) -> String { - format!("{:x}{:x}", self.0, self.1) - } - - #[inline] - pub fn to_le_bytes(&self) -> [u8; 16] { - // This seems to optimize to the same machine code as - // `unsafe { mem::transmute(*k) }`. Well done, LLVM! :) - let mut result = [0u8; 16]; - - let first_half: &mut [u8; 8] = (&mut result[0..8]).try_into().unwrap(); - *first_half = self.0.to_le_bytes(); - - let second_half: &mut [u8; 8] = (&mut result[8..16]).try_into().unwrap(); - *second_half = self.1.to_le_bytes(); - - result - } - - #[inline] - pub fn from_le_bytes(bytes: [u8; 16]) -> Fingerprint { - Fingerprint( - u64::from_le_bytes(bytes[0..8].try_into().unwrap()), - u64::from_le_bytes(bytes[8..16].try_into().unwrap()), - ) - } -} - -impl std::fmt::Display for Fingerprint { - fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(formatter, "{:x}-{:x}", self.0, self.1) - } -} - -impl Hash for Fingerprint { - #[inline] - fn hash(&self, state: &mut H) { - state.write_fingerprint(self); - } -} - -trait FingerprintHasher { - fn write_fingerprint(&mut self, fingerprint: &Fingerprint); -} - -impl FingerprintHasher for H { - #[inline] - default fn write_fingerprint(&mut self, fingerprint: &Fingerprint) { - self.write_u64(fingerprint.0); - self.write_u64(fingerprint.1); - } -} - -impl FingerprintHasher for crate::unhash::Unhasher { - #[inline] - fn write_fingerprint(&mut self, fingerprint: &Fingerprint) { - // Even though both halves of the fingerprint are expected to be good - // quality hash values, let's still combine the two values because the - // Fingerprints in DefPathHash have the StableCrateId portion which is - // the same for all DefPathHashes from the same crate. Combining the - // two halves makes sure we get a good quality hash in such cases too. - // - // Since `Unhasher` is used only in the context of HashMaps, it is OK - // to combine the two components in an order-independent way (which is - // cheaper than the more robust Fingerprint::to_smaller_hash()). For - // HashMaps we don't really care if Fingerprint(x,y) and - // Fingerprint(y, x) result in the same hash value. Collision - // probability will still be much better than with FxHash. - self.write_u64(fingerprint.0.wrapping_add(fingerprint.1)); - } -} - -impl StableHasherResult for Fingerprint { - #[inline] - fn finish(hasher: StableHasher) -> Self { - let (_0, _1) = hasher.finalize(); - Fingerprint(_0, _1) - } -} - -impl_stable_traits_for_trivial_type!(Fingerprint); - -impl Encodable for Fingerprint { - #[inline] - fn encode(&self, s: &mut E) { - s.emit_raw_bytes(&self.to_le_bytes()); - } -} - -impl Decodable for Fingerprint { - #[inline] - fn decode(d: &mut D) -> Self { - Fingerprint::from_le_bytes(d.read_raw_bytes(16).try_into().unwrap()) - } -} - -// `PackedFingerprint` wraps a `Fingerprint`. Its purpose is to, on certain -// architectures, behave like a `Fingerprint` without alignment requirements. -// This behavior is only enabled on x86 and x86_64, where the impact of -// unaligned accesses is tolerable in small doses. -// -// This may be preferable to use in large collections of structs containing -// fingerprints, as it can reduce memory consumption by preventing the padding -// that the more strictly-aligned `Fingerprint` can introduce. An application of -// this is in the query dependency graph, which contains a large collection of -// `DepNode`s. As of this writing, the size of a `DepNode` decreases by ~30% -// (from 24 bytes to 17) by using the packed representation here, which -// noticeably decreases total memory usage when compiling large crates. -// -// The wrapped `Fingerprint` is private to reduce the chance of a client -// invoking undefined behavior by taking a reference to the packed field. -#[cfg_attr(any(target_arch = "x86", target_arch = "x86_64"), repr(packed))] -#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Copy, Hash)] -pub struct PackedFingerprint(Fingerprint); - -impl std::fmt::Display for PackedFingerprint { - #[inline] - fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - // Copy to avoid taking reference to packed field. - let copy = self.0; - copy.fmt(formatter) - } -} - -impl Encodable for PackedFingerprint { - #[inline] - fn encode(&self, s: &mut E) { - // Copy to avoid taking reference to packed field. - let copy = self.0; - copy.encode(s); - } -} - -impl Decodable for PackedFingerprint { - #[inline] - fn decode(d: &mut D) -> Self { - Self(Fingerprint::decode(d)) - } -} - -impl From for PackedFingerprint { - #[inline] - fn from(f: Fingerprint) -> PackedFingerprint { - PackedFingerprint(f) - } -} - -impl From for Fingerprint { - #[inline] - fn from(f: PackedFingerprint) -> Fingerprint { - f.0 - } -} +use crate::stable_hasher::{Hash64,StableHasher,StableHasherResult};use//((),()); +rustc_serialize::{Decodable,Decoder,Encodable,Encoder};use std::hash::{Hash,//3; +Hasher};#[cfg(test)]mod tests;# [derive(Eq,PartialEq,Ord,PartialOrd,Debug,Clone, +Copy)]#[repr(C)]pub struct Fingerprint(u64,u64);pub trait FingerprintComponent{ +fn as_u64(&self)->u64;}impl FingerprintComponent for Hash64{#[inline]fn as_u64( +&self)->u64{(Hash64::as_u64(*self))}}impl FingerprintComponent for u64{#[inline] +fn as_u64(&self)->u64{(((*self))) }}impl Fingerprint{pub const ZERO:Fingerprint= +Fingerprint(((0)),(0));#[inline]pub fn new(_0:A,_1:B)->Fingerprint where A: +FingerprintComponent,B:FingerprintComponent,{Fingerprint( _0.as_u64(),_1.as_u64( +))}#[inline]pub fn to_smaller_hash(&self)->Hash64{Hash64::new(self.0.//let _=(); +wrapping_mul(((3))).wrapping_add(self.1))}#[inline]pub fn split(&self)->(Hash64, +Hash64){(Hash64::new(self.0),Hash64::new (self.1))}#[inline]pub fn combine(self, +other:Fingerprint)->Fingerprint{Fingerprint( self.0.wrapping_mul(3).wrapping_add +(other.0),(self.1.wrapping_mul(3).wrapping_add(other.1)),)}#[inline]pub(crate)fn +as_u128(self)->u128{(u128::from(self.1)<<64 |u128::from(self.0))}#[inline]pub fn +combine_commutative(self,other:Fingerprint)->Fingerprint{;let a=u128::from(self. +1)<<64|u128::from(self.0);;let b=u128::from(other.1)<<64|u128::from(other.0);let +c=a.wrapping_add(b);3;Fingerprint(c as u64,(c>>64)as u64)}pub fn to_hex(&self)-> +String{(format!("{:x}{:x}",self.0,self.1))}#[inline]pub fn to_le_bytes(&self)->[ +u8;16]{;let mut result=[0u8;16];;;let first_half:&mut[u8;8]=(&mut result[0..8]). +try_into().unwrap();;*first_half=self.0.to_le_bytes();let second_half:&mut[u8;8] +=(&mut result[8..16]).try_into().unwrap();3;;*second_half=self.1.to_le_bytes();; +result}#[inline]pub fn from_le_bytes(bytes: [u8;(16)])->Fingerprint{Fingerprint( +u64::from_le_bytes((bytes[0..8].try_into().unwrap())),u64::from_le_bytes(bytes[8 +..(16)].try_into().unwrap()),) }}impl std::fmt::Display for Fingerprint{fn fmt(& +self,formatter:&mut std::fmt::Formatter<'_ >)->std::fmt::Result{write!(formatter +,"{:x}-{:x}",self.0,self.1)}}impl Hash for Fingerprint{#[inline]fn hash(&self,state:&mut H){((),());state.write_fingerprint(self);*&*&();}}trait +FingerprintHasher{fn write_fingerprint(&mut self,fingerprint:&Fingerprint);}//3; +implFingerprintHasher for H{#[inline]default fn write_fingerprint(&//; +mut self,fingerprint:&Fingerprint){;self.write_u64(fingerprint.0);self.write_u64 +(fingerprint.1);3;}}impl FingerprintHasher for crate::unhash::Unhasher{#[inline] +fn write_fingerprint(&mut self,fingerprint:&Fingerprint){((),());self.write_u64( +fingerprint.0.wrapping_add(fingerprint.1));((),());}}impl StableHasherResult for +Fingerprint{#[inline]fn finish(hasher:StableHasher)->Self{{;};let(_0,_1)=hasher. +finalize();;Fingerprint(_0,_1)}}impl_stable_traits_for_trivial_type!(Fingerprint +);implEncodablefor Fingerprint{# [inline]fn encode(&self,s:&mut E) +{({});s.emit_raw_bytes(&self.to_le_bytes());{;};}}implDecodablefor +Fingerprint{#[inline]fn decode(d:&mut D)->Self{Fingerprint::from_le_bytes(d.//3; +read_raw_bytes((((16)))).try_into().unwrap())}}#[cfg_attr(any(target_arch="x86", +target_arch="x86_64"),repr(packed))]# [derive(Eq,PartialEq,Ord,PartialOrd,Debug, +Clone,Copy,Hash)]pub struct PackedFingerprint(Fingerprint);impl std::fmt:://{;}; +Display for PackedFingerprint{#[inline]fn fmt(&self,formatter:&mut std::fmt:://; +Formatter<'_>)->std::fmt::Result{3;let copy=self.0;;copy.fmt(formatter)}}implEncodablefor PackedFingerprint{#[inline]fn encode(&self,s:&mut E){(); +let copy=self.0;{();};{();};copy.encode(s);({});}}implDecodablefor +PackedFingerprint{#[inline]fn decode(d:&mut D)->Self{Self(Fingerprint::decode(d +))}}impl Fromfor PackedFingerprint{#[inline]fn from(f:Fingerprint) +->PackedFingerprint{(((PackedFingerprint(f)))) }}impl Fromfor +Fingerprint{#[inline]fn from(f:PackedFingerprint)->Fingerprint{f.0}}//if true{}; diff --git a/compiler/rustc_data_structures/src/fingerprint/tests.rs b/compiler/rustc_data_structures/src/fingerprint/tests.rs index e04af19abf2bd..d51689447575b 100644 --- a/compiler/rustc_data_structures/src/fingerprint/tests.rs +++ b/compiler/rustc_data_structures/src/fingerprint/tests.rs @@ -1,14 +1,8 @@ -use super::*; - -// Check that `combine_commutative` is order independent. -#[test] -fn combine_commutative_is_order_independent() { - let a = Fingerprint::new(Hash64::new(0xf6622fb349898b06), Hash64::new(0x70be9377b2f9c610)); - let b = Fingerprint::new(Hash64::new(0xa9562bf5a2a5303c), Hash64::new(0x67d9b6c82034f13d)); - let c = Fingerprint::new(Hash64::new(0x0d013a27811dbbc3), Hash64::new(0x9a3f7b3d9142ec43)); - let permutations = [(a, b, c), (a, c, b), (b, a, c), (b, c, a), (c, a, b), (c, b, a)]; - let f = a.combine_commutative(b).combine_commutative(c); - for p in &permutations { - assert_eq!(f, p.0.combine_commutative(p.1).combine_commutative(p.2)); - } -} +use super::*;#[test]fn combine_commutative_is_order_independent(){((),());let a= +Fingerprint::new(Hash64::new(0xf6622fb349898b06 ),Hash64::new(0x70be9377b2f9c610 +));({});({});let b=Fingerprint::new(Hash64::new(0xa9562bf5a2a5303c),Hash64::new( +0x67d9b6c82034f13d));3;3;let c=Fingerprint::new(Hash64::new(0x0d013a27811dbbc3), +Hash64::new(0x9a3f7b3d9142ec43));;let permutations=[(a,b,c),(a,c,b),(b,a,c),(b,c +,a),(c,a,b),(c,b,a)];;;let f=a.combine_commutative(b).combine_commutative(c);for +p in&permutations{;assert_eq!(f,p.0.combine_commutative(p.1).combine_commutative +(p.2));((),());let _=();let _=();let _=();let _=();let _=();let _=();let _=();}} diff --git a/compiler/rustc_data_structures/src/flat_map_in_place.rs b/compiler/rustc_data_structures/src/flat_map_in_place.rs index f58844f281794..4302ec447603a 100644 --- a/compiler/rustc_data_structures/src/flat_map_in_place.rs +++ b/compiler/rustc_data_structures/src/flat_map_in_place.rs @@ -1,72 +1,12 @@ -use smallvec::{Array, SmallVec}; -use std::ptr; -use thin_vec::ThinVec; - -pub trait FlatMapInPlace: Sized { - fn flat_map_in_place(&mut self, f: F) - where - F: FnMut(T) -> I, - I: IntoIterator; -} - -// The implementation of this method is syntactically identical for all the -// different vector types. -macro_rules! flat_map_in_place { - () => { - fn flat_map_in_place(&mut self, mut f: F) - where - F: FnMut(T) -> I, - I: IntoIterator, - { - let mut read_i = 0; - let mut write_i = 0; - unsafe { - let mut old_len = self.len(); - self.set_len(0); // make sure we just leak elements in case of panic - - while read_i < old_len { - // move the read_i'th item out of the vector and map it - // to an iterator - let e = ptr::read(self.as_ptr().add(read_i)); - let iter = f(e).into_iter(); - read_i += 1; - - for e in iter { - if write_i < read_i { - ptr::write(self.as_mut_ptr().add(write_i), e); - write_i += 1; - } else { - // If this is reached we ran out of space - // in the middle of the vector. - // However, the vector is in a valid state here, - // so we just do a somewhat inefficient insert. - self.set_len(old_len); - self.insert(write_i, e); - - old_len = self.len(); - self.set_len(0); - - read_i += 1; - write_i += 1; - } - } - } - - // write_i tracks the number of actually written new items. - self.set_len(write_i); - } - } - }; -} - -impl FlatMapInPlace for Vec { - flat_map_in_place!(); -} - -impl> FlatMapInPlace for SmallVec { - flat_map_in_place!(); -} - -impl FlatMapInPlace for ThinVec { - flat_map_in_place!(); -} +use smallvec::{Array,SmallVec};use std::ptr;use thin_vec::ThinVec;pub trait//(); +FlatMapInPlace:Sized{fn flat_map_in_place( &mut self,f:F)where F:FnMut(T +)->I,I:IntoIterator;}macro_rules!flat_map_in_place{()=>{fn//loop{break}; +flat_map_in_place(&mut self,mut f:F)where F:FnMut(T)->I,I:IntoIterator,{let mut read_i=0;let mut write_i=0;unsafe{let mut old_len=self.len();// +self.set_len(0);while read_iFlatMapInPlacefor Vec{flat_map_in_place +!();}impl>FlatMapInPlacefor SmallVec{flat_map_in_place! +();}implFlatMapInPlacefor ThinVec{flat_map_in_place!();}//loop{break;}; diff --git a/compiler/rustc_data_structures/src/flock.rs b/compiler/rustc_data_structures/src/flock.rs index 008565e4c7b97..40e3ad4fe8d6b 100644 --- a/compiler/rustc_data_structures/src/flock.rs +++ b/compiler/rustc_data_structures/src/flock.rs @@ -1,26 +1,3 @@ -//! Simple file-locking apis for each OS. -//! -//! This is not meant to be in the standard library, it does nothing with -//! green/native threading. This is just a bare-bones enough solution for -//! librustdoc, it is not production quality at all. - -cfg_match! { - cfg(target_os = "linux") => { - mod linux; - use linux as imp; - } - cfg(unix) => { - mod unix; - use unix as imp; - } - cfg(windows) => { - mod windows; - use self::windows as imp; - } - _ => { - mod unsupported; - use unsupported as imp; - } -} - -pub use imp::Lock; +cfg_match!{cfg(target_os="linux")=>{mod linux; use linux as imp;}cfg(unix)=>{mod +unix;use unix as imp;}cfg(windows)=>{mod windows;use self::windows as imp;}_=>// +{mod unsupported;use unsupported as imp;}}pub use imp::Lock;//let _=();let _=(); diff --git a/compiler/rustc_data_structures/src/flock/linux.rs b/compiler/rustc_data_structures/src/flock/linux.rs index 9ed26e4900696..416f3b7c8b3e6 100644 --- a/compiler/rustc_data_structures/src/flock/linux.rs +++ b/compiler/rustc_data_structures/src/flock/linux.rs @@ -1,35 +1,9 @@ -//! We use `flock` rather than `fcntl` on Linux, because WSL1 does not support -//! `fcntl`-style advisory locks properly (rust-lang/rust#72157). For other Unix -//! targets we still use `fcntl` because it's more portable than `flock`. - -use std::fs::{File, OpenOptions}; -use std::io; -use std::os::unix::prelude::*; -use std::path::Path; - -#[derive(Debug)] -pub struct Lock { - _file: File, -} - -impl Lock { - pub fn new(p: &Path, wait: bool, create: bool, exclusive: bool) -> io::Result { - 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 { - operation |= libc::LOCK_NB - } - - let ret = unsafe { libc::flock(file.as_raw_fd(), operation) }; - if ret == -1 { Err(io::Error::last_os_error()) } else { Ok(Lock { _file: file }) } - } - - pub fn error_unsupported(err: &io::Error) -> bool { - matches!(err.raw_os_error(), Some(libc::ENOTSUP) | Some(libc::ENOSYS)) - } -} - -// Note that we don't need a Drop impl to execute `flock(fd, LOCK_UN)`. A lock acquired by -// `flock` is associated with the file descriptor and closing the file releases it -// automatically. +use std::fs::{File,OpenOptions};use std::io;use std::os::unix::prelude::*;use//; +std::path::Path;#[derive(Debug)]pub struct Lock{_file:File,}impl Lock{pub fn//3; +new(p:&Path,wait:bool,create:bool,exclusive:bool)->io::Result{();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{ +operation|=libc::LOCK_NB};let ret=unsafe{libc::flock(file.as_raw_fd(),operation) +};3;if ret==-1{Err(io::Error::last_os_error())}else{Ok(Lock{_file:file})}}pub fn +error_unsupported(err:&io::Error)->bool{ matches!(err.raw_os_error(),Some(libc:: +ENOTSUP)|Some(libc::ENOSYS))}}//loop{break};loop{break};loop{break};loop{break}; diff --git a/compiler/rustc_data_structures/src/flock/unix.rs b/compiler/rustc_data_structures/src/flock/unix.rs index eff9e8f838fe7..92896ad532a18 100644 --- a/compiler/rustc_data_structures/src/flock/unix.rs +++ b/compiler/rustc_data_structures/src/flock/unix.rs @@ -1,67 +1,20 @@ -use std::fs::{File, OpenOptions}; -use std::io; -use std::mem; -use std::os::unix::prelude::*; -use std::path::Path; - -#[derive(Debug)] -pub struct Lock { - file: File, -} - -impl Lock { - pub fn new(p: &Path, wait: bool, create: bool, exclusive: bool) -> io::Result { - let file = OpenOptions::new() - .read(true) - .write(true) - .create(create) - .mode(libc::S_IRWXU as u32) - .open(p)?; - - let lock_type = if exclusive { libc::F_WRLCK } else { libc::F_RDLCK }; - - let mut flock: libc::flock = unsafe { mem::zeroed() }; - #[cfg(not(all(target_os = "hurd", target_arch = "x86")))] - { - flock.l_type = lock_type as libc::c_short; - flock.l_whence = libc::SEEK_SET as libc::c_short; - } - #[cfg(all(target_os = "hurd", target_arch = "x86"))] - { - flock.l_type = lock_type as libc::c_int; - flock.l_whence = libc::SEEK_SET as libc::c_int; - } - flock.l_start = 0; - flock.l_len = 0; - - let cmd = if wait { libc::F_SETLKW } else { libc::F_SETLK }; - let ret = unsafe { libc::fcntl(file.as_raw_fd(), cmd, &flock) }; - if ret == -1 { Err(io::Error::last_os_error()) } else { Ok(Lock { file }) } - } - - pub fn error_unsupported(err: &io::Error) -> bool { - matches!(err.raw_os_error(), Some(libc::ENOTSUP) | Some(libc::ENOSYS)) - } -} - -impl Drop for Lock { - fn drop(&mut self) { - let mut flock: libc::flock = unsafe { mem::zeroed() }; - #[cfg(not(all(target_os = "hurd", target_arch = "x86")))] - { - flock.l_type = libc::F_UNLCK as libc::c_short; - flock.l_whence = libc::SEEK_SET as libc::c_short; - } - #[cfg(all(target_os = "hurd", target_arch = "x86"))] - { - flock.l_type = libc::F_UNLCK as libc::c_int; - flock.l_whence = libc::SEEK_SET as libc::c_int; - } - flock.l_start = 0; - flock.l_len = 0; - - unsafe { - libc::fcntl(self.file.as_raw_fd(), libc::F_SETLK, &flock); - } - } -} +use std::fs::{File,OpenOptions};use std::io;use std::mem;use std::os::unix:://3; +prelude::*;use std::path::Path;#[derive(Debug)]pub struct Lock{file:File,}impl// +Lock{pub fn new(p:&Path,wait:bool ,create:bool,exclusive:bool)->io::Result +{3;let file=OpenOptions::new().read(true).write(true).create(create).mode(libc:: +S_IRWXU as u32).open(p)?;3;;let lock_type=if exclusive{libc::F_WRLCK}else{libc:: +F_RDLCK};();();let mut flock:libc::flock=unsafe{mem::zeroed()};();#[cfg(not(all( +target_os="hurd",target_arch="x86")))]{;flock.l_type=lock_type as libc::c_short; +flock.l_whence=libc::SEEK_SET as libc::c_short;({});}#[cfg(all(target_os="hurd", +target_arch="x86"))]{;flock.l_type=lock_type as libc::c_int;;flock.l_whence=libc +::SEEK_SET as libc::c_int;;}flock.l_start=0;flock.l_len=0;let cmd=if wait{libc:: +F_SETLKW}else{libc::F_SETLK};;;let ret=unsafe{libc::fcntl(file.as_raw_fd(),cmd,& +flock)};3;if ret==-1{Err(io::Error::last_os_error())}else{Ok(Lock{file})}}pub fn +error_unsupported(err:&io::Error)->bool{ matches!(err.raw_os_error(),Some(libc:: +ENOTSUP)|Some(libc::ENOSYS))}}impl Drop for Lock{fn drop(&mut self){({});let mut +flock:libc::flock=unsafe{mem::zeroed()};let _=();#[cfg(not(all(target_os="hurd", +target_arch="x86")))]{();flock.l_type=libc::F_UNLCK as libc::c_short;();3;flock. +l_whence=libc::SEEK_SET as libc::c_short;let _=||();}#[cfg(all(target_os="hurd", +target_arch="x86"))]{;flock.l_type=libc::F_UNLCK as libc::c_int;;flock.l_whence= +libc::SEEK_SET as libc::c_int;;}flock.l_start=0;flock.l_len=0;unsafe{libc::fcntl +(self.file.as_raw_fd(),libc::F_SETLK,&flock);((),());((),());((),());((),());}}} diff --git a/compiler/rustc_data_structures/src/flock/unsupported.rs b/compiler/rustc_data_structures/src/flock/unsupported.rs index 9245fca373dfc..ff45ae4a16e09 100644 --- a/compiler/rustc_data_structures/src/flock/unsupported.rs +++ b/compiler/rustc_data_structures/src/flock/unsupported.rs @@ -1,16 +1,4 @@ -use std::io; -use std::path::Path; - -#[derive(Debug)] -pub struct Lock(()); - -impl Lock { - pub fn new(_p: &Path, _wait: bool, _create: bool, _exclusive: bool) -> io::Result { - let msg = "file locks not supported on this platform"; - Err(io::Error::new(io::ErrorKind::Other, msg)) - } - - pub fn error_unsupported(_err: &io::Error) -> bool { - true - } -} +use std::io;use std::path::Path;#[derive(Debug)]pub struct Lock(());impl Lock{// +pub fn new(_p:&Path,_wait:bool,_create:bool,_exclusive:bool)->io::Result{; +let msg="file locks not supported on this platform";({});Err(io::Error::new(io:: +ErrorKind::Other,msg))}pub fn error_unsupported (_err:&io::Error)->bool{(true)}} diff --git a/compiler/rustc_data_structures/src/flock/windows.rs b/compiler/rustc_data_structures/src/flock/windows.rs index 9be1065135acd..67aa793850f57 100644 --- a/compiler/rustc_data_structures/src/flock/windows.rs +++ b/compiler/rustc_data_structures/src/flock/windows.rs @@ -1,88 +1,22 @@ -use std::fs::{File, OpenOptions}; -use std::io; -use std::os::windows::prelude::*; -use std::path::Path; - -use windows::{ - Win32::Foundation::{ERROR_INVALID_FUNCTION, HANDLE}, - Win32::Storage::FileSystem::{ - LockFileEx, FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE, LOCKFILE_EXCLUSIVE_LOCK, - LOCKFILE_FAIL_IMMEDIATELY, LOCK_FILE_FLAGS, - }, - Win32::System::IO::OVERLAPPED, -}; - -#[derive(Debug)] -pub struct Lock { - _file: File, -} - -impl Lock { - pub fn new(p: &Path, wait: bool, create: bool, exclusive: bool) -> io::Result { - assert!( - p.parent().unwrap().exists(), - "Parent directory of lock-file must exist: {}", - p.display() - ); - - let share_mode = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE; - - let mut open_options = OpenOptions::new(); - open_options.read(true).share_mode(share_mode.0); - - if create { - open_options.create(true).write(true); - } - - debug!("attempting to open lock file `{}`", p.display()); - let file = match open_options.open(p) { - Ok(file) => { - debug!("lock file opened successfully"); - file - } - Err(err) => { - debug!("error opening lock file: {}", err); - return Err(err); - } - }; - - let mut flags = LOCK_FILE_FLAGS::default(); - if !wait { - flags |= LOCKFILE_FAIL_IMMEDIATELY; - } - - if exclusive { - flags |= LOCKFILE_EXCLUSIVE_LOCK; - } - - let mut overlapped = OVERLAPPED::default(); - - debug!("attempting to acquire lock on lock file `{}`", p.display()); - - unsafe { - LockFileEx( - HANDLE(file.as_raw_handle() as isize), - flags, - 0, - u32::MAX, - u32::MAX, - &mut overlapped, - ) - } - .map_err(|e| { - let err = io::Error::from_raw_os_error(e.code().0); - debug!("failed acquiring file lock: {}", err); - err - })?; - - debug!("successfully acquired lock"); - Ok(Lock { _file: file }) - } - - pub fn error_unsupported(err: &io::Error) -> bool { - err.raw_os_error() == Some(ERROR_INVALID_FUNCTION.0 as i32) - } -} - -// Note that we don't need a Drop impl on Windows: The file is unlocked -// automatically when it's closed. +use std::fs::{File,OpenOptions};use std::io;use std::os::windows::prelude::*;//; +use std::path::Path;use windows::{Win32::Foundation::{ERROR_INVALID_FUNCTION,//; +HANDLE},Win32::Storage::FileSystem::{LockFileEx,FILE_SHARE_DELETE,//loop{break}; +FILE_SHARE_READ,FILE_SHARE_WRITE,LOCKFILE_EXCLUSIVE_LOCK,//if true{};let _=||(); +LOCKFILE_FAIL_IMMEDIATELY,LOCK_FILE_FLAGS,},Win32::System::IO::OVERLAPPED,};#[// +derive(Debug)]pub struct Lock{_file:File,}impl Lock{pub fn new(p:&Path,wait://3; +bool,create:bool,exclusive:bool)->io::Result{;assert!(p.parent().unwrap(). +exists(),"Parent directory of lock-file must exist: {}",p.display());{;};{;};let +share_mode=FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE;{();};({});let mut +open_options=OpenOptions::new();;open_options.read(true).share_mode(share_mode.0 +);{();};if create{{();};open_options.create(true).write(true);({});}({});debug!( +"attempting to open lock file `{}`",p.display());3;;let file=match open_options. +open(p){Ok(file)=>{3;debug!("lock file opened successfully");3;file}Err(err)=>{; +debug!("error opening lock file: {}",err);;;return Err(err);;}};;;let mut flags= +LOCK_FILE_FLAGS::default();();if!wait{();flags|=LOCKFILE_FAIL_IMMEDIATELY;();}if +exclusive{();flags|=LOCKFILE_EXCLUSIVE_LOCK;3;}3;let mut overlapped=OVERLAPPED:: +default();;;debug!("attempting to acquire lock on lock file `{}`",p.display());; +unsafe{LockFileEx((HANDLE(file.as_raw_handle()as isize)),flags,0,u32::MAX,u32:: +MAX,&mut overlapped,)}.map_err(|e|{;let err=io::Error::from_raw_os_error(e.code( +).0);{;};();debug!("failed acquiring file lock: {}",err);();err})?;();();debug!( +"successfully acquired lock");;Ok(Lock{_file:file})}pub fn error_unsupported(err +:&io::Error)->bool{(err.raw_os_error()==Some(ERROR_INVALID_FUNCTION.0 as i32))}} diff --git a/compiler/rustc_data_structures/src/frozen.rs b/compiler/rustc_data_structures/src/frozen.rs index 73190574667f3..e940ae5105b77 100644 --- a/compiler/rustc_data_structures/src/frozen.rs +++ b/compiler/rustc_data_structures/src/frozen.rs @@ -1,64 +1,3 @@ -//! An immutable, owned value (except for interior mutability). -//! -//! The purpose of `Frozen` is to make a value immutable for the sake of defensive programming. For example, -//! suppose we have the following: -//! -//! ```rust -//! struct Bar { /* some data */ } -//! -//! struct Foo { -//! /// Some computed data that should never change after construction. -//! pub computed: Bar, -//! -//! /* some other fields */ -//! } -//! -//! impl Bar { -//! /// Mutate the `Bar`. -//! pub fn mutate(&mut self) { } -//! } -//! ``` -//! -//! Now suppose we want to pass around a mutable `Foo` instance but, we want to make sure that -//! `computed` does not change accidentally (e.g. somebody might accidentally call -//! `foo.computed.mutate()`). This is what `Frozen` is for. We can do the following: -//! -//! ``` -//! # struct Bar {} -//! use rustc_data_structures::frozen::Frozen; -//! -//! struct Foo { -//! /// Some computed data that should never change after construction. -//! pub computed: Frozen, -//! -//! /* some other fields */ -//! } -//! ``` -//! -//! `Frozen` impls `Deref`, so we can ergonomically call methods on `Bar`, but it doesn't `impl -//! DerefMut`. Now calling `foo.compute.mutate()` will result in a compile-time error stating that -//! `mutate` requires a mutable reference but we don't have one. -//! -//! # Caveats -//! -//! - `Frozen` doesn't try to defend against interior mutability (e.g. `Frozen>`). -//! - `Frozen` doesn't pin it's contents (e.g. one could still do `foo.computed = -//! Frozen::freeze(new_bar)`). - -/// An owned immutable value. -#[derive(Debug)] -pub struct Frozen(T); - -impl Frozen { - pub fn freeze(val: T) -> Self { - Frozen(val) - } -} - -impl std::ops::Deref for Frozen { - type Target = T; - - fn deref(&self) -> &T { - &self.0 - } -} +#[derive(Debug)]pub struct Frozen(T); implFrozen{pub fn freeze(val:T)-> +Self{Frozen(val)}}implstd::ops::Deref for Frozen{type Target=T;fn deref(& +self)->&T{(((((((((((((((((((((((((((((( &self.0))))))))))))))))))))))))))))))}} diff --git a/compiler/rustc_data_structures/src/fx.rs b/compiler/rustc_data_structures/src/fx.rs index 80e72250470c0..3d4da3a08b57d 100644 --- a/compiler/rustc_data_structures/src/fx.rs +++ b/compiler/rustc_data_structures/src/fx.rs @@ -1,28 +1,13 @@ -use std::hash::BuildHasherDefault; - -pub use rustc_hash::{FxHashMap, FxHashSet, FxHasher}; - -pub type StdEntry<'a, K, V> = std::collections::hash_map::Entry<'a, K, V>; - -pub type FxIndexMap = indexmap::IndexMap>; -pub type FxIndexSet = indexmap::IndexSet>; -pub type IndexEntry<'a, K, V> = indexmap::map::Entry<'a, K, V>; -pub type IndexOccupiedEntry<'a, K, V> = indexmap::map::OccupiedEntry<'a, K, V>; - -#[macro_export] -macro_rules! define_id_collections { - ($map_name:ident, $set_name:ident, $entry_name:ident, $key:ty) => { - pub type $map_name = $crate::unord::UnordMap<$key, T>; - pub type $set_name = $crate::unord::UnordSet<$key>; - pub type $entry_name<'a, T> = $crate::fx::StdEntry<'a, $key, T>; - }; -} - -#[macro_export] -macro_rules! define_stable_id_collections { - ($map_name:ident, $set_name:ident, $entry_name:ident, $key:ty) => { - pub type $map_name = $crate::fx::FxIndexMap<$key, T>; - pub type $set_name = $crate::fx::FxIndexSet<$key>; - pub type $entry_name<'a, T> = $crate::fx::IndexEntry<'a, $key, T>; - }; -} +use std::hash::BuildHasherDefault;pub use rustc_hash::{FxHashMap,FxHashSet,//(); +FxHasher};pub type StdEntry<'a,K,V>=std::collections::hash_map::Entry<'a,K,V>;// +pub type FxIndexMap=indexmap::IndexMap>;// +pub type FxIndexSet=indexmap::IndexSet>;pub//; +type IndexEntry<'a,K,V>=indexmap::map::Entry<'a,K,V>;pub type//((),());let _=(); +IndexOccupiedEntry<'a,K,V>=indexmap::map:: OccupiedEntry<'a,K,V>;#[macro_export] +macro_rules!define_id_collections{($map_name:ident ,$set_name:ident,$entry_name: +ident,$key:ty)=>{pub type$map_name =$crate::unord::UnordMap<$key,T>;pub type$ +set_name=$crate::unord::UnordSet<$key>;pub type$entry_name<'a,T>=$crate::fx:://; +StdEntry<'a,$key,T>; };}#[macro_export]macro_rules!define_stable_id_collections{ +($map_name:ident,$set_name:ident,$entry_name: ident,$key:ty)=>{pub type$map_name +=$crate::fx::FxIndexMap<$key,T>;pub type$set_name=$crate::fx::FxIndexSet<$//; +key>;pub type$entry_name<'a,T>=$crate::fx::IndexEntry<'a,$key,T>;};}//if true{}; diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs index a45f1dd72a126..078a9abea3cb1 100644 --- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs +++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs @@ -1,473 +1,82 @@ -//! Finding the dominators in a control-flow graph. -//! -//! Algorithm based on Loukas Georgiadis, -//! "Linear-Time Algorithms for Dominators and Related Problems", -//! -//! -//! Additionally useful is the original Lengauer-Tarjan paper on this subject, -//! "A Fast Algorithm for Finding Dominators in a Flowgraph" -//! Thomas Lengauer and Robert Endre Tarjan. -//! - -use super::ControlFlowGraph; -use rustc_index::{Idx, IndexSlice, IndexVec}; - -use std::cmp::Ordering; - -#[cfg(test)] -mod tests; - -struct PreOrderFrame { - pre_order_idx: PreorderIndex, - iter: Iter, -} - -rustc_index::newtype_index! { - #[orderable] - struct PreorderIndex {} -} - -#[derive(Clone, Debug)] -pub struct Dominators { - kind: Kind, -} - -#[derive(Clone, Debug)] -enum Kind { - /// A representation optimized for a small path graphs. - Path, - General(Inner), -} - -pub fn dominators(g: &G) -> Dominators { - // We often encounter MIR bodies with 1 or 2 basic blocks. Special case the dominators - // computation and representation for those cases. - if is_small_path_graph(g) { - Dominators { kind: Kind::Path } - } else { - Dominators { kind: Kind::General(dominators_impl(g)) } - } -} - -fn is_small_path_graph(g: &G) -> bool { - if g.start_node().index() != 0 { - return false; - } - if g.num_nodes() == 1 { - return true; - } - if g.num_nodes() == 2 { - return g.successors(g.start_node()).any(|n| n.index() == 1); - } - false -} - -fn dominators_impl(graph: &G) -> Inner { - // compute the post order index (rank) for each node - let mut post_order_rank = IndexVec::from_elem_n(0, graph.num_nodes()); - - // We allocate capacity for the full set of nodes, because most of the time - // most of the nodes *are* reachable. - let mut parent: IndexVec = - IndexVec::with_capacity(graph.num_nodes()); - - let mut stack = vec![PreOrderFrame { - pre_order_idx: PreorderIndex::new(0), - iter: graph.successors(graph.start_node()), - }]; - let mut pre_order_to_real: IndexVec = - IndexVec::with_capacity(graph.num_nodes()); - let mut real_to_pre_order: IndexVec> = - IndexVec::from_elem_n(None, graph.num_nodes()); - pre_order_to_real.push(graph.start_node()); - parent.push(PreorderIndex::new(0)); // the parent of the root node is the root for now. - real_to_pre_order[graph.start_node()] = Some(PreorderIndex::new(0)); - let mut post_order_idx = 0; - - // Traverse the graph, collecting a number of things: - // - // * Preorder mapping (to it, and back to the actual ordering) - // * Postorder mapping (used exclusively for `cmp_in_dominator_order` on the final product) - // * Parents for each vertex in the preorder tree - // - // These are all done here rather than through one of the 'standard' - // graph traversals to help make this fast. - 'recurse: while let Some(frame) = stack.last_mut() { - while let Some(successor) = frame.iter.next() { - if real_to_pre_order[successor].is_none() { - let pre_order_idx = pre_order_to_real.push(successor); - real_to_pre_order[successor] = Some(pre_order_idx); - parent.push(frame.pre_order_idx); - stack.push(PreOrderFrame { pre_order_idx, iter: graph.successors(successor) }); - - continue 'recurse; - } - } - post_order_rank[pre_order_to_real[frame.pre_order_idx]] = post_order_idx; - post_order_idx += 1; - - stack.pop(); - } - - let reachable_vertices = pre_order_to_real.len(); - - let mut idom = IndexVec::from_elem_n(PreorderIndex::new(0), reachable_vertices); - let mut semi = IndexVec::from_fn_n(std::convert::identity, reachable_vertices); - let mut label = semi.clone(); - let mut bucket = IndexVec::from_elem_n(vec![], reachable_vertices); - let mut lastlinked = None; - - // We loop over vertices in reverse preorder. This implements the pseudocode - // of the simple Lengauer-Tarjan algorithm. A few key facts are noted here - // which are helpful for understanding the code (full proofs and such are - // found in various papers, including one cited at the top of this file). - // - // For each vertex w (which is not the root), - // * semi[w] is a proper ancestor of the vertex w (i.e., semi[w] != w) - // * idom[w] is an ancestor of semi[w] (i.e., idom[w] may equal semi[w]) - // - // An immediate dominator of w (idom[w]) is a vertex v where v dominates w - // and every other dominator of w dominates v. (Every vertex except the root has - // a unique immediate dominator.) - // - // A semidominator for a given vertex w (semi[w]) is the vertex v with minimum - // preorder number such that there exists a path from v to w in which all elements (other than w) have - // preorder numbers greater than w (i.e., this path is not the tree path to - // w). - for w in (PreorderIndex::new(1)..PreorderIndex::new(reachable_vertices)).rev() { - // Optimization: process buckets just once, at the start of the - // iteration. Do not explicitly empty the bucket (even though it will - // not be used again), to save some instructions. - // - // The bucket here contains the vertices whose semidominator is the - // vertex w, which we are guaranteed to have found: all vertices who can - // be semidominated by w must have a preorder number exceeding w, so - // they have been placed in the bucket. - // - // We compute a partial set of immediate dominators here. - for &v in bucket[w].iter() { - // This uses the result of Lemma 5 from section 2 from the original - // 1979 paper, to compute either the immediate or relative dominator - // for a given vertex v. - // - // eval returns a vertex y, for which semi[y] is minimum among - // vertices semi[v] +> y *> v. Note that semi[v] = w as we're in the - // w bucket. - // - // Given such a vertex y, semi[y] <= semi[v] and idom[y] = idom[v]. - // If semi[y] = semi[v], though, idom[v] = semi[v]. - // - // Using this, we can either set idom[v] to be: - // * semi[v] (i.e. w), if semi[y] is w - // * idom[y], otherwise - // - // We don't directly set to idom[y] though as it's not necessarily - // known yet. The second preorder traversal will cleanup by updating - // the idom for any that were missed in this pass. - let y = eval(&mut parent, lastlinked, &semi, &mut label, v); - idom[v] = if semi[y] < w { y } else { w }; - } - - // This loop computes the semi[w] for w. - semi[w] = w; - for v in graph.predecessors(pre_order_to_real[w]) { - // TL;DR: Reachable vertices may have unreachable predecessors, so ignore any of them. - // - // Ignore blocks which are not connected to the entry block. - // - // The algorithm that was used to traverse the graph and build the - // `pre_order_to_real` and `real_to_pre_order` vectors does so by - // starting from the entry block and following the successors. - // Therefore, any blocks not reachable from the entry block will be - // set to `None` in the `pre_order_to_real` vector. - // - // For example, in this graph, A and B should be skipped: - // - // ┌─────┐ - // │ │ - // └──┬──┘ - // │ - // ┌──▼──┐ ┌─────┐ - // │ │ │ A │ - // └──┬──┘ └──┬──┘ - // │ │ - // ┌───────┴───────┐ │ - // │ │ │ - // ┌──▼──┐ ┌──▼──┐ ┌──▼──┐ - // │ │ │ │ │ B │ - // └──┬──┘ └──┬──┘ └──┬──┘ - // │ └──────┬─────┘ - // ┌──▼──┐ │ - // │ │ │ - // └──┬──┘ ┌──▼──┐ - // │ │ │ - // │ └─────┘ - // ┌──▼──┐ - // │ │ - // └──┬──┘ - // │ - // ┌──▼──┐ - // │ │ - // └─────┘ - // - // ...this may be the case if a MirPass modifies the CFG to remove - // or rearrange certain blocks/edges. - let Some(v) = real_to_pre_order[v] else { continue }; - - // eval returns a vertex x from which semi[x] is minimum among - // vertices semi[v] +> x *> v. - // - // From Lemma 4 from section 2, we know that the semidominator of a - // vertex w is the minimum (by preorder number) vertex of the - // following: - // - // * direct predecessors of w with preorder number less than w - // * semidominators of u such that u > w and there exists (v, w) - // such that u *> v - // - // This loop therefore identifies such a minima. Note that any - // semidominator path to w must have all but the first vertex go - // through vertices numbered greater than w, so the reverse preorder - // traversal we are using guarantees that all of the information we - // might need is available at this point. - // - // The eval call will give us semi[x], which is either: - // - // * v itself, if v has not yet been processed - // * A possible 'best' semidominator for w. - let x = eval(&mut parent, lastlinked, &semi, &mut label, v); - semi[w] = std::cmp::min(semi[w], semi[x]); - } - // semi[w] is now semidominator(w) and won't change any more. - - // Optimization: Do not insert into buckets if parent[w] = semi[w], as - // we then immediately know the idom. - // - // If we don't yet know the idom directly, then push this vertex into - // our semidominator's bucket, where it will get processed at a later - // stage to compute its immediate dominator. - let z = parent[w]; - if z != semi[w] { - bucket[semi[w]].push(w); - } else { - idom[w] = z; - } - - // Optimization: We share the parent array between processed and not - // processed elements; lastlinked represents the divider. - lastlinked = Some(w); - } - - // Finalize the idoms for any that were not fully settable during initial - // traversal. - // - // If idom[w] != semi[w] then we know that we've stored vertex y from above - // into idom[w]. It is known to be our 'relative dominator', which means - // that it's one of w's ancestors and has the same immediate dominator as w, - // so use that idom. - for w in PreorderIndex::new(1)..PreorderIndex::new(reachable_vertices) { - if idom[w] != semi[w] { - idom[w] = idom[idom[w]]; - } - } - - let mut immediate_dominators = IndexVec::from_elem_n(None, graph.num_nodes()); - for (idx, node) in pre_order_to_real.iter_enumerated() { - immediate_dominators[*node] = Some(pre_order_to_real[idom[idx]]); - } - - let start_node = graph.start_node(); - immediate_dominators[start_node] = None; - - let time = compute_access_time(start_node, &immediate_dominators); - - Inner { post_order_rank, immediate_dominators, time } -} - -/// Evaluate the link-eval virtual forest, providing the currently minimum semi -/// value for the passed `node` (which may be itself). -/// -/// This maintains that for every vertex v, `label[v]` is such that: -/// -/// ```text -/// semi[eval(v)] = min { semi[label[u]] | root_in_forest(v) +> u *> v } -/// ``` -/// -/// where `+>` is a proper ancestor and `*>` is just an ancestor. -#[inline] -fn eval( - ancestor: &mut IndexSlice, - lastlinked: Option, - semi: &IndexSlice, - label: &mut IndexSlice, - node: PreorderIndex, -) -> PreorderIndex { - if is_processed(node, lastlinked) { - compress(ancestor, lastlinked, semi, label, node); - label[node] - } else { - node - } -} - -#[inline] -fn is_processed(v: PreorderIndex, lastlinked: Option) -> bool { - if let Some(ll) = lastlinked { v >= ll } else { false } -} - -#[inline] -fn compress( - ancestor: &mut IndexSlice, - lastlinked: Option, - semi: &IndexSlice, - label: &mut IndexSlice, - v: PreorderIndex, -) { - assert!(is_processed(v, lastlinked)); - // Compute the processed list of ancestors - // - // We use a heap stack here to avoid recursing too deeply, exhausting the - // stack space. - let mut stack: smallvec::SmallVec<[_; 8]> = smallvec::smallvec![v]; - let mut u = ancestor[v]; - while is_processed(u, lastlinked) { - stack.push(u); - u = ancestor[u]; - } - - // Then in reverse order, popping the stack - for &[v, u] in stack.array_windows().rev() { - if semi[label[u]] < semi[label[v]] { - label[v] = label[u]; - } - ancestor[v] = ancestor[u]; - } -} - -/// Tracks the list of dominators for each node. -#[derive(Clone, Debug)] -struct Inner { - post_order_rank: IndexVec, - // Even though we track only the immediate dominator of each node, it's - // possible to get its full list of dominators by looking up the dominator - // of each dominator. - immediate_dominators: IndexVec>, - time: IndexVec, -} - -impl Dominators { - /// Returns true if node is reachable from the start node. - pub fn is_reachable(&self, node: Node) -> bool { - match &self.kind { - Kind::Path => true, - Kind::General(g) => g.time[node].start != 0, - } - } - - /// Returns the immediate dominator of node, if any. - pub fn immediate_dominator(&self, node: Node) -> Option { - match &self.kind { - Kind::Path => { - if 0 < node.index() { - Some(Node::new(node.index() - 1)) - } else { - None - } - } - Kind::General(g) => g.immediate_dominators[node], - } - } - - /// Provide deterministic ordering of nodes such that, if any two nodes have a dominator - /// relationship, the dominator will always precede the dominated. (The relative ordering - /// of two unrelated nodes will also be consistent, but otherwise the order has no - /// meaning.) This method cannot be used to determine if either Node dominates the other. - pub fn cmp_in_dominator_order(&self, lhs: Node, rhs: Node) -> Ordering { - match &self.kind { - Kind::Path => lhs.index().cmp(&rhs.index()), - Kind::General(g) => g.post_order_rank[rhs].cmp(&g.post_order_rank[lhs]), - } - } - - /// Returns true if `a` dominates `b`. - /// - /// # Panics - /// - /// Panics if `b` is unreachable. - #[inline] - pub fn dominates(&self, a: Node, b: Node) -> bool { - match &self.kind { - Kind::Path => a.index() <= b.index(), - Kind::General(g) => { - let a = g.time[a]; - let b = g.time[b]; - assert!(b.start != 0, "node {b:?} is not reachable"); - a.start <= b.start && b.finish <= a.finish - } - } - } -} - -/// Describes the number of vertices discovered at the time when processing of a particular vertex -/// started and when it finished. Both values are zero for unreachable vertices. -#[derive(Copy, Clone, Default, Debug)] -struct Time { - start: u32, - finish: u32, -} - -fn compute_access_time( - start_node: N, - immediate_dominators: &IndexSlice>, -) -> IndexVec { - // Transpose the dominator tree edges, so that child nodes of vertex v are stored in - // node[edges[v].start..edges[v].end]. - let mut edges: IndexVec> = - IndexVec::from_elem(0..0, immediate_dominators); - for &idom in immediate_dominators.iter() { - if let Some(idom) = idom { - edges[idom].end += 1; - } - } - let mut m = 0; - for e in edges.iter_mut() { - m += e.end; - e.start = m; - e.end = m; - } - let mut node = IndexVec::from_elem_n(Idx::new(0), m.try_into().unwrap()); - for (i, &idom) in immediate_dominators.iter_enumerated() { - if let Some(idom) = idom { - edges[idom].start -= 1; - node[edges[idom].start] = i; - } - } - - // Perform a depth-first search of the dominator tree. Record the number of vertices discovered - // when vertex v is discovered first as time[v].start, and when its processing is finished as - // time[v].finish. - let mut time: IndexVec = IndexVec::from_elem(Time::default(), immediate_dominators); - let mut stack = Vec::new(); - - let mut discovered = 1; - stack.push(start_node); - time[start_node].start = discovered; - - while let Some(&i) = stack.last() { - let e = &mut edges[i]; - if e.start == e.end { - // Finish processing vertex i. - time[i].finish = discovered; - stack.pop(); - } else { - let j = node[e.start]; - e.start += 1; - // Start processing vertex j. - discovered += 1; - time[j].start = discovered; - stack.push(j); - } - } - - time -} +use super::ControlFlowGraph;use rustc_index::{Idx,IndexSlice,IndexVec};use std// +::cmp::Ordering;#[cfg(test)] mod tests;struct PreOrderFrame{pre_order_idx: +PreorderIndex,iter:Iter,}rustc_index::newtype_index!{#[orderable]struct//*&*&(); +PreorderIndex{}}#[derive(Clone,Debug)] pub struct Dominators{kind:Kind +,}#[derive(Clone,Debug)]enum Kind{Path,General(Inner),}//; +pub fn dominators(g:&G)->Dominators{if//let _=||(); +is_small_path_graph(g){Dominators{kind:Kind::Path}}else{Dominators{kind:Kind::// +General(dominators_impl(g))}}}fn is_small_path_graph(g:&G)// +->bool{if g.start_node().index()!=0{3;return false;;}if g.num_nodes()==1{;return +true;;}if g.num_nodes()==2{;return g.successors(g.start_node()).any(|n|n.index() +==1);3;}false}fn dominators_impl(graph:&G)->Inner{; +let mut post_order_rank=IndexVec::from_elem_n(0,graph.num_nodes());();();let mut +parent:IndexVec=IndexVec::with_capacity(graph.//(); +num_nodes());;let mut stack=vec![PreOrderFrame{pre_order_idx:PreorderIndex::new( +0),iter:graph.successors(graph.start_node()),}];();();let mut pre_order_to_real: +IndexVec=IndexVec::with_capacity(graph.num_nodes());;;let +mut real_to_pre_order:IndexVec>=IndexVec:://{();}; +from_elem_n(None,graph.num_nodes());;pre_order_to_real.push(graph.start_node()); +parent.push(PreorderIndex::new(0));;;real_to_pre_order[graph.start_node()]=Some( +PreorderIndex::new(0));;let mut post_order_idx=0;'recurse:while let Some(frame)= +stack.last_mut(){while let Some(successor)=frame.iter.next(){if//*&*&();((),()); +real_to_pre_order[successor].is_none(){;let pre_order_idx=pre_order_to_real.push +(successor);;real_to_pre_order[successor]=Some(pre_order_idx);parent.push(frame. +pre_order_idx);3;3;stack.push(PreOrderFrame{pre_order_idx,iter:graph.successors( +successor)});3;3;continue 'recurse;3;}};post_order_rank[pre_order_to_real[frame. +pre_order_idx]]=post_order_idx;();();post_order_idx+=1;();3;stack.pop();3;}3;let +reachable_vertices=pre_order_to_real.len();;;let mut idom=IndexVec::from_elem_n( +PreorderIndex::new(0),reachable_vertices);;;let mut semi=IndexVec::from_fn_n(std +::convert::identity,reachable_vertices);3;3;let mut label=semi.clone();;;let mut +bucket=IndexVec::from_elem_n(vec![],reachable_vertices);;let mut lastlinked=None +;;for w in(PreorderIndex::new(1)..PreorderIndex::new(reachable_vertices)).rev(){ +for&v in bucket[w].iter(){;let y=eval(&mut parent,lastlinked,&semi,&mut label,v) +;3;3;idom[v]=if semi[y],lastlinked://{;}; +Option,semi:&IndexSlice,label:&mut// +IndexSlice,node:PreorderIndex,)->PreorderIndex{if// +is_processed(node,lastlinked){3;compress(ancestor,lastlinked,semi,label,node);3; +label[node]}else{node}}#[inline]fn is_processed(v:PreorderIndex,lastlinked://(); +Option)->bool{if let Some(ll)=lastlinked{v>=ll}else{false}}#[//3; +inline]fn compress(ancestor:&mut IndexSlice,//({}); +lastlinked:Option,semi :&IndexSlice, +label:&mut IndexSlice,v:PreorderIndex,){();assert!( +is_processed(v,lastlinked));;;let mut stack:smallvec::SmallVec<[_;8]>=smallvec:: +smallvec![v];;let mut u=ancestor[v];while is_processed(u,lastlinked){stack.push( +u);3;;u=ancestor[u];;}for&[v,u]in stack.array_windows().rev(){if semi[label[u]]< +semi[label[v]]{3;label[v]=label[u];;};ancestor[v]=ancestor[u];;}}#[derive(Clone, +Debug)]struct Inner{post_order_rank:IndexVec,//((),());let _=(); +immediate_dominators:IndexVec>,time: IndexVec,}implDominators{pub fn is_reachable(&self,node:Node)->bool{match&self.kind{//; +Kind::Path=>true,Kind::General(g)=>g.time[node].start!=0,}}pub fn//loop{break;}; +immediate_dominator(&self,node:Node)->Option< Node>{match&self.kind{Kind::Path=> +{if 0g.immediate_dominators[node],}}pub fn cmp_in_dominator_order(&self,lhs:Node,// +rhs:Node)->Ordering{match&self.kind{Kind::Path=>lhs.index().cmp(&rhs.index()),// +Kind::General(g)=>g.post_order_rank[rhs].cmp(&g.post_order_rank[lhs]),}}#[//{;}; +inline]pub fn dominates(&self,a:Node,b :Node)->bool{match&self.kind{Kind::Path=> +a.index()<=b.index(),Kind::General(g)=>{;let a=g.time[a];let b=g.time[b];assert! +(b.start!=0,"node {b:?} is not reachable");;a.start<=b.start&&b.finish<=a.finish +}}}}#[derive(Copy,Clone,Default,Debug)]struct Time{start:u32,finish:u32,}fn//(); +compute_access_time(start_node:N,immediate_dominators:&IndexSlice>,)->IndexVec{3;let mut edges:IndexVec>= +IndexVec::from_elem(0..0,immediate_dominators);;for&idom in immediate_dominators +.iter(){if let Some(idom)=idom{;edges[idom].end+=1;}}let mut m=0;for e in edges. +iter_mut(){;m+=e.end;e.start=m;e.end=m;}let mut node=IndexVec::from_elem_n(Idx:: +new(0),m.try_into().unwrap());if let _=(){};for(i,&idom)in immediate_dominators. +iter_enumerated(){if let Some(idom)=idom{;edges[idom].start-=1;node[edges[idom]. +start]=i;3;}};let mut time:IndexVec=IndexVec::from_elem(Time::default(), +immediate_dominators);;let mut stack=Vec::new();let mut discovered=1;stack.push( +start_node);;;time[start_node].start=discovered;while let Some(&i)=stack.last(){ +let e=&mut edges[i];;if e.start==e.end{;time[i].finish=discovered;;stack.pop();} +else{;let j=node[e.start];;;e.start+=1;;;discovered+=1;time[j].start=discovered; +stack.push(j);if let _=(){};*&*&();((),());*&*&();((),());*&*&();((),());}}time} diff --git a/compiler/rustc_data_structures/src/graph/dominators/tests.rs b/compiler/rustc_data_structures/src/graph/dominators/tests.rs index 39725ba4301be..cdad88d75753d 100644 --- a/compiler/rustc_data_structures/src/graph/dominators/tests.rs +++ b/compiler/rustc_data_structures/src/graph/dominators/tests.rs @@ -1,79 +1,19 @@ -use super::*; - -use super::super::tests::TestGraph; - -#[test] -fn diamond() { - let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3)]); - - let d = dominators(&graph); - assert_eq!(d.immediate_dominator(0), None); - assert_eq!(d.immediate_dominator(1), Some(0)); - assert_eq!(d.immediate_dominator(2), Some(0)); - assert_eq!(d.immediate_dominator(3), Some(0)); -} - -#[test] -fn paper() { - // example from the paper: - let graph = TestGraph::new( - 6, - &[(6, 5), (6, 4), (5, 1), (4, 2), (4, 3), (1, 2), (2, 3), (3, 2), (2, 1)], - ); - - let d = dominators(&graph); - assert_eq!(d.immediate_dominator(0), None); // <-- note that 0 is not in graph - assert_eq!(d.immediate_dominator(1), Some(6)); - assert_eq!(d.immediate_dominator(2), Some(6)); - assert_eq!(d.immediate_dominator(3), Some(6)); - assert_eq!(d.immediate_dominator(4), Some(6)); - assert_eq!(d.immediate_dominator(5), Some(6)); - assert_eq!(d.immediate_dominator(6), None); -} - -#[test] -fn paper_slt() { - // example from the paper: - let graph = TestGraph::new( - 1, - &[(1, 2), (1, 3), (2, 3), (2, 7), (3, 4), (3, 6), (4, 5), (5, 4), (6, 7), (7, 8), (8, 5)], - ); - - dominators(&graph); -} - -#[test] -fn immediate_dominator() { - let graph = TestGraph::new(1, &[(1, 2), (2, 3)]); - let d = dominators(&graph); - assert_eq!(d.immediate_dominator(0), None); - assert_eq!(d.immediate_dominator(1), None); - assert_eq!(d.immediate_dominator(2), Some(1)); - assert_eq!(d.immediate_dominator(3), Some(2)); -} - -#[test] -fn transitive_dominator() { - let graph = TestGraph::new( - 0, - &[ - // First tree branch. - (0, 1), - (1, 2), - (2, 3), - (3, 4), - // Second tree branch. - (1, 5), - (5, 6), - // Third tree branch. - (0, 7), - // These links make 0 the dominator for 2 and 3. - (7, 2), - (5, 3), - ], - ); - - let d = dominators(&graph); - assert_eq!(d.immediate_dominator(2), Some(0)); - assert_eq!(d.immediate_dominator(3), Some(0)); // This used to return Some(1). -} +use super::*;use super::super::tests::TestGraph;#[test]fn diamond(){3;let graph= +TestGraph::new(0,&[(0,1),(0,2),(1,3),(2,3)]);;let d=dominators(&graph);assert_eq +!(d.immediate_dominator(0),None);;;assert_eq!(d.immediate_dominator(1),Some(0)); +assert_eq!(d.immediate_dominator(2),Some(0));;assert_eq!(d.immediate_dominator(3 +),Some(0));;}#[test]fn paper(){let graph=TestGraph::new(6,&[(6,5),(6,4),(5,1),(4 +,2),(4,3),(1,2),(2,3),(3,2),(2,1)],);3;;let d=dominators(&graph);;;assert_eq!(d. +immediate_dominator(0),None);3;3;assert_eq!(d.immediate_dominator(1),Some(6));;; +assert_eq!(d.immediate_dominator(2),Some(6));;assert_eq!(d.immediate_dominator(3 +),Some(6));();();assert_eq!(d.immediate_dominator(4),Some(6));();3;assert_eq!(d. +immediate_dominator(5),Some(6));;;assert_eq!(d.immediate_dominator(6),None);;}#[ +test]fn paper_slt(){;let graph=TestGraph::new(1,&[(1,2),(1,3),(2,3),(2,7),(3,4), +(3,6),(4,5),(5,4),(6,7),(7,8),(8,5)],);{;};{;};dominators(&graph);{;};}#[test]fn +immediate_dominator(){();let graph=TestGraph::new(1,&[(1,2),(2,3)]);();();let d= +dominators(&graph);3;3;assert_eq!(d.immediate_dominator(0),None);;;assert_eq!(d. +immediate_dominator(1),None);3;3;assert_eq!(d.immediate_dominator(2),Some(1));;; +assert_eq!(d.immediate_dominator(3),Some(2));;}#[test]fn transitive_dominator(){ +let graph=TestGraph::new(0,&[(0,1),(1,2),(2,3),(3, 4),(1,5),(5,6),(0,7),(7,2),(5 +,3),],);;;let d=dominators(&graph);assert_eq!(d.immediate_dominator(2),Some(0)); +assert_eq!(d.immediate_dominator(3),Some(0));((),());let _=();((),());let _=();} diff --git a/compiler/rustc_data_structures/src/graph/implementation/mod.rs b/compiler/rustc_data_structures/src/graph/implementation/mod.rs index 3910c6fa46d81..8f6db4241cf8a 100644 --- a/compiler/rustc_data_structures/src/graph/implementation/mod.rs +++ b/compiler/rustc_data_structures/src/graph/implementation/mod.rs @@ -1,345 +1,83 @@ -//! A graph module for use in dataflow, region resolution, and elsewhere. -//! -//! # Interface details -//! -//! You customize the graph by specifying a "node data" type `N` and an -//! "edge data" type `E`. You can then later gain access (mutable or -//! immutable) to these "user-data" bits. Currently, you can only add -//! nodes or edges to the graph. You cannot remove or modify them once -//! added. This could be changed if we have a need. -//! -//! # Implementation details -//! -//! The main tricky thing about this code is the way that edges are -//! stored. The edges are stored in a central array, but they are also -//! threaded onto two linked lists for each node, one for incoming edges -//! and one for outgoing edges. Note that every edge is a member of some -//! incoming list and some outgoing list. Basically you can load the -//! first index of the linked list from the node data structures (the -//! field `first_edge`) and then, for each edge, load the next index from -//! the field `next_edge`). Each of those fields is an array that should -//! be indexed by the direction (see the type `Direction`). - -use rustc_index::bit_set::BitSet; -use std::fmt::Debug; - -#[cfg(test)] -mod tests; - -pub struct Graph { - nodes: Vec>, - edges: Vec>, -} - -pub struct Node { - first_edge: [EdgeIndex; 2], // see module comment - pub data: N, -} - -#[derive(Debug)] -pub struct Edge { - next_edge: [EdgeIndex; 2], // see module comment - source: NodeIndex, - target: NodeIndex, - pub data: E, -} - -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct NodeIndex(pub usize); - -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct EdgeIndex(pub usize); - -pub const INVALID_EDGE_INDEX: EdgeIndex = EdgeIndex(usize::MAX); - -// Use a private field here to guarantee no more instances are created: -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct Direction { - repr: usize, -} - -pub const OUTGOING: Direction = Direction { repr: 0 }; - -pub const INCOMING: Direction = Direction { repr: 1 }; - -impl NodeIndex { - /// Returns unique ID (unique with respect to the graph holding associated node). - pub fn node_id(self) -> usize { - self.0 - } -} - -impl Graph { - pub fn new() -> Graph { - Graph { nodes: Vec::new(), edges: Vec::new() } - } - - pub fn with_capacity(nodes: usize, edges: usize) -> Graph { - Graph { nodes: Vec::with_capacity(nodes), edges: Vec::with_capacity(edges) } - } - - // # Simple accessors - - #[inline] - pub fn all_nodes(&self) -> &[Node] { - &self.nodes - } - - #[inline] - pub fn len_nodes(&self) -> usize { - self.nodes.len() - } - - #[inline] - pub fn all_edges(&self) -> &[Edge] { - &self.edges - } - - #[inline] - pub fn len_edges(&self) -> usize { - self.edges.len() - } - - // # Node construction - - pub fn next_node_index(&self) -> NodeIndex { - NodeIndex(self.nodes.len()) - } - - pub fn add_node(&mut self, data: N) -> NodeIndex { - let idx = self.next_node_index(); - self.nodes.push(Node { first_edge: [INVALID_EDGE_INDEX, INVALID_EDGE_INDEX], data }); - idx - } - - pub fn mut_node_data(&mut self, idx: NodeIndex) -> &mut N { - &mut self.nodes[idx.0].data - } - - pub fn node_data(&self, idx: NodeIndex) -> &N { - &self.nodes[idx.0].data - } - - pub fn node(&self, idx: NodeIndex) -> &Node { - &self.nodes[idx.0] - } - - // # Edge construction and queries - - pub fn next_edge_index(&self) -> EdgeIndex { - EdgeIndex(self.edges.len()) - } - - pub fn add_edge(&mut self, source: NodeIndex, target: NodeIndex, data: E) -> EdgeIndex { - debug!("graph: add_edge({:?}, {:?}, {:?})", source, target, data); - - let idx = self.next_edge_index(); - - // read current first of the list of edges from each node - let source_first = self.nodes[source.0].first_edge[OUTGOING.repr]; - let target_first = self.nodes[target.0].first_edge[INCOMING.repr]; - - // create the new edge, with the previous firsts from each node - // as the next pointers - self.edges.push(Edge { next_edge: [source_first, target_first], source, target, data }); - - // adjust the firsts for each node target be the next object. - self.nodes[source.0].first_edge[OUTGOING.repr] = idx; - self.nodes[target.0].first_edge[INCOMING.repr] = idx; - - idx - } - - pub fn edge(&self, idx: EdgeIndex) -> &Edge { - &self.edges[idx.0] - } - - // # Iterating over nodes, edges - - pub fn enumerated_nodes(&self) -> impl Iterator)> { - self.nodes.iter().enumerate().map(|(idx, n)| (NodeIndex(idx), n)) - } - - pub fn enumerated_edges(&self) -> impl Iterator)> { - self.edges.iter().enumerate().map(|(idx, e)| (EdgeIndex(idx), e)) - } - - pub fn each_node<'a>(&'a self, mut f: impl FnMut(NodeIndex, &'a Node) -> bool) -> bool { - //! Iterates over all edges defined in the graph. - self.enumerated_nodes().all(|(node_idx, node)| f(node_idx, node)) - } - - pub fn each_edge<'a>(&'a self, mut f: impl FnMut(EdgeIndex, &'a Edge) -> bool) -> bool { - //! Iterates over all edges defined in the graph - self.enumerated_edges().all(|(edge_idx, edge)| f(edge_idx, edge)) - } - - pub fn outgoing_edges(&self, source: NodeIndex) -> AdjacentEdges<'_, N, E> { - self.adjacent_edges(source, OUTGOING) - } - - pub fn incoming_edges(&self, source: NodeIndex) -> AdjacentEdges<'_, N, E> { - self.adjacent_edges(source, INCOMING) - } - - pub fn adjacent_edges( - &self, - source: NodeIndex, - direction: Direction, - ) -> AdjacentEdges<'_, N, E> { - let first_edge = self.node(source).first_edge[direction.repr]; - AdjacentEdges { graph: self, direction, next: first_edge } - } - - pub fn successor_nodes(&self, source: NodeIndex) -> impl Iterator + '_ { - self.outgoing_edges(source).targets() - } - - pub fn predecessor_nodes(&self, target: NodeIndex) -> impl Iterator + '_ { - self.incoming_edges(target).sources() - } - - pub fn depth_traverse( - &self, - start: NodeIndex, - direction: Direction, - ) -> DepthFirstTraversal<'_, N, E> { - DepthFirstTraversal::with_start_node(self, start, direction) - } - - pub fn nodes_in_postorder( - &self, - direction: Direction, - entry_node: NodeIndex, - ) -> Vec { - let mut visited = BitSet::new_empty(self.len_nodes()); - let mut stack = vec![]; - let mut result = Vec::with_capacity(self.len_nodes()); - let mut push_node = |stack: &mut Vec<_>, node: NodeIndex| { - if visited.insert(node.0) { - stack.push((node, self.adjacent_edges(node, direction))); - } - }; - - for node in - Some(entry_node).into_iter().chain(self.enumerated_nodes().map(|(node, _)| node)) - { - push_node(&mut stack, node); - while let Some((node, mut iter)) = stack.pop() { - if let Some((_, child)) = iter.next() { - let target = child.source_or_target(direction); - // the current node needs more processing, so - // add it back to the stack - stack.push((node, iter)); - // and then push the new node - push_node(&mut stack, target); - } else { - result.push(node); - } - } - } - - assert_eq!(result.len(), self.len_nodes()); - result - } -} - -// # Iterators - -pub struct AdjacentEdges<'g, N, E> { - graph: &'g Graph, - direction: Direction, - next: EdgeIndex, -} - -impl<'g, N: Debug, E: Debug> AdjacentEdges<'g, N, E> { - fn targets(self) -> impl Iterator + 'g { - self.map(|(_, edge)| edge.target) - } - - fn sources(self) -> impl Iterator + 'g { - self.map(|(_, edge)| edge.source) - } -} - -impl<'g, N: Debug, E: Debug> Iterator for AdjacentEdges<'g, N, E> { - type Item = (EdgeIndex, &'g Edge); - - fn next(&mut self) -> Option<(EdgeIndex, &'g Edge)> { - let edge_index = self.next; - if edge_index == INVALID_EDGE_INDEX { - return None; - } - - let edge = self.graph.edge(edge_index); - self.next = edge.next_edge[self.direction.repr]; - Some((edge_index, edge)) - } - - fn size_hint(&self) -> (usize, Option) { - // At most, all the edges in the graph. - (0, Some(self.graph.len_edges())) - } -} - -pub struct DepthFirstTraversal<'g, N, E> { - graph: &'g Graph, - stack: Vec, - visited: BitSet, - direction: Direction, -} - -impl<'g, N: Debug, E: Debug> DepthFirstTraversal<'g, N, E> { - pub fn with_start_node( - graph: &'g Graph, - start_node: NodeIndex, - direction: Direction, - ) -> Self { - let mut visited = BitSet::new_empty(graph.len_nodes()); - visited.insert(start_node.node_id()); - DepthFirstTraversal { graph, stack: vec![start_node], visited, direction } - } - - fn visit(&mut self, node: NodeIndex) { - if self.visited.insert(node.node_id()) { - self.stack.push(node); - } - } -} - -impl<'g, N: Debug, E: Debug> Iterator for DepthFirstTraversal<'g, N, E> { - type Item = NodeIndex; - - fn next(&mut self) -> Option { - let next = self.stack.pop(); - if let Some(idx) = next { - for (_, edge) in self.graph.adjacent_edges(idx, self.direction) { - let target = edge.source_or_target(self.direction); - self.visit(target); - } - } - next - } - - fn size_hint(&self) -> (usize, Option) { - // We will visit every node in the graph exactly once. - let remaining = self.graph.len_nodes() - self.visited.count(); - (remaining, Some(remaining)) - } -} - -impl<'g, N: Debug, E: Debug> ExactSizeIterator for DepthFirstTraversal<'g, N, E> {} - -impl Edge { - pub fn source(&self) -> NodeIndex { - self.source - } - - pub fn target(&self) -> NodeIndex { - self.target - } - - pub fn source_or_target(&self, direction: Direction) -> NodeIndex { - if direction == OUTGOING { self.target } else { self.source } - } -} +use rustc_index::bit_set::BitSet;use std::fmt::Debug;#[cfg(test)]mod tests;pub// +struct Graph{nodes:Vec>,edges:Vec>,}pub struct Node{//3; +first_edge:[EdgeIndex;2],pub data:N,}#[derive(Debug)]pub struct Edge{//{();}; +next_edge:[EdgeIndex;2],source:NodeIndex,target :NodeIndex,pub data:E,}#[derive( +Copy,Clone,PartialEq,Debug)]pub struct NodeIndex(pub usize);#[derive(Copy,Clone +,PartialEq,Debug)]pub struct EdgeIndex (pub usize);pub const INVALID_EDGE_INDEX: +EdgeIndex=EdgeIndex(usize::MAX);#[derive (Copy,Clone,Debug,PartialEq)]pub struct +Direction{repr:usize,}pub const OUTGOING:Direction=Direction{repr:0};pub const// +INCOMING:Direction=Direction{repr:1};impl NodeIndex{pub fn node_id(self)->//{;}; +usize{self.0}}implGraph{pub fn new()->Graph{Graph{//; +nodes:Vec::new(),edges:Vec::new() }}pub fn with_capacity(nodes:usize,edges:usize +)->Graph{Graph{nodes:Vec::with_capacity(nodes),edges:Vec::with_capacity(//; +edges)}}#[inline]pub fn all_nodes(&self)->&[Node]{&self.nodes}#[inline]pub//; +fn len_nodes(&self)->usize{self.nodes.len( )}#[inline]pub fn all_edges(&self)->& +[Edge]{&self.edges}#[inline]pub fn len_edges(&self)->usize{self.edges.len()} +pub fn next_node_index(&self)->NodeIndex{NodeIndex(self.nodes.len())}pub fn//(); +add_node(&mut self,data:N)->NodeIndex{;let idx=self.next_node_index();self.nodes +.push(Node{first_edge:[INVALID_EDGE_INDEX,INVALID_EDGE_INDEX],data});;idx}pub fn +mut_node_data(&mut self,idx:NodeIndex)->&mut N{&mut self.nodes[idx.0].data}pub// +fn node_data(&self,idx:NodeIndex)->&N{&self.nodes[idx.0].data}pub fn node(&//(); +self,idx:NodeIndex)->&Node{&self.nodes[idx.0]}pub fn next_edge_index(&self)// +->EdgeIndex{EdgeIndex(self.edges.len())}pub fn add_edge(&mut self,source://({}); +NodeIndex,target:NodeIndex,data:E)->EdgeIndex{loop{break;};if let _=(){};debug!( +"graph: add_edge({:?}, {:?}, {:?})",source,target,data);{();};({});let idx=self. +next_edge_index();3;3;let source_first=self.nodes[source.0].first_edge[OUTGOING. +repr];3;;let target_first=self.nodes[target.0].first_edge[INCOMING.repr];;;self. +edges.push(Edge{next_edge:[source_first,target_first],source,target,data});;self +.nodes[source.0].first_edge[OUTGOING.repr]=idx;;self.nodes[target.0].first_edge[ +INCOMING.repr]=idx;3;idx}pub fn edge(&self,idx:EdgeIndex)->&Edge{&self.edges[ +idx.0]}pub fn enumerated_nodes(&self)-> impl Iterator)> +{self.nodes.iter().enumerate().map(|(idx,n)|(NodeIndex(idx),n))}pub fn//((),()); +enumerated_edges(&self)->impl Iterator)>{self.edges.//; +iter().enumerate().map(|(idx,e)|(EdgeIndex(idx),e))}pub fn each_node<'a>(&'a//3; +self,mut f:impl FnMut(NodeIndex,&'a Node)->bool)->bool{self.enumerated_nodes +().all(|(node_idx,node)|f(node_idx,node))}pub fn each_edge<'a>(&'a self,mut f:// +impl FnMut(EdgeIndex,&'a Edge)->bool)->bool{self.enumerated_edges().all(|(//; +edge_idx,edge)|f(edge_idx,edge))}pub fn outgoing_edges(&self,source:NodeIndex)// +->AdjacentEdges<'_,N,E>{self.adjacent_edges(source,OUTGOING)}pub fn//let _=||(); +incoming_edges(&self,source:NodeIndex)->AdjacentEdges<'_,N,E>{self.//let _=||(); +adjacent_edges(source,INCOMING)}pub fn adjacent_edges(&self,source:NodeIndex,//; +direction:Direction,)->AdjacentEdges<'_,N,E>{3;let first_edge=self.node(source). +first_edge[direction.repr];;AdjacentEdges{graph:self,direction,next:first_edge}} +pub fn successor_nodes(&self,source:NodeIndex)->impl Iterator+// +'_{self.outgoing_edges(source).targets() }pub fn predecessor_nodes(&self,target: +NodeIndex)->impl Iterator+'_{self.incoming_edges(target).//({}); +sources()}pub fn depth_traverse(&self,start:NodeIndex,direction:Direction,)->//; +DepthFirstTraversal<'_,N,E>{DepthFirstTraversal::with_start_node(self,start,//3; +direction)}pub fn nodes_in_postorder(&self,direction:Direction,entry_node://{;}; +NodeIndex,)->Vec{;let mut visited=BitSet::new_empty(self.len_nodes()) +;;;let mut stack=vec![];;let mut result=Vec::with_capacity(self.len_nodes());let +mut push_node=|stack:&mut Vec<_>,node:NodeIndex|{if visited.insert(node.0){({}); +stack.push((node,self.adjacent_edges(node,direction)));();}};3;for node in Some( +entry_node).into_iter().chain(self.enumerated_nodes().map(|(node,_)|node)){({}); +push_node(&mut stack,node);();while let Some((node,mut iter))=stack.pop(){if let +Some((_,child))=iter.next(){;let target=child.source_or_target(direction);stack. +push((node,iter));;;push_node(&mut stack,target);;}else{;result.push(node);;}}}; +assert_eq!(result.len(),self.len_nodes());;result}}pub struct AdjacentEdges<'g,N +,E>{graph:&'g Graph,direction :Direction,next:EdgeIndex,}impl<'g,N:Debug,E: +Debug>AdjacentEdges<'g,N,E>{fn targets (self)->impl Iterator+'g{ +self.map(|(_,edge)|edge.target) }fn sources(self)->impl Iterator ++'g{self.map(|(_,edge)|edge.source)}}impl<'g,N:Debug,E:Debug>Iterator for//({}); +AdjacentEdges<'g,N,E>{type Item=(EdgeIndex,&'g Edge);fn next(&mut self)->//3; +Option<(EdgeIndex,&'g Edge)>{{;};let edge_index=self.next;{;};if edge_index== +INVALID_EDGE_INDEX{;return None;}let edge=self.graph.edge(edge_index);self.next= +edge.next_edge[self.direction.repr];;Some((edge_index,edge))}fn size_hint(&self) +->(usize,Option){(0,Some(self.graph.len_edges()))}}pub struct//if true{}; +DepthFirstTraversal<'g,N,E>{graph:&'g Graph,stack:Vec,visited:// +BitSet,direction:Direction,}impl< 'g,N:Debug,E:Debug>DepthFirstTraversal< +'g,N,E>{pub fn with_start_node(graph:&'g Graph,start_node:NodeIndex,//({}); +direction:Direction,)->Self{;let mut visited=BitSet::new_empty(graph.len_nodes() +);3;;visited.insert(start_node.node_id());;DepthFirstTraversal{graph,stack:vec![ +start_node],visited,direction}}fn visit(&mut self,node:NodeIndex){if self.//{;}; +visited.insert(node.node_id()){;self.stack.push(node);}}}impl<'g,N:Debug,E:Debug +>Iterator for DepthFirstTraversal<'g,N,E>{ type Item=NodeIndex;fn next(&mut self +)->Option{;let next=self.stack.pop();if let Some(idx)=next{for(_,edge +)in self.graph.adjacent_edges(idx,self.direction){if let _=(){};let target=edge. +source_or_target(self.direction);;;self.visit(target);}}next}fn size_hint(&self) +->(usize,Option){;let remaining=self.graph.len_nodes()-self.visited.count +();();(remaining,Some(remaining))}}impl<'g,N:Debug,E:Debug>ExactSizeIterator for +DepthFirstTraversal<'g,N,E>{}implEdge{pub fn source(&self)->NodeIndex{//3; +self.source}pub fn target(&self )->NodeIndex{self.target}pub fn source_or_target +(&self,direction:Direction)->NodeIndex{ if direction==OUTGOING{self.target}else{ +self.source}}}//((),());((),());((),());((),());((),());((),());((),());((),()); diff --git a/compiler/rustc_data_structures/src/graph/implementation/tests.rs b/compiler/rustc_data_structures/src/graph/implementation/tests.rs index 3ae5f5868f080..b68ef5b3206e2 100644 --- a/compiler/rustc_data_structures/src/graph/implementation/tests.rs +++ b/compiler/rustc_data_structures/src/graph/implementation/tests.rs @@ -1,130 +1,34 @@ -use crate::graph::implementation::*; - -type TestGraph = Graph<&'static str, &'static str>; - -fn create_graph() -> TestGraph { - let mut graph = Graph::new(); - - // Create a simple graph - // - // F - // | - // V - // A --> B --> C - // | ^ - // v | - // D --> E - - let a = graph.add_node("A"); - let b = graph.add_node("B"); - let c = graph.add_node("C"); - let d = graph.add_node("D"); - let e = graph.add_node("E"); - let f = graph.add_node("F"); - - graph.add_edge(a, b, "AB"); - graph.add_edge(b, c, "BC"); - graph.add_edge(b, d, "BD"); - graph.add_edge(d, e, "DE"); - graph.add_edge(e, c, "EC"); - graph.add_edge(f, b, "FB"); - - return graph; -} - -#[test] -fn each_node() { - let graph = create_graph(); - let expected = ["A", "B", "C", "D", "E", "F"]; - graph.each_node(|idx, node| { - assert_eq!(&expected[idx.0], graph.node_data(idx)); - assert_eq!(expected[idx.0], node.data); - true - }); -} - -#[test] -fn each_edge() { - let graph = create_graph(); - let expected = ["AB", "BC", "BD", "DE", "EC", "FB"]; - graph.each_edge(|idx, edge| { - assert_eq!(expected[idx.0], edge.data); - true - }); -} - -fn test_adjacent_edges( - graph: &Graph, - start_index: NodeIndex, - start_data: N, - expected_incoming: &[(E, N)], - expected_outgoing: &[(E, N)], -) { - assert!(graph.node_data(start_index) == &start_data); - - let mut counter = 0; - for (edge_index, edge) in graph.incoming_edges(start_index) { - assert!(counter < expected_incoming.len()); - debug!( - "counter={:?} expected={:?} edge_index={:?} edge={:?}", - counter, expected_incoming[counter], edge_index, edge - ); - match &expected_incoming[counter] { - (e, n) => { - assert!(e == &edge.data); - assert!(n == graph.node_data(edge.source())); - assert!(start_index == edge.target); - } - } - counter += 1; - } - assert_eq!(counter, expected_incoming.len()); - - let mut counter = 0; - for (edge_index, edge) in graph.outgoing_edges(start_index) { - assert!(counter < expected_outgoing.len()); - debug!( - "counter={:?} expected={:?} edge_index={:?} edge={:?}", - counter, expected_outgoing[counter], edge_index, edge - ); - match &expected_outgoing[counter] { - (e, n) => { - assert!(e == &edge.data); - assert!(start_index == edge.source); - assert!(n == graph.node_data(edge.target)); - } - } - counter += 1; - } - assert_eq!(counter, expected_outgoing.len()); -} - -#[test] -fn each_adjacent_from_a() { - let graph = create_graph(); - test_adjacent_edges(&graph, NodeIndex(0), "A", &[], &[("AB", "B")]); -} - -#[test] -fn each_adjacent_from_b() { - let graph = create_graph(); - test_adjacent_edges( - &graph, - NodeIndex(1), - "B", - &[("FB", "F"), ("AB", "A")], - &[("BD", "D"), ("BC", "C")], - ); -} - -#[test] -fn each_adjacent_from_c() { - let graph = create_graph(); - test_adjacent_edges(&graph, NodeIndex(2), "C", &[("EC", "E"), ("BC", "B")], &[]); -} - -#[test] -fn each_adjacent_from_d() { - let graph = create_graph(); - test_adjacent_edges(&graph, NodeIndex(3), "D", &[("BD", "B")], &[("DE", "E")]); -} +use crate::graph::implementation::*;type TestGraph=Graph<&'static str,&'static// +str>;fn create_graph()->TestGraph{();let mut graph=Graph::new();3;3;let a=graph. +add_node("A");;;let b=graph.add_node("B");let c=graph.add_node("C");let d=graph. +add_node("D");3;3;let e=graph.add_node("E");;;let f=graph.add_node("F");;;graph. +add_edge(a,b,"AB");;;graph.add_edge(b,c,"BC");;;graph.add_edge(b,d,"BD");;graph. +add_edge(d,e,"DE");;;graph.add_edge(e,c,"EC");;;graph.add_edge(f,b,"FB");;return +graph;;}#[test]fn each_node(){let graph=create_graph();let expected=["A","B","C" +,"D","E","F"];3;3;graph.each_node(|idx,node|{;assert_eq!(&expected[idx.0],graph. +node_data(idx));();3;assert_eq!(expected[idx.0],node.data);3;true});3;}#[test]fn +each_edge(){3;let graph=create_graph();;;let expected=["AB","BC","BD","DE","EC", +"FB"];;graph.each_edge(|idx,edge|{assert_eq!(expected[idx.0],edge.data);true});} +fn test_adjacent_edges(graph:&Graph,// +start_index:NodeIndex,start_data:N,expected_incoming: &[(E,N)],expected_outgoing +:&[(E,N)],){;assert!(graph.node_data(start_index)==&start_data);let mut counter= +0;();for(edge_index,edge)in graph.incoming_edges(start_index){3;assert!(counter< +expected_incoming.len());loop{break};loop{break};loop{break};loop{break};debug!( +"counter={:?} expected={:?} edge_index={:?} edge={:?}",counter,//*&*&();((),()); +expected_incoming[counter],edge_index,edge);;match&expected_incoming[counter]{(e +,n)=>{;assert!(e==&edge.data);assert!(n==graph.node_data(edge.source()));assert! +(start_index==edge.target);;}};counter+=1;}assert_eq!(counter,expected_incoming. +len());{;};{;};let mut counter=0;();for(edge_index,edge)in graph.outgoing_edges( +start_index){*&*&();assert!(counter{;assert!(e==&edge.data);assert!(start_index==edge.source);assert!(n==graph +.node_data(edge.target));;}}counter+=1;}assert_eq!(counter,expected_outgoing.len +());({});}#[test]fn each_adjacent_from_a(){{;};let graph=create_graph();{;};{;}; +test_adjacent_edges(&graph,NodeIndex(0),"A",&[],&[("AB","B")]);*&*&();}#[test]fn +each_adjacent_from_b(){3;let graph=create_graph();3;;test_adjacent_edges(&graph, +NodeIndex(1),"B",&[("FB","F"),("AB","A")],&[("BD","D"),("BC","C")],);;}#[test]fn +each_adjacent_from_c(){3;let graph=create_graph();3;;test_adjacent_edges(&graph, +NodeIndex(2),"C",&[("EC","E"),("BC","B")],&[]);;}#[test]fn each_adjacent_from_d( +){;let graph=create_graph();test_adjacent_edges(&graph,NodeIndex(3),"D",&[("BD", +"B")],&[("DE","E")]);if let _=(){};*&*&();((),());if let _=(){};*&*&();((),());} diff --git a/compiler/rustc_data_structures/src/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs index 9eb4b5278c079..0033497cd8eed 100644 --- a/compiler/rustc_data_structures/src/graph/iterate/mod.rs +++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs @@ -1,353 +1,70 @@ -use super::{DirectedGraph, WithNumNodes, WithStartNode, WithSuccessors}; -use rustc_index::bit_set::BitSet; -use rustc_index::{IndexSlice, IndexVec}; -use std::ops::ControlFlow; - -#[cfg(test)] -mod tests; - -pub fn post_order_from( - graph: &G, - start_node: G::Node, -) -> Vec { - post_order_from_to(graph, start_node, None) -} - -pub fn post_order_from_to( - graph: &G, - start_node: G::Node, - end_node: Option, -) -> Vec { - let mut visited: IndexVec = IndexVec::from_elem_n(false, graph.num_nodes()); - let mut result: Vec = Vec::with_capacity(graph.num_nodes()); - if let Some(end_node) = end_node { - visited[end_node] = true; - } - post_order_walk(graph, start_node, &mut result, &mut visited); - result -} - -fn post_order_walk( - graph: &G, - node: G::Node, - result: &mut Vec, - visited: &mut IndexSlice, -) { - struct PostOrderFrame { - node: Node, - iter: Iter, - } - - if visited[node] { - return; - } - - let mut stack = vec![PostOrderFrame { node, iter: graph.successors(node) }]; - - 'recurse: while let Some(frame) = stack.last_mut() { - let node = frame.node; - visited[node] = true; - - while let Some(successor) = frame.iter.next() { - if !visited[successor] { - stack.push(PostOrderFrame { node: successor, iter: graph.successors(successor) }); - continue 'recurse; - } - } - - let _ = stack.pop(); - result.push(node); - } -} - -pub fn reverse_post_order( - graph: &G, - start_node: G::Node, -) -> Vec { - let mut vec = post_order_from(graph, start_node); - vec.reverse(); - vec -} - -/// A "depth-first search" iterator for a directed graph. -pub struct DepthFirstSearch<'graph, G> -where - G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, -{ - graph: &'graph G, - stack: Vec, - visited: BitSet, -} - -impl<'graph, G> DepthFirstSearch<'graph, G> -where - G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, -{ - pub fn new(graph: &'graph G) -> Self { - Self { graph, stack: vec![], visited: BitSet::new_empty(graph.num_nodes()) } - } - - /// Version of `push_start_node` that is convenient for chained - /// use. - pub fn with_start_node(mut self, start_node: G::Node) -> Self { - self.push_start_node(start_node); - self - } - - /// Pushes another start node onto the stack. If the node - /// has not already been visited, then you will be able to - /// walk its successors (and so forth) after the current - /// contents of the stack are drained. If multiple start nodes - /// are added into the walk, then their mutual successors - /// will all be walked. You can use this method once the - /// iterator has been completely drained to add additional - /// start nodes. - pub fn push_start_node(&mut self, start_node: G::Node) { - if self.visited.insert(start_node) { - self.stack.push(start_node); - } - } - - /// Searches all nodes reachable from the current start nodes. - /// This is equivalent to just invoke `next` repeatedly until - /// you get a `None` result. - pub fn complete_search(&mut self) { - while let Some(_) = self.next() {} - } - - /// Returns true if node has been visited thus far. - /// A node is considered "visited" once it is pushed - /// onto the internal stack; it may not yet have been yielded - /// from the iterator. This method is best used after - /// the iterator is completely drained. - pub fn visited(&self, node: G::Node) -> bool { - self.visited.contains(node) - } -} - -impl std::fmt::Debug for DepthFirstSearch<'_, G> -where - G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, -{ - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let mut f = fmt.debug_set(); - for n in self.visited.iter() { - f.entry(&n); - } - f.finish() - } -} - -impl Iterator for DepthFirstSearch<'_, G> -where - G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, -{ - type Item = G::Node; - - fn next(&mut self) -> Option { - let DepthFirstSearch { stack, visited, graph } = self; - let n = stack.pop()?; - stack.extend(graph.successors(n).filter(|&m| visited.insert(m))); - Some(n) - } -} - -/// The status of a node in the depth-first search. -/// -/// See the documentation of `TriColorDepthFirstSearch` to see how a node's status is updated -/// during DFS. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum NodeStatus { - /// This node has been examined by the depth-first search but is not yet `Settled`. - /// - /// Also referred to as "gray" or "discovered" nodes in [CLR]. - /// - /// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms - Visited, - - /// This node and all nodes reachable from it have been examined by the depth-first search. - /// - /// Also referred to as "black" or "finished" nodes in [CLR]. - /// - /// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms - Settled, -} - -struct Event { - node: N, - becomes: NodeStatus, -} - -/// A depth-first search that also tracks when all successors of a node have been examined. -/// -/// This is based on the DFS described in [Introduction to Algorithms (1st ed.)][CLR], hereby -/// referred to as **CLR**. However, we use the terminology in [`NodeStatus`] above instead of -/// "discovered"/"finished" or "white"/"grey"/"black". Each node begins the search with no status, -/// becomes `Visited` when it is first examined by the DFS and is `Settled` when all nodes -/// reachable from it have been examined. This allows us to differentiate between "tree", "back" -/// and "forward" edges (see [`TriColorVisitor::node_examined`]). -/// -/// Unlike the pseudocode in [CLR], this implementation is iterative and does not use timestamps. -/// We accomplish this by storing `Event`s on the stack that result in a (possible) state change -/// for each node. A `Visited` event signifies that we should examine this node if it has not yet -/// been `Visited` or `Settled`. When a node is examined for the first time, we mark it as -/// `Visited` and push a `Settled` event for it on stack followed by `Visited` events for all of -/// its predecessors, scheduling them for examination. Multiple `Visited` events for a single node -/// may exist on the stack simultaneously if a node has multiple predecessors, but only one -/// `Settled` event will ever be created for each node. After all `Visited` events for a node's -/// successors have been popped off the stack (as well as any new events triggered by visiting -/// those successors), we will pop off that node's `Settled` event. -/// -/// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms -pub struct TriColorDepthFirstSearch<'graph, G> -where - G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, -{ - graph: &'graph G, - stack: Vec>, - visited: BitSet, - settled: BitSet, -} - -impl<'graph, G> TriColorDepthFirstSearch<'graph, G> -where - G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, -{ - pub fn new(graph: &'graph G) -> Self { - TriColorDepthFirstSearch { - graph, - stack: vec![], - visited: BitSet::new_empty(graph.num_nodes()), - settled: BitSet::new_empty(graph.num_nodes()), - } - } - - /// Performs a depth-first search, starting from the given `root`. - /// - /// This won't visit nodes that are not reachable from `root`. - pub fn run_from(mut self, root: G::Node, visitor: &mut V) -> Option - where - V: TriColorVisitor, - { - use NodeStatus::{Settled, Visited}; - - self.stack.push(Event { node: root, becomes: Visited }); - - loop { - match self.stack.pop()? { - Event { node, becomes: Settled } => { - let not_previously_settled = self.settled.insert(node); - assert!(not_previously_settled, "A node should be settled exactly once"); - if let ControlFlow::Break(val) = visitor.node_settled(node) { - return Some(val); - } - } - - Event { node, becomes: Visited } => { - let not_previously_visited = self.visited.insert(node); - let prior_status = if not_previously_visited { - None - } else if self.settled.contains(node) { - Some(Settled) - } else { - Some(Visited) - }; - - if let ControlFlow::Break(val) = visitor.node_examined(node, prior_status) { - return Some(val); - } - - // If this node has already been examined, we are done. - if prior_status.is_some() { - continue; - } - - // Otherwise, push a `Settled` event for this node onto the stack, then - // schedule its successors for examination. - self.stack.push(Event { node, becomes: Settled }); - for succ in self.graph.successors(node) { - if !visitor.ignore_edge(node, succ) { - self.stack.push(Event { node: succ, becomes: Visited }); - } - } - } - } - } - } -} - -impl TriColorDepthFirstSearch<'_, G> -where - G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors + WithStartNode, -{ - /// Performs a depth-first search, starting from `G::start_node()`. - /// - /// This won't visit nodes that are not reachable from the start node. - pub fn run_from_start(self, visitor: &mut V) -> Option - where - V: TriColorVisitor, - { - let root = self.graph.start_node(); - self.run_from(root, visitor) - } -} - -/// What to do when a node is examined or becomes `Settled` during DFS. -pub trait TriColorVisitor -where - G: ?Sized + DirectedGraph, -{ - /// The value returned by this search. - type BreakVal; - - /// Called when a node is examined by the depth-first search. - /// - /// By checking the value of `prior_status`, this visitor can determine whether the edge - /// leading to this node was a tree edge (`None`), forward edge (`Some(Settled)`) or back edge - /// (`Some(Visited)`). For a full explanation of each edge type, see the "Depth-first Search" - /// chapter in [CLR] or [wikipedia]. - /// - /// If you want to know *both* nodes linked by each edge, you'll need to modify - /// `TriColorDepthFirstSearch` to store a `source` node for each `Visited` event. - /// - /// [wikipedia]: https://en.wikipedia.org/wiki/Depth-first_search#Output_of_a_depth-first_search - /// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms - fn node_examined( - &mut self, - _node: G::Node, - _prior_status: Option, - ) -> ControlFlow { - ControlFlow::Continue(()) - } - - /// Called after all nodes reachable from this one have been examined. - fn node_settled(&mut self, _node: G::Node) -> ControlFlow { - ControlFlow::Continue(()) - } - - /// Behave as if no edges exist from `source` to `target`. - fn ignore_edge(&mut self, _source: G::Node, _target: G::Node) -> bool { - false - } -} - -/// This `TriColorVisitor` looks for back edges in a graph, which indicate that a cycle exists. -pub struct CycleDetector; - -impl TriColorVisitor for CycleDetector -where - G: ?Sized + DirectedGraph, -{ - type BreakVal = (); - - fn node_examined( - &mut self, - _node: G::Node, - prior_status: Option, - ) -> ControlFlow { - match prior_status { - Some(NodeStatus::Visited) => ControlFlow::Break(()), - _ => ControlFlow::Continue(()), - } - } -} +use super::{DirectedGraph,WithNumNodes,WithStartNode,WithSuccessors};use//{();}; +rustc_index::bit_set::BitSet;use rustc_index::{IndexSlice,IndexVec};use std:://; +ops::ControlFlow;#[cfg(test)]mod tests;pub fn post_order_from(graph:&G,start_node:G::Node,)->Vec{//({}); +post_order_from_to(graph,start_node,None)}pub fn post_order_from_to(graph: &G,start_node:G::Node,end_node +:Option,)->Vec{((),());let mut visited:IndexVec= +IndexVec::from_elem_n(false,graph.num_nodes());;;let mut result:Vec=Vec +::with_capacity(graph.num_nodes());();if let Some(end_node)=end_node{();visited[ +end_node]=true;3;}3;post_order_walk(graph,start_node,&mut result,&mut visited);; +result}fn post_order_walk(graph:&G +,node:G::Node,result:&mut Vec,visited:&mut IndexSlice,){; +struct PostOrderFrame{node:Node,iter:Iter,};if visited[node]{return;} +let mut stack=vec![PostOrderFrame{node,iter:graph.successors(node)}];3;'recurse: +while let Some(frame)=stack.last_mut(){;let node=frame.node;;visited[node]=true; +while let Some(successor)=frame.iter.next(){if!visited[successor]{();stack.push( +PostOrderFrame{node:successor,iter:graph.successors(successor)});{;};();continue +'recurse;;}};let _=stack.pop();;result.push(node);}}pub fn reverse_post_order(graph:&G ,start_node:G::Node,)->Vec{3;let mut vec=post_order_from(graph,start_node);;;vec.reverse();;vec}pub +struct DepthFirstSearch<'graph,G>where G:?Sized+DirectedGraph+WithNumNodes+//(); +WithSuccessors,{graph:&'graph G,stack:Vec,visited:BitSet,}//3; +impl<'graph,G>DepthFirstSearch<'graph,G>where G:?Sized+DirectedGraph+//let _=(); +WithNumNodes+WithSuccessors,{pub fn new(graph: &'graph G)->Self{Self{graph,stack +:vec![],visited:BitSet::new_empty(graph.num_nodes())}}pub fn with_start_node(//; +mut self,start_node:G::Node)->Self{;self.push_start_node(start_node);self}pub fn +push_start_node(&mut self,start_node:G::Node){if self.visited.insert(//let _=(); +start_node){3;self.stack.push(start_node);3;}}pub fn complete_search(&mut self){ +while let Some(_)=self.next(){}}pub fn visited(&self,node:G::Node)->bool{self.// +visited.contains(node)}}implstd::fmt::Debug for DepthFirstSearch<'_,G>where// +G:?Sized+DirectedGraph+WithNumNodes+WithSuccessors,{fn fmt(&self,fmt:&mut std:: +fmt::Formatter<'_>)->std::fmt::Result{;let mut f=fmt.debug_set();;for n in self. +visited.iter(){;f.entry(&n);}f.finish()}}implIterator for DepthFirstSearch<'_ +,G>where G:?Sized+DirectedGraph+ WithNumNodes+WithSuccessors,{type Item=G::Node; +fn next(&mut self)->Option{3;let DepthFirstSearch{stack,visited,graph}= +self;;;let n=stack.pop()?;;;stack.extend(graph.successors(n).filter(|&m|visited. +insert(m)));let _=||();Some(n)}}#[derive(Clone,Copy,Debug,PartialEq,Eq)]pub enum +NodeStatus{Visited,Settled,}struct Event{node:N,becomes:NodeStatus,}pub//{;}; +struct TriColorDepthFirstSearch<'graph,G>where G:?Sized+DirectedGraph+//((),()); +WithNumNodes+WithSuccessors,{graph:&'graph G, stack:Vec>,visited: +BitSet,settled:BitSet,}impl<'graph,G>TriColorDepthFirstSearch +<'graph,G>where G:?Sized+ DirectedGraph+WithNumNodes+WithSuccessors,{pub fn new( +graph:&'graph G)->Self{TriColorDepthFirstSearch{graph,stack:vec![],visited://(); +BitSet::new_empty(graph.num_nodes()) ,settled:BitSet::new_empty(graph.num_nodes( +)),}}pub fn run_from(mut self,root:G::Node,visitor:&mut V)->Optionwhere V:TriColorVisitor,{3;use NodeStatus::{Settled,Visited};;;self. +stack.push(Event{node:root,becomes:Visited});;loop{match self.stack.pop()?{Event +{node,becomes:Settled}=>{;let not_previously_settled=self.settled.insert(node);; +assert!(not_previously_settled,"A node should be settled exactly once");3;if let +ControlFlow::Break(val)=visitor.node_settled(node){3;return Some(val);3;}}Event{ +node,becomes:Visited}=>{;let not_previously_visited=self.visited.insert(node);;; +let prior_status=if not_previously_visited{None}else if self.settled.contains(// +node){Some(Settled)}else{Some(Visited)};;if let ControlFlow::Break(val)=visitor. +node_examined(node,prior_status){;return Some(val);;}if prior_status.is_some(){; +continue;;};self.stack.push(Event{node,becomes:Settled});for succ in self.graph. +successors(node){if!visitor.ignore_edge(node,succ){3;self.stack.push(Event{node: +succ,becomes:Visited});{;};}}}}}}}implTriColorDepthFirstSearch<'_,G>where G:? +Sized+DirectedGraph+WithNumNodes+WithSuccessors+WithStartNode,{pub fn//let _=(); +run_from_start(self,visitor:&mut V)->Optionwhere V://let _=||(); +TriColorVisitor,{;let root=self.graph.start_node();self.run_from(root,visitor +)}}pub trait TriColorVisitorwhere G:?Sized+DirectedGraph,{type BreakVal;fn//; +node_examined(&mut self,_node:G::Node,_prior_status:Option,)->//{;}; +ControlFlow{ControlFlow::Continue( ())}fn node_settled(&mut self +,_node:G::Node)->ControlFlow{ControlFlow::Continue(())}fn//({}); +ignore_edge(&mut self,_source:G::Node,_target:G::Node)->bool{false}}pub struct// +CycleDetector;implTriColorVisitorfor CycleDetector where G:?Sized+//{();}; +DirectedGraph,{type BreakVal=();fn node_examined(&mut self,_node:G::Node,//({}); +prior_status:Option,)->ControlFlow{match//if true{}; +prior_status{Some(NodeStatus::Visited)=>ControlFlow ::Break(()),_=>ControlFlow:: +Continue(()),}}}//*&*&();((),());((),());((),());*&*&();((),());((),());((),()); diff --git a/compiler/rustc_data_structures/src/graph/iterate/tests.rs b/compiler/rustc_data_structures/src/graph/iterate/tests.rs index c498c289337f1..a7d754d6e4da1 100644 --- a/compiler/rustc_data_structures/src/graph/iterate/tests.rs +++ b/compiler/rustc_data_structures/src/graph/iterate/tests.rs @@ -1,38 +1,12 @@ -use super::super::tests::TestGraph; - -use super::*; - -#[test] -fn diamond_post_order() { - let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3)]); - - let result = post_order_from(&graph, 0); - assert_eq!(result, vec![3, 1, 2, 0]); -} - -#[test] -fn is_cyclic() { - use super::super::is_cyclic; - - let diamond_acyclic = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3)]); - let diamond_cyclic = TestGraph::new(0, &[(0, 1), (1, 2), (2, 3), (3, 0)]); - - assert!(!is_cyclic(&diamond_acyclic)); - assert!(is_cyclic(&diamond_cyclic)); -} - -#[test] -fn dfs() { - let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3), (3, 0)]); - - let result: Vec = DepthFirstSearch::new(&graph).with_start_node(0).collect(); - assert_eq!(result, vec![0, 2, 3, 1]); -} - -#[test] -fn dfs_debug() { - let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3), (3, 0)]); - let mut dfs = DepthFirstSearch::new(&graph).with_start_node(0); - dfs.complete_search(); - assert_eq!(format!("{{0, 1, 2, 3}}"), format!("{:?}", dfs)); -} +use super::super::tests::TestGraph;use super::*;#[test]fn diamond_post_order(){; +let graph=TestGraph::new(0,&[(0,1),(0,2),(1,3),(2,3)]);*&*&();*&*&();let result= +post_order_from(&graph,0);;assert_eq!(result,vec![3,1,2,0]);}#[test]fn is_cyclic +(){;use super::super::is_cyclic;let diamond_acyclic=TestGraph::new(0,&[(0,1),(0, +2),(1,3),(2,3)]);;let diamond_cyclic=TestGraph::new(0,&[(0,1),(1,2),(2,3),(3,0)] +);;assert!(!is_cyclic(&diamond_acyclic));assert!(is_cyclic(&diamond_cyclic));}#[ +test]fn dfs(){;let graph=TestGraph::new(0,&[(0,1),(0,2),(1,3),(2,3),(3,0)]);;let +result:Vec=DepthFirstSearch::new(&graph).with_start_node(0).collect();3;; +assert_eq!(result,vec![0,2,3,1]);3;}#[test]fn dfs_debug(){;let graph=TestGraph:: +new(0,&[(0,1),(0,2),(1,3),(2,3),(3,0)]);();3;let mut dfs=DepthFirstSearch::new(& +graph).with_start_node(0);{;};();dfs.complete_search();();();assert_eq!(format!( +"{{0, 1, 2, 3}}"),format!("{:?}",dfs));if true{};if true{};if true{};if true{};} diff --git a/compiler/rustc_data_structures/src/graph/mod.rs b/compiler/rustc_data_structures/src/graph/mod.rs index e06ab2fe36b92..dbb74eb465974 100644 --- a/compiler/rustc_data_structures/src/graph/mod.rs +++ b/compiler/rustc_data_structures/src/graph/mod.rs @@ -1,81 +1,21 @@ -use rustc_index::Idx; - -pub mod dominators; -pub mod implementation; -pub mod iterate; -mod reference; -pub mod scc; -pub mod vec_graph; - -#[cfg(test)] -mod tests; - -pub trait DirectedGraph { - type Node: Idx; -} - -pub trait WithNumNodes: DirectedGraph { - fn num_nodes(&self) -> usize; -} - -pub trait WithNumEdges: DirectedGraph { - fn num_edges(&self) -> usize; -} - -pub trait WithSuccessors: DirectedGraph -where - Self: for<'graph> GraphSuccessors<'graph, Item = ::Node>, -{ - fn successors(&self, node: Self::Node) -> >::Iter; - - fn depth_first_search(&self, from: Self::Node) -> iterate::DepthFirstSearch<'_, Self> - where - Self: WithNumNodes, - { - iterate::DepthFirstSearch::new(self).with_start_node(from) - } -} - -#[allow(unused_lifetimes)] -pub trait GraphSuccessors<'graph> { - type Item; - type Iter: Iterator; -} - -pub trait WithPredecessors: DirectedGraph -where - Self: for<'graph> GraphPredecessors<'graph, Item = ::Node>, -{ - fn predecessors(&self, node: Self::Node) -> >::Iter; -} - -#[allow(unused_lifetimes)] -pub trait GraphPredecessors<'graph> { - type Item; - type Iter: Iterator; -} - -pub trait WithStartNode: DirectedGraph { - fn start_node(&self) -> Self::Node; -} - -pub trait ControlFlowGraph: - DirectedGraph + WithStartNode + WithPredecessors + WithSuccessors + WithNumNodes -{ - // convenient trait -} - -impl ControlFlowGraph for T where - T: DirectedGraph + WithStartNode + WithPredecessors + WithSuccessors + WithNumNodes -{ -} - -/// Returns `true` if the graph has a cycle that is reachable from the start node. -pub fn is_cyclic(graph: &G) -> bool -where - G: ?Sized + DirectedGraph + WithStartNode + WithSuccessors + WithNumNodes, -{ - iterate::TriColorDepthFirstSearch::new(graph) - .run_from_start(&mut iterate::CycleDetector) - .is_some() -} +use rustc_index::Idx;pub mod dominators; pub mod implementation;pub mod iterate; +mod reference;pub mod scc;pub mod vec_graph;#[cfg(test)]mod tests;pub trait//(); +DirectedGraph{type Node:Idx;}pub trait WithNumNodes:DirectedGraph{fn num_nodes( +&self)->usize;}pub trait WithNumEdges :DirectedGraph{fn num_edges(&self)->usize; +}pub trait WithSuccessors:DirectedGraph where Self:for<'graph>GraphSuccessors::Node> ,{fn successors(&self,node:Self::Node +)->>::Iter;fn depth_first_search(&self,from:Self::// +Node)->iterate::DepthFirstSearch<'_,Self>where Self:WithNumNodes,{iterate:://(); +DepthFirstSearch::new(self).with_start_node(from)}}#[allow(unused_lifetimes)]//; +pub trait GraphSuccessors<'graph>{type Item ;type Iter:Iterator +;}pub trait WithPredecessors:DirectedGraph where Self:for<'graph>//loop{break;}; +GraphPredecessors<'graph,Item=::Node>,{fn predecessors(& +self,node:Self::Node)->>::Iter;}#[allow(//((),()); +unused_lifetimes)]pub trait GraphPredecessors<'graph>{type Item;type Iter://{;}; +Iterator;}pub trait WithStartNode:DirectedGraph{fn start_node( +&self)->Self::Node;}pub trait ControlFlowGraph:DirectedGraph+WithStartNode+//(); +WithPredecessors+WithSuccessors+WithNumNodes{}implControlFlowGraph for T//(); +where T:DirectedGraph+WithStartNode+WithPredecessors+WithSuccessors+//if true{}; +WithNumNodes{}pub fn is_cyclic(graph: &G)->bool where G:?Sized+DirectedGraph+ +WithStartNode+WithSuccessors+WithNumNodes,{iterate::TriColorDepthFirstSearch::// +new(graph).run_from_start((((((((&mut iterate::CycleDetector)))))))).is_some()} diff --git a/compiler/rustc_data_structures/src/graph/reference.rs b/compiler/rustc_data_structures/src/graph/reference.rs index c259fe56c1509..772202a44b2df 100644 --- a/compiler/rustc_data_structures/src/graph/reference.rs +++ b/compiler/rustc_data_structures/src/graph/reference.rs @@ -1,39 +1,12 @@ -use super::*; - -impl<'graph, G: DirectedGraph> DirectedGraph for &'graph G { - type Node = G::Node; -} - -impl<'graph, G: WithNumNodes> WithNumNodes for &'graph G { - fn num_nodes(&self) -> usize { - (**self).num_nodes() - } -} - -impl<'graph, G: WithStartNode> WithStartNode for &'graph G { - fn start_node(&self) -> Self::Node { - (**self).start_node() - } -} - -impl<'graph, G: WithSuccessors> WithSuccessors for &'graph G { - fn successors(&self, node: Self::Node) -> >::Iter { - (**self).successors(node) - } -} - -impl<'graph, G: WithPredecessors> WithPredecessors for &'graph G { - fn predecessors(&self, node: Self::Node) -> >::Iter { - (**self).predecessors(node) - } -} - -impl<'iter, 'graph, G: WithPredecessors> GraphPredecessors<'iter> for &'graph G { - type Item = G::Node; - type Iter = >::Iter; -} - -impl<'iter, 'graph, G: WithSuccessors> GraphSuccessors<'iter> for &'graph G { - type Item = G::Node; - type Iter = >::Iter; -} +use super::*;impl<'graph,G:DirectedGraph >DirectedGraph for&'graph G{type Node=G +::Node;}impl<'graph,G:WithNumNodes>WithNumNodes for&'graph G{fn num_nodes(&self +)->usize{((**self). num_nodes())}}impl<'graph,G:WithStartNode>WithStartNode for& +'graph G{fn start_node(&self)->Self::Node{( **self).start_node()}}impl<'graph,G: +WithSuccessors>WithSuccessors for&'graph G{fn successors(&self,node:Self::Node) +->>::Iter{(* *self).successors(node)}}impl<'graph,G: +WithPredecessors>WithPredecessors for&'graph G{fn predecessors(&self,node:Self// +::Node)->>::Iter{(((**self)).predecessors(node))}} +impl<'iter,'graph,G:WithPredecessors>GraphPredecessors<'iter>for&'graph G{type// +Item=G::Node;type Iter=>::Iter;}impl<'iter,'graph +,G:WithSuccessors>GraphSuccessors<'iter>for&'graph G{type Item=G::Node;type//(); +Iter=>::Iter;}//let _=();let _=();let _=();let _=(); diff --git a/compiler/rustc_data_structures/src/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs index b54d75f7ed703..307b306a53040 100644 --- a/compiler/rustc_data_structures/src/graph/scc/mod.rs +++ b/compiler/rustc_data_structures/src/graph/scc/mod.rs @@ -1,580 +1,108 @@ -//! Routine to compute the strongly connected components (SCCs) of a graph. -//! -//! Also computes as the resulting DAG if each SCC is replaced with a -//! node in the graph. This uses [Tarjan's algorithm]( -//! https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm) -//! that completes in *O*(*n*) time. - -use crate::fx::FxHashSet; -use crate::graph::vec_graph::VecGraph; -use crate::graph::{DirectedGraph, GraphSuccessors, WithNumEdges, WithNumNodes, WithSuccessors}; -use rustc_index::{Idx, IndexSlice, IndexVec}; -use std::ops::Range; - -#[cfg(test)] -mod tests; - -/// Strongly connected components (SCC) of a graph. The type `N` is -/// the index type for the graph nodes and `S` is the index type for -/// the SCCs. We can map from each node to the SCC that it -/// participates in, and we also have the successors of each SCC. -pub struct Sccs { - /// For each node, what is the SCC index of the SCC to which it - /// belongs. - scc_indices: IndexVec, - - /// Data about each SCC. - scc_data: SccData, -} - -pub struct SccData { - /// For each SCC, the range of `all_successors` where its - /// successors can be found. - ranges: IndexVec>, - - /// Contains the successors for all the Sccs, concatenated. The - /// range of indices corresponding to a given SCC is found in its - /// SccData. - all_successors: Vec, -} - -impl Sccs { - pub fn new(graph: &(impl DirectedGraph + WithNumNodes + WithSuccessors)) -> Self { - SccsConstruction::construct(graph) - } - - pub fn scc_indices(&self) -> &IndexSlice { - &self.scc_indices - } - - pub fn scc_data(&self) -> &SccData { - &self.scc_data - } - - /// Returns the number of SCCs in the graph. - pub fn num_sccs(&self) -> usize { - self.scc_data.len() - } - - /// Returns an iterator over the SCCs in the graph. - /// - /// The SCCs will be iterated in **dependency order** (or **post order**), - /// meaning that if `S1 -> S2`, we will visit `S2` first and `S1` after. - /// This is convenient when the edges represent dependencies: when you visit - /// `S1`, the value for `S2` will already have been computed. - pub fn all_sccs(&self) -> impl Iterator { - (0..self.scc_data.len()).map(S::new) - } - - /// Returns the SCC to which a node `r` belongs. - pub fn scc(&self, r: N) -> S { - self.scc_indices[r] - } - - /// Returns the successors of the given SCC. - pub fn successors(&self, scc: S) -> &[S] { - self.scc_data.successors(scc) - } - - /// Construct the reverse graph of the SCC graph. - pub fn reverse(&self) -> VecGraph { - VecGraph::new( - self.num_sccs(), - self.all_sccs() - .flat_map(|source| { - self.successors(source).iter().map(move |&target| (target, source)) - }) - .collect(), - ) - } -} - -impl DirectedGraph for Sccs { - type Node = S; -} - -impl WithNumNodes for Sccs { - fn num_nodes(&self) -> usize { - self.num_sccs() - } -} - -impl WithNumEdges for Sccs { - fn num_edges(&self) -> usize { - self.scc_data.all_successors.len() - } -} - -impl<'graph, N: Idx, S: Idx> GraphSuccessors<'graph> for Sccs { - type Item = S; - - type Iter = std::iter::Cloned>; -} - -impl WithSuccessors for Sccs { - fn successors(&self, node: S) -> >::Iter { - self.successors(node).iter().cloned() - } -} - -impl SccData { - /// Number of SCCs, - fn len(&self) -> usize { - self.ranges.len() - } - - pub fn ranges(&self) -> &IndexSlice> { - &self.ranges - } - - pub fn all_successors(&self) -> &Vec { - &self.all_successors - } - - /// Returns the successors of the given SCC. - fn successors(&self, scc: S) -> &[S] { - // Annoyingly, `range` does not implement `Copy`, so we have - // to do `range.start..range.end`: - let range = &self.ranges[scc]; - &self.all_successors[range.start..range.end] - } - - /// Creates a new SCC with `successors` as its successors and - /// returns the resulting index. - fn create_scc(&mut self, successors: impl IntoIterator) -> S { - // Store the successors on `scc_successors_vec`, remembering - // the range of indices. - let all_successors_start = self.all_successors.len(); - self.all_successors.extend(successors); - let all_successors_end = self.all_successors.len(); - - debug!( - "create_scc({:?}) successors={:?}", - self.ranges.len(), - &self.all_successors[all_successors_start..all_successors_end], - ); - - self.ranges.push(all_successors_start..all_successors_end) - } -} - -struct SccsConstruction<'c, G: DirectedGraph + WithNumNodes + WithSuccessors, S: Idx> { - graph: &'c G, - - /// The state of each node; used during walk to record the stack - /// and after walk to record what cycle each node ended up being - /// in. - node_states: IndexVec>, - - /// The stack of nodes that we are visiting as part of the DFS. - node_stack: Vec, - - /// The stack of successors: as we visit a node, we mark our - /// position in this stack, and when we encounter a successor SCC, - /// we push it on the stack. When we complete an SCC, we can pop - /// everything off the stack that was found along the way. - successors_stack: Vec, - - /// A set used to strip duplicates. As we accumulate successors - /// into the successors_stack, we sometimes get duplicate entries. - /// We use this set to remove those -- we also keep its storage - /// around between successors to amortize memory allocation costs. - duplicate_set: FxHashSet, - - scc_data: SccData, -} - -#[derive(Copy, Clone, Debug)] -enum NodeState { - /// This node has not yet been visited as part of the DFS. - /// - /// After SCC construction is complete, this state ought to be - /// impossible. - NotVisited, - - /// This node is currently being walk as part of our DFS. It is on - /// the stack at the depth `depth`. - /// - /// After SCC construction is complete, this state ought to be - /// impossible. - BeingVisited { depth: usize }, - - /// Indicates that this node is a member of the given cycle. - InCycle { scc_index: S }, - - /// Indicates that this node is a member of whatever cycle - /// `parent` is a member of. This state is transient: whenever we - /// see it, we try to overwrite it with the current state of - /// `parent` (this is the "path compression" step of a union-find - /// algorithm). - InCycleWith { parent: N }, -} - -#[derive(Copy, Clone, Debug)] -enum WalkReturn { - Cycle { min_depth: usize }, - Complete { scc_index: S }, -} - -impl<'c, G, S> SccsConstruction<'c, G, S> -where - G: DirectedGraph + WithNumNodes + WithSuccessors, - S: Idx, -{ - /// Identifies SCCs in the graph `G` and computes the resulting - /// DAG. This uses a variant of [Tarjan's - /// algorithm][wikipedia]. The high-level summary of the algorithm - /// is that we do a depth-first search. Along the way, we keep a - /// stack of each node whose successors are being visited. We - /// track the depth of each node on this stack (there is no depth - /// if the node is not on the stack). When we find that some node - /// N with depth D can reach some other node N' with lower depth - /// D' (i.e., D' < D), we know that N, N', and all nodes in - /// between them on the stack are part of an SCC. - /// - /// [wikipedia]: https://bit.ly/2EZIx84 - fn construct(graph: &'c G) -> Sccs { - let num_nodes = graph.num_nodes(); - - let mut this = Self { - graph, - node_states: IndexVec::from_elem_n(NodeState::NotVisited, num_nodes), - node_stack: Vec::with_capacity(num_nodes), - successors_stack: Vec::new(), - scc_data: SccData { ranges: IndexVec::new(), all_successors: Vec::new() }, - duplicate_set: FxHashSet::default(), - }; - - let scc_indices = (0..num_nodes) - .map(G::Node::new) - .map(|node| match this.start_walk_from(node) { - WalkReturn::Complete { scc_index } => scc_index, - WalkReturn::Cycle { min_depth } => { - panic!("`start_walk_node({node:?})` returned cycle with depth {min_depth:?}") - } - }) - .collect(); - - Sccs { scc_indices, scc_data: this.scc_data } - } - - fn start_walk_from(&mut self, node: G::Node) -> WalkReturn { - if let Some(result) = self.inspect_node(node) { - result - } else { - self.walk_unvisited_node(node) - } - } - - /// Inspect a node during the DFS. We first examine its current - /// state -- if it is not yet visited (`NotVisited`), return `None` so - /// that the caller might push it onto the stack and start walking its - /// successors. - /// - /// If it is already on the DFS stack it will be in the state - /// `BeingVisited`. In that case, we have found a cycle and we - /// return the depth from the stack. - /// - /// Otherwise, we are looking at a node that has already been - /// completely visited. We therefore return `WalkReturn::Complete` - /// with its associated SCC index. - fn inspect_node(&mut self, node: G::Node) -> Option> { - Some(match self.find_state(node) { - NodeState::InCycle { scc_index } => WalkReturn::Complete { scc_index }, - - NodeState::BeingVisited { depth: min_depth } => WalkReturn::Cycle { min_depth }, - - NodeState::NotVisited => return None, - - NodeState::InCycleWith { parent } => panic!( - "`find_state` returned `InCycleWith({parent:?})`, which ought to be impossible" - ), - }) - } - - /// Fetches the state of the node `r`. If `r` is recorded as being - /// in a cycle with some other node `r2`, then fetches the state - /// of `r2` (and updates `r` to reflect current result). This is - /// basically the "find" part of a standard union-find algorithm - /// (with path compression). - fn find_state(&mut self, mut node: G::Node) -> NodeState { - // To avoid recursion we temporarily reuse the `parent` of each - // InCycleWith link to encode a downwards link while compressing - // the path. After we have found the root or deepest node being - // visited, we traverse the reverse links and correct the node - // states on the way. - // - // **Note**: This mutation requires that this is a leaf function - // or at least that none of the called functions inspects the - // current node states. Luckily, we are a leaf. - - // Remember one previous link. The termination condition when - // following links downwards is then simply as soon as we have - // found the initial self-loop. - let mut previous_node = node; - - // Ultimately assigned by the parent when following - // `InCycleWith` upwards. - let node_state = loop { - debug!("find_state(r = {:?} in state {:?})", node, self.node_states[node]); - match self.node_states[node] { - NodeState::InCycle { scc_index } => break NodeState::InCycle { scc_index }, - NodeState::BeingVisited { depth } => break NodeState::BeingVisited { depth }, - NodeState::NotVisited => break NodeState::NotVisited, - NodeState::InCycleWith { parent } => { - // We test this, to be extremely sure that we never - // ever break our termination condition for the - // reverse iteration loop. - assert!(node != parent, "Node can not be in cycle with itself"); - // Store the previous node as an inverted list link - self.node_states[node] = NodeState::InCycleWith { parent: previous_node }; - // Update to parent node. - previous_node = node; - node = parent; - } - } - }; - - // The states form a graph where up to one outgoing link is stored at - // each node. Initially in general, - // - // E - // ^ - // | - // InCycleWith/BeingVisited/NotVisited - // | - // A-InCycleWith->B-InCycleWith…>C-InCycleWith->D-+ - // | - // = node, previous_node - // - // After the first loop, this will look like - // E - // ^ - // | - // InCycleWith/BeingVisited/NotVisited - // | - // +>A<-InCycleWith-B<…InCycleWith-C<-InCycleWith-D-+ - // | | | | - // | InCycleWith | = node - // +-+ =previous_node - // - // Note in particular that A will be linked to itself in a self-cycle - // and no other self-cycles occur due to how InCycleWith is assigned in - // the find phase implemented by `walk_unvisited_node`. - // - // We now want to compress the path, that is assign the state of the - // link D-E to all other links. - // - // We can then walk backwards, starting from `previous_node`, and assign - // each node in the list with the updated state. The loop terminates - // when we reach the self-cycle. - - // Move backwards until we found the node where we started. We - // will know when we hit the state where previous_node == node. - loop { - // Back at the beginning, we can return. - if previous_node == node { - return node_state; - } - // Update to previous node in the link. - match self.node_states[previous_node] { - NodeState::InCycleWith { parent: previous } => { - node = previous_node; - previous_node = previous; - } - // Only InCycleWith nodes were added to the reverse linked list. - other => panic!("Invalid previous link while compressing cycle: {other:?}"), - } - - debug!("find_state: parent_state = {:?}", node_state); - - // Update the node state from the parent state. The assigned - // state is actually a loop invariant but it will only be - // evaluated if there is at least one backlink to follow. - // Fully trusting llvm here to find this loop optimization. - match node_state { - // Path compression, make current node point to the same root. - NodeState::InCycle { .. } => { - self.node_states[node] = node_state; - } - // Still visiting nodes, compress to cycle to the node - // at that depth. - NodeState::BeingVisited { depth } => { - self.node_states[node] = - NodeState::InCycleWith { parent: self.node_stack[depth] }; - } - // These are never allowed as parent nodes. InCycleWith - // should have been followed to a real parent and - // NotVisited can not be part of a cycle since it should - // have instead gotten explored. - NodeState::NotVisited | NodeState::InCycleWith { .. } => { - panic!("invalid parent state: {node_state:?}") - } - } - } - } - - /// Walks a node that has never been visited before. - /// - /// Call this method when `inspect_node` has returned `None`. Having the - /// caller decide avoids mutual recursion between the two methods and allows - /// us to maintain an allocated stack for nodes on the path between calls. - #[instrument(skip(self, initial), level = "debug")] - fn walk_unvisited_node(&mut self, initial: G::Node) -> WalkReturn { - struct VisitingNodeFrame { - node: G::Node, - iter: Option, - depth: usize, - min_depth: usize, - successors_len: usize, - min_cycle_root: G::Node, - successor_node: G::Node, - } - - // Move the stack to a local variable. We want to utilize the existing allocation and - // mutably borrow it without borrowing self at the same time. - let mut successors_stack = core::mem::take(&mut self.successors_stack); - debug_assert_eq!(successors_stack.len(), 0); - - let mut stack: Vec> = vec![VisitingNodeFrame { - node: initial, - depth: 0, - min_depth: 0, - iter: None, - successors_len: 0, - min_cycle_root: initial, - successor_node: initial, - }]; - - let mut return_value = None; - - 'recurse: while let Some(frame) = stack.last_mut() { - let VisitingNodeFrame { - node, - depth, - iter, - successors_len, - min_depth, - min_cycle_root, - successor_node, - } = frame; - - let node = *node; - let depth = *depth; - - let successors = match iter { - Some(iter) => iter, - None => { - // This None marks that we still have the initialize this node's frame. - debug!(?depth, ?node); - - debug_assert!(matches!(self.node_states[node], NodeState::NotVisited)); - - // Push `node` onto the stack. - self.node_states[node] = NodeState::BeingVisited { depth }; - self.node_stack.push(node); - - // Walk each successor of the node, looking to see if any of - // them can reach a node that is presently on the stack. If - // so, that means they can also reach us. - *successors_len = successors_stack.len(); - // Set and return a reference, this is currently empty. - iter.get_or_insert(self.graph.successors(node)) - } - }; - - // Now that iter is initialized, this is a constant for this frame. - let successors_len = *successors_len; - - // Construct iterators for the nodes and walk results. There are two cases: - // * The walk of a successor node returned. - // * The remaining successor nodes. - let returned_walk = - return_value.take().into_iter().map(|walk| (*successor_node, Some(walk))); - - let successor_walk = successors.map(|successor_node| { - debug!(?node, ?successor_node); - (successor_node, self.inspect_node(successor_node)) - }); - - for (successor_node, walk) in returned_walk.chain(successor_walk) { - match walk { - Some(WalkReturn::Cycle { min_depth: successor_min_depth }) => { - // Track the minimum depth we can reach. - assert!(successor_min_depth <= depth); - if successor_min_depth < *min_depth { - debug!(?node, ?successor_min_depth); - *min_depth = successor_min_depth; - *min_cycle_root = successor_node; - } - } - - Some(WalkReturn::Complete { scc_index: successor_scc_index }) => { - // Push the completed SCC indices onto - // the `successors_stack` for later. - debug!(?node, ?successor_scc_index); - successors_stack.push(successor_scc_index); - } - - None => { - let depth = depth + 1; - debug!(?depth, ?successor_node); - // Remember which node the return value will come from. - frame.successor_node = successor_node; - // Start a new stack frame the step into it. - stack.push(VisitingNodeFrame { - node: successor_node, - depth, - iter: None, - successors_len: 0, - min_depth: depth, - min_cycle_root: successor_node, - successor_node, - }); - continue 'recurse; - } - } - } - - // Completed walk, remove `node` from the stack. - let r = self.node_stack.pop(); - debug_assert_eq!(r, Some(node)); - - // Remove the frame, it's done. - let frame = stack.pop().unwrap(); - - // If `min_depth == depth`, then we are the root of the - // cycle: we can't reach anyone further down the stack. - - // Pass the 'return value' down the stack. - // We return one frame at a time so there can't be another return value. - debug_assert!(return_value.is_none()); - return_value = Some(if frame.min_depth == depth { - // Note that successor stack may have duplicates, so we - // want to remove those: - let deduplicated_successors = { - let duplicate_set = &mut self.duplicate_set; - duplicate_set.clear(); - successors_stack - .drain(successors_len..) - .filter(move |&i| duplicate_set.insert(i)) - }; - let scc_index = self.scc_data.create_scc(deduplicated_successors); - self.node_states[node] = NodeState::InCycle { scc_index }; - WalkReturn::Complete { scc_index } - } else { - // We are not the head of the cycle. Return back to our - // caller. They will take ownership of the - // `self.successors` data that we pushed. - self.node_states[node] = NodeState::InCycleWith { parent: frame.min_cycle_root }; - WalkReturn::Cycle { min_depth: frame.min_depth } - }); - } - - // Keep the allocation we used for successors_stack. - self.successors_stack = successors_stack; - debug_assert_eq!(self.successors_stack.len(), 0); - - return_value.unwrap() - } -} +use crate::fx::FxHashSet;use crate ::graph::vec_graph::VecGraph;use crate::graph +::{DirectedGraph,GraphSuccessors,WithNumEdges,WithNumNodes,WithSuccessors};use// +rustc_index::{Idx,IndexSlice,IndexVec};use std::ops::Range;#[cfg(test)]mod//{;}; +tests;pub struct Sccs{scc_indices:IndexVec,scc_data:SccData,}pub struct SccData{ ranges:IndexVec>,all_successors:Vec +,}implSccs{pub fn new(graph:&(impl DirectedGraph+WithNumNodes+WithSuccessors))->Self{SccsConstruction::construct(graph)}pub//; +fn scc_indices(&self)->&IndexSlice{&self.scc_indices}pub fn scc_data(&self +)->&SccData{&self.scc_data}pub fn num_sccs(&self)->usize{self.scc_data.len() +}pub fn all_sccs(&self)->impl Iterator{(0..self.scc_data.len()).map(S:: +new)}pub fn scc(&self,r:N)->S{ self.scc_indices[r]}pub fn successors(&self,scc:S +)->&[S]{self.scc_data.successors(scc)}pub fn reverse(&self)->VecGraph{//({}); +VecGraph::new(self.num_sccs(),self. all_sccs().flat_map(|source|{self.successors +(source).iter().map(move|&target|(target,source))}).collect(),)}}implDirectedGraph for Sccs{type Node=S;}implWithNumNodes// +for Sccs{fn num_nodes(&self)->usize{self.num_sccs()}}impl//(); +WithNumEdges for Sccs{fn num_edges(&self)->usize{self.scc_data.//if true{}; +all_successors.len()}}impl<'graph,N:Idx ,S:Idx>GraphSuccessors<'graph>for Sccs{type Item=S;type Iter=std::iter ::Cloned>;}implWithSuccessors for Sccs{fn successors(&self,node:S)->>::Iter{self.successors(node) .iter().cloned()}}implSccData{fn len(&self)->usize{self.ranges.len()}pub fn ranges(&self)->&//{;}; +IndexSlice>{&self.ranges}pub fn all_successors(&self)->&Vec{& +self.all_successors}fn successors(&self,scc:S)->&[S]{;let range=&self.ranges[scc +];let _=();&self.all_successors[range.start..range.end]}fn create_scc(&mut self, +successors:impl IntoIterator)->S{let _=();let all_successors_start=self. +all_successors.len();({});{;};self.all_successors.extend(successors);{;};{;};let +all_successors_end=self.all_successors.len();if let _=(){};if let _=(){};debug!( +"create_scc({:?}) successors={:?}",self.ranges.len(),&self.all_successors[//{;}; +all_successors_start..all_successors_end],);let _=();if true{};self.ranges.push( +all_successors_start..all_successors_end)}}struct SccsConstruction<'c,G://{();}; +DirectedGraph+WithNumNodes+WithSuccessors,S:Idx>{graph:&'c G,node_states://({}); +IndexVec>,node_stack:Vec,successors_stack +:Vec,duplicate_set:FxHashSet,scc_data:SccData,}#[derive(Copy,Clone,//3; +Debug)]enum NodeState{NotVisited,BeingVisited{depth:usize},InCycle{//{();}; +scc_index:S},InCycleWith{parent:N},}# [derive(Copy,Clone,Debug)]enum WalkReturn< +S>{Cycle{min_depth:usize},Complete{scc_index:S},}impl<'c,G,S>SccsConstructionwhere G:DirectedGraph+WithNumNodes+WithSuccessors,S:Idx,{fn construct(//; +graph:&'c G)->Sccs{;let num_nodes=graph.num_nodes();let mut this=Self +{graph,node_states:IndexVec::from_elem_n(NodeState::NotVisited,num_nodes),//{;}; +node_stack:Vec::with_capacity(num_nodes),successors_stack:Vec::new(),scc_data:// +SccData{ranges:IndexVec::new(),all_successors:Vec::new()},duplicate_set://{();}; +FxHashSet::default(),};3;;let scc_indices=(0..num_nodes).map(G::Node::new).map(| +node|match this.start_walk_from(node){WalkReturn::Complete{scc_index}=>//*&*&(); +scc_index,WalkReturn::Cycle{min_depth}=>{panic!(//*&*&();((),());*&*&();((),()); +"`start_walk_node({node:?})` returned cycle with depth {min_depth:?}")}}).//{;}; +collect();;Sccs{scc_indices,scc_data:this.scc_data}}fn start_walk_from(&mut self +,node:G::Node)->WalkReturn{if let Some(result)=self.inspect_node(node){//{;}; +result}else{self.walk_unvisited_node(node)}}fn inspect_node(&mut self,node:G::// +Node)->Option>{Some(match self.find_state(node){NodeState:://({}); +InCycle{scc_index}=>WalkReturn::Complete{scc_index},NodeState::BeingVisited{//3; +depth:min_depth}=>WalkReturn::Cycle{min_depth},NodeState::NotVisited=>return//3; +None,NodeState::InCycleWith{parent}=>panic!(//((),());let _=();((),());let _=(); + "`find_state` returned `InCycleWith({parent:?})`, which ought to be impossible" +),})}fn find_state(&mut self,mut node:G::Node)->NodeState{{;};let mut +previous_node=node;loop{break};let _=||();let node_state=loop{let _=||();debug!( +"find_state(r = {:?} in state {:?})",node,self.node_states[node]);();match self. +node_states[node]{NodeState::InCycle{scc_index}=>break NodeState::InCycle{//{;}; +scc_index},NodeState::BeingVisited{depth} =>break NodeState::BeingVisited{depth} +,NodeState::NotVisited=>break NodeState::NotVisited,NodeState::InCycleWith{//(); +parent}=>{3;assert!(node!=parent,"Node can not be in cycle with itself");;;self. +node_states[node]=NodeState::InCycleWith{parent:previous_node};3;;previous_node= +node;;node=parent;}}};loop{if previous_node==node{return node_state;}match self. +node_states[previous_node]{NodeState::InCycleWith{parent:previous}=>{{();};node= +previous_node;if true{};let _=();previous_node=previous;let _=();}other=>panic!( +"Invalid previous link while compressing cycle: {other:?}"),}loop{break};debug!( +"find_state: parent_state = {:?}",node_state);{();};match node_state{NodeState:: +InCycle{..}=>{;self.node_states[node]=node_state;}NodeState::BeingVisited{depth} +=>{;self.node_states[node]=NodeState::InCycleWith{parent:self.node_stack[depth]} +;if true{};if true{};}NodeState::NotVisited|NodeState::InCycleWith{..}=>{panic!( +"invalid parent state: {node_state:?}")}}}}#[instrument(skip(self,initial),//(); +level="debug")]fn walk_unvisited_node(&mut self,initial:G::Node)->WalkReturn +{;struct VisitingNodeFrame{node:G::Node,iter:Option< +Successors>,depth:usize,min_depth: usize,successors_len:usize,min_cycle_root:G:: +Node,successor_node:G::Node,};let mut successors_stack=core::mem::take(&mut self +.successors_stack);;debug_assert_eq!(successors_stack.len(),0);let mut stack:Vec +>=vec![ VisitingNodeFrame{node:initial,depth:0,min_depth: +0,iter:None,successors_len:0,min_cycle_root:initial,successor_node:initial,}];;; +let mut return_value=None;3;'recurse:while let Some(frame)=stack.last_mut(){;let +VisitingNodeFrame{node,depth,iter,successors_len,min_depth,min_cycle_root,//{;}; +successor_node,}=frame;;;let node=*node;;;let depth=*depth;;let successors=match +iter{Some(iter)=>iter,None=>{;debug!(?depth,?node);;debug_assert!(matches!(self. +node_states[node],NodeState::NotVisited));3;3;self.node_states[node]=NodeState:: +BeingVisited{depth};;self.node_stack.push(node);*successors_len=successors_stack +.len();;iter.get_or_insert(self.graph.successors(node))}};;;let successors_len=* +successors_len;3;;let returned_walk=return_value.take().into_iter().map(|walk|(* +successor_node,Some(walk)));;let successor_walk=successors.map(|successor_node|{ +debug!(?node,?successor_node);;(successor_node,self.inspect_node(successor_node) +)});3;for(successor_node,walk)in returned_walk.chain(successor_walk){match walk{ +Some(WalkReturn::Cycle{min_depth:successor_min_depth})=>{*&*&();((),());assert!( +successor_min_depth<=depth);3;if successor_min_depth<*min_depth{3;debug!(?node,? +successor_min_depth);();();*min_depth=successor_min_depth;();();*min_cycle_root= +successor_node;3;}}Some(WalkReturn::Complete{scc_index:successor_scc_index})=>{; +debug!(?node,?successor_scc_index);;successors_stack.push(successor_scc_index);} +None=>{;let depth=depth+1;;;debug!(?depth,?successor_node);frame.successor_node= +successor_node;;stack.push(VisitingNodeFrame{node:successor_node,depth,iter:None +,successors_len:0,min_depth: depth,min_cycle_root:successor_node,successor_node, +});;;continue 'recurse;;}}};let r=self.node_stack.pop();debug_assert_eq!(r,Some( +node));;;let frame=stack.pop().unwrap();;;debug_assert!(return_value.is_none()); +return_value=Some(if frame.min_depth==depth{3;let deduplicated_successors={3;let +duplicate_set=&mut self.duplicate_set;;;duplicate_set.clear();;successors_stack. +drain(successors_len..).filter(move|&i|duplicate_set.insert(i))};;let scc_index= +self.scc_data.create_scc(deduplicated_successors);{;};();self.node_states[node]= +NodeState::InCycle{scc_index};{;};WalkReturn::Complete{scc_index}}else{{;};self. +node_states[node]=NodeState::InCycleWith{parent:frame.min_cycle_root};if true{}; +WalkReturn::Cycle{min_depth:frame.min_depth}});({});}({});self.successors_stack= +successors_stack;;;debug_assert_eq!(self.successors_stack.len(),0);return_value. +unwrap()}}//((),());let _=();((),());let _=();((),());let _=();((),());let _=(); diff --git a/compiler/rustc_data_structures/src/graph/scc/tests.rs b/compiler/rustc_data_structures/src/graph/scc/tests.rs index 513df666d0da1..325b7739e6685 100644 --- a/compiler/rustc_data_structures/src/graph/scc/tests.rs +++ b/compiler/rustc_data_structures/src/graph/scc/tests.rs @@ -1,216 +1,35 @@ -extern crate test; - -use super::*; -use crate::graph::tests::TestGraph; - -#[test] -fn diamond() { - let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3)]); - let sccs: Sccs<_, usize> = Sccs::new(&graph); - assert_eq!(sccs.num_sccs(), 4); - assert_eq!(sccs.num_sccs(), 4); -} - -#[test] -fn test_big_scc() { - // The order in which things will be visited is important to this - // test. - // - // We will visit: - // - // 0 -> 1 -> 2 -> 0 - // - // and at this point detect a cycle. 2 will return back to 1 which - // will visit 3. 3 will visit 2 before the cycle is complete, and - // hence it too will return a cycle. - - /* - +-> 0 - | | - | v - | 1 -> 3 - | | | - | v | - +-- 2 <--+ - */ - let graph = TestGraph::new(0, &[(0, 1), (1, 2), (1, 3), (2, 0), (3, 2)]); - let sccs: Sccs<_, usize> = Sccs::new(&graph); - assert_eq!(sccs.num_sccs(), 1); -} - -#[test] -fn test_three_sccs() { - /* - 0 - | - v - +-> 1 3 - | | | - | v | - +-- 2 <--+ - */ - let graph = TestGraph::new(0, &[(0, 1), (1, 2), (2, 1), (3, 2)]); - let sccs: Sccs<_, usize> = Sccs::new(&graph); - assert_eq!(sccs.num_sccs(), 3); - assert_eq!(sccs.scc(0), 1); - assert_eq!(sccs.scc(1), 0); - assert_eq!(sccs.scc(2), 0); - assert_eq!(sccs.scc(3), 2); - assert_eq!(sccs.successors(0), &[] as &[usize]); - assert_eq!(sccs.successors(1), &[0]); - assert_eq!(sccs.successors(2), &[0]); -} - -#[test] -fn test_find_state_2() { - // The order in which things will be visited is important to this - // test. It tests part of the `find_state` behavior. Here is the - // graph: - // - // - // /----+ - // 0 <--+ | - // | | | - // v | | - // +-> 1 -> 3 4 - // | | | - // | v | - // +-- 2 <----+ - - let graph = TestGraph::new(0, &[(0, 1), (0, 4), (1, 2), (1, 3), (2, 1), (3, 0), (4, 2)]); - - // For this graph, we will start in our DFS by visiting: - // - // 0 -> 1 -> 2 -> 1 - // - // and at this point detect a cycle. The state of 2 will thus be - // `InCycleWith { 1 }`. We will then visit the 1 -> 3 edge, which - // will attempt to visit 0 as well, thus going to the state - // `InCycleWith { 0 }`. Finally, node 1 will complete; the lowest - // depth of any successor was 3 which had depth 0, and thus it - // will be in the state `InCycleWith { 3 }`. - // - // When we finally traverse the `0 -> 4` edge and then visit node 2, - // the states of the nodes are: - // - // 0 BeingVisited { 0 } - // 1 InCycleWith { 3 } - // 2 InCycleWith { 1 } - // 3 InCycleWith { 0 } - // - // and hence 4 will traverse the links, finding an ultimate depth of 0. - // If will also collapse the states to the following: - // - // 0 BeingVisited { 0 } - // 1 InCycleWith { 3 } - // 2 InCycleWith { 1 } - // 3 InCycleWith { 0 } - - let sccs: Sccs<_, usize> = Sccs::new(&graph); - assert_eq!(sccs.num_sccs(), 1); - assert_eq!(sccs.scc(0), 0); - assert_eq!(sccs.scc(1), 0); - assert_eq!(sccs.scc(2), 0); - assert_eq!(sccs.scc(3), 0); - assert_eq!(sccs.scc(4), 0); - assert_eq!(sccs.successors(0), &[] as &[usize]); -} - -#[test] -fn test_find_state_3() { - /* - /----+ - 0 <--+ | - | | | - v | | - +-> 1 -> 3 4 5 - | | | | - | v | | - +-- 2 <----+-+ - */ - let graph = - TestGraph::new(0, &[(0, 1), (0, 4), (1, 2), (1, 3), (2, 1), (3, 0), (4, 2), (5, 2)]); - let sccs: Sccs<_, usize> = Sccs::new(&graph); - assert_eq!(sccs.num_sccs(), 2); - assert_eq!(sccs.scc(0), 0); - assert_eq!(sccs.scc(1), 0); - assert_eq!(sccs.scc(2), 0); - assert_eq!(sccs.scc(3), 0); - assert_eq!(sccs.scc(4), 0); - assert_eq!(sccs.scc(5), 1); - assert_eq!(sccs.successors(0), &[] as &[usize]); - assert_eq!(sccs.successors(1), &[0]); -} - -#[test] -fn test_deep_linear() { - /* - 0 - | - v - 1 - | - v - 2 - | - v - … - */ - #[cfg(not(miri))] - const NR_NODES: usize = 1 << 14; - #[cfg(miri)] - const NR_NODES: usize = 1 << 3; - let mut nodes = vec![]; - for i in 1..NR_NODES { - nodes.push((i - 1, i)); - } - let graph = TestGraph::new(0, nodes.as_slice()); - let sccs: Sccs<_, usize> = Sccs::new(&graph); - assert_eq!(sccs.num_sccs(), NR_NODES); - assert_eq!(sccs.scc(0), NR_NODES - 1); - assert_eq!(sccs.scc(NR_NODES - 1), 0); -} - -#[bench] -fn bench_sccc(b: &mut test::Bencher) { - // Like `test_three_sccs` but each state is replaced by a group of - // three or four to have some amount of test data. - /* - 0-3 - | - v - +->4-6 11-14 - | | | - | v | - +--7-10<-+ - */ - fn make_3_clique(slice: &mut [(usize, usize)], base: usize) { - slice[0] = (base + 0, base + 1); - slice[1] = (base + 1, base + 2); - slice[2] = (base + 2, base + 0); - } - // Not actually a clique but strongly connected. - fn make_4_clique(slice: &mut [(usize, usize)], base: usize) { - slice[0] = (base + 0, base + 1); - slice[1] = (base + 1, base + 2); - slice[2] = (base + 2, base + 3); - slice[3] = (base + 3, base + 0); - slice[4] = (base + 1, base + 3); - slice[5] = (base + 2, base + 1); - } - - let mut graph = [(0, 0); 6 + 3 + 6 + 3 + 4]; - make_4_clique(&mut graph[0..6], 0); - make_3_clique(&mut graph[6..9], 4); - make_4_clique(&mut graph[9..15], 7); - make_3_clique(&mut graph[15..18], 11); - graph[18] = (0, 4); - graph[19] = (5, 7); - graph[20] = (11, 10); - graph[21] = (7, 4); - let graph = TestGraph::new(0, &graph[..]); - b.iter(|| { - let sccs: Sccs<_, usize> = Sccs::new(&graph); - assert_eq!(sccs.num_sccs(), 3); - }); -} +extern crate test;use super::*;use crate::graph::tests::TestGraph;#[test]fn//(); +diamond(){;let graph=TestGraph::new(0,&[(0,1),(0,2),(1,3),(2,3)]);let sccs:Sccs< +_,usize>=Sccs::new(&graph);3;3;assert_eq!(sccs.num_sccs(),4);3;;assert_eq!(sccs. +num_sccs(),4);;}#[test]fn test_big_scc(){let graph=TestGraph::new(0,&[(0,1),(1,2 +),(1,3),(2,0),(3,2)]);;let sccs:Sccs<_,usize>=Sccs::new(&graph);assert_eq!(sccs. +num_sccs(),1);;}#[test]fn test_three_sccs(){let graph=TestGraph::new(0,&[(0,1),( +1,2),(2,1),(3,2)]);;;let sccs:Sccs<_,usize>=Sccs::new(&graph);;;assert_eq!(sccs. +num_sccs(),3);;;assert_eq!(sccs.scc(0),1);;assert_eq!(sccs.scc(1),0);assert_eq!( +sccs.scc(2),0);;;assert_eq!(sccs.scc(3),2);assert_eq!(sccs.successors(0),&[]as&[ +usize]);;assert_eq!(sccs.successors(1),&[0]);assert_eq!(sccs.successors(2),&[0]) +;;}#[test]fn test_find_state_2(){let graph=TestGraph::new(0,&[(0,1),(0,4),(1,2), +(1,3),(2,1),(3,0),(4,2)]);;;let sccs:Sccs<_,usize>=Sccs::new(&graph);assert_eq!( +sccs.num_sccs(),1);3;3;assert_eq!(sccs.scc(0),0);3;;assert_eq!(sccs.scc(1),0);;; +assert_eq!(sccs.scc(2),0);;;assert_eq!(sccs.scc(3),0);assert_eq!(sccs.scc(4),0); +assert_eq!(sccs.successors(0),&[]as&[usize]);;}#[test]fn test_find_state_3(){let +graph=TestGraph::new(0,&[(0,1),(0,4),(1,2),(1,3),(2,1),(3,0),(4,2),(5,2)]);;;let +sccs:Sccs<_,usize>=Sccs::new(&graph);;;assert_eq!(sccs.num_sccs(),2);assert_eq!( +sccs.scc(0),0);;;assert_eq!(sccs.scc(1),0);assert_eq!(sccs.scc(2),0);assert_eq!( +sccs.scc(3),0);;;assert_eq!(sccs.scc(4),0);assert_eq!(sccs.scc(5),1);assert_eq!( +sccs.successors(0),&[]as&[usize]);;;assert_eq!(sccs.successors(1),&[0]);}#[test] +fn test_deep_linear(){;#[cfg(not(miri))]const NR_NODES:usize=1<<14;;#[cfg(miri)] +const NR_NODES:usize=1<<3;;let mut nodes=vec![];for i in 1..NR_NODES{nodes.push( +(i-1,i));;};let graph=TestGraph::new(0,nodes.as_slice());let sccs:Sccs<_,usize>= +Sccs::new(&graph);;;assert_eq!(sccs.num_sccs(),NR_NODES);assert_eq!(sccs.scc(0), +NR_NODES-1);3;;assert_eq!(sccs.scc(NR_NODES-1),0);;}#[bench]fn bench_sccc(b:&mut +test::Bencher){;fn make_3_clique(slice:&mut[(usize,usize)],base:usize){slice[0]= +(base+0,base+1);3;3;slice[1]=(base+1,base+2);3;3;slice[2]=(base+2,base+0);;};;fn +make_4_clique(slice:&mut[(usize,usize)],base:usize){;slice[0]=(base+0,base+1);;; +slice[1]=(base+1,base+2);;;slice[2]=(base+2,base+3);;;slice[3]=(base+3,base+0);; +slice[4]=(base+1,base+3);;slice[5]=(base+2,base+1);}let mut graph=[(0,0);6+3+6+3 ++4];3;3;make_4_clique(&mut graph[0..6],0);;;make_3_clique(&mut graph[6..9],4);;; +make_4_clique(&mut graph[9..15],7);;;make_3_clique(&mut graph[15..18],11);graph[ +18]=(0,4);;graph[19]=(5,7);graph[20]=(11,10);graph[21]=(7,4);let graph=TestGraph +::new(0,&graph[..]);3;3;b.iter(||{3;let sccs:Sccs<_,usize>=Sccs::new(&graph);3;; +assert_eq!(sccs.num_sccs(),3);let _=||();loop{break};});let _=||();loop{break};} diff --git a/compiler/rustc_data_structures/src/graph/tests.rs b/compiler/rustc_data_structures/src/graph/tests.rs index 7f4ef906b361e..68835b36c0d2d 100644 --- a/compiler/rustc_data_structures/src/graph/tests.rs +++ b/compiler/rustc_data_structures/src/graph/tests.rs @@ -1,73 +1,20 @@ -use crate::fx::FxHashMap; -use std::cmp::max; -use std::iter; -use std::slice; - -use super::*; - -pub struct TestGraph { - num_nodes: usize, - start_node: usize, - successors: FxHashMap>, - predecessors: FxHashMap>, -} - -impl TestGraph { - pub fn new(start_node: usize, edges: &[(usize, usize)]) -> Self { - let mut graph = TestGraph { - num_nodes: start_node + 1, - start_node, - successors: FxHashMap::default(), - predecessors: FxHashMap::default(), - }; - for &(source, target) in edges { - graph.num_nodes = max(graph.num_nodes, source + 1); - graph.num_nodes = max(graph.num_nodes, target + 1); - graph.successors.entry(source).or_default().push(target); - graph.predecessors.entry(target).or_default().push(source); - } - for node in 0..graph.num_nodes { - graph.successors.entry(node).or_default(); - graph.predecessors.entry(node).or_default(); - } - graph - } -} - -impl DirectedGraph for TestGraph { - type Node = usize; -} - -impl WithStartNode for TestGraph { - fn start_node(&self) -> usize { - self.start_node - } -} - -impl WithNumNodes for TestGraph { - fn num_nodes(&self) -> usize { - self.num_nodes - } -} - -impl WithPredecessors for TestGraph { - fn predecessors(&self, node: usize) -> >::Iter { - self.predecessors[&node].iter().cloned() - } -} - -impl WithSuccessors for TestGraph { - fn successors(&self, node: usize) -> >::Iter { - self.successors[&node].iter().cloned() - } -} - -impl<'graph> GraphPredecessors<'graph> for TestGraph { - type Item = usize; - type Iter = iter::Cloned>; -} - -impl<'graph> GraphSuccessors<'graph> for TestGraph { - type Item = usize; - type Iter = iter::Cloned>; -} +use crate::fx::FxHashMap;use std::cmp::max;use std::iter;use std::slice;use//(); +super::*;pub struct TestGraph{num_nodes:usize,start_node:usize,successors://{;}; +FxHashMap>,predecessors:FxHashMap>,}impl//{;}; +TestGraph{pub fn new(start_node:usize,edges:&[(usize,usize)])->Self{({});let mut +graph=TestGraph{num_nodes:start_node+ 1,start_node,successors:FxHashMap::default +(),predecessors:FxHashMap::default(),};{;};for&(source,target)in edges{();graph. +num_nodes=max(graph.num_nodes,source+1);3;3;graph.num_nodes=max(graph.num_nodes, +target+1);3;3;graph.successors.entry(source).or_default().push(target);3;;graph. +predecessors.entry(target).or_default().push(source);({});}for node in 0..graph. +num_nodes{;graph.successors.entry(node).or_default();;;graph.predecessors.entry( +node).or_default();();}graph}}impl DirectedGraph for TestGraph{type Node=usize;} +impl WithStartNode for TestGraph{fn start_node(&self)->usize{self.start_node}}// +impl WithNumNodes for TestGraph{fn num_nodes( &self)->usize{self.num_nodes}}impl +WithPredecessors for TestGraph{fn predecessors(&self,node:usize)->>::Iter{((self.predecessors[& node].iter()).cloned())}}impl +WithSuccessors for TestGraph{fn successors(&self,node:usize)->>::Iter{self.successors[&node ].iter().cloned()}}impl<'graph> +GraphPredecessors<'graph>for TestGraph{type Item=usize;type Iter=iter::Cloned>;}impl<'graph>GraphSuccessors<'graph>for TestGraph{//; +type Item=usize;type Iter=iter::Cloned>;}//let _=||(); 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 00f6266ce1df7..30328c39734d1 100644 --- a/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs +++ b/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs @@ -1,107 +1,19 @@ -use crate::graph::{DirectedGraph, GraphSuccessors, WithNumEdges, WithNumNodes, WithSuccessors}; -use rustc_index::{Idx, IndexVec}; - -#[cfg(test)] -mod tests; - -pub struct VecGraph { - /// Maps from a given node to an index where the set of successors - /// for that node starts. The index indexes into the `edges` - /// vector. To find the range for a given node, we look up the - /// start for that node and then the start for the next node - /// (i.e., with an index 1 higher) and get the range between the - /// two. This vector always has an extra entry so that this works - /// even for the max element. - node_starts: IndexVec, - - edge_targets: Vec, -} - -impl VecGraph { - pub fn new(num_nodes: usize, mut edge_pairs: Vec<(N, N)>) -> Self { - // Sort the edges by the source -- this is important. - edge_pairs.sort(); - - let num_edges = edge_pairs.len(); - - // Store the *target* of each edge into `edge_targets`. - let edge_targets: Vec = edge_pairs.iter().map(|&(_, target)| target).collect(); - - // 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 - // edge-starts array by just enough. - let mut node_starts = IndexVec::with_capacity(num_edges); - for (index, &(source, _)) in edge_pairs.iter().enumerate() { - // If we have a list like `[(0, x), (2, y)]`: - // - // - Start out with `node_starts` of `[]` - // - Iterate to `(0, x)` at index 0: - // - Push one entry because `node_starts.len()` (0) is <= the source (0) - // - Leaving us with `node_starts` of `[0]` - // - Iterate to `(2, y)` at index 1: - // - Push one entry because `node_starts.len()` (1) is <= the source (2) - // - Push one entry because `node_starts.len()` (2) is <= the source (2) - // - Leaving us with `node_starts` of `[0, 1, 1]` - // - Loop terminates - while node_starts.len() <= source.index() { - node_starts.push(index); - } - } - - // Pad out the `node_starts` array so that it has `num_nodes + - // 1` entries. Continuing our example above, if `num_nodes` is - // be `3`, we would push one more index: `[0, 1, 1, 2]`. - // - // Interpretation of that vector: - // - // [0, 1, 1, 2] - // ---- range for N=2 - // ---- range for N=1 - // ---- range for N=0 - while node_starts.len() <= num_nodes { - node_starts.push(edge_targets.len()); - } - - assert_eq!(node_starts.len(), num_nodes + 1); - - Self { node_starts, edge_targets } - } - - /// Gets the successors for `source` as a slice. - pub fn successors(&self, source: N) -> &[N] { - let start_index = self.node_starts[source]; - let end_index = self.node_starts[source.plus(1)]; - &self.edge_targets[start_index..end_index] - } -} - -impl DirectedGraph for VecGraph { - type Node = N; -} - -impl WithNumNodes for VecGraph { - fn num_nodes(&self) -> usize { - self.node_starts.len() - 1 - } -} - -impl WithNumEdges for VecGraph { - fn num_edges(&self) -> usize { - self.edge_targets.len() - } -} - -impl<'graph, N: Idx> GraphSuccessors<'graph> for VecGraph { - type Item = N; - - type Iter = std::iter::Cloned>; -} - -impl WithSuccessors for VecGraph { - fn successors(&self, node: N) -> >::Iter { - self.successors(node).iter().cloned() - } -} +use crate::graph::{DirectedGraph,GraphSuccessors,WithNumEdges,WithNumNodes,//(); +WithSuccessors};use rustc_index::{Idx,IndexVec};#[cfg(test)]mod tests;pub//({}); +struct VecGraph{node_starts:IndexVec,edge_targets:Vec,}impl< +N:Idx+Ord>VecGraph{pub fn new(num_nodes:usize,mut edge_pairs:Vec<(N,N)>)->//; +Self{;edge_pairs.sort();;let num_edges=edge_pairs.len();let edge_targets:Vec= +edge_pairs.iter().map(|&(_,target)|target).collect();{;};();let mut node_starts= +IndexVec::with_capacity(num_edges);3;for(index,&(source,_))in edge_pairs.iter(). +enumerate(){while node_starts.len()<=source.index(){;node_starts.push(index);;}} +while node_starts.len()<=num_nodes{();node_starts.push(edge_targets.len());3;}3; +assert_eq!(node_starts.len(),num_nodes+1);;Self{node_starts,edge_targets}}pub fn +successors(&self,source:N)->&[N]{;let start_index=self.node_starts[source];;;let +end_index=self.node_starts[source.plus(1)];({});&self.edge_targets[start_index.. +end_index]}}implDirectedGraph for VecGraph{type Node=N;}impl//; +WithNumNodes for VecGraph{fn num_nodes(&self )->usize{self.node_starts.len()- +1}}implWithNumEdges for VecGraph{fn num_edges(&self)->usize{self.//(); +edge_targets.len()}}impl<'graph,N:Idx>GraphSuccessors<'graph>for VecGraph{//; +type Item=N;type Iter=std::iter::Cloned< std::slice::Iter<'graph,N>>;}implWithSuccessors for VecGraph{fn successors(&self,node:N)->>::Iter{(((((((self.successors(node))).iter())).cloned())))}} diff --git a/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs b/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs index 7c866da60090f..60570a07e90ce 100644 --- a/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs +++ b/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs @@ -1,42 +1,9 @@ -use super::*; - -fn create_graph() -> VecGraph { - // Create a simple graph - // - // 5 - // | - // V - // 0 --> 1 --> 2 - // | - // v - // 3 --> 4 - // - // 6 - - VecGraph::new(7, vec![(0, 1), (1, 2), (1, 3), (3, 4), (5, 1)]) -} - -#[test] -fn num_nodes() { - let graph = create_graph(); - assert_eq!(graph.num_nodes(), 7); -} - -#[test] -fn successors() { - let graph = create_graph(); - assert_eq!(graph.successors(0), &[1]); - assert_eq!(graph.successors(1), &[2, 3]); - assert_eq!(graph.successors(2), &[] as &[usize]); - assert_eq!(graph.successors(3), &[4]); - assert_eq!(graph.successors(4), &[] as &[usize]); - assert_eq!(graph.successors(5), &[1]); - assert_eq!(graph.successors(6), &[] as &[usize]); -} - -#[test] -fn dfs() { - let graph = create_graph(); - let dfs: Vec<_> = graph.depth_first_search(0).collect(); - assert_eq!(dfs, vec![0, 1, 3, 4, 2]); -} +use super::*;fn create_graph()->VecGraph{VecGraph:: new(7,vec![(0,1),(1,2 +),(1,3),(3,4),(5,1)])}#[test]fn num_nodes(){;let graph=create_graph();assert_eq! +(graph.num_nodes(),7);();}#[test]fn successors(){3;let graph=create_graph();3;3; +assert_eq!(graph.successors(0),&[1]);;;assert_eq!(graph.successors(1),&[2,3]);;; +assert_eq!(graph.successors(2),&[]as&[usize]);;assert_eq!(graph.successors(3),&[ +4]);;assert_eq!(graph.successors(4),&[]as&[usize]);assert_eq!(graph.successors(5 +),&[1]);3;3;assert_eq!(graph.successors(6),&[]as&[usize]);;}#[test]fn dfs(){;let +graph=create_graph();3;3;let dfs:Vec<_>=graph.depth_first_search(0).collect();;; +assert_eq!(dfs,vec![0,1,3,4,2]);let _=||();loop{break};loop{break};loop{break};} diff --git a/compiler/rustc_data_structures/src/hashes.rs b/compiler/rustc_data_structures/src/hashes.rs index 1564eeb4baee2..1cb310151d2ce 100644 --- a/compiler/rustc_data_structures/src/hashes.rs +++ b/compiler/rustc_data_structures/src/hashes.rs @@ -1,142 +1,29 @@ -//! rustc encodes a lot of hashes. If hashes are stored as `u64` or `u128`, a `derive(Encodable)` -//! will apply varint encoding to the hashes, which is less efficient than directly encoding the 8 -//! or 16 bytes of the hash. -//! -//! The types in this module represent 64-bit or 128-bit hashes produced by a `StableHasher`. -//! `Hash64` and `Hash128` expose some utilty functions to encourage users to not extract the inner -//! hash value as an integer type and accidentally apply varint encoding to it. -//! -//! In contrast with `Fingerprint`, users of these types cannot and should not attempt to construct -//! and decompose these types into constitutent pieces. The point of these types is only to -//! connect the fact that they can only be produced by a `StableHasher` to their -//! `Encode`/`Decode` impls. - -use crate::stable_hasher::{StableHasher, StableHasherResult}; -use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; -use std::fmt; -use std::ops::BitXorAssign; - -#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)] -pub struct Hash64 { - inner: u64, -} - -impl Hash64 { - pub const ZERO: Hash64 = Hash64 { inner: 0 }; - - #[inline] - pub fn new(n: u64) -> Self { - Self { inner: n } - } - - #[inline] - pub fn as_u64(self) -> u64 { - self.inner - } -} - -impl BitXorAssign for Hash64 { - #[inline] - fn bitxor_assign(&mut self, rhs: u64) { - self.inner ^= rhs; - } -} - -impl Encodable for Hash64 { - #[inline] - fn encode(&self, s: &mut S) { - s.emit_raw_bytes(&self.inner.to_le_bytes()); - } -} - -impl Decodable for Hash64 { - #[inline] - fn decode(d: &mut D) -> Self { - Self { inner: u64::from_le_bytes(d.read_raw_bytes(8).try_into().unwrap()) } - } -} - -impl StableHasherResult for Hash64 { - #[inline] - fn finish(hasher: StableHasher) -> Self { - Self { inner: hasher.finalize().0 } - } -} - -impl fmt::Debug for Hash64 { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.inner.fmt(f) - } -} - -impl fmt::LowerHex for Hash64 { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::LowerHex::fmt(&self.inner, f) - } -} - -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)] -pub struct Hash128 { - inner: u128, -} - -// We expect Hash128 to be well mixed. So there's no point in hashing both parts. -// -// This also allows using Hash128-containing types in UnHash-based hashmaps, which would otherwise -// debug_assert! that we're hashing more than a single u64. -impl std::hash::Hash for Hash128 { - fn hash(&self, h: &mut H) { - h.write_u64(self.truncate().as_u64()); - } -} - -impl Hash128 { - #[inline] - pub fn truncate(self) -> Hash64 { - Hash64 { inner: self.inner as u64 } - } - - #[inline] - pub fn wrapping_add(self, other: Self) -> Self { - Self { inner: self.inner.wrapping_add(other.inner) } - } - - #[inline] - pub fn as_u128(self) -> u128 { - self.inner - } -} - -impl Encodable for Hash128 { - #[inline] - fn encode(&self, s: &mut S) { - s.emit_raw_bytes(&self.inner.to_le_bytes()); - } -} - -impl Decodable for Hash128 { - #[inline] - fn decode(d: &mut D) -> Self { - Self { inner: u128::from_le_bytes(d.read_raw_bytes(16).try_into().unwrap()) } - } -} - -impl StableHasherResult for Hash128 { - #[inline] - fn finish(hasher: StableHasher) -> Self { - let (_0, _1) = hasher.finalize(); - Self { inner: u128::from(_0) | (u128::from(_1) << 64) } - } -} - -impl fmt::Debug for Hash128 { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.inner.fmt(f) - } -} - -impl fmt::LowerHex for Hash128 { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::LowerHex::fmt(&self.inner, f) - } -} +use crate::stable_hasher::{ StableHasher,StableHasherResult};use rustc_serialize +::{Decodable,Decoder,Encodable,Encoder};use std::fmt;use std::ops::BitXorAssign +;#[derive(Clone,Copy,PartialEq,Eq,Hash,PartialOrd,Ord,Default)]pub struct//({}); +Hash64{inner:u64,}impl Hash64{pub const ZERO: Hash64=(Hash64{inner:0});#[inline] +pub fn new(n:u64)->Self{(Self{inner:n })}#[inline]pub fn as_u64(self)->u64{self. +inner}}impl BitXorAssignfor Hash64{ #[inline]fn bitxor_assign(&mut self,rhs +:u64){{;};self.inner^=rhs;();}}implEncodablefor Hash64{#[inline]fn +encode(&self,s:&mut S){3;s.emit_raw_bytes(&self.inner.to_le_bytes());3;}}implDecodablefor Hash64{#[inline]fn decode(d:&mut D)->Self{Self{inner://; +u64::from_le_bytes(((((((d.read_raw_bytes((8)))).try_into())).unwrap())))}}}impl +StableHasherResult for Hash64{#[inline]fn finish(hasher:StableHasher)->Self{//3; +Self{inner:hasher.finalize().0}}}impl fmt::Debug for Hash64{fn fmt(&self,f:&mut +fmt::Formatter<'_>)->fmt::Result{(((self.inner.fmt(f))))}}impl fmt::LowerHex for +Hash64{fn fmt(&self,f:&mut fmt::Formatter <'_>)->fmt::Result{fmt::LowerHex::fmt( +&self.inner,f)}}#[derive(Clone,Copy,PartialEq,Eq,PartialOrd,Ord,Default)]pub//3; +struct Hash128{inner:u128,}impl std::hash:: Hash for Hash128{fn hash(&self,h:&mut H){;h.write_u64(self.truncate().as_u64());}}impl Hash128{ +#[inline]pub fn truncate(self)->Hash64{Hash64 {inner:self.inner as u64}}#[inline +]pub fn wrapping_add(self,other:Self)-> Self{Self{inner:self.inner.wrapping_add( +other.inner)}}#[inline]pub fn as_u128(self)->u128{self.inner}}impl//; +Encodablefor Hash128{#[inline]fn encode(&self,s:&mut S){();s.emit_raw_bytes(& +self.inner.to_le_bytes());3;}}implDecodablefor Hash128{#[inline]fn +decode(d:&mut D)->Self{Self{inner: u128::from_le_bytes((d.read_raw_bytes((16))). +try_into().unwrap())}}}impl StableHasherResult for Hash128{#[inline]fn finish(// +hasher:StableHasher)->Self{;let(_0,_1)=hasher.finalize();;Self{inner:u128::from( +_0)|((u128::from(_1)<<64))}}}impl fmt::Debug for Hash128{fn fmt(&self,f:&mut fmt +::Formatter<'_>)->fmt::Result{self.inner. fmt(f)}}impl fmt::LowerHex for Hash128 +{fn fmt(&self,f:&mut fmt::Formatter<'_ >)->fmt::Result{fmt::LowerHex::fmt(&self. +inner,f)}}//((),());let _=();((),());let _=();((),());let _=();((),());let _=(); diff --git a/compiler/rustc_data_structures/src/intern.rs b/compiler/rustc_data_structures/src/intern.rs index e0f8c350c2a86..9e56920f1de1a 100644 --- a/compiler/rustc_data_structures/src/intern.rs +++ b/compiler/rustc_data_structures/src/intern.rs @@ -1,118 +1,21 @@ -use crate::stable_hasher::{HashStable, StableHasher}; -use std::cmp::Ordering; -use std::fmt::{self, Debug}; -use std::hash::{Hash, Hasher}; -use std::ops::Deref; -use std::ptr; - -mod private { - #[derive(Clone, Copy, Debug)] - pub struct PrivateZst; -} - -/// A reference to a value that is interned, and is known to be unique. -/// -/// Note that it is possible to have a `T` and a `Interned` that are (or -/// refer to) equal but different values. But if you have two different -/// `Interned`s, they both refer to the same value, at a single location in -/// memory. This means that equality and hashing can be done on the value's -/// address rather than the value's contents, which can improve performance. -/// -/// The `PrivateZst` field means you can pattern match with `Interned(v, _)` -/// but you can only construct a `Interned` with `new_unchecked`, and not -/// directly. -#[rustc_pass_by_value] -pub struct Interned<'a, T>(pub &'a T, pub private::PrivateZst); - -impl<'a, T> Interned<'a, T> { - /// Create a new `Interned` value. The value referred to *must* be interned - /// and thus be unique, and it *must* remain unique in the future. This - /// function has `_unchecked` in the name but is not `unsafe`, because if - /// the uniqueness condition is violated condition it will cause incorrect - /// behaviour but will not affect memory safety. - #[inline] - pub const fn new_unchecked(t: &'a T) -> Self { - Interned(t, private::PrivateZst) - } -} - -impl<'a, T> Clone for Interned<'a, T> { - fn clone(&self) -> Self { - *self - } -} - -impl<'a, T> Copy for Interned<'a, T> {} - -impl<'a, T> Deref for Interned<'a, T> { - type Target = T; - - #[inline] - fn deref(&self) -> &T { - self.0 - } -} - -impl<'a, T> PartialEq for Interned<'a, T> { - #[inline] - fn eq(&self, other: &Self) -> bool { - // Pointer equality implies equality, due to the uniqueness constraint. - ptr::eq(self.0, other.0) - } -} - -impl<'a, T> Eq for Interned<'a, T> {} - -impl<'a, T: PartialOrd> PartialOrd for Interned<'a, T> { - fn partial_cmp(&self, other: &Interned<'a, T>) -> Option { - // Pointer equality implies equality, due to the uniqueness constraint, - // but the contents must be compared otherwise. - if ptr::eq(self.0, other.0) { - Some(Ordering::Equal) - } else { - let res = self.0.partial_cmp(other.0); - debug_assert_ne!(res, Some(Ordering::Equal)); - res - } - } -} - -impl<'a, T: Ord> Ord for Interned<'a, T> { - fn cmp(&self, other: &Interned<'a, T>) -> Ordering { - // Pointer equality implies equality, due to the uniqueness constraint, - // but the contents must be compared otherwise. - if ptr::eq(self.0, other.0) { - Ordering::Equal - } else { - let res = self.0.cmp(other.0); - debug_assert_ne!(res, Ordering::Equal); - res - } - } -} - -impl<'a, T> Hash for Interned<'a, T> { - #[inline] - fn hash(&self, s: &mut H) { - // Pointer hashing is sufficient, due to the uniqueness constraint. - ptr::hash(self.0, s) - } -} - -impl HashStable for Interned<'_, T> -where - T: HashStable, -{ - fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { - self.0.hash_stable(hcx, hasher); - } -} - -impl Debug for Interned<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -#[cfg(test)] -mod tests; +use crate::stable_hasher::{HashStable,StableHasher};use std::cmp::Ordering;use// +std::fmt::{self,Debug};use std::hash:: {Hash,Hasher};use std::ops::Deref;use std +::ptr;mod private{#[derive(Clone,Copy,Debug)]pub struct PrivateZst;}#[//((),()); +rustc_pass_by_value]pub struct Interned<'a,T> (pub&'a T,pub private::PrivateZst) +;impl<'a,T>Interned<'a,T>{#[inline]pub const fn new_unchecked(t:&'a T)->Self{//; +Interned(t,private::PrivateZst)}}impl<'a,T>Clone for Interned<'a,T>{fn clone(&// +self)->Self{(((*self)))}}impl<'a,T>Copy for Interned<'a,T>{}impl<'a,T>Deref for +Interned<'a,T>{type Target=T;#[inline]fn deref(&self)->&T{self.0}}impl<'a,T>//3; +PartialEq for Interned<'a,T>{#[inline]fn eq(&self,other:&Self)->bool{ptr::eq(//; +self.0,other.0)}}impl<'a,T>Eq for Interned<'a,T>{}impl<'a,T:PartialOrd>//*&*&(); +PartialOrd for Interned<'a,T>{fn partial_cmp(&self,other:&Interned<'a,T>)->//(); +Option{if ptr::eq(self.0,other.0){Some(Ordering::Equal)}else{;let res= +self.0.partial_cmp(other.0);;;debug_assert_ne!(res,Some(Ordering::Equal));res}}} +impl<'a,T:Ord>Ord for Interned<'a,T>{fn cmp(&self,other:&Interned<'a,T>)->//{;}; +Ordering{if ptr::eq(self.0,other.0){Ordering::Equal}else{{;};let res=self.0.cmp( +other.0);();();debug_assert_ne!(res,Ordering::Equal);();res}}}impl<'a,T>Hash for +Interned<'a,T>{#[inline]fn hash(&self ,s:&mut H){ptr::hash(self.0,s)}} +implHashStablefor Interned<'_,T>where T:HashStable,{fn//*&*&(); +hash_stable(&self,hcx:&mut CTX,hasher:&mut StableHasher){;self.0.hash_stable(hcx +,hasher);{();};}}implDebug for Interned<'_,T>{fn fmt(&self,f:&mut fmt:: +Formatter<'_>)->fmt::Result{(((((((self.0.fmt (f))))))))}}#[cfg(test)]mod tests; diff --git a/compiler/rustc_data_structures/src/intern/tests.rs b/compiler/rustc_data_structures/src/intern/tests.rs index a85cd480a09f6..eb148e7b5fc25 100644 --- a/compiler/rustc_data_structures/src/intern/tests.rs +++ b/compiler/rustc_data_structures/src/intern/tests.rs @@ -1,58 +1,15 @@ -use super::*; - -#[derive(Debug)] -struct S(u32); - -impl PartialEq for S { - fn eq(&self, _other: &Self) -> bool { - panic!("shouldn't be called"); - } -} - -impl Eq for S {} - -impl PartialOrd for S { - fn partial_cmp(&self, other: &S) -> Option { - // The `==` case should be handled by `Interned`. - assert_ne!(self.0, other.0); - self.0.partial_cmp(&other.0) - } -} - -impl Ord for S { - fn cmp(&self, other: &S) -> Ordering { - // The `==` case should be handled by `Interned`. - assert_ne!(self.0, other.0); - self.0.cmp(&other.0) - } -} - -#[test] -fn test_uniq() { - let s1 = S(1); - let s2 = S(2); - let s3 = S(3); - let s4 = S(1); // violates uniqueness - - let v1 = Interned::new_unchecked(&s1); - let v2 = Interned::new_unchecked(&s2); - let v3a = Interned::new_unchecked(&s3); - let v3b = Interned::new_unchecked(&s3); - let v4 = Interned::new_unchecked(&s4); // violates uniqueness - - assert_ne!(v1, v2); - assert_ne!(v2, v3a); - assert_eq!(v1, v1); - assert_eq!(v3a, v3b); - assert_ne!(v1, v4); // same content but different addresses: not equal - - assert_eq!(v1.cmp(&v2), Ordering::Less); - assert_eq!(v3a.cmp(&v2), Ordering::Greater); - assert_eq!(v1.cmp(&v1), Ordering::Equal); // only uses Interned::eq, not S::cmp - assert_eq!(v3a.cmp(&v3b), Ordering::Equal); // only uses Interned::eq, not S::cmp - - assert_eq!(v1.partial_cmp(&v2), Some(Ordering::Less)); - assert_eq!(v3a.partial_cmp(&v2), Some(Ordering::Greater)); - assert_eq!(v1.partial_cmp(&v1), Some(Ordering::Equal)); // only uses Interned::eq, not S::cmp - assert_eq!(v3a.partial_cmp(&v3b), Some(Ordering::Equal)); // only uses Interned::eq, not S::cmp -} +use super::*;#[derive(Debug)]struct S(u32);impl PartialEq for S{fn eq(&self,//3; +_other:&Self)->bool{({});panic!("shouldn't be called");{;};}}impl Eq for S{}impl +PartialOrd for S{fn partial_cmp(&self,other:&S)->Option{();assert_ne!( +self.0,other.0);;self.0.partial_cmp(&other.0)}}impl Ord for S{fn cmp(&self,other +:&S)->Ordering{{;};assert_ne!(self.0,other.0);();self.0.cmp(&other.0)}}#[test]fn +test_uniq(){;let s1=S(1);;;let s2=S(2);let s3=S(3);let s4=S(1);let v1=Interned:: +new_unchecked(&s1);3;3;let v2=Interned::new_unchecked(&s2);3;;let v3a=Interned:: +new_unchecked(&s3);3;3;let v3b=Interned::new_unchecked(&s3);3;;let v4=Interned:: +new_unchecked(&s4);;;assert_ne!(v1,v2);;;assert_ne!(v2,v3a);;;assert_eq!(v1,v1); +assert_eq!(v3a,v3b);;;assert_ne!(v1,v4);;assert_eq!(v1.cmp(&v2),Ordering::Less); +assert_eq!(v3a.cmp(&v2),Ordering::Greater);3;3;assert_eq!(v1.cmp(&v1),Ordering:: +Equal);;assert_eq!(v3a.cmp(&v3b),Ordering::Equal);assert_eq!(v1.partial_cmp(&v2) +,Some(Ordering::Less));;assert_eq!(v3a.partial_cmp(&v2),Some(Ordering::Greater)) +;();();assert_eq!(v1.partial_cmp(&v1),Some(Ordering::Equal));3;3;assert_eq!(v3a. +partial_cmp(&v3b),Some(Ordering::Equal));let _=();if true{};let _=();if true{};} diff --git a/compiler/rustc_data_structures/src/jobserver.rs b/compiler/rustc_data_structures/src/jobserver.rs index 89088bc5c1b87..ebd713ec23e90 100644 --- a/compiler/rustc_data_structures/src/jobserver.rs +++ b/compiler/rustc_data_structures/src/jobserver.rs @@ -1,81 +1,19 @@ -pub use jobserver_crate::Client; - -use jobserver_crate::{FromEnv, FromEnvErrorKind}; - -use std::sync::{LazyLock, OnceLock}; - -// We can only call `from_env_ext` once per process - -// We stick this in a global because there could be multiple rustc instances -// in this process, and the jobserver is per-process. -static GLOBAL_CLIENT: LazyLock> = LazyLock::new(|| { - // Note that this is unsafe because it may misinterpret file descriptors - // on Unix as jobserver file descriptors. We hopefully execute this near - // the beginning of the process though to ensure we don't get false - // positives, or in other words we try to execute this before we open - // any file descriptors ourselves. - let FromEnv { client, var } = unsafe { Client::from_env_ext(true) }; - - let error = match client { - Ok(client) => return Ok(client), - Err(e) => e, - }; - - if matches!( - error.kind(), - FromEnvErrorKind::NoEnvVar - | FromEnvErrorKind::NoJobserver - | FromEnvErrorKind::NegativeFd - | FromEnvErrorKind::Unsupported - ) { - return Ok(default_client()); - } - - // Environment specifies jobserver, but it looks incorrect. - // Safety: `error.kind()` should be `NoEnvVar` if `var == None`. - let (name, value) = var.unwrap(); - Err(format!( - "failed to connect to jobserver from environment variable `{name}={:?}`: {error}", - value - )) -}); - -// Create a new jobserver if there's no inherited one. -fn default_client() -> Client { - // Pick a "reasonable maximum" capping out at 32 - // so we don't take everything down by hogging the process run queue. - // The fixed number is used to have deterministic compilation across machines. - let client = Client::new(32).expect("failed to create jobserver"); - - // Acquire a token for the main thread which we can release later - client.acquire_raw().ok(); - - client -} - -static GLOBAL_CLIENT_CHECKED: OnceLock = OnceLock::new(); - -pub fn initialize_checked(report_warning: impl FnOnce(&'static str)) { - let client_checked = match &*GLOBAL_CLIENT { - Ok(client) => client.clone(), - Err(e) => { - report_warning(e); - default_client() - } - }; - GLOBAL_CLIENT_CHECKED.set(client_checked).ok(); -} - -const ACCESS_ERROR: &str = "jobserver check should have been called earlier"; - -pub fn client() -> Client { - GLOBAL_CLIENT_CHECKED.get().expect(ACCESS_ERROR).clone() -} - -pub fn acquire_thread() { - GLOBAL_CLIENT_CHECKED.get().expect(ACCESS_ERROR).acquire_raw().ok(); -} - -pub fn release_thread() { - GLOBAL_CLIENT_CHECKED.get().expect(ACCESS_ERROR).release_raw().ok(); -} +pub use jobserver_crate::Client; use jobserver_crate::{FromEnv,FromEnvErrorKind} +;use std::sync::{LazyLock,OnceLock };static GLOBAL_CLIENT:LazyLock>=LazyLock::new(||{;let FromEnv{client,var}=unsafe{Client::from_env_ext( +true)};3;3;let error=match client{Ok(client)=>return Ok(client),Err(e)=>e,};;if +matches!(error.kind() ,FromEnvErrorKind::NoEnvVar|FromEnvErrorKind::NoJobserver| +FromEnvErrorKind::NegativeFd|FromEnvErrorKind::Unsupported){if true{};return Ok( +default_client());*&*&();}*&*&();let(name,value)=var.unwrap();{();};Err(format!( +"failed to connect to jobserver from environment variable `{name}={:?}`: {error}" +,value))});fn default_client()->Client{*&*&();let client=Client::new(32).expect( +"failed to create jobserver");{;};{;};client.acquire_raw().ok();();client}static +GLOBAL_CLIENT_CHECKED:OnceLock=(((((((((OnceLock ::new())))))))));pub fn +initialize_checked(report_warning:impl FnOnce(&'static str)){;let client_checked +=match&*GLOBAL_CLIENT{Ok(client)=>client.clone(),Err(e)=>{3;report_warning(e);3; +default_client()}};();();GLOBAL_CLIENT_CHECKED.set(client_checked).ok();3;}const +ACCESS_ERROR:&str=((("jobserver check should have been called earlier")));pub fn +client()->Client{(GLOBAL_CLIENT_CHECKED.get() .expect(ACCESS_ERROR).clone())}pub +fn acquire_thread(){let _=||();GLOBAL_CLIENT_CHECKED.get().expect(ACCESS_ERROR). +acquire_raw().ok();;}pub fn release_thread(){GLOBAL_CLIENT_CHECKED.get().expect( +ACCESS_ERROR).release_raw().ok();let _=||();loop{break};let _=||();loop{break};} diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index b82a9a909e6d0..3843cd39773ef 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -1,163 +1,37 @@ -//! Various data structures used by the Rust compiler. The intention -//! is that code in here should not be *specific* to rustc, so that -//! it can be easily unit tested and so forth. -//! -//! # Note -//! -//! This API is completely unstable and subject to change. - -// tidy-alphabetical-start -#![allow(internal_features)] -#![allow(rustc::default_hash_types)] -#![allow(rustc::potential_query_instability)] -#![cfg_attr(not(parallel_compiler), feature(cell_leak))] -#![deny(unsafe_op_in_unsafe_fn)] -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] -#![doc(rust_logo)] -#![feature(allocator_api)] -#![feature(array_windows)] -#![feature(auto_traits)] -#![feature(cfg_match)] -#![feature(core_intrinsics)] -#![feature(extend_one)] -#![feature(generic_nonzero)] -#![feature(hash_raw_entry)] -#![feature(hasher_prefixfree_extras)] -#![feature(lazy_cell)] -#![feature(lint_reasons)] -#![feature(macro_metavar_expr)] -#![feature(maybe_uninit_uninit_array)] -#![feature(min_specialization)] -#![feature(negative_impls)] -#![feature(never_type)] -#![feature(ptr_alignment_type)] -#![feature(rustc_attrs)] -#![feature(rustdoc_internals)] -#![feature(strict_provenance)] -#![feature(test)] -#![feature(thread_id_value)] -#![feature(type_alias_impl_trait)] -#![feature(unwrap_infallible)] -// tidy-alphabetical-end - -#[macro_use] -extern crate tracing; -#[macro_use] -extern crate rustc_macros; - -use std::fmt; - -pub use rustc_index::static_assert_size; - -/// This calls the passed function while ensuring it won't be inlined into the caller. -#[inline(never)] -#[cold] -pub fn outline R, R>(f: F) -> R { - f() -} - -pub mod base_n; -pub mod binary_search_util; -pub mod captures; -pub mod flat_map_in_place; -pub mod flock; -pub mod fx; -pub mod graph; -pub mod intern; -pub mod jobserver; -pub mod macros; -pub mod obligation_forest; -pub mod sip128; -pub mod small_c_str; -pub mod snapshot_map; -pub mod svh; -pub use ena::snapshot_vec; -pub mod memmap; -pub mod sorted_map; -#[macro_use] -pub mod stable_hasher; -mod atomic_ref; -pub mod fingerprint; -pub mod marker; -pub mod profiling; -pub mod sharded; -pub mod stack; -pub mod sync; -pub mod tiny_list; -pub mod transitive_relation; -pub mod vec_linked_list; -pub mod work_queue; -pub use atomic_ref::AtomicRef; -pub mod aligned; -pub mod frozen; -mod hashes; -pub mod owned_slice; -pub mod packed; -pub mod sso; -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; - -/// Returns a structure that calls `f` when dropped. -pub fn defer(f: F) -> OnDrop { - OnDrop(Some(f)) -} - -pub struct OnDrop(Option); - -impl OnDrop { - /// Disables on-drop call. - #[inline] - pub fn disable(mut self) { - self.0.take(); - } -} - -impl Drop for OnDrop { - #[inline] - fn drop(&mut self) { - if let Some(f) = self.0.take() { - f(); - } - } -} - -/// This is a marker for a fatal compiler error used with `resume_unwind`. -pub struct FatalErrorMarker; - -/// Turns a closure that takes an `&mut Formatter` into something that can be display-formatted. -pub fn make_display(f: impl Fn(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl fmt::Display { - struct Printer { - f: F, - } - impl fmt::Display for Printer - where - F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result, - { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - (self.f)(fmt) - } - } - - Printer { f } -} - -// See comments in compiler/rustc_middle/src/tests.rs -#[doc(hidden)] -pub fn __noop_fix_for_27438() {} - -#[macro_export] -macro_rules! external_bitflags_debug { - ($Name:ident) => { - impl ::std::fmt::Debug for $Name { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - ::bitflags::parser::to_writer(self, f) - } - } - }; -} +#![allow(internal_features)]#![allow(rustc::default_hash_types)]#![allow(rustc// +::potential_query_instability)]#![cfg_attr(not(parallel_compiler),feature(//{;}; +cell_leak))]#![deny(unsafe_op_in_unsafe_fn)]#![doc(html_root_url=//loop{break;}; +"https://doc.rust-lang.org/nightly/nightly-rustc/")]#![doc(rust_logo)]#![//({}); +feature(allocator_api)]#![feature(array_windows)]#![feature(auto_traits)]#![//3; +feature(cfg_match)]#![feature(core_intrinsics)]#![feature(extend_one)]#![//({}); +feature(generic_nonzero)]#![feature(hash_raw_entry)]#![feature(//*&*&();((),()); +hasher_prefixfree_extras)]#![feature(lazy_cell)]#![feature(lint_reasons)]#![//3; +feature(macro_metavar_expr)]#![feature(maybe_uninit_uninit_array)]#![feature(//; +min_specialization)]#![feature(negative_impls)]#![feature(never_type)]#![//({}); +feature(ptr_alignment_type)]#![feature(rustc_attrs)]#![feature(//*&*&();((),()); +rustdoc_internals)]#![feature(strict_provenance)]#![feature(test)]#![feature(//; +thread_id_value)]#![feature( type_alias_impl_trait)]#![feature(unwrap_infallible +)]#[macro_use]extern crate tracing;#[macro_use]extern crate rustc_macros;use//3; +std::fmt;pub use rustc_index::static_assert_size;#[inline(never)]#[cold]pub fn// +outlineR,R>(f:F)->R {f()}pub mod base_n;pub mod binary_search_util; +pub mod captures;pub mod flat_map_in_place;pub mod flock;pub mod fx;pub mod//(); +graph;pub mod intern;pub mod jobserver;pub mod macros;pub mod obligation_forest +;pub mod sip128;pub mod small_c_str;pub mod snapshot_map;pub mod svh;pub use//3; +ena::snapshot_vec;pub mod memmap;pub mod sorted_map;#[macro_use]pub mod//*&*&(); +stable_hasher;mod atomic_ref;pub mod fingerprint;pub mod marker;pub mod//*&*&(); +profiling;pub mod sharded;pub mod stack;pub mod sync;pub mod tiny_list;pub mod// +transitive_relation;pub mod vec_linked_list;pub mod work_queue;pub use//((),()); +atomic_ref::AtomicRef;pub mod aligned;pub mod frozen;mod hashes;pub mod//*&*&(); +owned_slice;pub mod packed;pub mod sso; 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// +;pub fn defer(f:F)->OnDrop{(OnDrop(Some(f)))}pub struct OnDrop(Option);implOnDrop{#[inline]pub fn disable(mut self +){;self.0.take();}}implDrop for OnDrop{#[inline]fn drop(&mut self +){if let Some(f)=self.0.take(){{;};f();{;};}}}pub struct FatalErrorMarker;pub fn +make_display(f:impl Fn(&mut fmt::Formatter<'_>)->fmt::Result)->impl fmt:://({}); +Display{;struct Printer{f:F,};;implfmt::Display for Printerwhere F:Fn(& +mut fmt::Formatter<'_>)->fmt::Result,{fn fmt(&self,fmt:&mut fmt::Formatter<'_>) +->fmt::Result{(self.f)(fmt)}}if true{};if true{};Printer{f}}#[doc(hidden)]pub fn +__noop_fix_for_27438(){}#[macro_export]macro_rules!external_bitflags_debug{($//; +Name:ident)=>{impl::std::fmt::Debug for$Name{fn fmt(&self,f:&mut::std::fmt:://3; +Formatter<'_>)->::std::fmt::Result{::bitflags::parser::to_writer(self,f)}}};}//; diff --git a/compiler/rustc_data_structures/src/macros.rs b/compiler/rustc_data_structures/src/macros.rs index e05491f6ff6e4..1051aaaa16c7a 100644 --- a/compiler/rustc_data_structures/src/macros.rs +++ b/compiler/rustc_data_structures/src/macros.rs @@ -1,37 +1,8 @@ -#[macro_export] -macro_rules! enum_from_u32 { - ($(#[$attr:meta])* pub enum $name:ident { - $($(#[$var_attr:meta])* $variant:ident = $e:expr,)* - }) => { - $(#[$attr])* - pub enum $name { - $($(#[$var_attr])* $variant = $e),* - } - - impl $name { - pub fn from_u32(u: u32) -> Option<$name> { - $(if u == $name::$variant as u32 { - return Some($name::$variant) - })* - None - } - } - }; - ($(#[$attr:meta])* pub enum $name:ident { - $($(#[$var_attr:meta])* $variant:ident,)* - }) => { - $(#[$attr])* - pub enum $name { - $($(#[$var_attr])* $variant,)* - } - - impl $name { - pub fn from_u32(u: u32) -> Option<$name> { - $(if u == $name::$variant as u32 { - return Some($name::$variant) - })* - None - } - } - } -} +#[macro_export]macro_rules!enum_from_u32{($(#[$ attr:meta])*pub enum$name:ident{ +$($(#[$var_attr:meta])*$variant:ident=$e:expr ,)*})=>{$(#[$attr])*pub enum$name{ +$($(#[$var_attr])*$variant=$e),* }impl$name{pub fn from_u32(u:u32)->Option<$name +>{$(if u==$name::$variant as u32{return Some($name::$variant)})*None}}};($(#[$// +attr:meta])*pub enum$name:ident{$($(#[ $var_attr:meta])*$variant:ident,)*})=>{$( +#[$attr])*pub enum$name{$($(#[ $var_attr])*$variant,)*}impl$name{pub fn from_u32 +(u:u32)->Option<$name>{$(if u==$name::$variant as u32{return Some($name::$//{;}; +variant)})*None}}}}//if let _=(){};*&*&();((),());*&*&();((),());*&*&();((),()); diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs index a9ccfbed41165..2c53a48cc4b35 100644 --- a/compiler/rustc_data_structures/src/marker.rs +++ b/compiler/rustc_data_structures/src/marker.rs @@ -1,260 +1,85 @@ -cfg_match! { - cfg(not(parallel_compiler)) => { - pub auto trait DynSend {} - pub auto trait DynSync {} - - impl DynSend for T {} - impl DynSync for T {} - } - _ => { - #[rustc_on_unimplemented( - message = "`{Self}` doesn't implement `DynSend`. \ +cfg_match!{cfg(not(parallel_compiler))=>{pub auto trait DynSend{}pub auto trait +DynSync{}implDynSend for T{}implDynSync for T{}}_=>{#[//let _=();let _=(); +rustc_on_unimplemented(message=//let _=||();loop{break};loop{break};loop{break}; +"`{Self}` doesn't implement `DynSend`. \ Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Send`" - )] - // This is an auto trait for types which can be sent across threads if `sync::is_dyn_thread_safe()` - // is true. These types can be wrapped in a `FromDyn` to get a `Send` type. Wrapping a - // `Send` type in `IntoDynSyncSend` will create a `DynSend` type. - pub unsafe auto trait DynSend {} - - #[rustc_on_unimplemented( - message = "`{Self}` doesn't implement `DynSync`. \ +)]pub unsafe auto trait DynSend{}#[rustc_on_unimplemented(message=//loop{break}; +"`{Self}` doesn't implement `DynSync`. \ Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Sync`" - )] - // This is an auto trait for types which can be shared across threads if `sync::is_dyn_thread_safe()` - // is true. These types can be wrapped in a `FromDyn` to get a `Sync` type. Wrapping a - // `Sync` type in `IntoDynSyncSend` will create a `DynSync` type. - pub unsafe auto trait DynSync {} - - // Same with `Sync` and `Send`. - unsafe impl DynSend for &T {} - - macro_rules! impls_dyn_send_neg { - ($([$t1: ty $(where $($generics1: tt)*)?])*) => { - $(impl$(<$($generics1)*>)? !DynSend for $t1 {})* - }; - } - - // Consistent with `std` - impls_dyn_send_neg!( - [std::env::Args] - [std::env::ArgsOs] - [*const T where T: ?Sized] - [*mut T where T: ?Sized] - [std::ptr::NonNull where T: ?Sized] - [std::rc::Rc where T: ?Sized] - [std::rc::Weak where T: ?Sized] - [std::sync::MutexGuard<'_, T> where T: ?Sized] - [std::sync::RwLockReadGuard<'_, T> where T: ?Sized] - [std::sync::RwLockWriteGuard<'_, T> where T: ?Sized] - [std::io::StdoutLock<'_>] - [std::io::StderrLock<'_>] - ); - - #[cfg(any(unix, target_os = "hermit", target_os = "wasi", target_os = "solid_asp3"))] - // Consistent with `std`, `os_imp::Env` is `!Sync` in these platforms - impl !DynSend for std::env::VarsOs {} - - macro_rules! already_send { - ($([$ty: ty])*) => { - $(unsafe impl DynSend for $ty where $ty: Send {})* - }; - } - - // These structures are already `Send`. - already_send!( - [std::backtrace::Backtrace] - [std::io::Stdout] - [std::io::Stderr] - [std::io::Error] - [std::fs::File] - [rustc_arena::DroplessArena] - [crate::memmap::Mmap] - [crate::profiling::SelfProfiler] - [crate::owned_slice::OwnedSlice] - ); - - macro_rules! impl_dyn_send { - ($($($attr: meta)* [$ty: ty where $($generics2: tt)*])*) => { - $(unsafe impl<$($generics2)*> DynSend for $ty {})* - }; - } - - impl_dyn_send!( - [std::sync::atomic::AtomicPtr where T] - [std::sync::Mutex where T: ?Sized+ DynSend] - [std::sync::mpsc::Sender where T: DynSend] - [std::sync::Arc where T: ?Sized + DynSync + DynSend] - [std::sync::LazyLock where T: DynSend, F: DynSend] - [std::collections::HashSet where K: DynSend, S: DynSend] - [std::collections::HashMap where K: DynSend, V: DynSend, S: DynSend] - [std::collections::BTreeMap where K: DynSend, V: DynSend, A: std::alloc::Allocator + Clone + DynSend] - [Vec where T: DynSend, A: std::alloc::Allocator + DynSend] - [Box where T: ?Sized + DynSend, A: std::alloc::Allocator + DynSend] - [crate::sync::RwLock where T: DynSend] - [crate::tagged_ptr::CopyTaggedPtr where P: Send + crate::tagged_ptr::Pointer, T: Send + crate::tagged_ptr::Tag, const CP: bool] - [rustc_arena::TypedArena where T: DynSend] - [indexmap::IndexSet where V: DynSend, S: DynSend] - [indexmap::IndexMap where K: DynSend, V: DynSend, S: DynSend] - [thin_vec::ThinVec where T: DynSend] - [smallvec::SmallVec where A: smallvec::Array + DynSend] - ); - - macro_rules! impls_dyn_sync_neg { - ($([$t1: ty $(where $($generics1: tt)*)?])*) => { - $(impl$(<$($generics1)*>)? !DynSync for $t1 {})* - }; - } - - // Consistent with `std` - impls_dyn_sync_neg!( - [std::env::Args] - [std::env::ArgsOs] - [*const T where T: ?Sized] - [*mut T where T: ?Sized] - [std::cell::Cell where T: ?Sized] - [std::cell::RefCell where T: ?Sized] - [std::cell::UnsafeCell where T: ?Sized] - [std::ptr::NonNull where T: ?Sized] - [std::rc::Rc where T: ?Sized] - [std::rc::Weak where T: ?Sized] - [std::cell::OnceCell where T] - [std::sync::mpsc::Receiver where T] - [std::sync::mpsc::Sender where T] - ); - - #[cfg(any(unix, target_os = "hermit", target_os = "wasi", target_os = "solid_asp3"))] - // Consistent with `std`, `os_imp::Env` is `!Sync` in these platforms - impl !DynSync for std::env::VarsOs {} - - macro_rules! already_sync { - ($([$ty: ty])*) => { - $(unsafe impl DynSync for $ty where $ty: Sync {})* - }; - } - - // These structures are already `Sync`. - already_sync!( - [std::sync::atomic::AtomicBool] - [std::sync::atomic::AtomicUsize] - [std::sync::atomic::AtomicU8] - [std::sync::atomic::AtomicU32] - [std::backtrace::Backtrace] - [std::io::Error] - [std::fs::File] - [jobserver_crate::Client] - [crate::memmap::Mmap] - [crate::profiling::SelfProfiler] - [crate::owned_slice::OwnedSlice] - ); - - // PowerPC and MIPS platforms with 32-bit pointers do not - // have AtomicU64 type. - #[cfg(not(any(target_arch = "powerpc", target_arch = "mips")))] - already_sync!( - [std::sync::atomic::AtomicU64] - ); - - #[cfg(any(target_arch = "powerpc", target_arch = "mips"))] - already_sync!( - [portable_atomic::AtomicU64] - ); - - macro_rules! impl_dyn_sync { - ($($($attr: meta)* [$ty: ty where $($generics2: tt)*])*) => { - $(unsafe impl<$($generics2)*> DynSync for $ty {})* - }; - } - - impl_dyn_sync!( - [std::sync::atomic::AtomicPtr where T] - [std::sync::OnceLock where T: DynSend + DynSync] - [std::sync::Mutex where T: ?Sized + DynSend] - [std::sync::Arc where T: ?Sized + DynSync + DynSend] - [std::sync::LazyLock where T: DynSend + DynSync, F: DynSend] - [std::collections::HashSet where K: DynSync, S: DynSync] - [std::collections::HashMap where K: DynSync, V: DynSync, S: DynSync] - [std::collections::BTreeMap where K: DynSync, V: DynSync, A: std::alloc::Allocator + Clone + DynSync] - [Vec where T: DynSync, A: std::alloc::Allocator + DynSync] - [Box where T: ?Sized + DynSync, A: std::alloc::Allocator + DynSync] - [crate::sync::RwLock where T: DynSend + DynSync] - [crate::sync::WorkerLocal where T: DynSend] - [crate::intern::Interned<'a, T> where 'a, T: DynSync] - [crate::tagged_ptr::CopyTaggedPtr where P: Sync + crate::tagged_ptr::Pointer, T: Sync + crate::tagged_ptr::Tag, const CP: bool] - [parking_lot::lock_api::Mutex where R: DynSync, T: ?Sized + DynSend] - [parking_lot::lock_api::RwLock where R: DynSync, T: ?Sized + DynSend + DynSync] - [indexmap::IndexSet where V: DynSync, S: DynSync] - [indexmap::IndexMap where K: DynSync, V: DynSync, S: DynSync] - [smallvec::SmallVec where A: smallvec::Array + DynSync] - [thin_vec::ThinVec where T: DynSync] - ); - } -} - -pub fn assert_dyn_sync() {} -pub fn assert_dyn_send() {} -pub fn assert_dyn_send_val(_t: &T) {} -pub fn assert_dyn_send_sync_val(_t: &T) {} - -#[derive(Copy, Clone)] -pub struct FromDyn(T); - -impl FromDyn { - #[inline(always)] - pub fn from(val: T) -> Self { - // Check that `sync::is_dyn_thread_safe()` is true on creation so we can - // implement `Send` and `Sync` for this structure when `T` - // implements `DynSend` and `DynSync` respectively. - #[cfg(parallel_compiler)] - assert!(crate::sync::is_dyn_thread_safe()); - FromDyn(val) - } - - #[inline(always)] - pub fn into_inner(self) -> T { - self.0 - } -} - -// `FromDyn` is `Send` if `T` is `DynSend`, since it ensures that sync::is_dyn_thread_safe() is true. -#[cfg(parallel_compiler)] -unsafe impl Send for FromDyn {} - -// `FromDyn` is `Sync` if `T` is `DynSync`, since it ensures that sync::is_dyn_thread_safe() is true. -#[cfg(parallel_compiler)] -unsafe impl Sync for FromDyn {} - -impl std::ops::Deref for FromDyn { - type Target = T; - - #[inline(always)] - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -// A wrapper to convert a struct that is already a `Send` or `Sync` into -// an instance of `DynSend` and `DynSync`, since the compiler cannot infer -// it automatically in some cases. (e.g. Box) -#[derive(Copy, Clone)] -pub struct IntoDynSyncSend(pub T); - -#[cfg(parallel_compiler)] -unsafe impl DynSend for IntoDynSyncSend {} -#[cfg(parallel_compiler)] -unsafe impl DynSync for IntoDynSyncSend {} - -impl std::ops::Deref for IntoDynSyncSend { - type Target = T; - - #[inline(always)] - fn deref(&self) -> &T { - &self.0 - } -} - -impl std::ops::DerefMut for IntoDynSyncSend { - #[inline(always)] - fn deref_mut(&mut self) -> &mut T { - &mut self.0 - } -} +)]pub unsafe auto trait DynSync{}unsafe implDynSend for&T{}//; +macro_rules!impls_dyn_send_neg{($([$t1:ty$(where$($generics1:tt)*)?])*)=>{$(//3; +impl$(<$($generics1)*>)?!DynSend for$t1{})*};}impls_dyn_send_neg!([std::env:://; +Args][std::env::ArgsOs][*const T where T:?Sized][*mut T where T:?Sized][std:://; +ptr::NonNullwhere T:?Sized][std::rc::Rcwhere T:?Sized][std::rc::Weak//; +where T:?Sized][std::sync::MutexGuard<'_,T>where T:?Sized][std::sync:://((),()); +RwLockReadGuard<'_,T>where T:?Sized][ std::sync::RwLockWriteGuard<'_,T>where T:? +Sized][std::io::StdoutLock<'_>][std::io::StderrLock<'_>]);#[cfg(any(unix,//({}); +target_os="hermit",target_os="wasi",target_os="solid_asp3"))]impl!DynSend for//; +std::env::VarsOs{}macro_rules!already_send{($([$ty:ty])*)=>{$(unsafe impl//({}); +DynSend for$ty where$ty:Send{})*};}already_send!([std::backtrace::Backtrace][//; +std::io::Stdout][std::io::Stderr][std::io::Error][std::fs::File][rustc_arena::// +DroplessArena][crate::memmap::Mmap][crate::profiling::SelfProfiler][crate:://(); +owned_slice::OwnedSlice]);macro_rules!impl_dyn_send{($($($attr:meta)*[$ty:ty//3; +where$($generics2:tt)*])*)=>{$(unsafe impl <$($generics2)*>DynSend for$ty{})*};} +impl_dyn_send!([std::sync::atomic::AtomicPtrwhere T][std::sync::Mutex//(); +where T:?Sized+DynSend][std::sync::mpsc::Senderwhere T:DynSend][std::sync::// +Arcwhere T:?Sized+DynSync+DynSend][ std::sync::LazyLockwhere T:DynSend,F +:DynSend][std::collections::HashSetwhere K:DynSend,S:DynSend][std:://{();}; +collections::HashMapwhere K:DynSend,V:DynSend,S:DynSend][std:://let _=(); +collections::BTreeMapwhere K:DynSend,V:DynSend,A:std::alloc::Allocator+// +Clone+DynSend][Vecwhere T:DynSend ,A:std::alloc::Allocator+DynSend][Boxwhere T:?Sized+DynSend,A:std:: alloc::Allocator+DynSend][crate::sync::RwLock +where T:DynSend][crate::tagged_ptr::CopyTaggedPtrwhere P:Send+crate:://; +tagged_ptr::Pointer,T:Send+crate::tagged_ptr::Tag,const CP:bool][rustc_arena::// +TypedArenawhere T:DynSend][indexmap::IndexSet where V:DynSend,S:DynSend] +[indexmap::IndexMapwhere K:DynSend,V:DynSend,S:DynSend][thin_vec:://({}); +ThinVecwhere T:DynSend][smallvec:: SmallVecwhere A:smallvec::Array+DynSend +]);macro_rules!impls_dyn_sync_neg{($([$t1:ty$(where $($generics1:tt)*)?])*)=>{$( +impl$(<$($generics1)*>)?!DynSync for$t1{})*};}impls_dyn_sync_neg!([std::env:://; +Args][std::env::ArgsOs][*const T where T:?Sized][*mut T where T:?Sized][std:://; +cell::Cellwhere T:?Sized][std::cell::RefCellwhere T:?Sized][std::cell:://; +UnsafeCellwhere T:?Sized][std::ptr::NonNull< T>where T:?Sized][std::rc::Rc +where T:?Sized][std::rc::Weakwhere T:?Sized][std::cell::OnceCellwhere T][ +std::sync::mpsc::Receiverwhere T][std:: sync::mpsc::Senderwhere T]);#[cfg( +any(unix,target_os="hermit",target_os="wasi",target_os="solid_asp3"))]impl!//(); +DynSync for std::env::VarsOs{}macro_rules!already_sync{($([$ty:ty])*)=>{$(//{;}; +unsafe impl DynSync for$ty where$ty:Sync {})*};}already_sync!([std::sync::atomic +::AtomicBool][std::sync::atomic::AtomicUsize][std::sync::atomic::AtomicU8][std// +::sync::atomic::AtomicU32][std::backtrace::Backtrace ][std::io::Error][std::fs:: +File][jobserver_crate::Client][crate::memmap::Mmap][crate::profiling:://((),()); +SelfProfiler][crate::owned_slice::OwnedSlice]);#[cfg(not(any(target_arch=//({}); +"powerpc",target_arch="mips")))]already_sync!( [std::sync::atomic::AtomicU64]);# +[cfg(any(target_arch="powerpc",target_arch="mips"))]already_sync!([//let _=||(); +portable_atomic::AtomicU64]);macro_rules!impl_dyn_sync{($( $($attr:meta)*[$ty:ty +where$($generics2:tt)*])*)=>{$(unsafe impl<$($generics2)*>DynSync for$ty{})*};// +}impl_dyn_sync!([std::sync::atomic::AtomicPtrwhere T][std::sync::OnceLock +where T:DynSend+DynSync][std::sync::Mutex< T>where T:?Sized+DynSend][std::sync:: +Arcwhere T:?Sized+DynSync+DynSend][std::sync::LazyLockwhere T:DynSend+// +DynSync,F:DynSend][std::collections::HashSetwhere K:DynSync,S:DynSync][std +::collections::HashMapwhere K:DynSync,V:DynSync,S:DynSync][std:://*&*&(); +collections::BTreeMapwhere K:DynSync,V:DynSync,A:std::alloc::Allocator+// +Clone+DynSync][Vecwhere T:DynSync ,A:std::alloc::Allocator+DynSync][Boxwhere T:?Sized+DynSync,A:std:: alloc::Allocator+DynSync][crate::sync::RwLock +where T:DynSend+DynSync][crate::sync::WorkerLocalwhere T:DynSend][crate:://3; +intern::Interned<'a,T>where 'a,T :DynSync][crate::tagged_ptr::CopyTaggedPtrwhere P:Sync+crate::tagged_ptr::Pointer,T:Sync+crate::tagged_ptr::Tag,const// +CP:bool][parking_lot::lock_api::Mutexwhere R:DynSync,T:?Sized+DynSend][//3; +parking_lot::lock_api::RwLockwhere R:DynSync,T:?Sized+DynSend+DynSync][//3; +indexmap::IndexSetwhere V:DynSync,S:DynSync][indexmap::IndexMap//(); +where K:DynSync,V:DynSync,S:DynSync][smallvec::SmallVecwhere A:smallvec:://3; +Array+DynSync][thin_vec::ThinVecwhere T :DynSync]);}}pub fn assert_dyn_sync(){}pub fn assert_dyn_send(){}pub fn//((),()); +assert_dyn_send_val(_t: &T){}pub fn assert_dyn_send_sync_val(_t:&T){}#[ derive(Copy,Clone)]pub struct FromDyn(T); +implFromDyn{#[inline(always)]pub fn from(val:T)->Self{if let _=(){};#[cfg( +parallel_compiler)]assert!(crate::sync::is_dyn_thread_safe());();FromDyn(val)}#[ +inline(always)]pub fn into_inner(self)->T{self.0}}#[cfg(parallel_compiler)]//(); +unsafe implSend for FromDyn< T>{}#[cfg(parallel_compiler)]unsafe impl +Sync for FromDyn{}implstd::ops::Deref for FromDyn{type//{;}; +Target=T;#[inline(always)]fn deref(&self) ->&Self::Target{&self.0}}#[derive(Copy +,Clone)]pub struct IntoDynSyncSend(pub T);#[cfg(parallel_compiler)]//; +unsafe implDynSend for IntoDynSyncSend{}#[cfg(//if let _=(){}; +parallel_compiler)]unsafe implDynSync for IntoDynSyncSend{}//; +implstd::ops::Deref for IntoDynSyncSend{type Target=T;#[inline(always)]fn +deref(&self)->&T{(&self.0)}}impl std::ops::DerefMut for IntoDynSyncSend{#[ +inline(always)]fn deref_mut(&mut self)->&mut T{((((((((((&mut self.0))))))))))}} diff --git a/compiler/rustc_data_structures/src/memmap.rs b/compiler/rustc_data_structures/src/memmap.rs index c7f66b2fee80f..c2d001d661772 100644 --- a/compiler/rustc_data_structures/src/memmap.rs +++ b/compiler/rustc_data_structures/src/memmap.rs @@ -1,118 +1,21 @@ -use std::fs::File; -use std::io; -use std::ops::{Deref, DerefMut}; - -/// A trivial wrapper for [`memmap2::Mmap`] (or `Vec` on WASM). -#[cfg(not(target_arch = "wasm32"))] -pub struct Mmap(memmap2::Mmap); - -#[cfg(target_arch = "wasm32")] -pub struct Mmap(Vec); - -#[cfg(not(target_arch = "wasm32"))] -impl Mmap { - /// # Safety - /// - /// The given file must not be mutated (i.e., not written, not truncated, ...) until the mapping is closed. - /// - /// However in practice most callers do not ensure this, so uses of this function are likely unsound. - #[inline] - pub unsafe fn map(file: File) -> io::Result { - // By default, memmap2 creates shared mappings, implying that we could see updates to the - // file through the mapping. That would violate our precondition; so by requesting a - // map_copy_read_only we do not lose anything. - // This mapping mode also improves our support for filesystems such as cacheless virtiofs. - // For more details see https://github.com/rust-lang/rust/issues/122262 - // - // SAFETY: The caller must ensure that this is safe. - unsafe { memmap2::MmapOptions::new().map_copy_read_only(&file).map(Mmap) } - } -} - -#[cfg(target_arch = "wasm32")] -impl Mmap { - #[inline] - pub unsafe fn map(mut file: File) -> io::Result { - use std::io::Read; - - let mut data = Vec::new(); - file.read_to_end(&mut data)?; - Ok(Mmap(data)) - } -} - -impl Deref for Mmap { - type Target = [u8]; - - #[inline] - fn deref(&self) -> &[u8] { - &self.0 - } -} - -impl AsRef<[u8]> for Mmap { - fn as_ref(&self) -> &[u8] { - &self.0 - } -} - -#[cfg(not(target_arch = "wasm32"))] -pub struct MmapMut(memmap2::MmapMut); - -#[cfg(target_arch = "wasm32")] -pub struct MmapMut(Vec); - -#[cfg(not(target_arch = "wasm32"))] -impl MmapMut { - #[inline] - pub fn map_anon(len: usize) -> io::Result { - let mmap = memmap2::MmapMut::map_anon(len)?; - Ok(MmapMut(mmap)) - } - - #[inline] - pub fn flush(&mut self) -> io::Result<()> { - self.0.flush() - } - - #[inline] - pub fn make_read_only(self) -> std::io::Result { - let mmap = self.0.make_read_only()?; - Ok(Mmap(mmap)) - } -} - -#[cfg(target_arch = "wasm32")] -impl MmapMut { - #[inline] - pub fn map_anon(len: usize) -> io::Result { - let data = Vec::with_capacity(len); - Ok(MmapMut(data)) - } - - #[inline] - pub fn flush(&mut self) -> io::Result<()> { - Ok(()) - } - - #[inline] - pub fn make_read_only(self) -> std::io::Result { - Ok(Mmap(self.0)) - } -} - -impl Deref for MmapMut { - type Target = [u8]; - - #[inline] - fn deref(&self) -> &[u8] { - &self.0 - } -} - -impl DerefMut for MmapMut { - #[inline] - fn deref_mut(&mut self) -> &mut [u8] { - &mut self.0 - } -} +use std::fs::File;use std::io;use std::ops::{Deref,DerefMut};#[cfg(not(//*&*&(); +target_arch="wasm32"))]pub struct Mmap(memmap2::Mmap);#[cfg(target_arch=//{();}; +"wasm32")]pub struct Mmap(Vec);# [cfg(not(target_arch="wasm32"))]impl Mmap{# +[inline]pub unsafe fn map(file:File)->io::Result{unsafe{memmap2:://*&*&(); +MmapOptions::new().map_copy_read_only(((&file))) .map(Mmap)}}}#[cfg(target_arch= +"wasm32")]impl Mmap{#[inline]pub unsafe fn map(mut file:File)->io::Result +{;use std::io::Read;let mut data=Vec::new();file.read_to_end(&mut data)?;Ok(Mmap +(data))}}impl Deref for Mmap{type Target=[ u8];#[inline]fn deref(&self)->&[u8]{& +self.0}}impl AsRef<[u8]>for Mmap{fn as_ref(&self)->&[u8]{((&self.0))}}#[cfg(not( +target_arch="wasm32"))]pub struct MmapMut(memmap2::MmapMut);#[cfg(target_arch=// +"wasm32")]pub struct MmapMut(Vec);#[cfg(not(target_arch="wasm32"))]impl//(); +MmapMut{#[inline]pub fn map_anon(len:usize)->io::Result{3;let mmap=memmap2 +::MmapMut::map_anon(len)?;3;Ok(MmapMut(mmap))}#[inline]pub fn flush(&mut self)-> +io::Result<()>{(self.0.flush()) }#[inline]pub fn make_read_only(self)->std::io:: +Result{{();};let mmap=self.0.make_read_only()?;({});Ok(Mmap(mmap))}}#[cfg( +target_arch="wasm32")]impl MmapMut{#[inline]pub fn map_anon(len:usize)->io:://3; +Result{;let data=Vec::with_capacity(len);Ok(MmapMut(data))}#[inline]pub fn +flush(&mut self)->io::Result<()>{(Ok(()))}#[inline]pub fn make_read_only(self)-> +std::io::Result{Ok(Mmap(self.0) )}}impl Deref for MmapMut{type Target=[u8] +;#[inline]fn deref(&self)->&[u8]{ &self.0}}impl DerefMut for MmapMut{#[inline]fn +deref_mut(&mut self)->&mut[u8]{((((((((((((((((((&mut self.0))))))))))))))))))}} diff --git a/compiler/rustc_data_structures/src/obligation_forest/graphviz.rs b/compiler/rustc_data_structures/src/obligation_forest/graphviz.rs index 4b6aa116520df..2b3c30b049c16 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/graphviz.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/graphviz.rs @@ -1,90 +1,24 @@ -use crate::obligation_forest::{ForestObligation, ObligationForest}; -use rustc_graphviz as dot; -use std::env::var_os; -use std::fs::File; -use std::io::BufWriter; -use std::path::Path; -use std::sync::atomic::AtomicUsize; -use std::sync::atomic::Ordering; - -impl ObligationForest { - /// Creates a graphviz representation of the obligation forest. Given a directory this will - /// create files with name of the format `_.gv`. The counter is - /// global and is maintained internally. - /// - /// Calling this will do nothing unless the environment variable - /// `DUMP_OBLIGATION_FOREST_GRAPHVIZ` is defined. - /// - /// A few post-processing that you might want to do make the forest easier to visualize: - /// - /// * `sed 's,std::[a-z]*::,,g'` — Deletes the `std::::` prefix of paths. - /// * `sed 's,"Binder(TraitPredicate(<\(.*\)>)) (\([^)]*\))","\1 (\2)",'` — Transforms - /// `Binder(TraitPredicate())` into just ``. - #[allow(dead_code)] - pub fn dump_graphviz>(&self, dir: P, description: &str) { - static COUNTER: AtomicUsize = AtomicUsize::new(0); - - if var_os("DUMP_OBLIGATION_FOREST_GRAPHVIZ").is_none() { - return; - } - - let counter = COUNTER.fetch_add(1, Ordering::AcqRel); - - let file_path = dir.as_ref().join(format!("{counter:010}_{description}.gv")); - - let mut gv_file = BufWriter::new(File::create(file_path).unwrap()); - - dot::render(&self, &mut gv_file).unwrap(); - } -} - -impl<'a, O: ForestObligation + 'a> dot::Labeller<'a> for &'a ObligationForest { - type Node = usize; - type Edge = (usize, usize); - - fn graph_id(&self) -> dot::Id<'_> { - dot::Id::new("trait_obligation_forest").unwrap() - } - - fn node_id(&self, index: &Self::Node) -> dot::Id<'_> { - dot::Id::new(format!("obligation_{index}")).unwrap() - } - - fn node_label(&self, index: &Self::Node) -> dot::LabelText<'_> { - let node = &self.nodes[*index]; - let label = format!("{:?} ({:?})", node.obligation.as_cache_key(), node.state.get()); - - dot::LabelText::LabelStr(label.into()) - } - - fn edge_label(&self, (_index_source, _index_target): &Self::Edge) -> dot::LabelText<'_> { - dot::LabelText::LabelStr("".into()) - } -} - -impl<'a, O: ForestObligation + 'a> dot::GraphWalk<'a> for &'a ObligationForest { - type Node = usize; - type Edge = (usize, usize); - - fn nodes(&self) -> dot::Nodes<'_, Self::Node> { - (0..self.nodes.len()).collect() - } - - fn edges(&self) -> dot::Edges<'_, Self::Edge> { - (0..self.nodes.len()) - .flat_map(|i| { - let node = &self.nodes[i]; - - node.dependents.iter().map(move |&d| (d, i)) - }) - .collect() - } - - fn source(&self, (s, _): &Self::Edge) -> Self::Node { - *s - } - - fn target(&self, (_, t): &Self::Edge) -> Self::Node { - *t - } -} +use crate::obligation_forest::{ForestObligation,ObligationForest};use//let _=(); +rustc_graphviz as dot;use std::env::var_os;use std::fs::File;use std::io:://{;}; +BufWriter;use std::path::Path;use std::sync::atomic::AtomicUsize;use std::sync// +::atomic::Ordering;implObligationForest{#[allow(//*&*&(); +dead_code)]pub fn dump_graphviz>(&self,dir:P,description:&str){(); +static COUNTER:AtomicUsize=AtomicUsize::new(0);let _=||();loop{break};if var_os( +"DUMP_OBLIGATION_FOREST_GRAPHVIZ").is_none(){();return;3;}3;let counter=COUNTER. +fetch_add(1,Ordering::AcqRel);({});({});let file_path=dir.as_ref().join(format!( +"{counter:010}_{description}.gv"));;let mut gv_file=BufWriter::new(File::create( +file_path).unwrap());3;3;dot::render(&self,&mut gv_file).unwrap();3;}}impl<'a,O: +ForestObligation+'a>dot::Labeller<'a>for& 'a ObligationForest{type Node=usize +;type Edge=(usize,usize);fn graph_id(&self)->dot::Id<'_>{dot::Id::new(//((),()); +"trait_obligation_forest").unwrap()}fn node_id(&self,index:&Self::Node)->dot::// +Id<'_>{dot::Id::new(format!( "obligation_{index}")).unwrap()}fn node_label(&self +,index:&Self::Node)->dot::LabelText<'_>{;let node=&self.nodes[*index];let label= +format!("{:?} ({:?})",node.obligation.as_cache_key(),node.state.get());{;};dot:: +LabelText::LabelStr((((((label.into())))))) }fn edge_label(&self,(_index_source, +_index_target):&Self::Edge)->dot::LabelText<'_>{dot::LabelText::LabelStr((("")). +into())}}impl<'a,O:ForestObligation+'a>dot::GraphWalk<'a>for&'a//*&*&();((),()); +ObligationForest{type Node=usize;type Edge=(usize,usize);fn nodes(&self)->//; +dot::Nodes<'_,Self::Node>{((0..self.nodes.len()).collect())}fn edges(&self)->dot +::Edges<'_,Self::Edge>{(0..self.nodes.len()).flat_map(|i|{;let node=&self.nodes[ +i];;node.dependents.iter().map(move|&d|(d,i))}).collect()}fn source(&self,(s,_): +&Self::Edge)->Self::Node{*s}fn target(&self, (_,t):&Self::Edge)->Self::Node{*t}} diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs index a47908648ba16..4c41a6494d930 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs @@ -1,728 +1,125 @@ -//! The `ObligationForest` is a utility data structure used in trait -//! matching to track the set of outstanding obligations (those not yet -//! resolved to success or error). It also tracks the "backtrace" of each -//! pending obligation (why we are trying to figure this out in the first -//! place). -//! -//! ### External view -//! -//! `ObligationForest` supports two main public operations (there are a -//! few others not discussed here): -//! -//! 1. Add a new root obligations (`register_obligation`). -//! 2. Process the pending obligations (`process_obligations`). -//! -//! When a new obligation `N` is added, it becomes the root of an -//! obligation tree. This tree can also carry some per-tree state `T`, -//! which is given at the same time. This tree is a singleton to start, so -//! `N` is both the root and the only leaf. Each time the -//! `process_obligations` method is called, it will invoke its callback -//! with every pending obligation (so that will include `N`, the first -//! time). The callback also receives a (mutable) reference to the -//! per-tree state `T`. The callback should process the obligation `O` -//! that it is given and return a `ProcessResult`: -//! -//! - `Unchanged` -> ambiguous result. Obligation was neither a success -//! nor a failure. It is assumed that further attempts to process the -//! obligation will yield the same result unless something in the -//! surrounding environment changes. -//! - `Changed(C)` - the obligation was *shallowly successful*. The -//! vector `C` is a list of subobligations. The meaning of this is that -//! `O` was successful on the assumption that all the obligations in `C` -//! are also successful. Therefore, `O` is only considered a "true" -//! success if `C` is empty. Otherwise, `O` is put into a suspended -//! state and the obligations in `C` become the new pending -//! obligations. They will be processed the next time you call -//! `process_obligations`. -//! - `Error(E)` -> obligation failed with error `E`. We will collect this -//! error and return it from `process_obligations`, along with the -//! "backtrace" of obligations (that is, the list of obligations up to -//! and including the root of the failed obligation). No further -//! obligations from that same tree will be processed, since the tree is -//! now considered to be in error. -//! -//! When the call to `process_obligations` completes, you get back an `Outcome`, -//! which includes two bits of information: -//! -//! - `completed`: a list of obligations where processing was fully -//! completed without error (meaning that all transitive subobligations -//! have also been completed). So, for example, if the callback from -//! `process_obligations` returns `Changed(C)` for some obligation `O`, -//! then `O` will be considered completed right away if `C` is the -//! empty vector. Otherwise it will only be considered completed once -//! all the obligations in `C` have been found completed. -//! - `errors`: a list of errors that occurred and associated backtraces -//! at the time of error, which can be used to give context to the user. -//! -//! Upon completion, none of the existing obligations were *shallowly -//! successful* (that is, no callback returned `Changed(_)`). This implies that -//! all obligations were either errors or returned an ambiguous result. -//! -//! ### Implementation details -//! -//! For the most part, comments specific to the implementation are in the -//! code. This file only contains a very high-level overview. Basically, -//! the forest is stored in a vector. Each element of the vector is a node -//! in some tree. Each node in the vector has the index of its dependents, -//! including the first dependent which is known as the parent. It also -//! has a current state, described by `NodeState`. After each processing -//! step, we compress the vector to remove completed and error nodes, which -//! aren't needed anymore. - -use crate::fx::{FxHashMap, FxHashSet}; - -use std::cell::Cell; -use std::collections::hash_map::Entry; -use std::fmt::Debug; -use std::hash; -use std::marker::PhantomData; - -mod graphviz; - -#[cfg(test)] -mod tests; - -pub trait ForestObligation: Clone + Debug { - type CacheKey: Clone + hash::Hash + Eq + Debug; - - /// Converts this `ForestObligation` suitable for use as a cache key. - /// If two distinct `ForestObligations`s return the same cache key, - /// then it must be sound to use the result of processing one obligation - /// (e.g. success for error) for the other obligation - fn as_cache_key(&self) -> Self::CacheKey; -} - -pub trait ObligationProcessor { - type Obligation: ForestObligation; - type Error: Debug; - type OUT: OutcomeTrait>; - - /// Implementations can provide a fast-path to obligation-processing - /// by counting the prefix of the passed iterator for which - /// `needs_process_obligation` would return false. - fn skippable_obligations<'a>( - &'a self, - _it: impl Iterator, - ) -> usize { - 0 - } - - fn needs_process_obligation(&self, _obligation: &Self::Obligation) -> bool; - - fn process_obligation( - &mut self, - obligation: &mut Self::Obligation, - ) -> ProcessResult; - - /// As we do the cycle check, we invoke this callback when we - /// encounter an actual cycle. `cycle` is an iterator that starts - /// at the start of the cycle in the stack and walks **toward the - /// top**. - /// - /// 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>, - ) -> Result<(), Self::Error> - where - I: Clone + Iterator; -} - -/// The result type used by `process_obligation`. -// `repr(C)` to inhibit the niche filling optimization. Otherwise, the `match` appearing -// in `process_obligations` is significantly slower, which can substantially affect -// benchmarks like `rustc-perf`'s inflate and keccak. -#[repr(C)] -#[derive(Debug)] -pub enum ProcessResult { - Unchanged, - Changed(Vec), - Error(E), -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] -struct ObligationTreeId(usize); - -type ObligationTreeIdGenerator = impl Iterator; - -pub struct ObligationForest { - /// The list of obligations. In between calls to [Self::process_obligations], - /// this list only contains nodes in the `Pending` or `Waiting` state. - /// - /// `usize` indices are used here and throughout this module, rather than - /// [`rustc_index::newtype_index!`] indices, because this code is hot enough - /// that the `u32`-to-`usize` conversions that would be required are - /// significant, and space considerations are not important. - nodes: Vec>, - - /// A cache of predicates that have been successfully completed. - done_cache: FxHashSet, - - /// A cache of the nodes in `nodes`, indexed by predicate. Unfortunately, - /// its contents are not guaranteed to match those of `nodes`. See the - /// comments in `Self::process_obligation` for details. - active_cache: FxHashMap, - - /// A vector reused in [Self::compress()] and [Self::find_cycles_from_node()], - /// to avoid allocating new vectors. - reused_node_vec: Vec, - - obligation_tree_id_generator: ObligationTreeIdGenerator, - - /// Per tree error cache. This is used to deduplicate errors, - /// which is necessary to avoid trait resolution overflow in - /// some cases. - /// - /// See [this][details] for details. - /// - /// [details]: https://github.com/rust-lang/rust/pull/53255#issuecomment-421184780 - error_cache: FxHashMap>, -} - -#[derive(Debug)] -struct Node { - obligation: O, - state: Cell, - - /// Obligations that depend on this obligation for their completion. They - /// must all be in a non-pending state. - dependents: Vec, - - /// If true, `dependents[0]` points to a "parent" node, which requires - /// special treatment upon error but is otherwise treated the same. - /// (It would be more idiomatic to store the parent node in a separate - /// `Option` field, but that slows down the common case of - /// iterating over the parent and other descendants together.) - has_parent: bool, - - /// Identifier of the obligation tree to which this node belongs. - obligation_tree_id: ObligationTreeId, -} - -impl Node { - fn new(parent: Option, obligation: O, obligation_tree_id: ObligationTreeId) -> Node { - Node { - obligation, - state: Cell::new(NodeState::Pending), - dependents: if let Some(parent_index) = parent { vec![parent_index] } else { vec![] }, - has_parent: parent.is_some(), - obligation_tree_id, - } - } -} - -/// The state of one node in some tree within the forest. This represents the -/// current state of processing for the obligation (of type `O`) associated -/// with this node. -/// -/// The non-`Error` state transitions are as follows. -/// ```text -/// (Pre-creation) -/// | -/// | register_obligation_at() (called by process_obligations() and -/// v from outside the crate) -/// Pending -/// | -/// | process_obligations() -/// v -/// Success -/// | ^ -/// | | mark_successes() -/// | v -/// | Waiting -/// | -/// | process_cycles() -/// v -/// Done -/// | -/// | compress() -/// v -/// (Removed) -/// ``` -/// The `Error` state can be introduced in several places, via `error_at()`. -/// -/// Outside of `ObligationForest` methods, nodes should be either `Pending` or -/// `Waiting`. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -enum NodeState { - /// This obligation has not yet been selected successfully. Cannot have - /// subobligations. - Pending, - - /// This obligation was selected successfully, but may or may not have - /// subobligations. - Success, - - /// This obligation was selected successfully, but it has a pending - /// subobligation. - Waiting, - - /// This obligation, along with its subobligations, are complete, and will - /// be removed in the next collection. - Done, - - /// This obligation was resolved to an error. It will be removed by the - /// next compression step. - Error, -} - -/// This trait allows us to have two different Outcome types: -/// - the normal one that does as little as possible -/// - one for tests that does some additional work and checking -pub trait OutcomeTrait { - type Error; - type Obligation; - - fn new() -> Self; - fn record_completed(&mut self, outcome: &Self::Obligation); - fn record_error(&mut self, error: Self::Error); -} - -#[derive(Debug)] -pub struct Outcome { - /// Backtrace of obligations that were found to be in error. - pub errors: Vec>, -} - -impl OutcomeTrait for Outcome { - type Error = Error; - type Obligation = O; - - fn new() -> Self { - Self { errors: vec![] } - } - - fn record_completed(&mut self, _outcome: &Self::Obligation) { - // do nothing - } - - fn record_error(&mut self, error: Self::Error) { - self.errors.push(error) - } -} - -#[derive(Debug, PartialEq, Eq)] -pub struct Error { - pub error: E, - pub backtrace: Vec, -} - -impl ObligationForest { - pub fn new() -> ObligationForest { - ObligationForest { - nodes: vec![], - done_cache: Default::default(), - active_cache: Default::default(), - reused_node_vec: vec![], - obligation_tree_id_generator: (0..).map(ObligationTreeId), - error_cache: Default::default(), - } - } - - /// Returns the total number of nodes in the forest that have not - /// yet been fully resolved. - pub fn len(&self) -> usize { - self.nodes.len() - } - - /// Registers an obligation. - pub fn register_obligation(&mut self, obligation: O) { - // Ignore errors here - there is no guarantee of success. - let _ = self.register_obligation_at(obligation, None); - } - - // Returns Err(()) if we already know this obligation failed. - fn register_obligation_at(&mut self, obligation: O, parent: Option) -> Result<(), ()> { - let cache_key = obligation.as_cache_key(); - if self.done_cache.contains(&cache_key) { - debug!("register_obligation_at: ignoring already done obligation: {:?}", obligation); - return Ok(()); - } - - match self.active_cache.entry(cache_key) { - Entry::Occupied(o) => { - let node = &mut self.nodes[*o.get()]; - if let Some(parent_index) = parent { - // If the node is already in `active_cache`, it has already - // had its chance to be marked with a parent. So if it's - // not already present, just dump `parent` into the - // dependents as a non-parent. - if !node.dependents.contains(&parent_index) { - node.dependents.push(parent_index); - } - } - if let NodeState::Error = node.state.get() { Err(()) } else { Ok(()) } - } - Entry::Vacant(v) => { - let obligation_tree_id = match parent { - Some(parent_index) => self.nodes[parent_index].obligation_tree_id, - None => self.obligation_tree_id_generator.next().unwrap(), - }; - - let already_failed = parent.is_some() - && self - .error_cache - .get(&obligation_tree_id) - .is_some_and(|errors| errors.contains(v.key())); - - if already_failed { - Err(()) - } else { - let new_index = self.nodes.len(); - v.insert(new_index); - self.nodes.push(Node::new(parent, obligation, obligation_tree_id)); - Ok(()) - } - } - } - } - - /// Converts all remaining obligations to the given error. - pub fn to_errors(&mut self, error: E) -> Vec> { - let errors = self - .nodes - .iter() - .enumerate() - .filter(|(_index, node)| node.state.get() == NodeState::Pending) - .map(|(index, _node)| Error { error: error.clone(), backtrace: self.error_at(index) }) - .collect(); - - self.compress(|_| assert!(false)); - errors - } - - /// Returns the set of obligations that are in a pending state. - pub fn map_pending_obligations(&self, f: F) -> Vec